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 }