TDME2  1.9.200
GUIParentNode.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <string>
5 #include <unordered_set>
6 #include <vector>
7 
8 #include <tdme/tdme.h>
11 #include <tdme/gui/nodes/GUINode.h>
26 #include <tdme/gui/GUI.h>
27 #include <tdme/gui/GUIParser.h>
29 #include <tdme/math/Math.h>
31 
32 using std::remove;
33 using std::string;
34 using std::to_string;
35 using std::unordered_set;
36 using std::vector;
37 
56 using tdme::gui::GUI;
59 using tdme::math::Math;
61 
62 GUIParentNode::GUIParentNode(
63  GUIScreenNode* screenNode,
64  GUIParentNode* parentNode,
65  const string& id,
66  GUINode_Flow* flow,
67  GUIParentNode_Overflow* overflowX,
68  GUIParentNode_Overflow* overflowY,
69  const GUINode_Alignments& alignments,
70  const GUINode_RequestedConstraints& requestedConstraints,
71  const GUIColor& backgroundColor,
72  const string& backgroundImage,
73  const GUINode_Scale9Grid& backgroundImageScale9Grid,
74  const GUIColor& backgroundImageEffectColorMul,
75  const GUIColor& backgroundImageEffectColorAdd,
76  const GUINode_Border& border,
77  const GUINode_Padding& padding,
78  const GUINodeConditions& showOn,
79  const GUINodeConditions& hideOn,
80  const string& tooltip
81  ):
82  GUINode(screenNode, parentNode, id, flow, alignments, requestedConstraints, backgroundColor, backgroundImage, backgroundImageScale9Grid, backgroundImageEffectColorMul, backgroundImageEffectColorAdd, border, padding, showOn, hideOn, tooltip)
83 {
84  this->overflowX = overflowX;
85  this->overflowY = overflowY;
86  this->childrenRenderOffsetX = 0.0f;
87  this->childrenRenderOffsetY = 0.0f;
88  this->computeViewportCache = true;
89 }
90 
92  if (index < 0 || index >= subNodes.size()) return nullptr;
93  //
94  auto detachedSubNode = subNodes[index];
95  subNodes.erase(subNodes.begin() + index);
96 
97  //
98  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
99 
100  {
101  auto _parentControllerNode = parentControllerNode;
102  while (_parentControllerNode != nullptr) {
103  _parentControllerNode->getController()->onSubTreeChange();
104  _parentControllerNode = _parentControllerNode->getParentControllerNode();
105  }
106  }
107 
109 
111  floatingNodesCache.clear();
113 
114  {
115  auto _parentControllerNode = parentControllerNode;
116  while (_parentControllerNode != nullptr) {
117  _parentControllerNode->getController()->onSubTreeChange();
118  _parentControllerNode = _parentControllerNode->getParentControllerNode();
119  }
120  }
121 
122  //
123  return detachedSubNode;
124 }
125 
127 {
128  //
129  auto detachedSubNodes = subNodes;
130  for (auto subNode: detachedSubNodes) {
131  subNode->parentNode = nullptr;
132  }
133 
134  //
135  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
136 
137  childrenRenderOffsetX = 0.0f;
138  childrenRenderOffsetY = 0.0f;
139  subNodes.clear();
140 
141  {
142  auto _parentControllerNode = parentControllerNode;
143  while (_parentControllerNode != nullptr) {
144  _parentControllerNode->getController()->onSubTreeChange();
145  _parentControllerNode = _parentControllerNode->getParentControllerNode();
146  }
147  }
148 
150 
152  floatingNodesCache.clear();
154 
155  {
156  auto _parentControllerNode = parentControllerNode;
157  while (_parentControllerNode != nullptr) {
158  _parentControllerNode->getController()->onSubTreeChange();
159  _parentControllerNode = _parentControllerNode->getParentControllerNode();
160  }
161  }
162 
163  //
164  return detachedSubNodes;
165 }
166 
168 {
169  //
170  auto detachedSubNodes = detachSubNodes();
171 
172  //
173  for (auto i = 0; i < detachedSubNodes.size(); i++) {
174  auto subNode = detachedSubNodes[i];
175  screenNode->removeNode(subNode);
176  }
177 }
178 
179 void GUIParentNode::replaceSubNodes(const string& xml, bool resetScrollOffsets)
180 {
181  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
182 
183  for (auto i = 0; i < subNodes.size(); i++) {
184  auto subNode = subNodes[i];
185  screenNode->removeNode(subNode);
186  }
187  subNodes.clear();
188 
189  {
190  auto _parentControllerNode = parentControllerNode;
191  while (_parentControllerNode != nullptr) {
192  _parentControllerNode->getController()->onSubTreeChange();
193  _parentControllerNode = _parentControllerNode->getParentControllerNode();
194  }
195  }
196 
198  GUIParser::parse(this, xml);
199 
200  floatingNodesCache.clear();
201  for (auto i = 0; i < subNodes.size(); i++) {
202  auto guiSubNode = subNodes[i];
203  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
204  floatingNodesCache.push_back(guiSubNode);
205  }
206  }
207 
210 
211  if (layouted == false || resetScrollOffsets == true) {
214  } else {
216  float elementWidth = computedConstraints.width;
217  float contentWidth = getContentWidth();
218  auto scrollableWidth = contentWidth - elementWidth;
219  if (scrollableWidth < 0.0f) scrollableWidth = 0.0;
220  if (childrenRenderOffsetX < 0.0f) childrenRenderOffsetX = 0.0f;
221  if (scrollableWidth > 0 && childrenRenderOffsetX > scrollableWidth) childrenRenderOffsetX = scrollableWidth;
222  }
223 
225  float elementHeight = computedConstraints.height;
226  float contentHeight = getContentHeight();
227  auto scrollableHeight = contentHeight - elementHeight;
228  if (scrollableHeight < 0.0f) scrollableHeight = 0.0f;
229  if (childrenRenderOffsetY < 0.0f) childrenRenderOffsetY = 0.0f;
230  if (scrollableHeight > 0 && childrenRenderOffsetY > scrollableHeight) childrenRenderOffsetY = scrollableHeight;
231  }
232  }
233 
234  {
235  auto _parentControllerNode = parentControllerNode;
236  while (_parentControllerNode != nullptr) {
237  _parentControllerNode->getController()->onSubTreeChange();
238  _parentControllerNode = _parentControllerNode->getParentControllerNode();
239  }
240  }
241 }
242 
243 void GUIParentNode::addSubNodes(const string& xml, bool resetScrollOffsets)
244 {
246  GUIParser::parse(this, xml);
247 
248  floatingNodesCache.clear();
249  for (auto i = 0; i < subNodes.size(); i++) {
250  auto guiSubNode = subNodes[i];
251  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
252  floatingNodesCache.push_back(guiSubNode);
253  }
254  }
255 
258 
259  if (layouted == false || resetScrollOffsets == true) {
262  } else {
264  float elementWidth = computedConstraints.width;
265  float contentWidth = getContentWidth();
266  auto scrollableWidth = contentWidth - elementWidth;
267  if (scrollableWidth < 0.0f) scrollableWidth = 0.0;
268  if (childrenRenderOffsetX < 0.0f) childrenRenderOffsetX = 0.0f;
269  if (scrollableWidth > 0 && childrenRenderOffsetX > scrollableWidth) childrenRenderOffsetX = scrollableWidth;
270  }
271 
273  float elementHeight = computedConstraints.height;
274  float contentHeight = getContentHeight();
275  auto scrollableHeight = contentHeight - elementHeight;
276  if (scrollableHeight < 0.0f) scrollableHeight = 0.0f;
277  if (childrenRenderOffsetY < 0.0f) childrenRenderOffsetY = 0.0f;
278  if (scrollableHeight > 0 && childrenRenderOffsetY > scrollableHeight) childrenRenderOffsetY = scrollableHeight;
279  }
280  }
281 
282  {
283  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
284  while (parentControllerNode != nullptr) {
285  parentControllerNode->getController()->onSubTreeChange();
286  parentControllerNode = parentControllerNode->getParentControllerNode();
287  }
288  }
289 }
290 
292 {
293  if (screenNode->addNode(node) == false) {
294  throw GUIParserException(
295  "Screen '" +
296  (screenNode->id) +
297  "' already has a node attached with given node id '" +
298  (node->id) +
299  "'"
300  );
301  }
302  subNodes.push_back(node);
303  if (node->flow == GUINode_Flow::FLOATING) {
304  floatingNodesCache.push_back(node);
305  }
306 }
307 
308 void GUIParentNode::moveSubNode(GUIParentNode* otherParentNode, int index) {
309  auto detachedSubNode = otherParentNode->detachSubNode(index);
310  if (detachedSubNode == nullptr) return;
311 
312  //
314 
315  // attach detached sub nodes here
316  detachedSubNode->parentNode = this;
317  subNodes.push_back(detachedSubNode);
318 
319  floatingNodesCache.clear();
320  for (auto i = 0; i < subNodes.size(); i++) {
321  auto guiSubNode = subNodes[i];
322  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
323  floatingNodesCache.push_back(guiSubNode);
324  }
325  }
326 
329 
332 
333  //
334  {
335  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
336  while (parentControllerNode != nullptr) {
337  parentControllerNode->getController()->onSubTreeChange();
338  parentControllerNode = parentControllerNode->getParentControllerNode();
339  }
340  }
341 }
342 
344  auto detachedSubNodes = otherParentNode->detachSubNodes();
345 
346  //
348 
349  // attach detached sub nodes here
350  for (auto subNode: detachedSubNodes) {
351  subNode->parentNode = this;
352  subNodes.push_back(subNode);
353  }
354 
355  floatingNodesCache.clear();
356  for (auto i = 0; i < subNodes.size(); i++) {
357  auto guiSubNode = subNodes[i];
358  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
359  floatingNodesCache.push_back(guiSubNode);
360  }
361  }
362 
365 
368 
369  //
370  {
371  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
372  while (parentControllerNode != nullptr) {
373  parentControllerNode->getController()->onSubTreeChange();
374  parentControllerNode = parentControllerNode->getParentControllerNode();
375  }
376  }
377 }
378 
380 {
381  return overflowX;
382 }
383 
385 {
386  return overflowY;
387 }
388 
390 {
391  if (StringTools::equalsIgnoreCase(StringTools::trim(overflow), "hidden") == true) {
393  } else
394  if (StringTools::equalsIgnoreCase(StringTools::trim(overflow), "downsize-children") == true) {
396  } else
397  if (StringTools::equalsIgnoreCase(StringTools::trim(overflow), "scroll") == true) {
399  } else
400  if (overflow.empty() == true || StringTools::trim(overflow).length() == 0) {
402  } else {
403  throw GUIParserException(
404  "Unknown overflow '" +
405  (overflow) +
406  "'"
407  );
408  }
409 }
410 
411 void GUIParentNode::setChildrenRenderOffsetX(float childrenRenderOffsetX)
412 {
414  this->childrenRenderOffsetX = childrenRenderOffsetX;
415 }
416 
417 void GUIParentNode::setChildrenRenderOffsetY(float childrenRenderOffsetY)
418 {
420  this->childrenRenderOffsetY = childrenRenderOffsetY;
421 }
422 
423 GUINode_RequestedConstraints GUIParentNode::createRequestedConstraints(const string& left, const string& top, const string& width, const string& height, int factor)
424 {
425  GUINode_RequestedConstraints constraints;
427  constraints.left = getRequestedConstraintsValue(StringTools::trim(left), 0);
429  constraints.top = getRequestedConstraintsValue(StringTools::trim(top), 0);
431  constraints.width = getRequestedConstraintsValue(StringTools::trim(width), -1);
433  constraints.height = getRequestedConstraintsValue(StringTools::trim(height), -1);
434  if (constraints.leftType == GUINode_RequestedConstraints_RequestedConstraintsType::PIXEL) constraints.left*= factor;
435  if (constraints.topType == GUINode_RequestedConstraints_RequestedConstraintsType::PIXEL) constraints.top*= factor;
436  if (constraints.widthType == GUINode_RequestedConstraints_RequestedConstraintsType::PIXEL) constraints.width*= factor;
437  if (constraints.heightType == GUINode_RequestedConstraints_RequestedConstraintsType::PIXEL) constraints.height*= factor;
438  return constraints;
439 }
440 
442 {
443  if (conditionsMet == false) return;
444  GUINode::layout();
445  layoutSubNodes();
446 }
447 
449 {
450  if (conditionsMet == false) {
451  layouted = false;
452  return;
453  }
454  for (auto i = 0; i < subNodes.size(); i++) {
455  subNodes[i]->layout();
456  }
457 }
458 
460 {
461  {
463  for (auto i = 0; i < subNodes.size(); i++) {
464  auto guiSubNode = subNodes[i];
465  if (guiSubNode->conditionsMet == false) continue;
466  guiSubNode->computedConstraints.alignmentLeft = Math::max(0, border.left + padding.left);
467  }
468  } else
470  for (auto i = 0; i < subNodes.size(); i++) {
471  auto guiSubNode = subNodes[i];
472  if (guiSubNode->conditionsMet == false) continue;
473  guiSubNode->computedConstraints.alignmentLeft = Math::max(0, (computedConstraints.width - guiSubNode->computedConstraints.width) / 2);
474  }
475  } else
477  for (auto i = 0; i < subNodes.size(); i++) {
478  auto guiSubNode = subNodes[i];
479  if (guiSubNode->conditionsMet == false) continue;
480  guiSubNode->computedConstraints.alignmentLeft = Math::max(0, (computedConstraints.width - guiSubNode->computedConstraints.width - border.right - padding.right));
481  }
482  }
483  }
484 }
485 
487 {
488  {
490  for (auto i = 0; i < subNodes.size(); i++) {
491  auto guiSubNode = subNodes[i];
492  if (guiSubNode->conditionsMet == false) continue;
493  guiSubNode->computedConstraints.alignmentTop = Math::max(0, border.top + padding.top);
494  }
495  } else
497  for (auto i = 0; i < subNodes.size(); i++) {
498  auto guiSubNode = subNodes[i];
499  if (guiSubNode->conditionsMet == false) continue;
500  guiSubNode->computedConstraints.alignmentTop = Math::max(0, (computedConstraints.height - guiSubNode->computedConstraints.height) / 2);
501  }
502  } else
504  for (auto i = 0; i < subNodes.size(); i++) {
505  auto guiSubNode = subNodes[i];
506  if (guiSubNode->conditionsMet == false) continue;
507  guiSubNode->computedConstraints.alignmentTop = Math::max(0, (computedConstraints.height - guiSubNode->computedConstraints.height - border.bottom - padding.bottom));
508  }
509  }
510  }
511 }
512 
513 void GUIParentNode::getChildControllerNodesInternal(vector<GUINode*>& childControllerNodes, bool requireConditionsMet)
514 {
515  if (requireConditionsMet == true && conditionsMet == false) return;
516  for (auto i = 0; i < subNodes.size(); i++) {
517  auto node = subNodes[i];
518  if (node->controller != nullptr) {
519  childControllerNodes.push_back(node);
520  }
521  if (dynamic_cast<GUIParentNode*>(node) != nullptr) {
522  (required_dynamic_cast<GUIParentNode*>(node))->getChildControllerNodesInternal(childControllerNodes);
523  }
524  }
525 }
526 
527 void GUIParentNode::getChildControllerNodes(vector<GUINode*>& childControllerNodes, bool requireConditionsMet)
528 {
529  childControllerNodes.clear();
530  getChildControllerNodesInternal(childControllerNodes, requireConditionsMet);
531 }
532 
534 {
535  for (auto i = 0; i < subNodes.size(); i++) {
536  subNodes[i]->dispose();
537  }
539 }
540 
542 {
543  auto conditionsMetBefore = conditionsMet;
545  for (auto i = 0; i < subNodes.size(); i++) {
546  auto guiSubNode = subNodes[i];
547  guiSubNode->setConditionsMet();
548  }
549  if (conditionsMetBefore != conditionsMet) invalidateRenderCaches();
550 }
551 
553 {
554  layoutOnDemand();
555 
556  if (shouldRender() == false) return;
557 
558  auto renderAreaLeftCurrent = guiRenderer->getRenderAreaLeft();
559  auto renderAreaTopCurrent = guiRenderer->getRenderAreaTop();
560  auto renderAreaRightCurrent = guiRenderer->getRenderAreaRight();
561  auto renderAreaBottomCurrent = guiRenderer->getRenderAreaBottom();
562  auto screenWidth = screenNode->getScreenWidth();
563  auto screenHeight = screenNode->getScreenHeight();
566  float width = computedConstraints.width;
567  float height = computedConstraints.height;
568  auto renderOffsetXCurrent = guiRenderer->getRenderOffsetX();
569  auto renderOffsetYCurrent = guiRenderer->getRenderOffsetY();
570  auto renderOffsetXPixel = 0.0f;
571  auto renderOffsetYPixel = 0.0f;
572  for (auto *_parentNode = this; _parentNode != nullptr; _parentNode = _parentNode->parentNode) {
573  renderOffsetXPixel += _parentNode->childrenRenderOffsetX;
574  renderOffsetYPixel += _parentNode->childrenRenderOffsetY;
575  }
576  auto renderOffsetX = renderOffsetXPixel / (screenWidth / 2.0f);
577  auto renderOffsetY = renderOffsetYPixel / (screenHeight / 2.0f);
578  auto renderAreaLeft = renderAreaLeftCurrent;
579  auto renderAreaTop = renderAreaTopCurrent;
580  auto renderAreaRight = renderAreaRightCurrent;
581  auto renderAreaBottom = renderAreaBottomCurrent;
582  // Floating node does not have correct dimension and such due non existance when layouting
584  renderAreaLeft = ((left) / (screenWidth / 2.0f)) - renderOffsetXCurrent - 1.0f;
585  renderAreaTop = ((screenHeight - top) / (screenHeight / 2.0f)) + renderOffsetYCurrent - 1.0f;
586  renderAreaRight = ((left + width) / (screenWidth / 2.0f)) - renderOffsetXCurrent - 1.0f;
587  renderAreaBottom = ((screenHeight - top - height) / (screenHeight / 2.0f)) + renderOffsetYCurrent - 1.0f;
588  }
589  guiRenderer->setSubRenderAreaLeft(renderAreaLeft);
590  guiRenderer->setSubRenderAreaTop(renderAreaTop);
591  guiRenderer->setSubRenderAreaRight(renderAreaRight);
592  guiRenderer->setSubRenderAreaBottom(renderAreaBottom);
593  guiRenderer->setRenderOffsetX(renderOffsetX);
594  guiRenderer->setRenderOffsetY(renderOffsetY);
595 
596  //
597  GUINode::render(guiRenderer);
598 
599  //
600  if (computeViewportCache == true) {
601  for (auto i = 0; i < subNodes.size(); i++) {
602  auto guiSubNode = subNodes[i];
603  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
604  continue;
605  }
606  if (guiSubNode->layouted == false) {
607  continue;
608  }
609  guiRenderer->setRenderAreaLeft(renderAreaLeftCurrent);
610  guiRenderer->setRenderAreaTop(renderAreaTopCurrent);
611  guiRenderer->setRenderAreaRight(renderAreaRightCurrent);
612  guiRenderer->setRenderAreaBottom(renderAreaBottomCurrent);
613  guiRenderer->setSubRenderAreaLeft(renderAreaLeft);
614  guiRenderer->setSubRenderAreaTop(renderAreaTop);
615  guiRenderer->setSubRenderAreaRight(renderAreaRight);
616  guiRenderer->setSubRenderAreaBottom(renderAreaBottom);
617  guiRenderer->setRenderOffsetX(renderOffsetX);
618  guiRenderer->setRenderOffsetY(renderOffsetY);
619  float left = guiSubNode->computedConstraints.left + guiSubNode->computedConstraints.alignmentLeft + guiSubNode->border.left;
620  float top = guiSubNode->computedConstraints.top + guiSubNode->computedConstraints.alignmentTop + guiSubNode->border.top;
621  float width = guiSubNode->computedConstraints.width - guiSubNode->border.left - guiSubNode->border.right;
622  float height = guiSubNode->computedConstraints.height - guiSubNode->border.top - guiSubNode->border.bottom;
623  if (guiRenderer->isQuadVisible(
624  ((left) / (screenWidth / 2.0f)) - 1.0f,
625  ((screenHeight - top) / (screenHeight / 2.0f)) - 1.0f,
626  ((left + width) / (screenWidth / 2.0f)) - 1.0f,
627  ((screenHeight - top) / (screenHeight / 2.0f)) - 1.0f,
628  ((left + width) / (screenWidth / 2.0f)) - 1.0f,
629  ((screenHeight - top - height) / (screenHeight / 2.0f)) - 1.0f,
630  ((left) / (screenWidth / 2.0f)) - 1.0f,
631  ((screenHeight - top - height) / (screenHeight / 2.0f)) - 1.0f) == true) {
632  //
633  //
634  if (guiSubNode->hasEffects() == true) guiSubNode->applyEffects(guiRenderer);
635  guiSubNode->render(guiRenderer);
636  if (guiSubNode->hasEffects() == true) guiSubNode->undoEffects(guiRenderer);
637  vieportSubNodesCache.push_back(guiSubNode);
638  }
639  }
640  computeViewportCache = false;
641  } else {
642  for (auto i = 0; i < vieportSubNodesCache.size(); i++) {
643  auto guiSubNode = vieportSubNodesCache[i];
644  guiRenderer->setRenderAreaLeft(renderAreaLeftCurrent);
645  guiRenderer->setRenderAreaTop(renderAreaTopCurrent);
646  guiRenderer->setRenderAreaRight(renderAreaRightCurrent);
647  guiRenderer->setRenderAreaBottom(renderAreaBottomCurrent);
648  guiRenderer->setSubRenderAreaLeft(renderAreaLeft);
649  guiRenderer->setSubRenderAreaTop(renderAreaTop);
650  guiRenderer->setSubRenderAreaRight(renderAreaRight);
651  guiRenderer->setSubRenderAreaBottom(renderAreaBottom);
652  guiRenderer->setRenderOffsetX(renderOffsetX);
653  guiRenderer->setRenderOffsetY(renderOffsetY);
654  if (guiSubNode->hasEffects() == true) guiSubNode->applyEffects(guiRenderer);
655  guiSubNode->render(guiRenderer);
656  if (guiSubNode->hasEffects() == true) guiSubNode->undoEffects(guiRenderer);
657  }
658  }
659 
660  //
661  guiRenderer->setRenderOffsetX(renderOffsetXCurrent);
662  guiRenderer->setRenderOffsetY(renderOffsetYCurrent);
663  guiRenderer->setRenderAreaLeft(renderAreaLeftCurrent);
664  guiRenderer->setRenderAreaTop(renderAreaTopCurrent);
665  guiRenderer->setRenderAreaRight(renderAreaRightCurrent);
666  guiRenderer->setRenderAreaBottom(renderAreaBottomCurrent);
667 }
668 
669 void GUIParentNode::determineNodesByCoordinate(const Vector2& coordinate, unordered_set<string>& nodeIds) {
670  if (conditionsMet == false)
671  return;
672 
673  //
674  if (isCoordinateBelongingToNode(coordinate) == true || flow == GUINode_Flow::FLOATING) {
675  for (auto i = 0; i < vieportSubNodesCache.size(); i++) {
676  auto subNode = vieportSubNodesCache[i];
677  subNode->determineNodesByCoordinate(coordinate, nodeIds);
678  }
679  }
680 
681  //
682  GUINode::determineNodesByCoordinate(coordinate, nodeIds);
683 }
684 
685 void GUIParentNode::determineMouseEventNodes(GUIMouseEvent* event, bool floatingNode, unordered_set<string>& eventNodeIds, unordered_set<string>& eventFloatingNodeIds, int flags)
686 {
687  if (conditionsMet == false)
688  return;
689 
690  if (isEventBelongingToNode(event) == true || flow == GUINode_Flow::FLOATING) {
691  if (event->getType() == GUIMouseEvent::MOUSEEVENT_WHEEL_MOVED) {
692  if (event->getWheelX() != 0.0f && overflowX == GUIParentNode_Overflow::SCROLL) {
693  childrenRenderOffsetX -= event->getWheelX() * 10.0f;
694  float nodeWidth = this->computedConstraints.width;
695  float contentWidth = this->getContentWidth();
696  auto scrollableWidth = contentWidth - nodeWidth;
697  if (static_cast<int>(nodeWidth) >= static_cast<int>(contentWidth)) {
698  childrenRenderOffsetX = 0.0f;
699  } else {
701  if (childrenRenderOffsetX > scrollableWidth) childrenRenderOffsetX = scrollableWidth;
702  event->setProcessed(true);
703  }
705  return;
706  }
707  if (event->getWheelY() != 0.0f && overflowY == GUIParentNode_Overflow::SCROLL) {
708  childrenRenderOffsetY -= event->getWheelY() * 10.0f;
709  float nodeHeight = this->computedConstraints.height;
710  float contentHeight = this->getContentHeight();
711  auto scrollableHeight = contentHeight - nodeHeight;
712  if (static_cast<int>(nodeHeight) >= static_cast<int>(contentHeight)) {
713  childrenRenderOffsetY = 0.0f;
714  } else {
715  if (childrenRenderOffsetY < 0.0f) childrenRenderOffsetY = 0.0f;
716  if (childrenRenderOffsetY > scrollableHeight) childrenRenderOffsetY = scrollableHeight;
717  event->setProcessed(true);
718  }
720  return;
721  }
722  }
723  for (auto i = 0; i < vieportSubNodesCache.size(); i++) {
724  auto subNode = vieportSubNodesCache[i];
725  subNode->determineMouseEventNodes(event, floatingNode == true || subNode->flow == GUINode_Flow::FLOATING, eventNodeIds, eventFloatingNodeIds, flags);
726  }
727  }
728 
729  GUINode::determineMouseEventNodes(event, floatingNode, eventNodeIds, eventFloatingNodeIds, flags);
730 }
731 
733  computeViewportCache = true;
734  vieportSubNodesCache.clear();
735  for (auto i = 0; i < subNodes.size(); i++) {
736  auto guiSubNodeParentNode = dynamic_cast<GUIParentNode*>(subNodes[i]);
737  if (guiSubNodeParentNode != nullptr) guiSubNodeParentNode->invalidateRenderCaches();
738  }
739 }
740 
741 void GUIParentNode::removeSubNode(GUINode* node, bool resetScrollOffsets)
742 {
744  subNodes.erase(remove(subNodes.begin(), subNodes.end(), node), subNodes.end());
745 
746  floatingNodesCache.clear();
747  for (auto i = 0; i < subNodes.size(); i++) {
748  auto guiSubNode = subNodes[i];
749  if (guiSubNode->flow == GUINode_Flow::FLOATING) {
750  floatingNodesCache.push_back(guiSubNode);
751  }
752  }
753 
756 
757  {
758  auto parentControllerNode = controller != nullptr?this:getParentControllerNode();
759  while (parentControllerNode != nullptr) {
760  parentControllerNode->getController()->onSubTreeChange();
761  parentControllerNode = parentControllerNode->getParentControllerNode();
762  }
763  }
764 
765  if (layouted == false || resetScrollOffsets == true) {
768  } else {
770  float elementWidth = computedConstraints.width;
771  float contentWidth = getContentWidth();
772  auto scrollableWidth = contentWidth - elementWidth;
773  if (scrollableWidth < 0.0f) scrollableWidth = 0.0;
774  if (childrenRenderOffsetX < 0.0f) childrenRenderOffsetX = 0.0f;
775  if (scrollableWidth > 0 && childrenRenderOffsetX > scrollableWidth) childrenRenderOffsetX = scrollableWidth;
776  }
777 
779  float elementHeight = computedConstraints.height;
780  float contentHeight = getContentHeight();
781  auto scrollableHeight = contentHeight - elementHeight;
782  if (scrollableHeight < 0.0f) scrollableHeight = 0.0f;
783  if (childrenRenderOffsetY < 0.0f) childrenRenderOffsetY = 0.0f;
784  if (scrollableHeight > 0 && childrenRenderOffsetY > scrollableHeight) childrenRenderOffsetY = scrollableHeight;
785  }
786  }
787 }
788 
790  for (auto i = 0; i < subNodes.size(); i++) {
791  auto guiSubNode = subNodes[i];
792  auto guiElementSubNode = dynamic_cast<GUIElementNode*>(guiSubNode);
793  if (guiElementSubNode != nullptr) {
795  guiElementSubNode->getActiveConditions().remove(GUIElementNode::CONDITION_CLICK);
796  guiElementSubNode->unsetMouseStates();
797  } else {
798  auto guiParentSubNode = dynamic_cast<GUIParentNode*>(guiSubNode);
799  if (guiParentSubNode != nullptr) guiParentSubNode->unsetMouseStates();
800  }
801  }
802 }
GUI parser.
Definition: GUIParser.h:40
static GUIScreenNode * parse(const string &pathName, const string &fileName, const unordered_map< string, string > &variables={}, const EngineMiniScript::ScriptVariable &miniScriptArguments=EngineMiniScript::ScriptVariable(), Context *context=nullptr)
Parses a GUI XML file.
GUI module class.
Definition: GUI.h:64
GUIMouseEventType getType() const
Definition: GUIMouseEvent.h:78
static STATIC_DLL_IMPEXT string CONDITION_ONMOUSEOVER
static STATIC_DLL_IMPEXT string CONDITION_CLICK
GUINodeConditions & getActiveConditions()
GUI element node conditions.
bool remove(const string &condition)
Remove a condition.
GUI node controller base class.
static STATIC_DLL_IMPEXT GUINode_AlignmentHorizontal * RIGHT
static STATIC_DLL_IMPEXT GUINode_AlignmentHorizontal * CENTER
static STATIC_DLL_IMPEXT GUINode_AlignmentHorizontal * LEFT
static STATIC_DLL_IMPEXT GUINode_AlignmentVertical * BOTTOM
static STATIC_DLL_IMPEXT GUINode_AlignmentVertical * CENTER
static STATIC_DLL_IMPEXT GUINode_AlignmentVertical * TOP
static STATIC_DLL_IMPEXT GUINode_Flow * FLOATING
Definition: GUINode_Flow.h:31
static STATIC_DLL_IMPEXT GUINode_Flow * INTEGRATED
Definition: GUINode_Flow.h:30
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * NONE
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * PIXEL
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * AUTO
GUI node base class.
Definition: GUINode.h:64
virtual int getContentHeight()=0
static GUINode_RequestedConstraints_RequestedConstraintsType * getRequestedConstraintsType(const string &constraint, GUINode_RequestedConstraints_RequestedConstraintsType *defaultConstraintsType)
Get requested constraints type.
Definition: GUINode.cpp:288
GUINode_Border border
Definition: GUINode.h:160
virtual void determineMouseEventNodes(GUIMouseEvent *event, bool floatingNode, unordered_set< string > &eventNodeIds, unordered_set< string > &eventFloatingNodeIds, int flags=DETERMINEMOUSEEVENTNODES_FLAG_NONE)
Determine mouse event nodes.
Definition: GUINode.cpp:1030
virtual int getContentWidth()=0
virtual void layoutOnDemand()
Layout on demand.
Definition: GUINode.cpp:473
virtual void determineNodesByCoordinate(const Vector2 &coordinate, unordered_set< string > &nodeIds)
Determine nodes by coordinate.
Definition: GUINode.cpp:1020
virtual void render(GUIRenderer *guiRenderer)
Render.
Definition: GUINode.cpp:509
unique_ptr< GUINodeController > controller
Definition: GUINode.h:163
bool isEventBelongingToNode(GUIMouseEvent *event, Vector2 &nodeCoordinate)
Is event belonging to node.
Definition: GUINode.h:604
GUINode_ComputedConstraints computedConstraints
Definition: GUINode.h:152
GUINode_Padding padding
Definition: GUINode.h:159
virtual void setConditionsMet()
Set conditions met for this node and its subnodes.
Definition: GUINode.cpp:468
GUIScreenNode * screenNode
Definition: GUINode.h:147
bool shouldRender()
Returns if to render.
Definition: GUINode.h:302
GUIParentNode * getParentControllerNode()
Definition: GUINode.cpp:1011
virtual void dispose()
Dispose node.
Definition: GUINode.cpp:462
GUINode_Alignments alignments
Definition: GUINode.h:150
bool isCoordinateBelongingToNode(const Vector2 &coordinate, Vector2 &nodeCoordinate)
Is coordinate belonging to node.
Definition: GUINode.h:575
virtual void layout()
Layout.
Definition: GUINode.cpp:191
GUINode_Flow * flow
Definition: GUINode.h:86
static int getRequestedConstraintsValue(const string &constraint, int defaultConstraintsValue)
Get requested constraints value.
Definition: GUINode.cpp:306
static STATIC_DLL_IMPEXT GUIParentNode_Overflow * DOWNSIZE_CHILDREN
static STATIC_DLL_IMPEXT GUIParentNode_Overflow * HIDDEN
static STATIC_DLL_IMPEXT GUIParentNode_Overflow * SCROLL
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:42
GUIParentNode_Overflow * overflowX
Definition: GUIParentNode.h:66
void getChildControllerNodes(vector< GUINode * > &childControllerNodes, bool requireConditionsMet=false)
Get child controller nodes.
void dispose() override
Dispose node.
virtual void computeHorizontalChildrenAlignment()
Compute horizontal children alignment.
void setConditionsMet() override
Set conditions met for this node and its subnodes.
void getChildControllerNodesInternal(vector< GUINode * > &childControllerNodes, bool requireConditionsMet=false)
Get child controller nodes internal.
static GUIParentNode_Overflow * createOverflow(const string &overflow)
Create over flow.
void setChildrenRenderOffsetX(float childrenRenderOffSetX)
Set children render offset x.
GUIParentNode_Overflow * getOverflowX()
void removeSubNode(GUINode *node, bool resetScrollOffsets)
Remove sub node.
vector< GUINode * > vieportSubNodesCache
Definition: GUIParentNode.h:64
void replaceSubNodes(const string &xml, bool resetScrollOffsets)
Replace sub nodes with given XML.
void layout() override
Layout.
void clearSubNodes()
Clear sub nodes.
void unsetMouseStates()
Unset mouse over and click conditions on element nodes.
GUIParentNode_Overflow * getOverflowY()
vector< GUINode * > floatingNodesCache
Definition: GUIParentNode.h:65
void determineMouseEventNodes(GUIMouseEvent *event, bool floatingNode, unordered_set< string > &eventNodeIds, unordered_set< string > &eventFloatingNodeIds, int flags=DETERMINEMOUSEEVENTNODES_FLAG_NONE) override
Determine mouse event nodes.
void moveSubNodes(GUIParentNode *otherParentNode)
Move children nodes from other parent node into this parent node.
void render(GUIRenderer *guiRenderer) override
Render.
void moveSubNode(GUIParentNode *otherParentNode, int index)
Move children node from other parent node into this parent node.
GUINode * detachSubNode(int index)
Detach sub node at given index.
GUIParentNode_Overflow * overflowY
Definition: GUIParentNode.h:67
virtual void layoutSubNodes()
Layout sub nodes.
vector< GUINode * > subNodes
Definition: GUIParentNode.h:62
static GUINode_RequestedConstraints createRequestedConstraints(const string &left, const string &top, const string &width, const string &height, int factor)
Create requested constraints.
vector< GUINode * > detachSubNodes()
Detach sub nodes.
void setChildrenRenderOffsetY(float childrenRenderOffSetY)
Set children render offset y.
void addSubNode(GUINode *node)
Add sub node.
void determineNodesByCoordinate(const Vector2 &coordinate, unordered_set< string > &nodeIds) override
Determine nodes by coordinate.
virtual void computeVerticalChildrenAlignment()
Compute vertical children alignment.
void addSubNodes(const string &xml, bool resetScrollOffsets)
Add sub nodes with given XML.
void invalidateRenderCaches()
Invalidate render caches.
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.
bool removeNode(GUINode *node)
Add node.
bool addNode(GUINode *node)
Add node.
void setSubRenderAreaBottom(float renderAreaBottom)
Set sub render area bottom.
Definition: GUIRenderer.h:340
void setRenderAreaLeft(float renderAreaLeft)
Set up render area left.
Definition: GUIRenderer.h:263
void setRenderAreaRight(float renderAreaRight)
Set up render area right.
Definition: GUIRenderer.h:309
void setRenderAreaTop(float renderAreaTop)
Set up render area top.
Definition: GUIRenderer.h:286
void setSubRenderAreaRight(float renderAreaRight)
Set sub render area right.
Definition: GUIRenderer.h:317
void setSubRenderAreaLeft(float renderAreaLeft)
Set sub render area left.
Definition: GUIRenderer.h:271
bool isQuadVisible(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
Definition: GUIRenderer.h:411
void setSubRenderAreaTop(float renderAreaTop)
Set sub render area top.
Definition: GUIRenderer.h:294
void setRenderOffsetY(float renderOffsetY)
Set render offset y.
Definition: GUIRenderer.h:370
void setRenderAreaBottom(float renderAreaBottom)
Set up render area bottom.
Definition: GUIRenderer.h:332
void setRenderOffsetX(float renderOffsetX)
Set render offset x.
Definition: GUIRenderer.h:355
Standard math functions.
Definition: Math.h:19
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
String tools class.
Definition: StringTools.h:22
GUINode_AlignmentVertical * vertical
GUINode_AlignmentHorizontal * horizontal
GUI node border entity.
GUI node padding entity.
GUINode_RequestedConstraints_RequestedConstraintsType * topType
GUINode_RequestedConstraints_RequestedConstraintsType * widthType
GUINode_RequestedConstraints_RequestedConstraintsType * leftType
GUINode_RequestedConstraints_RequestedConstraintsType * heightType
GUI node scale 9 grid entity.