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 }