TDME2  1.9.200
GUISelectBoxController.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <unordered_set>
5 
6 #include <tdme/tdme.h>
13 #include <tdme/gui/nodes/GUINode.h>
17 #include <tdme/gui/GUI.h>
21 
22 
23 using std::count;
24 using std::unordered_set;
25 
37 using tdme::gui::GUI;
41 
42 string GUISelectBoxController::CONDITION_DISABLED = "disabled";
43 string GUISelectBoxController::CONDITION_ENABLED = "enabled";
44 
45 GUISelectBoxController::GUISelectBoxController(GUINode* node)
46  : GUIElementController(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  }
80  selectCurrent();
81 }
82 
84 {
85  GUIElementController::dispose();
86 }
87 
89 {
90 }
91 
93 {
94  if (selectBoxOptionControllers.empty() == true) {
95  focussedOptionIdx = -1;
96  } else
97  if (focussedOptionIdx == -1) {
99  } else
100  if (focussedOptionIdx < 0) {
101  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 
125 void GUISelectBoxController::select(int optionIdx) {
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 
150 void GUISelectBoxController::focus(int optionIdx)
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 {
168  setValue(getValue());
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 
257 void GUISelectBoxController::expand(int optionIdx) {
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 
269 void GUISelectBoxController::collapse(int optionIdx) {
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  }
366  focusPrevious();
367  if (multipleSelection == false) {
369  }
370  } else
371  if (event->getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_RELEASED) {
372  node->getScreenNode()->forwardChange(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()->forwardChange(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()->forwardChange(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 (const 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 
509 void 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 
520 void GUISelectBoxController::expandParentOptionsByValues(const vector<string>& expandedParentOptionValues) {
522  for (const 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:64
void setFoccussedNode(GUIElementNode *newFoccussedNode)
Set focussed node.
Definition: GUI.cpp:267
void dispose() override
Dispose controller.
void postLayout() override
Post layout event.
void determineExpandedParentOptionValues(vector< string > &expandedParentOptionValues)
Determine expanded parent option values.
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.
static constexpr STATIC_DLL_IMPEXT char VALUE_DELIMITER
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.
GUIKeyboardEventType getType() const
GUIMouseEventType getType() const
Definition: GUIMouseEvent.h:78
GUI element node conditions.
GUI node base class.
Definition: GUINode.h:64
void scrollToNodeY(GUIParentNode *toNode=nullptr)
Scroll to node Y.
Definition: GUINode.cpp:1100
void scrollToNodeX(GUIParentNode *toNode=nullptr)
Scroll to node X.
Definition: GUINode.cpp:1096
bool isEventBelongingToNode(GUIMouseEvent *event, Vector2 &nodeCoordinate)
Is event belonging to node.
Definition: GUINode.h:604
GUINodeController * getController()
Definition: GUINode.h:661
GUIScreenNode * getScreenNode()
Definition: GUINode.h:325
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:42
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:72
void invalidateLayout(GUINode *node)
Mark a node to be invalidated regarding layout.
void forwardChange(GUIElementNode *node)
Forward change event.
Mutable utf8 aware string class.
Definition: MutableString.h:23
MutableString & append(char c)
Append character.
bool equals(const string &s2) const
Equals.
const string & getString() const
MutableString & set(char c)
Set character.
MutableString & reset()
Reset.
Definition: MutableString.h:95
void replace(const string &what, const string &by, int beginIndex=0)
Replace string with another string.
String tokenizer class.
void tokenize(const string &str, const string &delimiters, bool emptyTokens=false)
Tokenize.
String tools class.
Definition: StringTools.h:22