TDME2 1.9.121
GUISelectBoxController.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <unordered_set>
5
6#include <tdme/tdme.h>
17#include <tdme/gui/GUI.h>
21
22
23using std::count;
24using std::unordered_set;
25
37using tdme::gui::GUI;
41
42string GUISelectBoxController::CONDITION_DISABLED = "disabled";
43string GUISelectBoxController::CONDITION_ENABLED = "enabled";
44
45GUISelectBoxController::GUISelectBoxController(GUINode* node)
47{
48 this->disabled = required_dynamic_cast<GUIElementNode*>(node)->isDisabled();
49 this->multipleSelection = required_dynamic_cast<GUIElementNode*>(node)->hasOption("multiple");
50 this->keyControl = false;
51 this->focussedOptionIdx = -1;
52}
53
55 return multipleSelection;
56}
57
59 return keyControl;
60}
61
63{
64 GUIElementController::initialize();
65 value.reset();
67 for (auto selectBoxOptionController: selectBoxOptionControllers) {
68 if (selectBoxOptionController->isSelected() == false) continue;
69 if (multipleSelection == true) {
70 if (value.empty() == true) {
72 }
73 value.append(required_dynamic_cast<GUIElementNode*>(selectBoxOptionController->getNode())->getValue());
75 } else {
76 value.set(required_dynamic_cast<GUIElementNode*>(selectBoxOptionController->getNode())->getValue());
77 }
78 }
81}
82
84{
85 GUIElementController::dispose();
86}
87
89{
90}
91
93{
94 if (selectBoxOptionControllers.empty() == true) {
96 } else
97 if (focussedOptionIdx == -1) {
99 } else
100 if (focussedOptionIdx < 0) {
102 } else
105 }
106 return focussedOptionIdx;
107}
108
110 auto optionElementNodeController = optionElementNode->getController();
111 for (auto i = 0; i < selectBoxOptionControllers.size(); i++) {
112 if (selectBoxOptionControllers[i] == optionElementNodeController) return i;
113 }
114 return -1;
115}
116
118{
120 auto optionIdx = getFocussedOptionIdx();
121 if (optionIdx == -1) return;
122 selectBoxOptionControllers[optionIdx]->unselect();
123}
124
126 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
127 if (multipleSelection == true) {
128 for (auto selectBoxOptionController: selectBoxOptionControllers) selectBoxOptionController->unselect();
129 }
130 selectBoxOptionControllers[optionIdx]->select();
131 value.reset();
133 value.append(required_dynamic_cast<GUIElementNode*>(selectBoxOptionControllers[optionIdx]->getNode())->getValue());
135}
136
138 auto optionIdx = getOptionIdx(optionElementNode);
139 if (optionIdx == -1) return;
140 select(optionIdx);
141}
142
144{
145 auto optionIdx = getFocussedOptionIdx();
146 if (optionIdx == -1) return;
147 selectBoxOptionControllers[optionIdx]->unfocus();
148}
149
151{
152 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
153 selectBoxOptionControllers[optionIdx]->focus();
154 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeX(required_dynamic_cast<GUIParentNode*>(node));
155 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeY(required_dynamic_cast<GUIParentNode*>(node));
156 focussedOptionIdx = optionIdx;
157}
158
160{
161 auto optionIdx = getOptionIdx(optionElementNode);
162 if (optionIdx == -1) return;
163 focus(optionIdx);
164}
165
167{
169}
170
172{
173 auto optionIdx = getFocussedOptionIdx();
174 if (optionIdx == -1) return;
175
176 unfocus();
177
178 auto disabledCount = 0;
179 while (disabledCount < selectBoxOptionControllers.size()) {
180 if (++optionIdx >= selectBoxOptionControllers.size()) optionIdx = selectBoxOptionControllers.size() - 1;
181 if (selectBoxOptionControllers[optionIdx]->isDisabled() == false) break;
182 disabledCount++;
183 }
184 if (disabledCount == selectBoxOptionControllers.size()) {
185 optionIdx = -1;
186 return;
187 }
188
189 focus(optionIdx);
190}
191
193{
194 auto optionIdx = getFocussedOptionIdx();
195 if (optionIdx == -1) return;
196
197 unfocus();
198
199 auto disabledCount = 0;
200 while (disabledCount < selectBoxOptionControllers.size()) {
201 if (--optionIdx < 0) optionIdx = 0;
202 if (selectBoxOptionControllers[optionIdx]->isDisabled() == false) break;
203 disabledCount++;
204 }
205 if (disabledCount == selectBoxOptionControllers.size()) {
206 optionIdx = -1;
207 return;
208 }
209
210 focus(optionIdx);
211}
212
214{
215 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
216 selectBoxOptionControllers[optionIdx]->toggle();
217 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeX(required_dynamic_cast<GUIParentNode*>(node));
218 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeY(required_dynamic_cast<GUIParentNode*>(node));
219 string selectionValue;
220 selectionValue+= VALUE_DELIMITER;
221 selectionValue+= required_dynamic_cast<GUIElementNode*>(selectBoxOptionControllers[optionIdx]->getNode())->getValue();
222 selectionValue+= VALUE_DELIMITER;
223 if (selectBoxOptionControllers[optionIdx]->isSelected() == true) {
224 value.append(value.getString().empty() == false?selectionValue.substr(1):selectionValue);
225 } else {
226 value.replace(selectionValue, "|");
227 if (value.equals("|") == true) value.reset();
228 }
229}
230
232{
233 auto optionIdx = getOptionIdx(optionElementNode);
234 if (optionIdx == -1) return;
235 toggle(optionIdx);
236}
237
239{
240 auto optionIdx = getFocussedOptionIdx();
241 if (optionIdx == -1) return;
242 selectBoxOptionControllers[optionIdx]->select();
243 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeX(required_dynamic_cast<GUIParentNode*>(node));
244 selectBoxOptionControllers[optionIdx]->getNode()->scrollToNodeY(required_dynamic_cast<GUIParentNode*>(node));
245}
246
248 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
249
250 auto selectBoxParentOptionController = dynamic_cast<GUISelectBoxParentOptionController*>(selectBoxOptionControllers[optionIdx]);
251 if (selectBoxParentOptionController != nullptr) selectBoxParentOptionController->toggleExpandState();
252
253 // TODO: this is a workaround, actually due to condition updates, the relayout should happen automatically
255}
256
258 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
259
260 auto selectBoxParentOptionController = dynamic_cast<GUISelectBoxParentOptionController*>(selectBoxOptionControllers[optionIdx]);
261 if (selectBoxParentOptionController != nullptr) {
262 if (selectBoxParentOptionController->isExpanded() == false) selectBoxParentOptionController->toggleExpandState();
263 }
264
265 // TODO: this is a workaround, actually due to condition updates, the relayout should happen automatically
267}
268
270 if (optionIdx < 0 || optionIdx >= selectBoxOptionControllers.size()) return;
271
272 auto selectBoxParentOptionController = dynamic_cast<GUISelectBoxParentOptionController*>(selectBoxOptionControllers[optionIdx]);
273 if (selectBoxParentOptionController != nullptr) {
274 if (selectBoxParentOptionController->isExpanded() == true) selectBoxParentOptionController->toggleExpandState();
275 }
276
277 // TODO: this is a workaround, actually due to condition updates, the relayout should happen automatically
279}
280
282 auto optionIdx = getOptionIdx(optionElementNode);
283 if (optionIdx == -1) return;
284
285 toggleOpenState(optionIdx);
286
288}
289
291 vector<GUINode*> childControllerNodes;
292 //
293 required_dynamic_cast<GUIParentNode*>(node)->getChildControllerNodes(childControllerNodes);
294 //
296 for (auto i = 0; i < childControllerNodes.size(); i++) {
297 auto childControllerNode = childControllerNodes[i];
298 auto childController = childControllerNode->getController();
299 auto selectBoxOptionController = dynamic_cast<GUISelectBoxOptionController*>(childController);
300 if (selectBoxOptionController != nullptr) {
301 selectBoxOptionControllers.push_back(selectBoxOptionController);
302 }
303 }
304}
305
307 vector<GUINode*> childControllerNodes;
308 //
309 required_dynamic_cast<GUIParentNode*>(node)->getChildControllerNodes(childControllerNodes);
310 //
312 for (auto i = 0; i < childControllerNodes.size(); i++) {
313 auto childControllerNode = childControllerNodes[i];
314 auto childController = childControllerNode->getController();
315 auto selectBoxOptionController = dynamic_cast<GUISelectBoxOptionController*>(childController);
316 if (selectBoxOptionController != nullptr && selectBoxOptionController->isHierarchyExpanded() == true) {
317 selectBoxOptionControllers.push_back(selectBoxOptionController);
318 }
319 }
321}
322
324 vector<GUINode*> childControllerNodes;
325 //
326 required_dynamic_cast<GUIParentNode*>(node)->getChildControllerNodes(childControllerNodes);
327 //
329 for (auto i = 0; i < childControllerNodes.size(); i++) {
330 auto childControllerNode = childControllerNodes[i];
331 auto childController = childControllerNode->getController();
332 auto selectBoxParentOptionController = dynamic_cast<GUISelectBoxParentOptionController*>(childController);
333 if (selectBoxParentOptionController != nullptr) {
334 selectBoxOptionControllers.push_back(selectBoxParentOptionController);
335 }
336 }
337}
338
340{
341 GUIElementController::handleMouseEvent(node, event);
342 auto disabled = required_dynamic_cast<GUISelectBoxController*>(this->node->getController())->isDisabled();
343 if (disabled == false && node == this->node && node->isEventBelongingToNode(event) && event->getButton() == MOUSE_BUTTON_LEFT) {
344 if (event->getType() == GUIMouseEvent::MOUSEEVENT_PRESSED) {
345 node->getScreenNode()->getGUI()->setFoccussedNode(required_dynamic_cast<GUIElementNode*>(node));
346 }
347 }
348}
349
351{
352 GUIElementController::handleKeyboardEvent(event);
353 if (disabled == false) {
354 if (event->getType() != GUIKeyboardEvent::KEYBOARDEVENT_KEY_TYPED) {
355 auto isKeyDown = event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED;
356 if (event->getKeyCode() == KEYBOARD_KEYCODE_LEFT_CTRL) keyControl = isKeyDown;
357 }
358
359 switch (event->getKeyCode()) {
360 case GUIKeyboardEvent::KEYCODE_UP: {
361 event->setProcessed(true);
362 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED) {
363 if (multipleSelection == false) {
364 unselect();
365 }
367 if (multipleSelection == false) {
369 }
370 } else
371 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_RELEASED) {
372 node->getScreenNode()->delegateValueChanged(required_dynamic_cast<GUIElementNode*>(node));
373 }
374 }
375 break;
376 case GUIKeyboardEvent::KEYCODE_DOWN: {
377 event->setProcessed(true);
378 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED) {
379 if (multipleSelection == false) {
380 unselect();
381 }
382 focusNext();
383 if (multipleSelection == false) {
385 }
386 } else
387 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_RELEASED) {
388 node->getScreenNode()->delegateValueChanged(required_dynamic_cast<GUIElementNode*>(node));
389 }
390 }
391 break;
392 case GUIKeyboardEvent::KEYCODE_RIGHT:
393 event->setProcessed(true);
394 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED) {
397 }
398 break;
399 case GUIKeyboardEvent::KEYCODE_LEFT: {
400 event->setProcessed(true);
401 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED) {
404 }
405 }
406 break;
407 case GUIKeyboardEvent::KEYCODE_SPACE: {
408 event->setProcessed(true);
409 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED) {
410 if (multipleSelection == true) {
412 }
413 } else
414 if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_RELEASED) {
415 node->getScreenNode()->delegateValueChanged(required_dynamic_cast<GUIElementNode*>(node));
416 }
417 }
418 break;
419 }
420 }
421}
422
424{
425 GUIElementController::tick();
426}
427
429{
430}
431
433{
434 keyControl = false;
435}
436
438{
439 return true;
440}
441
443{
444 // check if single value
445 if (multipleSelection == true &&
446 count(value.getString().begin(), value.getString().end(), '|') == 2) {
447 singleValue.set(StringTools::substring(value.getString(), 1, value.getString().size() - 1));
448 return singleValue;
449 }
450 // nope, take multiple value
451 return value;
452}
453
455{
456 unfocus();
458 unordered_set<string> valueSet;
459 StringTokenizer valueTokenizer;
460 valueTokenizer.tokenize(value.getString(), "|");
461 while (valueTokenizer.hasMoreTokens()) {
462 valueSet.insert(valueTokenizer.nextToken());
463 }
464 MutableString searchValue;
465 GUISelectBoxOptionController* selectBoxOptionNodeControllerLast = nullptr;
466 // TODO: actually we should rebuild value to remove options that have not been found
467 for (auto i = 0; i < selectBoxOptionControllers.size(); i++) {
468 auto selectBoxOptionController = selectBoxOptionControllers[i];
469 auto selectBoxOptionNode = required_dynamic_cast<GUIElementNode*>(selectBoxOptionController->getNode());
470 auto optionValue = selectBoxOptionNode->getValue();
471 if (selectBoxOptionController->isSelected() == true) selectBoxOptionController->unselect();
472 if (selectBoxOptionController->isFocussed() == true) selectBoxOptionController->unfocus();
473 if (valueSet.find(optionValue) != valueSet.end()) {
474 selectBoxOptionController->expandHierarchy();
475 if (multipleSelection == true) toggle(i);
476 selectBoxOptionNodeControllerLast = selectBoxOptionController;
477 }
478 }
480 if (selectBoxOptionNodeControllerLast != nullptr) {
481 if (multipleSelection == false) select(required_dynamic_cast<GUIElementNode*>(selectBoxOptionNodeControllerLast->getNode()));
482 focus(required_dynamic_cast<GUIElementNode*>(selectBoxOptionNodeControllerLast->getNode()));
483 selectBoxOptionNodeControllerLast->getNode()->scrollToNodeX(required_dynamic_cast<GUIParentNode*>(node));
484 selectBoxOptionNodeControllerLast->getNode()->scrollToNodeY(required_dynamic_cast<GUIParentNode*>(node));
485 } else
486 if (selectBoxOptionControllers.empty() == false) {
487 auto selectBoxOptionController = selectBoxOptionControllers[0];
488 auto selectBoxOptionNode = required_dynamic_cast<GUIElementNode*>(selectBoxOptionController->getNode());
489 select(0);
490 focus(0);
491 selectBoxOptionNode->scrollToNodeX(required_dynamic_cast<GUIParentNode*>(node));
492 selectBoxOptionNode->scrollToNodeY(required_dynamic_cast<GUIParentNode*>(node));
493 }
494 // TODO: this is a workaround, actually due to condition updates, the relayout should happen automatically
496 //
497 this->value.reset();
498 for (auto& valueSetValue: valueSet) {
499 this->value.append(VALUE_DELIMITER);
500 this->value.append(valueSetValue);
501 }
502 if (valueSet.empty() == false) this->value.append(VALUE_DELIMITER);
503}
504
507}
508
509void GUISelectBoxController::determineExpandedParentOptionValues(vector<string>& expandedParentOptionValues) {
510 expandedParentOptionValues.clear();
512 for (auto selectBoxParentOptionController: selectBoxOptionControllers) {
513 if (required_dynamic_cast<GUISelectBoxParentOptionController*>(selectBoxParentOptionController)->isExpanded() == true) {
514 expandedParentOptionValues.push_back(required_dynamic_cast<GUIElementNode*>(selectBoxParentOptionController->getNode())->getValue());
515 }
516 }
518}
519
520void GUISelectBoxController::expandParentOptionsByValues(const vector<string>& expandedParentOptionValues) {
522 for (auto& expandedParentOptionValue: expandedParentOptionValues) {
523 for (auto selectBoxParentOptionController: selectBoxOptionControllers) {
524 if (expandedParentOptionValue == required_dynamic_cast<GUIElementNode*>(selectBoxParentOptionController->getNode())->getValue()) {
525 auto parentOptionNodeController = required_dynamic_cast<GUISelectBoxParentOptionController*>(selectBoxParentOptionController);
526 if (parentOptionNodeController->isExpanded() == false) parentOptionNodeController->toggleExpandState();
527 }
528 }
529 }
531 // TODO: this is a workaround, actually due to condition updates, the relayout should happen automatically
533}
#define KEYBOARD_KEYCODE_LEFT_CTRL
#define MOUSE_BUTTON_LEFT
GUI module class.
Definition: GUI.h:66
void setFoccussedNode(GUIElementNode *newFoccussedNode)
Set focussed node.
Definition: GUI.cpp:359
void dispose() override
Dispose controller.
void postLayout() override
Post layout event.
void determineExpandedParentOptionValues(vector< string > &expandedParentOptionValues)
Determine expanded parent option values.
static STATIC_DLL_IMPEXT constexpr char VALUE_DELIMITER
void initialize() override
Initialize controller after element has been created.
void handleKeyboardEvent(GUIKeyboardEvent *event) override
Handle keyboard event.
void determineExpandedOptions()
Determine expanded options.
void setValue(const MutableString &value) override
Set value.
void handleMouseEvent(GUINode *node, GUIMouseEvent *event) override
Handle mouse event.
void determineParentOptions()
Determine parent options.
void tick() override
Tick method will be executed once per frame.
void toggleOpenState(int optionIdx)
Toggle open state of current parent option.
vector< GUISelectBoxOptionController * > selectBoxOptionControllers
void expandParentOptionsByValues(const vector< string > &expandedParentOptionValues)
Expand parent options by values.
void onSubTreeChange() override
On sub tree change.
int getOptionIdx(GUIElementNode *optionElementNode)
Get focussed option idx.
GUI element node conditions.
GUI node base class.
Definition: GUINode.h:63
void scrollToNodeY(GUIParentNode *toNode=nullptr)
Scroll to node Y.
Definition: GUINode.cpp:1129
void scrollToNodeX(GUIParentNode *toNode=nullptr)
Scroll to node X.
Definition: GUINode.cpp:1125
bool isEventBelongingToNode(GUIMouseEvent *event, Vector2 &position)
Is event belonging to node.
Definition: GUINode.cpp:973
GUIScreenNode * getScreenNode()
Definition: GUINode.h:315
GUINodeController * getController()
Definition: GUINode.h:586
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:43
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:57
void invalidateLayout(GUINode *node)
Mark a node to be invalidated regarding layout.
void delegateValueChanged(GUIElementNode *node)
Delegate value changed.
Mutable string class.
Definition: MutableString.h:16
MutableString & append(char c)
Append character.
MutableString & reset()
Reset.
bool equals(const string &s2) const
Equals.
MutableString & set(char c)
Set character.
void replace(const string &what, const string &by, int beginIndex=0)
Replace string with another string.
const string & getString() const
String tokenizer class.
void tokenize(const string &str, const string &delimiters)
Tokenize.
String tools class.
Definition: StringTools.h:20