1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "GUI/BsGUIListBox.h" |
4 | #include "GUI/BsGUIWidget.h" |
5 | #include "GUI/BsGUIDimensions.h" |
6 | #include "GUI/BsGUIMouseEvent.h" |
7 | #include "GUI/BsGUIManager.h" |
8 | #include "GUI/BsGUIDropDownBoxManager.h" |
9 | |
10 | namespace bs |
11 | { |
12 | const String& GUIListBox::getGUITypeName() |
13 | { |
14 | static String name = "ListBox" ; |
15 | return name; |
16 | } |
17 | |
18 | GUIListBox::GUIListBox(const String& styleName, const Vector<HString>& elements, bool isMultiselect, const GUIDimensions& dimensions) |
19 | :GUIButtonBase(styleName, GUIContent(HString("" )), dimensions), mElements(elements), mIsMultiselect(isMultiselect) |
20 | { |
21 | mElementStates.resize(elements.size(), false); |
22 | if (!mIsMultiselect && mElementStates.size() > 0) |
23 | mElementStates[0] = true; |
24 | |
25 | updateContents(); |
26 | } |
27 | |
28 | GUIListBox::~GUIListBox() |
29 | { |
30 | closeListBox(); |
31 | } |
32 | |
33 | GUIListBox* GUIListBox::create(const Vector<HString>& elements, bool isMultiselect, const String& styleName) |
34 | { |
35 | return new (bs_alloc<GUIListBox>()) GUIListBox(getStyleName<GUIListBox>(styleName), elements, isMultiselect, GUIDimensions::create()); |
36 | } |
37 | |
38 | GUIListBox* GUIListBox::create(const Vector<HString>& elements, bool isMultiselect, const GUIOptions& options, const String& styleName) |
39 | { |
40 | return new (bs_alloc<GUIListBox>()) GUIListBox(getStyleName<GUIListBox>(styleName), elements, isMultiselect, GUIDimensions::create(options)); |
41 | } |
42 | |
43 | GUIListBox* GUIListBox::create(const Vector<HString>& elements, const GUIOptions& options, const String& styleName) |
44 | { |
45 | return new (bs_alloc<GUIListBox>()) GUIListBox(getStyleName<GUIListBox>(styleName), elements, false, GUIDimensions::create(options)); |
46 | } |
47 | |
48 | void GUIListBox::setElements(const Vector<HString>& elements) |
49 | { |
50 | bool wasOpen = mDropDownBox != nullptr; |
51 | |
52 | if(wasOpen) |
53 | closeListBox(); |
54 | |
55 | mElements = elements; |
56 | |
57 | mElementStates.clear(); |
58 | mElementStates.resize(mElements.size(), false); |
59 | if (!mIsMultiselect && mElementStates.size() > 0) |
60 | mElementStates[0] = true; |
61 | |
62 | updateContents(); |
63 | |
64 | if(wasOpen) |
65 | openListBox(); |
66 | } |
67 | |
68 | void GUIListBox::selectElement(UINT32 idx) |
69 | { |
70 | if (idx >= (UINT32)mElements.size()) |
71 | return; |
72 | |
73 | if (mElementStates[idx] != true) |
74 | elementSelected(idx); |
75 | } |
76 | |
77 | void GUIListBox::deselectElement(UINT32 idx) |
78 | { |
79 | if (!mIsMultiselect || idx >= (UINT32)mElements.size()) |
80 | return; |
81 | |
82 | if (mElementStates[idx] != false) |
83 | elementSelected(idx); |
84 | } |
85 | |
86 | void GUIListBox::setElementStates(const Vector<bool>& states) |
87 | { |
88 | UINT32 numElements = (UINT32)mElementStates.size(); |
89 | UINT32 min = std::min(numElements, (UINT32)states.size()); |
90 | |
91 | bool anythingModified = min != numElements; |
92 | if (!anythingModified) |
93 | { |
94 | for (UINT32 i = 0; i < numElements; i++) |
95 | { |
96 | if (mElementStates[i] != states[i]) |
97 | { |
98 | anythingModified = true; |
99 | break; |
100 | } |
101 | } |
102 | } |
103 | |
104 | if (!anythingModified) |
105 | return; |
106 | |
107 | bool wasOpen = mDropDownBox != nullptr; |
108 | |
109 | if (wasOpen) |
110 | closeListBox(); |
111 | |
112 | for (UINT32 i = 0; i < min; i++) |
113 | { |
114 | mElementStates[i] = states[i]; |
115 | |
116 | if (mElementStates[i] && !mIsMultiselect) |
117 | { |
118 | for (UINT32 j = i + 1; j < numElements; j++) |
119 | mElementStates[j] = false; |
120 | |
121 | break; |
122 | } |
123 | } |
124 | |
125 | updateContents(); |
126 | |
127 | if (wasOpen) |
128 | openListBox(); |
129 | } |
130 | |
131 | bool GUIListBox::_mouseEvent(const GUIMouseEvent& ev) |
132 | { |
133 | bool processed = GUIButtonBase::_mouseEvent(ev); |
134 | |
135 | if(ev.getType() == GUIMouseEventType::MouseDown) |
136 | { |
137 | if (!_isDisabled()) |
138 | { |
139 | if (mDropDownBox == nullptr) |
140 | openListBox(); |
141 | else |
142 | closeListBox(); |
143 | } |
144 | |
145 | processed = true; |
146 | } |
147 | |
148 | return processed; |
149 | } |
150 | |
151 | bool GUIListBox::_commandEvent(const GUICommandEvent& ev) |
152 | { |
153 | const bool processed = GUIButtonBase::_commandEvent(ev); |
154 | |
155 | if(ev.getType() == GUICommandEventType::Confirm) |
156 | { |
157 | if(!_isDisabled()) |
158 | { |
159 | if (mDropDownBox == nullptr) |
160 | openListBox(); |
161 | else |
162 | closeListBox(); |
163 | } |
164 | |
165 | return true; |
166 | } |
167 | |
168 | return processed; |
169 | } |
170 | |
171 | void GUIListBox::elementSelected(UINT32 idx) |
172 | { |
173 | if (idx >= (UINT32)mElements.size()) |
174 | return; |
175 | |
176 | if (mIsMultiselect) |
177 | { |
178 | bool selected = mElementStates[idx]; |
179 | mElementStates[idx] = !selected; |
180 | |
181 | if (!onSelectionToggled.empty()) |
182 | onSelectionToggled(idx, !selected); |
183 | } |
184 | else |
185 | { |
186 | for (UINT32 i = 0; i < (UINT32)mElementStates.size(); i++) |
187 | mElementStates[i] = false; |
188 | |
189 | mElementStates[idx] = true; |
190 | |
191 | if (!onSelectionToggled.empty()) |
192 | onSelectionToggled(idx, true); |
193 | |
194 | closeListBox(); |
195 | } |
196 | |
197 | updateContents(); |
198 | } |
199 | |
200 | void GUIListBox::openListBox() |
201 | { |
202 | closeListBox(); |
203 | |
204 | DROP_DOWN_BOX_DESC desc; |
205 | |
206 | UINT32 i = 0; |
207 | for(auto& elem : mElements) |
208 | { |
209 | String identifier = toString(i); |
210 | desc.dropDownData.entries.push_back(GUIDropDownDataEntry::button(identifier, std::bind(&GUIListBox::elementSelected, this, i))); |
211 | desc.dropDownData.localizedNames[identifier] = elem; |
212 | i++; |
213 | } |
214 | |
215 | GUIWidget* widget = _getParentWidget(); |
216 | |
217 | desc.camera = widget->getCamera(); |
218 | desc.skin = widget->getSkinResource(); |
219 | desc.placement = DropDownAreaPlacement::aroundBoundsHorz(mClippedBounds); |
220 | desc.dropDownData.states = mElementStates; |
221 | |
222 | GUIDropDownType type; |
223 | if (mIsMultiselect) |
224 | type = GUIDropDownType::MultiListBox; |
225 | else |
226 | type = GUIDropDownType::ListBox; |
227 | |
228 | mDropDownBox = GUIDropDownBoxManager::instance().openDropDownBox( |
229 | desc, type, std::bind(&GUIListBox::onListBoxClosed, this)); |
230 | |
231 | _setOn(true); |
232 | } |
233 | |
234 | void GUIListBox::closeListBox() |
235 | { |
236 | if (mDropDownBox != nullptr) |
237 | { |
238 | GUIDropDownBoxManager::instance().closeDropDownBox(); |
239 | |
240 | _setOn(false); |
241 | mDropDownBox = nullptr; |
242 | } |
243 | } |
244 | |
245 | void GUIListBox::updateContents() |
246 | { |
247 | UINT32 selectedIdx = 0; |
248 | UINT32 numSelected = 0; |
249 | for (UINT32 i = 0; i < (UINT32)mElementStates.size(); i++) |
250 | { |
251 | if (mElementStates[i]) |
252 | { |
253 | selectedIdx = i; |
254 | numSelected++; |
255 | } |
256 | } |
257 | |
258 | if (mIsMultiselect) |
259 | { |
260 | if (numSelected == 1) |
261 | setContent(GUIContent(mElements[selectedIdx])); |
262 | else if (numSelected == 0) |
263 | setContent(GUIContent(HEString("None" ))); |
264 | else |
265 | setContent(GUIContent(HEString("Multiple" ))); |
266 | } |
267 | else |
268 | { |
269 | if(!mElements.empty()) |
270 | setContent(GUIContent(mElements[selectedIdx])); |
271 | else |
272 | setContent(GUIContent(HEString("None" ))); |
273 | } |
274 | } |
275 | |
276 | void GUIListBox::onListBoxClosed() |
277 | { |
278 | _setOn(false); |
279 | mDropDownBox = nullptr; |
280 | } |
281 | } |