1 /**
2     Grid list
3 
4     Copyright: (c) Enalye 2017
5     License: Zlib
6     Authors: Enalye
7 */
8 
9 module atelier.ui.list.gridlist;
10 
11 import std.conv : to;
12 import atelier.core, atelier.render, atelier.common;
13 import atelier.ui.gui_element, atelier.ui.container, atelier.ui.slider;
14 
15 private final class ListContainer : GuiElement {
16     public {
17         GridContainer container;
18     }
19 
20     this(Vec2f sz) {
21         isLocked = true;
22         container = new GridContainer;
23         size(sz);
24         appendChild(container);
25         hasCanvas(true);
26     }
27 }
28 
29 class GridList : GuiElement {
30     protected {
31         ListContainer _container;
32         Slider _slider;
33         Vec2f _lastMousePos = Vec2f.zero;
34         float _layoutLength = 25f;
35         int _nbElements;
36         int _idElementSelected;
37     }
38 
39     @property {
40         /// The ID of the child that has been selected.
41         int selected() const {
42             return _idElementSelected;
43         }
44         /// Ditto
45         int selected(int id) {
46             if (id >= _nbElements)
47                 id = _nbElements - 1;
48             if (id < 0)
49                 id = 0;
50             _idElementSelected = id;
51 
52             //Update children
53             auto widgets = _container.container.children;
54             foreach (GuiElement gui; _container.container.children)
55                 gui.isSelected = false;
56             if (_idElementSelected < widgets.length)
57                 widgets[_idElementSelected].isSelected = true;
58             return _idElementSelected;
59         }
60 
61         /// Height of a single child.
62         float layoutLength() const {
63             return _layoutLength;
64         }
65         /// Ditto
66         float layoutLength(float length) {
67             _layoutLength = length;
68             _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
69             return _layoutLength;
70         }
71 
72         /// The number of children per line.
73         uint maxElementsPerLine() const {
74             return _container.container.maxElementsPerLine;
75         }
76         /// Ditto
77         uint maxElementsPerLine(uint maxElementsPerLine_) {
78             return _container.container.maxElementsPerLine = maxElementsPerLine_;
79         }
80 
81         /// The list of all its children.
82         override const(GuiElement[]) children() const {
83             return _container.container.children;
84         }
85         /// Ditto
86         override GuiElement[] children() {
87             return _container.container.children;
88         }
89 
90         /// Return the first child gui.
91         override GuiElement firstChild() {
92             return _container.container.firstChild;
93         }
94 
95         /// Return the last child gui.
96         override GuiElement lastChild() {
97             return _container.container.lastChild;
98         }
99 
100         /// The number of children it currently has.
101         override size_t childCount() const {
102             return _container.container.childCount;
103         }
104     }
105 
106     /// Ctor.
107     this(Vec2f sz) {
108         isLocked = true;
109         _slider = new VScrollbar;
110         _slider.setAlign(GuiAlignX.left, GuiAlignY.center);
111         _container = new ListContainer(sz);
112         _container.setAlign(GuiAlignX.left, GuiAlignY.top);
113         _container.container.setAlign(GuiAlignX.left, GuiAlignY.top);
114 
115         super.appendChild(_slider);
116         super.appendChild(_container);
117 
118         size(sz);
119         position(Vec2f.zero);
120 
121         setEventHook(true);
122 
123         _container.container.size = Vec2f(_container.size.x, 0f);
124     }
125 
126     override void onCallback(string id) {
127         if (id != "list")
128             return;
129         auto widgets = _container.container.children;
130         foreach (size_t elementId, ref GuiElement gui; _container.container.children) {
131             gui.isSelected = false;
132             if (gui.isHovered)
133                 _idElementSelected = cast(uint) elementId;
134         }
135         if (_idElementSelected < widgets.length)
136             widgets[_idElementSelected].isSelected = true;
137     }
138 
139     override void onEvent(Event event) {
140         if (event.type == Event.Type.mouseWheel)
141             _slider.onEvent(event);
142     }
143 
144     override void onSize() {
145         _slider.size = Vec2f(10f, _size.y);
146         _container.position = Vec2f(_slider.size.x, 0f);
147         _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
148         _container.size = Vec2f(size.x - _slider.size.x, size.y);
149         _container.canvas.renderSize = _container.size.to!Vec2i;
150     }
151 
152     override void update(float deltaTime) {
153         super.update(deltaTime);
154         const float min = 0f;
155         const float max = _container.container.size.y - _container.size.y;
156         const float exceedingHeight = _container.container.size.y - _container.canvas.size.y;
157 
158         if (exceedingHeight < 0f) {
159             _slider.max = 0;
160             _slider.step = 0;
161         }
162         else {
163             _slider.max = exceedingHeight / _layoutLength;
164             _slider.step = to!uint(_slider.max);
165         }
166         _container.canvas.position = _container.canvas.size / 2f + Vec2f(0f,
167                 lerp(min, max, _slider.offset));
168     }
169 
170     override void prependChild(GuiElement gui) {
171         gui.position = Vec2f.zero;
172         gui.isSelected = (_nbElements == 0u);
173         gui.setCallback(this, "list");
174 
175         _nbElements++;
176         _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
177         _container.container.position = Vec2f.zero;
178         _container.container.prependChild(gui);
179     }
180 
181     override void appendChild(GuiElement gui) {
182         gui.position = Vec2f.zero;
183         gui.isSelected = (_nbElements == 0u);
184         gui.setCallback(this, "list");
185 
186         _nbElements++;
187         _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
188         _container.container.position = Vec2f.zero;
189         _container.container.appendChild(gui);
190     }
191 
192     override void removeChildren() {
193         _nbElements = 0u;
194         _idElementSelected = 0u;
195         _container.container.size = Vec2f(_container.size.x, 0f);
196         _container.container.position = Vec2f.zero;
197         _container.container.removeChildren();
198     }
199 
200     override void removeChild(size_t id) {
201         _container.container.removeChild(id);
202         _nbElements = cast(int) _container.container.childCount;
203         _idElementSelected = 0u;
204         _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
205         _container.container.position = Vec2f(0f, _container.container.size.y / 2f);
206     }
207     
208     override void removeChild(GuiElement gui) {
209         _container.container.removeChild(gui);
210         _nbElements = cast(int) _container.container.childCount;
211         _idElementSelected = 0u;
212         _container.container.size = Vec2f(_container.size.x, _layoutLength * _nbElements);
213         _container.container.position = Vec2f(0f, _container.container.size.y / 2f);
214     }
215 }