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