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