1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.widget.input.select; 8 import w4d.parser.colorset, 9 w4d.style.rect, 10 w4d.style.scalar, 11 w4d.task.window, 12 w4d.widget.popup.menu, 13 w4d.widget.base, 14 w4d.widget.panel, 15 w4d.event, 16 w4d.exception; 17 import g4d.glfw.cursor; 18 import gl3n.linalg; 19 20 /// A handler that handles changing selection. 21 alias SelectChanged = EventHandler!( void, int ); 22 23 /// A widget of select input. 24 class SelectInputWidget : PanelWidget 25 { 26 protected class CustomPopupMenuWidget : PopupMenuWidget 27 { 28 override void handlePopup ( bool opened, WindowContext ctx ) 29 { 30 super.handlePopup( opened, ctx ); 31 _menuOpened = opened; 32 } 33 this () 34 { 35 super(); 36 } 37 } 38 39 protected CustomPopupMenuWidget _menu; 40 protected Widget _selected; 41 protected bool _menuOpened; 42 43 /// 44 override @property Widget[] children () 45 { 46 if ( _menuOpened ) return []; 47 return _selected? [_selected]: []; 48 } 49 50 /// 51 override bool handleMouseButton ( MouseButton btn, bool status, vec2 pos ) 52 { 53 if ( super.handleMouseButton(btn,status,pos) ) return true; 54 55 if ( !style.isPointInside( pos ) ) return false; 56 if ( btn == MouseButton.Left && !status ) { 57 openMenu(); 58 return true; 59 } 60 return false; 61 } 62 63 /// 64 override @property const(Cursor) cursor () 65 { 66 return Cursor.Hand; 67 } 68 69 /// 70 this () 71 { 72 super(); 73 _menu = new CustomPopupMenuWidget; 74 _selected = null; 75 _menuOpened = false; 76 77 parseColorSetsFromFile!"colorset/selectinput.yaml"( style ); 78 style.box.borderWidth = Rect(1.pixel); 79 style.box.paddings = Rect(1.mm); 80 style.box.margins = Rect(1.mm); 81 } 82 83 /// Changes selection. 84 void select ( MenuItemWidget s ) 85 { 86 _selected = s.child; 87 _selected.requestLayout(); 88 } 89 /// Opens select menu. 90 void openMenu () 91 { 92 enforce( _context, "WindowContext is null." ); 93 94 auto size = style.box.borderInsideSize; 95 auto late = style.box.borderInsideLeftTop; 96 late.y += size.y; 97 late += style.translate; 98 99 if ( _selected ) _selected.requestLayout(); 100 101 _context.setPopup( _menu ); 102 _menu.move( late, vec2( size.x, 0 ) ); 103 } 104 105 /// Adds an itme. 106 void addItem ( MenuItemWidget i ) 107 { 108 i.onPress = () { 109 select( i ); 110 return true; 111 }; 112 _menu.addItem( i ); 113 } 114 /// Removes an item. 115 void removeItem ( MenuItemWidget i ) 116 { 117 _menu.removeItem( i ); 118 } 119 /// Removes all items. 120 void removeAllItems () 121 { 122 _menu.removeAllItems(); 123 } 124 125 /// 126 override @property bool trackable () { return true; } 127 /// 128 override @property bool focusable () { return true; } 129 }