TDME2  1.9.200
GUIElementNode.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <set>
5 #include <string>
6 
7 #include <tdme/tdme.h>
14 #include <tdme/gui/nodes/GUINode.h>
27 #include <tdme/utilities/Console.h>
28 #include <tdme/utilities/Float.h>
29 #include <tdme/utilities/Integer.h>
30 #include <tdme/utilities/RTTI.h>
33 #include <tdme/utilities/Time.h>
34 
35 using std::begin;
36 using std::end;
37 using std::find;
38 using std::set;
39 using std::to_string;
40 
67 
68 string GUIElementNode::CONDITION_ALWAYS = "always";
69 string GUIElementNode::CONDITION_ONMOUSEOVER = "mouseover";
70 string GUIElementNode::CONDITION_CLICK = "click";
71 string GUIElementNode::CONDITION_FOCUS = "focus";
72 
73 GUIElementNode::GUIElementNode(
74  GUIScreenNode* screenNode,
75  GUIParentNode* parentNode,
76  const string& id,
77  GUINode_Flow* flow,
78  GUIParentNode_Overflow* overflowX,
79  GUIParentNode_Overflow* overflowY,
80  const GUINode_Alignments& alignments,
81  const GUINode_RequestedConstraints& requestedConstraints,
82  const GUIColor& backgroundColor,
83  const string& backgroundImage,
84  const GUINode_Scale9Grid& backgroundImageScaleGrid,
85  const GUIColor& backgroundImageEffectColorMul,
86  const GUIColor& backgroundImageEffectColorAdd,
87  const GUINode_Border& border,
88  const GUINode_Padding& padding,
89  const GUINodeConditions& showOn,
90  const GUINodeConditions& hideOn,
91  const string& tooltip,
92  const string& name,
93  const string& value,
94  bool selected,
95  bool disabled,
96  bool focusable,
97  bool ignoreEvents,
98  const string& onInitializeExpression,
99  const string& onMouseClickExpression,
100  const string& onMouseDoubleClickExpression,
101  const string& onMouseOverExpression,
102  const string& onMouseOutExpression,
103  const string& onChangeExpression,
104  const string& parentElementId,
105  const string& options
106  ) :
107  GUILayerNode(screenNode, parentNode, id, flow, overflowX, overflowY, alignments, requestedConstraints, backgroundColor, backgroundImage, backgroundImageScaleGrid, backgroundImageEffectColorMul, backgroundImageEffectColorAdd, border, padding, showOn, hideOn, tooltip),
108  activeConditions(this)
109 {
110  this->name = name;
111  this->value = value;
112  this->selected = selected;
113  this->disabled = disabled;
114  this->focusable = focusable;
115  this->ignoreEvents = ignoreEvents;
116  this->onInitializeExpression = onInitializeExpression;
117  this->onMouseClickExpression = onMouseClickExpression;
118  this->onMouseDoubleClickExpression = onMouseDoubleClickExpression;
119  this->onMouseOverExpression = onMouseOverExpression;
120  this->onMouseOutExpression = onMouseOutExpression;
121  this->onChangeExpression = onChangeExpression;
122  this->parentElementId = parentElementId;
123  // controller
124  auto controller = ignoreEvents == true?static_cast<GUINodeController*>(new GUIElementIgnoreEventsController(this)):static_cast<GUINodeController*>(new GUIElementController(this));
125  controller->initialize();
127  //
128  {
129  StringTokenizer t;
130  t.tokenize(StringTools::trim(options), ",");
131  while (t.hasMoreTokens() == true) this->options.push_back(StringTools::toLowerCase(StringTools::trim(t.nextToken())));
132 
133  }
134 }
135 
137 {
138  return "element";
139 }
140 
142 {
143  return false;
144 }
145 
147 {
148  return focusable;
149 }
150 
151 const string& GUIElementNode::getName()
152 {
153  return name;
154 }
155 
157 {
158  return value;
159 }
160 
162 {
163  return selected;
164 }
165 
167 {
168  return disabled;
169 }
170 
172  return onInitializeExpression;
173 }
174 
176  return onMouseClickExpression;
177 }
178 
181 }
182 
184  return onMouseOverExpression;
185 }
186 
188  return onMouseOutExpression;
189 }
190 
192  return onChangeExpression;
193 }
194 
195 void GUIElementNode::executeExpression(GUIScreenNode* screenNode, const string& expression) {
196  if (StringTools::startsWith(expression, "http://") == true || StringTools::startsWith(expression, "https://") == true) {
197  Application::openBrowser(expression);
198  return;
199  }
200  StringTokenizer t1;
201  StringTokenizer t2;
202  t1.tokenize(expression, ";");
203  while (t1.hasMoreTokens()) {
204  t2.tokenize(t1.nextToken(), "=");
205  string command;
206  string value;
207  string nodeId;
208  string subCommand;
209  if (t2.countTokens() > 0) {
210  command = StringTools::trim(t2.nextToken());
211  if (t2.countTokens() > 1) value = StringTools::trim(t2.nextToken());
212  }
213  t2.tokenize(command, ".");
214  if (t2.countTokens() == 2) {
215  nodeId = StringTools::trim(t2.nextToken());
216  subCommand = StringTools::trim(t2.nextToken());
217  }
218  // element (controller) values
219  if (subCommand == "value") {
220  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
221  auto nodeController = nodeElementNode != nullptr?nodeElementNode->getController():nullptr;
222  if (StringTools::startsWith(value, "'") == true && StringTools::endsWith(value, "'") == true) {
223  if (nodeController != nullptr) nodeController->setValue(MutableString(StringTools::substring(value, 1, value.size() - 1)));
224  } else
225  if (StringTools::endsWith(value, ".value") == true) {
226  auto nodeValueElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(StringTools::substring(value, 0, value.length() - string(".value").size())));
227  auto nodeValueController = nodeValueElementNode != nullptr?nodeValueElementNode->getController():nullptr;
228  if (nodeController != nullptr && nodeValueController != nullptr) nodeController->setValue(nodeValueController->getValue());
229  } else {
230  Console::println("GUIElementController::executeExpression(): Unknown value in expression: " + value);
231  }
232  } else
233  // element conditions
234  if (subCommand == "condition") {
235  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
236  if (nodeElementNode != nullptr) {
237  if (value.find('?') != string::npos &&
238  value.find(':') != string::npos &&
239  value.find(':') > value.find('?')) {
240  t2.tokenize(value, "?:");
241  string testCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
242  string setOnTrueCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
243  string setOnFalseCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
244  if (testCondition.empty() == true ||
245  setOnTrueCondition.empty() == true ||
246  setOnFalseCondition.empty() == true) {
247  Console::println("GUIElementController::executeExpression(): = ternary operator requires the following format 'node.condition=a?b:c'");
248  } else {
249  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
250  if (nodeElementNode != nullptr) {
251  if (nodeElementNode->getActiveConditions().has(testCondition) == true) {
252  nodeElementNode->getActiveConditions().removeAll();
253  nodeElementNode->getActiveConditions().add(setOnTrueCondition);
254  } else {
255  nodeElementNode->getActiveConditions().removeAll();
256  nodeElementNode->getActiveConditions().add(setOnFalseCondition);
257  }
258  }
259  }
260  } else {
261  nodeElementNode->getActiveConditions().removeAll();
262  nodeElementNode->getActiveConditions().add(value);
263  }
264  }
265  } else
266  if (subCommand == "condition-") {
267  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
268  if (nodeElementNode != nullptr) nodeElementNode->getActiveConditions().remove(value);
269  } else
270  if (subCommand == "condition+") {
271  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
272  if (nodeElementNode != nullptr) nodeElementNode->getActiveConditions().add(value);
273  } else
274  if (subCommand == "condition!") {
275  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
276  if (nodeElementNode != nullptr) {
277  if (nodeElementNode->getActiveConditions().has(value) == true) {
278  nodeElementNode->getActiveConditions().remove(value);
279  } else {
280  nodeElementNode->getActiveConditions().add(value);
281  }
282  }
283  } else
284  if (subCommand == "condition?") {
285  t2.tokenize(value, "?:");
286  string testCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
287  string setOnTrueCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
288  string setOnFalseCondition = t2.hasMoreTokens() == true?t2.nextToken():"";
289  if (value.find('?') == string::npos ||
290  value.find(':') == string::npos ||
291  value.find(':') < value.find('?') ||
292  testCondition.empty() == true ||
293  setOnTrueCondition.empty() == true ||
294  setOnFalseCondition.empty() == true) {
295  Console::println("GUIElementController::executeExpression(): ?= ternary operator requires the following format 'node.condition?=a?b:c'");
296  }
297  auto nodeElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(nodeId));
298  if (nodeElementNode != nullptr) {
299  if (nodeElementNode->getActiveConditions().has(testCondition) == true) {
300  nodeElementNode->getActiveConditions().remove(setOnFalseCondition);
301  nodeElementNode->getActiveConditions().add(setOnTrueCondition);
302  } else {
303  nodeElementNode->getActiveConditions().remove(setOnTrueCondition);
304  nodeElementNode->getActiveConditions().add(setOnFalseCondition);
305  }
306  }
307  } else
308  // image node specific data
309  if (subCommand == "maskmaxvalue") {
310  auto imageNode = dynamic_cast<GUIImageNode*>(screenNode->getNodeById(nodeId));
311  if (imageNode != nullptr) {
312  if (StringTools::endsWith(value, ".value") == true) {
313  auto nodeValueElementNode = dynamic_cast<GUIElementNode*>(screenNode->getNodeById(StringTools::substring(value, 0, value.length() - string(".value").size())));
314  auto nodeValueController = nodeValueElementNode != nullptr?nodeValueElementNode->getController():nullptr;
315  if (nodeValueController != nullptr) imageNode->setMaskMaxValue(Float::parse(nodeValueController->getValue().getString()));
316  } else {
317  imageNode->setMaskMaxValue(Float::parse(value));
318  }
319  }
320  } else
321  if (StringTools::startsWith(command,"delay(") == true &&
322  StringTools::endsWith(command,")") == true) {
323  int64_t delay = Integer::parse(StringTools::substring(command, command.find('(') + 1, command.rfind(')')));
324  while(t1.hasMoreTokens() == true) value+= t1.nextToken() + ";";
325  screenNode->addTimedExpression(Time::getCurrentMillis() + delay, value);
326  } else {
327  Console::println("GUIElementController::executeExpression(): Unknown sub command in expression: expression = " + expression + ", sub command = " + subCommand);
328  }
329  }
330 }
331 
334 }
335 
337  return parentElementId;
338 }
339 
340 bool GUIElementNode::hasOption(const string& option) {
341  return find(begin(options), end(options), option) != end(options);
342 }
343 
344 const string GUIElementNode::getOptionValue(const string& option) {
345  StringTokenizer t;
346  for (const auto& v: options) {
347  t.tokenize(v, "=");
348  if (t.hasMoreTokens() == false) continue;
349  auto optionName = StringTools::trim(t.nextToken());
350  if (optionName != option) continue;
351  if (t.hasMoreTokens() == false) continue;
352  return StringTools::trim(t.nextToken());
353  }
354  return string();
355 }
356 
358 {
359  return activeConditions;
360 }
361 
363 {
364  if (ignoreEvents == true)
365  return;
366 
367  if (conditionsMet == false)
368  return;
369 
370  vector<GUINode*> childControllerNodes;
371  getChildControllerNodes(childControllerNodes, true);
372  if (controller != nullptr) {
373  controller->handleKeyboardEvent(event);
374  }
375  if (event->isProcessed() == false) {
376  for (auto childControllerNode: childControllerNodes) {
377  childControllerNode->getController()->handleKeyboardEvent(event);
378  if (event->isProcessed() == true) break;
379  }
380  }
381 }
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:41
const string getNodeType() override
const string & getOnMouseClickExpression()
void executeOnChangeExpression()
Execute on change expression.
const string & getOnInitializeExpression()
const string & getOnMouseDoubleClickExpression()
GUINodeConditions activeConditions
const string getOptionValue(const string &option)
bool hasOption(const string &option)
static void executeExpression(GUIScreenNode *screenNode, const string &expression)
Execute expression.
void handleKeyboardEvent(GUIKeyboardEvent *event)
Handle keyboard event.
GUINodeConditions & getActiveConditions()
GUI element node conditions.
bool add(const string &condition)
Add a condition.
bool remove(const string &condition)
Remove a condition.
GUI node controller base class.
virtual void setValue(const MutableString &value)=0
Set value.
GUI node base class.
Definition: GUINode.h:64
unique_ptr< GUINodeController > controller
Definition: GUINode.h:163
GUINodeController * getController()
Definition: GUINode.h:661
GUIScreenNode * screenNode
Definition: GUINode.h:147
GUIScreenNode * getScreenNode()
Definition: GUINode.h:325
void setController(GUINodeController *controller)
Set up node controller.
Definition: GUINode.cpp:1046
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:42
void getChildControllerNodes(vector< GUINode * > &childControllerNodes, bool requireConditionsMet=false)
Get child controller nodes.
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:72
void addTimedExpression(int64_t time, const string &expression)
Add a timed expression.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
Console class.
Definition: Console.h:29
Float class.
Definition: Float.h:27
Integer class.
Definition: Integer.h:25
Mutable utf8 aware string class.
Definition: MutableString.h:23
Run time type information utility class.
Definition: RTTI.h:14
String tokenizer class.
void tokenize(const string &str, const string &delimiters, bool emptyTokens=false)
Tokenize.
String tools class.
Definition: StringTools.h:22
Time utility class.
Definition: Time.h:20
GUI node border entity.
GUI node padding entity.
GUI node scale 9 grid entity.