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 }