TDME2  1.9.200
UIEditorTabController.cpp
Go to the documentation of this file.
2 
3 #include <string>
4 
5 #include <tdme/tdme.h>
10 #include <tdme/engine/Engine.h>
15 #include <tdme/gui/nodes/GUINode.h>
19 #include <tdme/gui/GUI.h>
20 #include <tdme/gui/GUIParser.h>
34 #include <tdme/utilities/Action.h>
35 #include <tdme/utilities/Console.h>
38 #include <tdme/utilities/Integer.h>
41 
42 #include <ext/tinyxml/tinyxml.h>
43 
45 
46 using std::string;
47 
59 using tdme::gui::GUI;
81 
85 
86 #define AVOID_NULLPTR_STRING(arg) (arg == nullptr?"":arg)
87 
88 UIEditorTabController::UIEditorTabController(UIEditorTabView* view)
89 {
90  this->view = view;
91  this->popUps = view->getPopUps();
92 }
93 
95 }
96 
98 {
99  this->screenNode = screenNode;
100 }
101 
103 {
104 }
105 
107 {
108  switch (command) {
109  case COMMAND_REDO:
110  view->redo();
111  break;
112  case COMMAND_UNDO:
113  view->undo();
114  break;
115  case COMMAND_CUT:
116  view->cut();
117  break;
118  case COMMAND_COPY:
119  view->copy();
120  break;
121  case COMMAND_PASTE:
122  view->paste();
123  break;
124  case COMMAND_DELETE:
125  view->delete_();
126  break;
127  case COMMAND_SELECTALL:
128  view->selectAll();
129  break;
130  case COMMAND_SAVE:
131  save();
132  break;
133  case COMMAND_SAVEAS:
134  saveAs();
135  break;
136  case COMMAND_FINDREPLACE:
137  {
138  //
139  firstSearch = true;
141 
142  //
143  class FindAction: public virtual Action
144  {
145  public:
146  void performAction() override {
147  if (uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
148  uiEditorTabController->showInfoPopUp("Find", "No find string given.");
149  } else {
150  if (uiEditorTabController->view->find(
151  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
152  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
153  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
154  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly(),
155  uiEditorTabController->firstSearch,
156  uiEditorTabController->searchIndex
157  ) == false) {
158  uiEditorTabController->showInfoPopUp("Find", "Text not found.");
159  }
160  uiEditorTabController->firstSearch = false;
161  }
162  }
163  FindAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
164  }
165  private:
166  UIEditorTabController* uiEditorTabController;
167  };
168  //
169  class CountAction: public virtual Action
170  {
171  public:
172  void performAction() override {
173  if (uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
174  uiEditorTabController->showInfoPopUp("Count", "No find string given.");
175  } else {
176  auto count = uiEditorTabController->view->count(
177  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
178  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
179  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
180  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly()
181  );
182  uiEditorTabController->showInfoPopUp("Count", "The text occurred " + to_string(count) + " times.");
183  }
184  }
185  CountAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
186  }
187  private:
188  UIEditorTabController* uiEditorTabController;
189  };
190  //
191  class ReplaceAction: public virtual Action
192  {
193  public:
194  void performAction() override {
195  if (uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
196  uiEditorTabController->showInfoPopUp("Replace", "No find string given.");
197  } else {
198  if (uiEditorTabController->view->replace(
199  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
200  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getReplaceText(),
201  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
202  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
203  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly(),
204  uiEditorTabController->searchIndex
205  ) == false) {
206  uiEditorTabController->showInfoPopUp("Replace", "Text not found.");
207  }
208  }
209  }
210  ReplaceAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
211  }
212  private:
213  UIEditorTabController* uiEditorTabController;
214  };
215  //
216  class ReplaceAllAction: public virtual Action
217  {
218  public:
219  void performAction() override {
220  if (uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
221  uiEditorTabController->showInfoPopUp("Replace All", "No find string given.");
222  } else {
223  if (uiEditorTabController->view->replaceAll(
224  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
225  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->getReplaceText(),
226  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
227  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
228  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly()
229  ) == false) {
230  uiEditorTabController->showInfoPopUp("Replace All", "Text not found.");
231  }
232  }
233  }
234  ReplaceAllAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
235  }
236  private:
237  UIEditorTabController* uiEditorTabController;
238  };
239  //
240  class CompleteAction: public virtual Action
241  {
242  public:
243  void performAction() override {
244  uiEditorTabController->view->cancelFind();
245  uiEditorTabController->popUps->getFindReplaceDialogScreenController()->close();
246  }
247  CompleteAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
248  }
249  private:
250  UIEditorTabController* uiEditorTabController;
251  };
252  //
254  new FindAction(this),
255  new CountAction(this),
256  new ReplaceAction(this),
257  new ReplaceAllAction(this),
258  new CompleteAction(this)
259  );
260  }
261  break;
262  default:
263  showInfoPopUp("Warning", "This command is not supported yet");
264  break;
265  }
266 }
267 
268 void UIEditorTabController::onDrop(const string& payload, int mouseX, int mouseY) {
269  if (StringTools::startsWith(payload, "file:") == false) {
270  showInfoPopUp("Warning", "Unknown payload in drop");
271  } else {
272  auto fileName = StringTools::substring(payload, string("file:").size());
273  if (view->getEditorView()->getScreenController()->isDropOnNode(mouseX, mouseY, "screen") == true) {
274  if (Tools::hasFileExtension(fileName, {{ "xml" }}) == false) {
275  showInfoPopUp("Warning", "You can not drop this file here. Allowed file extensions are " + Tools::enumerateFileExtensions({{ "xml" }}));
276  } else {
277  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
278  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
279  setScreen(screenIdx, fileName);
280  }
281  } else
282  if (view->getEditorView()->getScreenController()->isDropOnNode(mouseX, mouseY, "projectedui_prototype") == true) {
283  if (Tools::hasFileExtension(fileName, PrototypeReader::getModelExtensions()) == false) {
284  showInfoPopUp("Warning", "You can not drop this file here. Allowed file extensions are " + Tools::enumerateFileExtensions(PrototypeReader::getModelExtensions()));
285  } else {
286  setPrototype(
287  Tools::getPathName(fileName),
288  Tools::getFileName(fileName),
291  );
292  }
293  } else {
294  showInfoPopUp("Warning", "You can not drop a file here");
295  }
296  }
297 }
298 
299 void UIEditorTabController::showInfoPopUp(const string& caption, const string& message)
300 {
301  popUps->getInfoDialogScreenController()->show(caption, message);
302 }
303 
305 {
306  if (node->getId() == "selectbox_outliner") {
308  auto outlinerNode = node->getController()->getValue().getString();
309  view->setScreenIdx(outlinerNode == "screens"?0:Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find("."))));
310  } else
311  if (node->getId() == "dropdown_outliner_add") {
312  auto addOutlinerType = node->getController()->getValue().getString();;
313  if (addOutlinerType == "screen") {
314  view->addScreen();
315  view->getEditorView()->reloadTabOutliner(to_string(view->getUIScreenNodes().size() - 1) + ".0");
316  }
317  } else
318  if (node->getId() == "projectedui_meshnode") {
321  } else
322  if (node->getId() == "projectedui_animation") {
325  } else
326  if (node->getId() == view->getTabId() + "_tab_checkbox_visualui" == true) {
327  auto visual = node->getController()->getValue().equals("1");
328  if (visual == true) {
329  view->storeUIXML();
331  } else {
332  view->setCodeEditor();
333  }
334  }
335 }
336 
338 }
339 
341 }
342 
343 void UIEditorTabController::onContextMenuRequest(GUIElementNode* node, int mouseX, int mouseY) {
344  if (node->getId() == "selectbox_outliner") {
345  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
346  if (outlinerNode == "screens") {
347  // clear
349 
350  // add screen
351  class OnAddScreenAction: public virtual Action
352  {
353  public:
354  OnAddScreenAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
355  }
356  void performAction() override {
357  auto view = uiEditorTabController->getView();
358  view->addScreen();
359  view->getEditorView()->reloadTabOutliner(to_string(view->getUIScreenNodes().size() - 1) + ".0");
360  }
361  private:
362  UIEditorTabController* uiEditorTabController;
363  };
364  popUps->getContextMenuScreenController()->addMenuItem("Add Screen", "contextmenu_add", new OnAddScreenAction(this));
365 
366  // reload screens
367  class OnScreensReloadAction: public virtual Action
368  {
369  public:
370  OnScreensReloadAction(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
371  }
372  void performAction() override {
373  uiEditorTabController->reloadScreens();
374  }
375  private:
376  UIEditorTabController* uiEditorTabController;
377  };
378  popUps->getContextMenuScreenController()->addMenuItem("Reload", "contextmenu_reload", new OnScreensReloadAction(this));
379 
380  // show
381  popUps->getContextMenuScreenController()->show(mouseX, mouseY);
382  } else
383  if (StringTools::endsWith(outlinerNode, ".0") == true && StringTools::startsWith(outlinerNode, "0.") == false) {
384  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
385 
386  // clear
388 
389  // remove screen
390  class OnScreenRemoveAction: public virtual Action
391  {
392  public:
393  OnScreenRemoveAction(UIEditorTabController* uiEditorTabController, int screenIdx): uiEditorTabController(uiEditorTabController), screenIdx(screenIdx) {
394  }
395  void performAction() override {
396  auto view = uiEditorTabController->getView();
397  view->removeScreen(screenIdx);
398  view->getEditorView()->reloadTabOutliner(to_string(view->getUIScreenNodes().size() - 1) + ".0");
399  }
400  private:
401  UIEditorTabController* uiEditorTabController;
402  int screenIdx;
403  };
404  popUps->getContextMenuScreenController()->addMenuItem("Remove", "contextmenu_remove", new OnScreenRemoveAction(this, screenIdx));
405 
406  // show
407  popUps->getContextMenuScreenController()->show(mouseX, mouseY);
408  }
409  }
410 }
411 
412 void UIEditorTabController::onTooltipShowRequest(GUINode* node, int mouseX, int mouseY) {
413  int tooltipLeft, tooltipTop;
414  if (view->getEditorView()->getCurrentTabTooltipPosition(screenNode, mouseX, mouseY, tooltipLeft, tooltipTop) == false) return;
415  //
416  popUps->getTooltipScreenController()->show(tooltipLeft, tooltipTop, node->getToolTip());
417 }
418 
421 }
422 
423 void UIEditorTabController::createOutlinerParentNodeNodesXML(TiXmlElement* xmlParentNode, string& xml, int screenIdx, int& nodeIdx) {
424  if (xmlParentNode->FirstChildElement() == nullptr) {
425  auto nodeId = string(AVOID_NULLPTR_STRING(xmlParentNode->Attribute("id")));
426  xml+= "<selectbox-option text=\"<" + GUIParser::escape(xmlParentNode->Value()) + ">" + (nodeId.empty() == false?string(" (") + nodeId + ")":"") + "\" value=\"" + to_string(screenIdx) + "." + GUIParser::escape(to_string(nodeIdx++)) + "\" />\n";
427  } else {
428  auto nodeId = string(AVOID_NULLPTR_STRING(xmlParentNode->Attribute("id")));
429  xml+= "<selectbox-parent-option text=\"<" + GUIParser::escape(xmlParentNode->Value()) + ">" + (nodeId.empty() == false?string(" (") + nodeId + ")":"") + "\" value=\"" + to_string(screenIdx) + "." + GUIParser::escape(to_string(nodeIdx++)) + "\" >\n";
430  for (auto* childNode = xmlParentNode->FirstChildElement(); childNode != nullptr; childNode = childNode->NextSiblingElement()) {
431  createOutlinerParentNodeNodesXML(childNode, xml, screenIdx, nodeIdx);
432  }
433  xml+= "</selectbox-parent-option>\n";
434  }
435 }
436 
438  string xml;
439  xml+= "<selectbox-parent-option text=\"Screens\" value=\"screens\">\n";
440  auto screenIdx = 0;
441  for (const auto& uiScreenNode: view->getUIScreenNodes()) {
442  auto screenNode = uiScreenNode.screenNode;
443  if (screenNode == nullptr) {
444  xml+= "<selectbox-option text=\"<screen>\" value=\"" + to_string(screenIdx) + ".0\" />\n";
445  screenIdx++;
446  continue;
447  }
448  if (uiScreenNode.xml.empty() == false) {
449  try {
450  TiXmlDocument xmlDocument;
451  xmlDocument.Parse(uiScreenNode.xml.c_str());
452  if (xmlDocument.Error() == true) {
453  auto message = "UIEditorTabController::setOutlinerContent(): Could not parse XML. Error='" + string(xmlDocument.ErrorDesc()) + "':\n\n" + uiScreenNode.xml;
454  Console::println(message);
455  throw GUIParserException(message);
456  }
457  TiXmlElement* xmlRoot = xmlDocument.RootElement();
458  int nodeIdx = 0;
459  createOutlinerParentNodeNodesXML(xmlRoot, xml, screenIdx, nodeIdx);
460  } catch (Exception& exception) {
461  showInfoPopUp("Warning", string(exception.what()));
462  }
463  }
464  screenIdx++;
465  }
466  xml+= "</selectbox-parent-option>\n";
468 }
469 
472  string("<dropdown-option text=\"Screen\" value=\"screen\" />\n")
473  );
474 }
475 
476 void UIEditorTabController::updateDetails(const string& outlinerNode) {
477  if (outlinerNode == "screens") {
479  } else
480  if (StringTools::endsWith(outlinerNode, ".0") == true) {
482  view->setScreenIdx(outlinerNode == "screens"?0:Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find("."))));
483  } else {
484  view->getEditorView()->setDetailsContent(string());
485  }
486 }
487 
490  string("<template id=\"details_screen\" src=\"resources/engine/gui/template_details_screen.xml\" />\n")
491  );
492 
493  //
494  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
495  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
496 
497  //
498  try {
499  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("details_screen"))->getActiveConditions().add("open");
500  if (screenIdx >= 0 &&
501  screenIdx < view->getUIScreenNodes().size() &&
502  view->getUIScreenNodes()[screenIdx].screenNode != nullptr &&
503  view->getUIScreenNodes()[screenIdx].fileName.empty() == false) {
504  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById("screen"))->setSource("resources/engine/images/gui_big.png");
505  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById("screen"))->setTooltip(view->getUIScreenNodes()[screenIdx].fileName);
506  }
507  } catch (Exception& exception) {
508  Console::println("UIEditorTabController::updateScreenDetails(): An error occurred: " + string(exception.what()));
509  showInfoPopUp("Warning", string(exception.what()));
510  }
511 }
512 
515  string("<template id=\"details_screens\" src=\"resources/engine/gui/template_details_projectedui.xml\" />\n")
516  );
517 
518  //
519  try {
520  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("details_screens"))->getActiveConditions().add("open");
521  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById("projectedui_prototype"))->setSource(prototypeFileName);
522  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById("projectedui_prototype"))->setTooltip(prototypeFileName);
523  } catch (Exception& exception) {
524  Console::println("UIEditorTabController::updateScreensDetails(): An error occurred: " + string(exception.what()));
525  showInfoPopUp("Warning", string(exception.what()));
526  }
527 
528  //
529  auto model = view->getPrototype() != nullptr?view->getPrototype()->getModel():nullptr;
530 
531  {
532  string modelMeshNodesXML;
533  modelMeshNodesXML =
534  modelMeshNodesXML +
535  "<dropdown-option text=\"<None>\" value=\"\" " + (modelMeshNodesXML.empty() == true?"selected=\"true\" ":"") + " />\n";
536  if (model != nullptr) {
537  for (const auto& nodeId: model->getNodeIds()) {
538  modelMeshNodesXML+=
539  "<dropdown-option text=\"" +
540  GUIParser::escape(nodeId) +
541  "\" value=\"" +
542  GUIParser::escape(nodeId) +
543  "\" " +
544  (modelMeshNodesXML == nodeId?"selected=\"true\" ":"") +
545  " />\n";
546  }
547  }
548  try {
549  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById("projectedui_meshnode_scrollarea"))->replaceSubNodes(modelMeshNodesXML, true);
550  } catch (Exception& exception) {
551  Console::print("UIEditorTabController::updateScreensDetails(): An error occurred: " + string(exception.what()));
552  }
553  }
554 
555  {
556  string animationsXML;
557  animationsXML = animationsXML + "<dropdown-option text=\"<No animation>\" value=\"\" selected=\"true\" />";
558  if (model != nullptr) {
559  for (const auto& animationSetupId: model->getAnimationSetupIds()) {
560  auto animationSetup = model->getAnimationSetup(animationSetupId);
561  if (animationSetup == nullptr || animationSetup->isOverlayAnimationSetup() == true) continue;
562  animationsXML =
563  animationsXML + "<dropdown-option text=\"" +
564  GUIParser::escape(animationSetup->getId()) +
565  "\" value=\"" +
566  GUIParser::escape(animationSetup->getId()) +
567  "\" " +
568  " />\n";
569  }
570  }
571  try {
572  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById("projectedui_animation_scrollarea"))->replaceSubNodes(animationsXML, true);
573  } catch (Exception& exception) {
574  Console::println("ModelEditorTabController::setAnimationPreviewDetails(): An error occurred: " + string(exception.what()));
575  }
576  }
577 }
578 
580  class OnLoadScreen: public virtual Action
581  {
582  public:
583  void performAction() override {
584  //
585  uiEditorTabController->setScreen(
586  screenIdx,
587  uiEditorTabController->popUps->getFileDialogScreenController()->getPathName() + "/" + uiEditorTabController->popUps->getFileDialogScreenController()->getFileName()
588  );
589  //
590  uiEditorTabController->view->getPopUps()->getFileDialogScreenController()->close();
591  }
592 
593  /**
594  * Public constructor
595  * @param uiEditorTabController UI editor tab controller
596  * @param screenIdx screen index
597  */
598  OnLoadScreen(UIEditorTabController* uiEditorTabController, int screenIdx)
599  : uiEditorTabController(uiEditorTabController), screenIdx(screenIdx) {
600  }
601 
602  private:
603  UIEditorTabController* uiEditorTabController;
604  int screenIdx;
605  };
606 
607  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
608  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
609  if (screenIdx < 0 || screenIdx >= view->getUIScreenNodes().size()) return;
610  auto screenNode = view->getUIScreenNodes()[screenIdx].screenNode;
611  auto pathName = screenNode != nullptr?Tools::getPathName(view->getUIScreenNodes()[screenIdx].fileName):string();
612  auto fileName = screenNode != nullptr?Tools::getFileName(view->getUIScreenNodes()[screenIdx].fileName):string();
614  pathName,
615  "Load screen from: ",
616  { { "xml" } },
617  fileName,
618  true,
619  new OnLoadScreen(this, screenIdx)
620  );
621 }
622 
624  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
625  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
626  if (screenIdx < 0 || screenIdx >= view->getUIScreenNodes().size()) return;
627  view->unsetScreen(screenIdx);
628  view->reAddScreens();
629  view->getEditorView()->reloadTabOutliner(to_string(screenIdx) + ".0");
630 }
631 
633  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
634  auto screenIdx = Integer::parse(StringTools::substring(outlinerNode, 0, outlinerNode.find(".")));
635  if (screenIdx < 0 || screenIdx >= view->getUIScreenNodes().size() || view->getUIScreenNodes()[screenIdx].fileName.empty() == true) {
636  showInfoPopUp("Browse To", "Nothing to browse to");
637  } else {
638  view->getEditorView()->getScreenController()->browseTo(view->getUIScreenNodes()[screenIdx].fileName);
639  }
640 }
641 
643  for (auto i = 0; i < view->getUIScreenNodes().size(); i++) {
644  auto fileName = view->getUIScreenNodes()[i].fileName;
645  view->unsetScreen(i);
646  try {
647  view->setScreen(
648  i,
649  fileName
650  );
651  } catch (Exception& exception) {
652  Console::println("UIEditorTabController::reloadScreens(): An error occurred: " + string(exception.what()));
653  }
654  }
655  view->reAddScreens();
656  view->getEditorView()->reloadTabOutliner("screens");
657 }
658 
660  class OnLoadPrototype: public virtual Action
661  {
662  public:
663  void performAction() override {
664  uiEditorTabController->setPrototype(
665  uiEditorTabController->popUps->getFileDialogScreenController()->getPathName(),
666  uiEditorTabController->popUps->getFileDialogScreenController()->getFileName(),
667  uiEditorTabController->prototypeMeshNode,
668  uiEditorTabController->prototypeMeshAnimation
669  );
670  uiEditorTabController->view->getPopUps()->getFileDialogScreenController()->close();
671  }
672 
673  /**
674  * Public constructor
675  * @param uiEditorTabController UI editor tab controller
676  */
677  OnLoadPrototype(UIEditorTabController* uiEditorTabController): uiEditorTabController(uiEditorTabController) {
678  }
679 
680  private:
681  UIEditorTabController* uiEditorTabController;
682  };
683 
684  //
685  auto pathName = screenNode != nullptr?Tools::getPathName(prototypeFileName):string();
686  auto fileName = screenNode != nullptr?Tools::getFileName(prototypeFileName):string();
688  pathName,
689  "Load prototype from: ",
690  PrototypeReader::getPrototypeExtensions(),
691  fileName,
692  true,
693  new OnLoadPrototype(this)
694  );
695 }
696 
698  prototypeFileName.clear();
700  view->reAddScreens();
701  view->getEditorView()->reloadTabOutliner("screens");
702 }
703 
705  if (prototypeFileName.empty() == true) {
706  showInfoPopUp("Browse To", "Nothing to browse to");
707  } else {
709  }
710 }
711 
713 {
714  if (type != GUIActionListenerType::PERFORMED) return;
715  if (node->getId() == "screen_open") {
716  onLoadScreen();
717  } else
718  if (node->getId() == "screen_remove") {
719  onUnsetScreen();
720  } else
721  if (node->getId() == "screen_browseto") {
723  } else
724  if (node->getId() == "projectedui_prototype_open") {
725  onLoadPrototype();
726  } else
727  if (node->getId() == "projectedui_prototype_remove") {
729  } else
730  if (node->getId() == "projectedui_prototype_browseto") {
732  }
733 }
734 
735 void UIEditorTabController::setScreen(int screenIdx, const string& fileName) {
736  view->unsetScreen(screenIdx);
737  try {
738  view->setScreen(screenIdx, fileName);
739  } catch (Exception& exception) {
740  Console::println("UIEditorTabController::setScreen(): An error occurred: " + string(exception.what()));
741  showInfoPopUp("Error", "An error occurred: " + string(exception.what()));
742  }
743  view->reAddScreens();
744  view->getEditorView()->reloadTabOutliner(to_string(screenIdx) + ".0");
745 }
746 
747 void UIEditorTabController::setPrototype(const string& pathName, const string& fileName, const string& modelMeshNode, const string& modelMeshAnimation) {
748  if (view->loadPrototype(pathName, fileName, prototypeMeshNode, prototypeMeshAnimation) != nullptr) {
749  prototypeFileName = pathName + "/" + fileName;
750  view->reAddScreens();
751  view->getEditorView()->reloadTabOutliner("screens");
752  } else {
753  showInfoPopUp("Error", string() + "Could not load prototype");
754  }
755 }
756 
759 }
760 
762  //
763  view->storeUIXML();
764 
765  //
766  class OnUISave: public virtual Action
767  {
768  public:
769  void performAction() override {
770  // skip if wrong screen index
771  if (screenIdx < 0 || screenIdx >= uiEditorTabController->view->getUIScreenNodes().size()) {
772  uiEditorTabController->popUps->getFileDialogScreenController()->close();
773  return;
774  }
775 
776  // get new path and file name
777  auto pathName = uiEditorTabController->popUps->getFileDialogScreenController()->getPathName();
778  auto fileName = Tools::ensureFileExtension(uiEditorTabController->popUps->getFileDialogScreenController()->getFileName(), "xml");
779  uiEditorTabController->view->getUIScreenNodes()[screenIdx].fileName = pathName + "/" + fileName;
780 
781  // save
782  try {
783  FileSystem::getInstance()->setContentFromString(
784  pathName,
785  fileName,
786  uiEditorTabController->view->getUIScreenNodes()[screenIdx].xml
787  );
788  // refresh outliner if required
789  if (uiEditorTabController->view->getScreenIdx() == screenIdx) {
790  uiEditorTabController->view->getEditorView()->reloadTabOutliner(to_string(screenIdx) + ".0");
791  }
792  } catch (Exception& exception) {
793  uiEditorTabController->showInfoPopUp("Warning", string(exception.what()));
794  }
795 
796  // iterate to next screen that we want to save
797  screenIdx++;
798  for (; screenIdx < uiEditorTabController->view->getUIScreenNodes().size(); screenIdx++) {
799  // skip on empty xml
800  if (uiEditorTabController->view->getUIScreenNodes()[screenIdx].xml.empty() == true) continue;
801  // skip on existin filename as we saved this before
802  if (uiEditorTabController->view->getUIScreenNodes()[screenIdx].fileName.empty() == false) continue;
803  //
804  break;
805  }
806 
807  // issue SAVE AS for next screen
808  if (screenIdx >= 0 && screenIdx < uiEditorTabController->view->getUIScreenNodes().size()) {
809  auto fileName = Tools::getPathName(uiEditorTabController->view->getFileName()) + "/Untitled.xml";
810  uiEditorTabController->popUps->getFileDialogScreenController()->show(
811  Tools::getPathName(fileName),
812  "Save to: ",
813  { { "xml" } },
814  Tools::getFileName(fileName),
815  false,
816  new OnUISave(uiEditorTabController, screenIdx)
817  );
818  }
819  // close this file dialog
820  uiEditorTabController->popUps->getFileDialogScreenController()->close();
821  }
822 
823  /**
824  * Public constructor
825  * @param uiEditorTabController ui editor tab controller
826  */
827  OnUISave(UIEditorTabController* uiEditorTabController, int screenIdx): uiEditorTabController(uiEditorTabController), screenIdx(screenIdx) {
828  }
829 
830  private:
831  UIEditorTabController* uiEditorTabController;
832  int screenIdx;
833  };
834 
835  // save files with file name
836  const auto& uiScreenNodes = view->getUIScreenNodes();
837  auto emptyFileNameIdx = -1;
838  for (auto screenIdx = 0; screenIdx < uiScreenNodes.size(); screenIdx++) {
839  // skip on empty xml
840  if (uiScreenNodes[screenIdx].xml.empty() == true) continue;
841  // empty filename?
842  if (uiScreenNodes[screenIdx].fileName.empty() == true) {
843  emptyFileNameIdx = screenIdx;
844  continue;
845  }
846 
847  //
848  const auto& uiScreenNode = uiScreenNodes[screenIdx];
849  try {
850  FileSystem::getInstance()->setContentFromString(
851  Tools::getPathName(uiScreenNode.fileName),
852  Tools::getFileName(uiScreenNode.fileName),
853  uiScreenNode.xml
854  );
855  } catch (Exception& exception) {
856  Console::println("UIEditorTabController::save(): An error occurred: " + string(exception.what()));
857  showInfoPopUp("Warning", string(exception.what()));
858  }
859  }
860 
861  //
862  if (emptyFileNameIdx != -1) {
863  const auto& uiScreenNode = uiScreenNodes[emptyFileNameIdx];
864  //
865  auto fileName = Tools::getPathName(view->getFileName()) + "/Untitled.xml";
867  Tools::getPathName(fileName),
868  "Save to: ",
869  { { "xml" } },
870  Tools::getFileName(fileName),
871  false,
872  new OnUISave(this, emptyFileNameIdx)
873  );
874  }
875 }
876 
878  //
879  view->storeUIXML();
880 
881  //
882  class OnUISaveAs: public virtual Action
883  {
884  public:
885  /**
886  * Public constructor
887  * @param uiEditorTabController ui editor tab controller
888  */
889  OnUISaveAs(UIEditorTabController* uiEditorTabController, int screenIdx): uiEditorTabController(uiEditorTabController), screenIdx(screenIdx) {
890  }
891 
892  void performAction() override {
893  // skip if wrong screen index
894  if (screenIdx < 0 || screenIdx >= uiEditorTabController->view->getUIScreenNodes().size()) {
895  uiEditorTabController->popUps->getFileDialogScreenController()->close();
896  return;
897  }
898 
899  // get new path and file name
900  auto pathName = uiEditorTabController->popUps->getFileDialogScreenController()->getPathName();
901  auto fileName = Tools::ensureFileExtension(uiEditorTabController->popUps->getFileDialogScreenController()->getFileName(), "xml");
902  uiEditorTabController->view->getUIScreenNodes()[screenIdx].fileName = pathName + "/" + fileName;
903 
904  // save
905  try {
906  FileSystem::getInstance()->setContentFromString(
907  pathName,
908  fileName,
909  uiEditorTabController->view->getUIScreenNodes()[screenIdx].xml
910  );
911  // refresh outliner if required
912  if (uiEditorTabController->view->getScreenIdx() == screenIdx) {
913  uiEditorTabController->view->getEditorView()->reloadTabOutliner(to_string(screenIdx) + ".0");
914  }
915  } catch (Exception& exception) {
916  uiEditorTabController->showInfoPopUp("Warning", string(exception.what()));
917  }
918 
919  // iterate to next screen that we want to save
920  screenIdx++;
921  for (; screenIdx < uiEditorTabController->view->getUIScreenNodes().size(); screenIdx++) {
922  //
923  if (uiEditorTabController->view->getUIScreenNodes()[screenIdx].xml.empty() == true) continue;
924  //
925  break;
926  }
927 
928  // issue SAVE AS for next screen
929  if (screenIdx >= 0 && screenIdx < uiEditorTabController->view->getUIScreenNodes().size()) {
930  auto fileName = uiEditorTabController->view->getUIScreenNodes()[screenIdx].fileName;
931  if (fileName.empty() == true) fileName = Tools::getPathName(uiEditorTabController->view->getFileName()) + "/Untitled.xml";
932  uiEditorTabController->popUps->getFileDialogScreenController()->show(
933  Tools::getPathName(fileName),
934  "Save to: ",
935  { { "xml" } },
936  Tools::getFileName(fileName),
937  false,
938  new OnUISaveAs(uiEditorTabController, screenIdx)
939  );
940  }
941  // close this file dialog
942  uiEditorTabController->popUps->getFileDialogScreenController()->close();
943  }
944 
945  private:
946  UIEditorTabController* uiEditorTabController;
947  int screenIdx;
948  };
949 
950  // find first screen to be saved
951  const auto& uiScreenNodes = view->getUIScreenNodes();
952  for (auto screenIdx = 0; screenIdx < uiScreenNodes.size(); screenIdx++) {
953  //
954  if (uiScreenNodes[screenIdx].xml.empty() == true) continue;
955 
956  //
957  auto fileName = uiScreenNodes[screenIdx].fileName;
958  if (fileName.empty() == true) fileName = Tools::getPathName(view->getFileName()) + "/Untitled.xml";
960  Tools::getPathName(fileName),
961  "Save to: ",
962  { { "xml" } },
963  Tools::getFileName(fileName),
964  false,
965  new OnUISaveAs(this, screenIdx)
966  );
967 
968  //
969  break;
970  }
971 }
#define AVOID_NULLPTR_STRING(arg)
Engine main class.
Definition: Engine.h:131
Representation of a 3D model.
Definition: Model.h:35
Model node.
Definition: Node.h:32
GUI parser.
Definition: GUIParser.h:40
GUI module class.
Definition: GUI.h:64
GUI node controller base class.
virtual const MutableString & getValue()=0
GUI node base class.
Definition: GUINode.h:64
const string & getToolTip()
Definition: GUINode.h:346
GUINodeController * getController()
Definition: GUINode.h:661
GUIScreenNode * screenNode
Definition: GUINode.h:147
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
GUINode * getInnerNodeById(const string &nodeId)
Get inner GUI node by id.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
File system singleton class.
Definition: FileSystem.h:17
void show(int mouseX, int mouseY)
Shows the pop up.
void addMenuItem(const string &text, const string &id, Action *action=nullptr)
Add menu item.
bool isDropOnNode(int dropX, int dropY, const string &nodeId)
Is drop on node.
void browseTo(const string &fileName)
Browse to file name.
void show(const string &cwd, const string &captionText, const vector< string > &extensions, const string &fileName, bool enableFilter, Action *applyAction, Action *cancelAction=nullptr, const string &settingsFileName=".filedialog.properties", const string &settingsPathName=string())
Shows the file dialog pop up.
void show(Action *findAction, Action *countAction, Action *replaceAction, Action *replaceAllAction, Action *completeAction)
Shows the pop up.
void show(const string &caption, const string &message)
Shows the pop up.
void show(int mouseX, int mouseY, const string &tooltip)
Show tooltip.
Pop ups controller accessor class.
Definition: PopUps.h:29
FindReplaceDialogScreenController * getFindReplaceDialogScreenController()
Definition: PopUps.h:110
FileDialogScreenController * getFileDialogScreenController()
Definition: PopUps.h:61
TooltipScreenController * getTooltipScreenController()
Definition: PopUps.h:131
ContextMenuScreenController * getContextMenuScreenController()
Definition: PopUps.h:96
InfoDialogScreenController * getInfoDialogScreenController()
Definition: PopUps.h:75
void onContextMenuRequest(GUIElementNode *node, int mouseX, int mouseY) override
On context menu request.
void onDrop(const string &payload, int mouseX, int mouseY) override
On drop.
void setOutlinerAddDropDownContent()
Set outliner add drop down content.
void onChange(GUIElementNode *node) override
On change.
void setScreen(int screenIdx, const string &fileName)
Set screen.
void setPrototype(const string &pathName, const string &fileName, const string &modelMeshNode, const string &modelMeshAnimation)
Set prototype.
void onCommand(TabControllerCommand command) override
On command.
void onUnfocus(GUIElementNode *node) override
On unfocus.
void onTooltipCloseRequest() override
On tooltip close request.
void updateDetails(const string &outlinerNode)
Update details panel.
void onFocus(GUIElementNode *node) override
On focus.
void initialize(GUIScreenNode *screenNode) override
Init.
void createOutlinerParentNodeNodesXML(TiXmlElement *xmlParentNode, string &xml, int screenIdx, int &nodeIdx)
Create outliner GUI parent node nodes xml.
void showInfoPopUp(const string &caption, const string &message)
Show the information pop up / modal.
void onAction(GUIActionListenerType type, GUIElementNode *node) override
void onTooltipShowRequest(GUINode *node, int mouseX, int mouseY) override
On tooltip show request.
Prototype * loadPrototype(const string &pathName, const string &fileName, const string &modelMeshNode, const string &modelMeshAnimation)
Load prototype.
void setScreen(int screenIdx, const string &fileName)
Set screen.
void setModelMeshAnimation(const string &modelMeshAnimation)
Set model mesh animation.
void removeScreen(int screenIdx)
Remove screen.
void unsetScreen(int screenIdx)
Unset screen.
void setModelMeshNode(const string &modelMeshNode)
Set model mesh node.
void setScreenIdx(int screenIdx)
Set screen index.
void setOutlinerAddDropDownContent(const string &xml)
Set outliner add drop down content.
Definition: EditorView.cpp:400
void setOutlinerContent(const string &xml)
Set outliner content.
Definition: EditorView.cpp:396
EditorScreenController * getScreenController()
Definition: EditorView.h:69
void setDetailsContent(const string &xml)
Set details content.
Definition: EditorView.cpp:404
bool getCurrentTabTooltipPosition(GUIScreenNode *screenNode, int mouseX, int mouseY, int &tooltipLeft, int &tooltipTop)
Determine current tab tooltip position.
Definition: EditorView.cpp:439
void reloadTabOutliner(const string &newSelectionValue=string())
Reload tab outliner.
Definition: EditorView.cpp:408
Console class.
Definition: Console.h:29
Exception base class.
Definition: ExceptionBase.h:19
Integer class.
Definition: Integer.h:25
Mutable utf8 aware string class.
Definition: MutableString.h:23
bool equals(const string &s2) const
Equals.
const string & getString() const
String tools class.
Definition: StringTools.h:22
An attribute is a name-value pair.
Definition: tinyxml.h:734
Always the top level node.
Definition: tinyxml.h:1317
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Parse the given null terminated block of xml data.
const char * ErrorDesc() const
Contains a textual (english) description of the error if one occurs.
Definition: tinyxml.h:1382
const TiXmlElement * RootElement() const
Get the root element – the only top level element – of the document.
Definition: tinyxml.h:1371
bool Error() const
If an error occurs, Error will be set to true.
Definition: tinyxml.h:1379
The element is a container class.
Definition: tinyxml.h:886
const char * Attribute(const char *name) const
Given an attribute name, Attribute() returns the value for the attribute of that name,...
Definition: tinyxml.cpp:564
const char * Value() const
The meaning of 'value' changes for the specific type of TiXmlNode.
Definition: tinyxml.h:457
const TiXmlElement * NextSiblingElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:471
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:441
std::exception Exception
Exception base class.
Definition: Exception.h:18
Tab controller, which connects UI with logic.
Definition: TabController.h:34
Action Interface.
Definition: Action.h:11