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 w )
29         {
30             if ( !opened ) {
31                 .SelectInputWidget.requestLayout();
32             }
33             super.handlePopup( opened, w );
34         }
35         this ()
36         {
37             super();
38         }
39     }
40 
41     protected CustomPopupMenuWidget _menu;
42     protected Widget                _selected;
43 
44     ///
45     override @property Widget[] children ()
46     {
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 
76         parseColorSetsFromFile!"colorset/selectinput.yaml"( style );
77         style.box.borderWidth = Rect(1.pixel);
78         style.box.paddings    = Rect(1.mm);
79         style.box.margins     = Rect(1.mm);
80     }
81 
82     /// Changes selection.
83     void select ( MenuItemWidget s )
84     {
85         _selected = s.child;
86         requestLayout();
87     }
88     /// Opens select menu.
89     void openMenu ()
90     {
91         enforce( _context, "WindowContext is null." );
92 
93         auto size = style.box.borderInsideSize;
94         auto late = style.box.borderInsideLeftTop;
95         late.y   += size.y;
96         late     += style.translate;
97 
98         _context.setPopup( _menu );
99         _menu.move( late, vec2( size.x, 0 ) );
100     }
101 
102     /// Adds an itme.
103     void addItem ( MenuItemWidget i )
104     {
105         i.onPress = () {
106             select( i );
107             return true;
108         };
109         _menu.addItem( i );
110     }
111     /// Removes an item.
112     void removeItem ( MenuItemWidget i )
113     {
114         _menu.removeItem( i );
115     }
116     /// Removes all items.
117     void removeAllItems ()
118     {
119         _menu.removeAllItems();
120     }
121 
122     ///
123     override @property bool trackable () { return true; }
124     ///
125     override @property bool focusable () { return true; }
126 }