TDME2  1.9.200
GUIScrollAreaController.cpp
Go to the documentation of this file.
2 
3 #include <memory>
4 
5 #include <tdme/tdme.h>
11 #include <tdme/gui/GUI.h>
12 
13 using std::make_unique;
14 using std::unique_ptr;
15 
23 using tdme::gui::GUI;
24 
25 GUIScrollAreaController::GUIScrollAreaController(GUINode* node)
26  : GUINodeController(node), actionListener(nullptr)
27 {
28 }
29 
31  auto contentNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_inner"));
32  float elementHeight = contentNode->getComputedConstraints().height;
33  float contentHeight = contentNode->getContentHeight();
34  auto scrollableHeight = contentHeight - elementHeight;
35  if (scrollableHeight <= 0.0f) return true;
36  auto childrenRenderOffsetY = contentHeight - contentNode->getComputedConstraints().height;
37  return contentNode->getChildrenRenderOffsetY() == childrenRenderOffsetY;
38 
39 }
40 
42  auto contentNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_inner"));
43  float elementHeight = contentNode->getComputedConstraints().height;
44  float contentHeight = contentNode->getContentHeight();
45  auto scrollableHeight = contentHeight - elementHeight;
46  if (scrollableHeight <= 0.0f) return;
47  auto childrenRenderOffsetY = contentHeight - contentNode->getComputedConstraints().height;
48  contentNode->setChildrenRenderOffsetY(childrenRenderOffsetY);
49 }
50 
52  // TODO: Currently we might need a layout pass after changing a scroll area content, hence this work around (1)
53  scrollToBottomIssued = true;
54  //
56 }
57 
59 {
60  return false;
61 }
62 
64 {
65 }
66 
68 {
69  class GUIScrollAreaControllerActionListener: public virtual GUIActionListener
70  {
71 
72  public:
73  void onAction(GUIActionListenerType type, GUIElementNode* node) override {
74  if (node == upArrowNode) {
75  float elementHeight = contentNode->getComputedConstraints().height;
76  float contentHeight = contentNode->getContentHeight();
77  auto scrollableHeight = contentHeight - elementHeight;
78  if (scrollableHeight <= 0.0f)
79  return;
80 
81  auto childrenRenderOffsetY = contentNode->getChildrenRenderOffsetY() - 1.0f;
82  if (childrenRenderOffsetY < 0.0f)
83  childrenRenderOffsetY = 0.0f;
84 
85  contentNode->setChildrenRenderOffsetY(childrenRenderOffsetY);
86  } else
87  if (node == downArrowNode) {
88  float elementHeight = contentNode->getComputedConstraints().height;
89  float contentHeight = contentNode->getContentHeight();
90  auto scrollableHeight = contentHeight - elementHeight;
91  if (scrollableHeight <= 0.0f)
92  return;
93 
94  auto childrenRenderOffsetY = contentNode->getChildrenRenderOffsetY() + 1.0f;
95  if (childrenRenderOffsetY > contentHeight - contentNode->getComputedConstraints().height) {
96  childrenRenderOffsetY = contentHeight - contentNode->getComputedConstraints().height;
97  }
98  contentNode->setChildrenRenderOffsetY(childrenRenderOffsetY);
99  } else
100  if (node == leftArrowNode) {
101  float elementWidth = contentNode->getComputedConstraints().width;
102  float contentWidth = contentNode->getContentWidth();
103  auto scrollableWidth = contentWidth - elementWidth;
104  if (scrollableWidth <= 0.0f)
105  return;
106 
107  auto childrenRenderOffsetX = contentNode->getChildrenRenderOffsetX() - 1.0f;
108  if (childrenRenderOffsetX < 0.0f)
109  childrenRenderOffsetX = 0.0f;
110 
111  contentNode->setChildrenRenderOffsetX(childrenRenderOffsetX);
112  } else
113  if (node == rightArrowNode) {
114  float elementWidth = contentNode->getComputedConstraints().width;
115  float contentWidth = contentNode->getContentWidth();
116  auto scrollableWidth = contentWidth - elementWidth;
117  if (scrollableWidth <= 0.0f)
118  return;
119 
120  auto childrenRenderOffsetX = contentNode->getChildrenRenderOffsetX() + 1.0f;
121  if (childrenRenderOffsetX > contentWidth - contentNode->getComputedConstraints().width) {
122  childrenRenderOffsetX = contentWidth - contentNode->getComputedConstraints().width;
123  }
124  contentNode->setChildrenRenderOffsetX(childrenRenderOffsetX);
125  }
126  }
127 
128  /**
129  * Public constructor
130  * @param guiScrollAreaController gui scroll area controller
131  * @param contentNode content node
132  * @param upArrowNode up arrow node
133  * @param downArrowNode down arrow node
134  * @param leftArrowNode left arrow node
135  * @param rightArrowNode right arrow node
136  */
137  GUIScrollAreaControllerActionListener(GUIScrollAreaController* guiScrollAreaController, GUIParentNode* contentNode, GUIElementNode* upArrowNode, GUIElementNode* downArrowNode, GUIElementNode* leftArrowNode, GUIElementNode* rightArrowNode)
138  : guiScrollAreaController(guiScrollAreaController)
139  , contentNode(contentNode)
140  , upArrowNode(upArrowNode)
141  , downArrowNode(downArrowNode)
142  , leftArrowNode(leftArrowNode)
143  , rightArrowNode(rightArrowNode) {
144  }
145 
146  private:
147  GUIScrollAreaController* guiScrollAreaController;
148  GUIElementNode* upArrowNode;
149  GUIParentNode* contentNode;
150  GUIElementNode* downArrowNode;
151  GUIElementNode* leftArrowNode;
152  GUIElementNode* rightArrowNode;
153  };
154 
155 
156  auto const contentNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_inner"));
157  auto const upArrowNode = dynamic_cast<GUIElementNode*>(node->getScreenNode()->getNodeById(node->getId() + "_scrollbar_vertical_layout_up"));
158  auto const downArrowNode = dynamic_cast<GUIElementNode*>(node->getScreenNode()->getNodeById(node->getId() + "_scrollbar_vertical_layout_down"));
159  auto const leftArrowNode = dynamic_cast<GUIElementNode*>(node->getScreenNode()->getNodeById(node->getId() + "_scrollbar_horizontal_layout_left"));
160  auto const rightArrowNode = dynamic_cast<GUIElementNode*>(node->getScreenNode()->getNodeById(node->getId() + "_scrollbar_horizontal_layout_right"));
161  node->getScreenNode()->addActionListener((actionListener = make_unique<GUIScrollAreaControllerActionListener>(this, contentNode, upArrowNode, downArrowNode, leftArrowNode, rightArrowNode)).get());
162 }
163 
165 {
166  if (actionListener != nullptr) {
168  actionListener = nullptr;
169  }
170 }
171 
173 {
174  // TODO: Currently we might need a layout pass after changing a scroll area content, hence this work around (2)
175  if (scrollToBottomIssued == true) {
177  scrollToBottomIssued = false;
178  }
179  //
180  {
181  auto const contentNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_inner"));
182  float elementHeight = contentNode->getComputedConstraints().height;
183  float contentHeight = contentNode->getContentHeight();
184  auto scrollableHeight = contentHeight - elementHeight;
185  auto horizontalScrollBarNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_horizontal-scrollbar"));;
186  if (contentHeight > elementHeight + horizontalScrollBarNode->getComputedConstraints().height) {
187  required_dynamic_cast<GUIElementNode*>(node)->getActiveConditions().add("vertical-scrollbar");
188  if (contentNode->getChildrenRenderOffsetY() + elementHeight > contentHeight) {
189  contentNode->setChildrenRenderOffsetY(contentHeight - elementHeight);
190  }
191  } else {
192  required_dynamic_cast<GUIElementNode*>(node)->getActiveConditions().remove("vertical-scrollbar");
193  contentNode->setChildrenRenderOffsetY(0.0f);
194  }
195  }
196  {
197  auto const contentNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_inner"));
198  float elementWidth = contentNode->getComputedConstraints().width;
199  float contentWidth = contentNode->getContentWidth();
200  auto scrollableWidth = contentWidth - elementWidth;
201  auto verticalScrollBarNode = required_dynamic_cast<GUIParentNode*>(node->getScreenNode()->getNodeById(node->getId() + "_vertical-scrollbar"));;
202  if (contentWidth > elementWidth + verticalScrollBarNode->getComputedConstraints().width) {
203  required_dynamic_cast<GUIElementNode*>(node)->getActiveConditions().add("horizontal-scrollbar");
204  if (contentNode->getChildrenRenderOffsetX() + elementWidth > contentWidth) {
205  contentNode->setChildrenRenderOffsetX(contentWidth - elementWidth);
206  }
207  } else {
208  contentNode->setChildrenRenderOffsetX(0.0f);
209  required_dynamic_cast<GUIElementNode*>(node)->getActiveConditions().remove("horizontal-scrollbar");
210  }
211  }
212 }
213 
215 {
216 }
217 
219 {
220 }
221 
223 {
224 }
225 
227 {
228 }
229 
231 {
232 }
233 
235 {
236  return false;
237 }
238 
240 {
241  return value;
242 }
243 
245 {
246 }
247 
249 {
250 }
GUI module class.
Definition: GUI.h:64
void initialize() override
Initialize controller after element has been created.
void handleKeyboardEvent(GUIKeyboardEvent *event) override
Handle keyboard event.
void setValue(const MutableString &value) override
Set value.
void handleMouseEvent(GUINode *node, GUIMouseEvent *event) override
Handle mouse event.
void scrollToBottomInternal()
Scroll to bottom internal.
void tick() override
Tick method will be executed once per frame.
void setDisabled(bool disabled) override
Set disabled.
void onSubTreeChange() override
On sub tree change.
GUI node controller base class.
GUI node base class.
Definition: GUINode.h:64
GUIScreenNode * getScreenNode()
Definition: GUINode.h:325
const string & getId()
Definition: GUINode.h:339
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 removeActionListener(GUIActionListener *listener)
Remove action listener.
void addActionListener(GUIActionListener *listener)
Add action listener.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
Mutable utf8 aware string class.
Definition: MutableString.h:23
GUI action listener interface.