TDME2  1.9.200
EditorScreenController.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <memory>
5 #include <string>
6 #include <string_view>
7 #include <unordered_set>
8 #include <vector>
9 
10 #include <tdme/tdme.h>
18 #include <tdme/engine/Texture.h>
21 #include <tdme/engine/fwd-tdme.h>
31 #include <tdme/engine/Engine.h>
36 #include <tdme/gui/nodes/GUINode.h>
43 #include <tdme/gui/GUI.h>
44 #include <tdme/gui/GUIParser.h>
45 #include <tdme/math/Matrix3x3.h>
84 #include <tdme/utilities/Action.h>
85 #include <tdme/utilities/Console.h>
87 #include <tdme/utilities/Integer.h>
91 
92 using std::make_unique;
93 using std::move;
94 using std::remove;
95 using std::string;
96 using std::string_view;
97 using std::unique_ptr;
98 using std::unordered_set;
99 using std::vector;
100 
180 
181 EditorScreenController::EditorScreenController(EditorView* view): fileEntitiesMutex("fileentities-mutex")
182 {
183  this->view = view;
184 }
185 
187 {
188  // TODO
189 }
190 
192 {
193  return screenNode;
194 }
195 
197 {
198  try {
199  screenNode = GUIParser::parse("resources/engine/gui", "screen_editor.xml");
206  projectPathsScrollArea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_projectpaths_scrollarea"));
207  projectPathFilesScrollArea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_projectpathfiles_scrollarea"));
208  tabs = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs"));
209  tabsHeader = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs-header"));
210  tabsContent = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs-content"));
211  outliner = required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("selectbox_outliner"));
212  outlinerScrollarea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_outliner_scrollarea"));
213  detailsScrollarea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_details_scrollarea"));
214  outlinerAddDropDown = required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"));
215  logStyledTextNode = required_dynamic_cast<GUIStyledTextNode*>(screenNode->getInnerNodeById("log"));
216  logScrollarea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("log_scrollarea"));
217 
218  //
219  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(true);
220  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(true);
221  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(true);
222  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(true);
223  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(true);
224  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(true);
225 
226  //
230  } catch (Exception& exception) {
231  Console::println("EditorScreenController::initialize(): An error occurred: " + string(exception.what()));
232  }
233  //
234  class EditorLogger: public Console::Logger {
235  public:
236  EditorLogger(EditorScreenController* editorScreenController): editorScreenController(editorScreenController) {
237  }
238  void println(const string_view& str) {
239  auto& messages = editorScreenController->logMessages;
240  if (messages.empty() == true || newline == true) messages.push_back(string());
241  messages[messages.size() - 1]+= str;
242  if (messages.size() == Console::HISTORY_LINECOUNT) messages.erase(messages.begin());
243  newline = true;
244  editorScreenController->logUpdateRequired = true;
245  }
246  void print(const string_view& str) {
247  auto& messages = editorScreenController->logMessages;
248  if (messages.empty() == true || newline == true) messages.push_back(string());
249  messages[messages.size() - 1]+= str;
250  if (messages.size() == Console::HISTORY_LINECOUNT) messages.erase(messages.begin());
251  newline = false;
252  editorScreenController->logUpdateRequired = true;
253  }
254  void println() {
255  auto& messages = editorScreenController->logMessages;
256  messages.push_back(string());
257  if (messages.size() == Console::HISTORY_LINECOUNT) messages.erase(messages.begin());
258  newline = true;
259  editorScreenController->logUpdateRequired = true;
260  }
261  private:
262  EditorScreenController* editorScreenController { nullptr };
263  bool newline { false };
264  };
265  //
266  Console::setLogger(new EditorLogger(this));
267  //
268  onOpenProject();
269 }
270 
272 {
273  stopScanFiles();
274  closeProject();
275 }
276 
278 {
279 }
280 
282 {
284 }
285 
286 void EditorScreenController::showInfoPopUp(const string& caption, const string& message)
287 {
288  view->getPopUps()->getInfoDialogScreenController()->show(caption, message);
289 }
290 
292 {
293  if (node->getId() == "projectpathfiles_search") {
295  timeFileNameSearchTerm = Time::getCurrentMillis();
296  } else
297  if (node->getId() == "selectbox_projectpaths") {
298  stopScanFiles();
299  resetScanFiles();
301  startScanFiles();
302  } else
303  if (node->getId() == "dropdown_projectlibrary_add") {
305  }
306  // forward onChange to active tab tab controller
307  auto selectedTab = getSelectedTab();
308  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onChange(node);
309 }
310 
312 {
313  if (type == GUIActionListenerType::PERFORMED) {
314  if (node->getId() == "menu_file_open") {
315  onOpenProject();
316  } else
317  if (node->getId() == "menu_file_save") {
318  auto selectedTab = getSelectedTab();
319  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_SAVE);
320  } else
321  if (node->getId() == "menu_file_saveas") {
322  auto selectedTab = getSelectedTab();
323  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_SAVEAS);
324  } else
325  if (node->getId() == "menu_file_saveall") {
326  // forward saveAs to active tab tab controller
327  for (auto tab: tabViewVector) {
328  tab->getTabView()->getTabController()->onCommand(TabController::COMMAND_SAVE);
329  }
330  } else
331  if (node->getId() == "menu_edit_undo") {
332  auto selectedTab = getSelectedTab();
333  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_UNDO);
334  } else
335  if (node->getId() == "menu_edit_redo") {
336  auto selectedTab = getSelectedTab();
337  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_REDO);
338  } else
339  if (node->getId() == "menu_edit_cut") {
340  auto selectedTab = getSelectedTab();
341  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_CUT);
342  } else
343  if (node->getId() == "menu_edit_copy") {
344  auto selectedTab = getSelectedTab();
345  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_COPY);
346  } else
347  if (node->getId() == "menu_edit_paste") {
348  auto selectedTab = getSelectedTab();
349  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_PASTE);
350  } else
351  if (node->getId() == "menu_edit_delete") {
352  auto selectedTab = getSelectedTab();
353  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_DELETE);
354  } else
355  if (node->getId() == "menu_edit_selectall") {
356  auto selectedTab = getSelectedTab();
357  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_SELECTALL);
358  } else
359  if (node->getId() == "menu_edit_findreplace") {
360  auto selectedTab = getSelectedTab();
361  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onCommand(TabController::COMMAND_FINDREPLACE);
362  } else
363  if (node->getId() == "menu_view_fullscreen") {
364  setFullScreen(isFullScreen() == false?true:false);
365  } else
366  if (node->getId() == "menu_help_guixml_documentation") {
367  openFile(FileSystem::getInstance()->getCurrentWorkingPathName() + "/README-GUI-XML.md");
368  } else
369  if (node->getId() == "menu_help_miniscript_documentation") {
370  openFile(FileSystem::getInstance()->getCurrentWorkingPathName() + "/README-MiniScript.md");
371  } else
372  if (node->getId() == "menu_help_about") {
374  } else
375  if (StringTools::startsWith(node->getId(), "projectpathfiles_file_") == true) {
376  onOpenFile(required_dynamic_cast<GUIElementNode*>(node)->getValue());
377  } else
378  if (StringTools::startsWith(node->getId(), "menu_view_tab_") == true) {
379  selectTabAt(Integer::parse(StringTools::substring(node->getId(), string("menu_view_tab_").size())));
380  } else
381  if (StringTools::startsWith(node->getId(), "tab_") == true) {
382  string tabIdToClose;
383  for (auto tab: tabViewVector) {
384  if (StringTools::startsWith(node->getId(), tab->getId() + "_close") == true) {
385  tabIdToClose = tab->getId();
386  }
387  }
388  if (tabIdToClose.empty() == false) closeTab(tabIdToClose);
389  } else
390  if (node->getId() == "menu_file_quit") {
392  }
393  }
394  // forward onAction to active tab tab controller
395  auto selectedTab = getSelectedTab();
396  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onAction(type, node);
397 }
398 
400  // forward onFocus to active tab tab controller
401  auto selectedTab = getSelectedTab();
402  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onFocus(node);
403 }
404 
406  // forward onFocus to active tab tab controller
407  auto selectedTab = getSelectedTab();
408  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onUnfocus(node);
409 }
410 
412  if (StringTools::startsWith(node->getId(), "projectpathfiles_file_") == true) {
413  //
414  auto absoluteFileName = required_dynamic_cast<GUIElementNode*>(node)->getValue();
415  // check if file is a path
416  auto path = false;
417  try {
418  path = FileSystem::getInstance()->isPath(absoluteFileName);
419  } catch (Exception& exception) {
420  // no op
421  }
422  // clear context menu
424  {
425  // open
426  class OnOpenAction: public virtual Action
427  {
428  public:
429  OnOpenAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
430  }
431  void performAction() override {
432  editorScreenController->openFile(absoluteFileName);
433  }
434  private:
435  EditorScreenController* editorScreenController;
436  string absoluteFileName;
437  };
438  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Open", "contextmenu_file_open", new OnOpenAction(this, absoluteFileName));
439  }
440  //
442  //
443  {
444  // copy path
445  class OnCopyPathAction: public virtual Action
446  {
447  public:
448  OnCopyPathAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
449  }
450  void performAction() override {
451  Application::getApplication()->setClipboardContent(absoluteFileName);
452  }
453  private:
454  EditorScreenController* editorScreenController;
455  string absoluteFileName;
456  };
457  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Copy Path", "contextmenu_file_copypath", new OnCopyPathAction(this, absoluteFileName));
458  }
459  //
460  if (path == false) {
461  // duplicate
462  class OnDuplicateAction: public virtual Action
463  {
464  public:
465  OnDuplicateAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
466  }
467  void performAction() override {
468  class DuplicateFileAction: public virtual Action
469  {
470  public:
471  DuplicateFileAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
472  }
473  // overridden methods
474  void performAction() override {
475  try {
476  // get duplicate file name and extension
477  string duplicateFileName = editorScreenController->view->getPopUps()->getInputDialogScreenController()->getInputText();
478  string extension;
479  if (FileSystem::getInstance()->isPath(absoluteFileName) == false) {
480  extension = Tools::getFileExtension(absoluteFileName);
481  }
482  // read file
483  vector<uint8_t> fileContent;
484  FileSystem::getInstance()->getContent(
485  Tools::getPathName(absoluteFileName),
486  Tools::getFileName(absoluteFileName),
487  fileContent
488  );
489  // write file
490  FileSystem::getInstance()->setContent(
491  Tools::getPathName(absoluteFileName),
492  (extension.empty() == true?
493  duplicateFileName:
494  Tools::ensureFileExtension(duplicateFileName, extension)
495  ),
496  fileContent
497  );
498  // reload file view
499  editorScreenController->reload();
500  } catch (Exception& exception) {
501  editorScreenController->showInfoPopUp("Warning", exception.what());
502  }
503  editorScreenController->view->getPopUps()->getInputDialogScreenController()->close();
504  }
505  private:
506  EditorScreenController* editorScreenController;
507  string absoluteFileName;
508  };
509  //
510  editorScreenController->view->getPopUps()->getInputDialogScreenController()->show(
511  "Duplicate",
512  Tools::removeFileExtension(Tools::getFileName(absoluteFileName)),
513  new DuplicateFileAction(editorScreenController, absoluteFileName)
514  );
515  }
516  private:
517  EditorScreenController* editorScreenController;
518  string absoluteFileName;
519  };
520  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Duplicate", "contextmenu_file_duplicate", new OnDuplicateAction(this, absoluteFileName));
521  }
522  //
523  {
524  // rename
525  class OnRenameAction: public virtual Action
526  {
527  public:
528  OnRenameAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
529  }
530  void performAction() override {
531  class RenameFileAction: public virtual Action
532  {
533  public:
534  RenameFileAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
535  }
536  // overridden methods
537  void performAction() override {
538  try {
539  // get duplicate file name and extension
540  string renameFileName = editorScreenController->view->getPopUps()->getInputDialogScreenController()->getInputText();
541  string extension;
542  if (FileSystem::getInstance()->isPath(absoluteFileName) == false) {
543  extension = Tools::getFileExtension(absoluteFileName);
544  }
545  // rename file
546  FileSystem::getInstance()->rename(
547  absoluteFileName,
548  Tools::getPathName(absoluteFileName) + "/" +
549  (extension.empty() == true?
550  renameFileName:
551  Tools::ensureFileExtension(renameFileName, extension)
552  )
553  );
554  // reload file view
555  editorScreenController->reload();
556  } catch (Exception& exception) {
557  editorScreenController->showInfoPopUp("Warning", exception.what());
558  }
559  editorScreenController->view->getPopUps()->getInputDialogScreenController()->close();
560  }
561  private:
562  EditorScreenController* editorScreenController;
563  string absoluteFileName;
564  };
565  //
566  editorScreenController->view->getPopUps()->getInputDialogScreenController()->show(
567  "Rename",
568  Tools::removeFileExtension(Tools::getFileName(absoluteFileName)),
569  new RenameFileAction(editorScreenController, absoluteFileName)
570  );
571  }
572  private:
573  EditorScreenController* editorScreenController;
574  string absoluteFileName;
575  };
576  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Rename", "contextmenu_file_rename", new OnRenameAction(this, absoluteFileName));
577  }
578  //
579  {
580  // move
581  class OnMoveAction: public virtual Action
582  {
583  public:
584  OnMoveAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
585  }
586  void performAction() override {
587  class FileMoveAction: public virtual Action
588  {
589  public:
590  /**
591  * Public constructor
592  * @param editorScreenController editor screen controller
593  */
594  FileMoveAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
595  }
596  // overridden methods
597  void performAction() override {
598  auto moveToPath = editorScreenController->view->getPopUps()->getFileDialogScreenController()->getPathName();
599  try {
600  // move file
601  FileSystem::getInstance()->rename(
602  absoluteFileName,
603  moveToPath + "/" + Tools::getFileName(absoluteFileName)
604  );
605  // reload file view
606  editorScreenController->reload();
607  } catch (Exception& exception) {
608  editorScreenController->showInfoPopUp("Warning", exception.what());
609  }
610  //
611  editorScreenController->view->getPopUps()->getFileDialogScreenController()->close();
612  }
613  private:
614  EditorScreenController* editorScreenController;
615  string absoluteFileName;
616  };
617 
618  //
619  editorScreenController->view->getPopUps()->getFileDialogScreenController()->show(
620  editorScreenController->projectPath + "/" + editorScreenController->relativeProjectPath,
621  "Move to folder: ",
622  {},
623  string(),
624  true,
625  new FileMoveAction(editorScreenController, absoluteFileName)
626  );
627  }
628  private:
629  EditorScreenController* editorScreenController;
630  string absoluteFileName;
631  };
632  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Move", "contextmenu_file_move", new OnMoveAction(this, absoluteFileName));
633  }
634  {
635  // delete
636  class OnDeleteAction: public virtual Action
637  {
638  public:
639  OnDeleteAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
640  }
641  void performAction() override {
642  try {
643  if (FileSystem::getInstance()->isPath(absoluteFileName) == true) {
644  FileSystem::getInstance()->removePath(absoluteFileName, true);
645  } else {
646  FileSystem::getInstance()->removeFile(Tools::getPathName(absoluteFileName), Tools::getFileName(absoluteFileName));
647  }
648  //
649  editorScreenController->reload();
650  } catch (Exception& exception) {
651  Console::println("OnDeleteAction::performAction(): An error occurred: " + string(exception.what()));
652  }
653  }
654  private:
655  EditorScreenController* editorScreenController;
656  string absoluteFileName;
657  };
658  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Delete", "contextmenu_file_delete", new OnDeleteAction(this, absoluteFileName));
659  }
660 
661  {
662  //
663  auto selectedTab = getSelectedTab();
664  if (selectedTab != nullptr) {
665  switch (selectedTab->getType()) {
667  {
668 
669  // add to scene
670  class OnAddToSceneAction: public virtual Action
671  {
672  public:
673  OnAddToSceneAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
674  }
675  void performAction() override {
676  auto currentTab = editorScreenController->getSelectedTab();
677  if (currentTab == nullptr) return;
678  SceneEditorTabView* sceneEditorTabView = dynamic_cast<SceneEditorTabView*>(currentTab->getTabView());
679  if (sceneEditorTabView == nullptr) return;
680  try {
681  // load prototype
682  auto prototype = PrototypeReader::read(
683  Tools::getPathName(absoluteFileName),
684  Tools::getFileName(absoluteFileName)
685  );
686  // mark as non embedded
687  prototype->setEmbedded(false);
688  // add to library
689  sceneEditorTabView->addPrototype(prototype);
690  } catch (Exception& exception) {
691  Console::println("OnOpenAction::performAction(): An error occurred: " + string(exception.what()));
692  editorScreenController->showInfoPopUp("Warning", exception.what());
693  }
694  }
695  private:
696  EditorScreenController* editorScreenController;
697  string absoluteFileName;
698  };
700  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Add to scene", "contextmenu_file_addtoscene", new OnAddToSceneAction(this, absoluteFileName));
701 
702  //
703  }
704  break;
705  default: break;
706  }
707  }
708  }
709  //
711  //
712  {
713  // show in file browser
714  class OnShowInFileBrowserAction: public virtual Action
715  {
716  public:
717  OnShowInFileBrowserAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
718  }
719  void performAction() override {
720  try {
721  if (FileSystem::getInstance()->isPath(absoluteFileName) == true) {
722  Application::openBrowser(absoluteFileName);
723  } else {
724  Application::openBrowser(Tools::getPathName(absoluteFileName));
725  }
726  } catch (Exception& exception) {
727  Console::println("OnShowInFileBrowserAction::performAction(): An error occurred: " + string(exception.what()));
728  }
729  }
730  private:
731  EditorScreenController* editorScreenController;
732  string absoluteFileName;
733  };
734  view->getPopUps()->getContextMenuScreenController()->addMenuItem("Show in File Browser", "contextmenu_file_showinfilebrowser", new OnShowInFileBrowserAction(this, absoluteFileName));
735  }
736  //
737  view->getPopUps()->getContextMenuScreenController()->show(mouseX, mouseY);
738  } else {
739  // forward onContextMenuRequest to active tab tab controller
740  auto selectedTab = getSelectedTab();
741  if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onContextMenuRequest(node, mouseX, mouseY);
742  }
743 }
744 
745 void EditorScreenController::onTooltipShowRequest(GUINode* node, int mouseX, int mouseY) {
746  //
747  view->getPopUps()->getTooltipScreenController()->show(mouseX, mouseY, node->getToolTip());
748 }
749 
752 }
753 
754 void EditorScreenController::onDragRequest(GUIElementNode* node, int mouseX, int mouseY) {
755  if (StringTools::startsWith(node->getId(), "projectpathfiles_file_") == true) {
756  //
757  class OnDragReleaseAction: public Action {
758  private:
759  EditorScreenController* editorScreenController;
760  public:
761  OnDragReleaseAction(EditorScreenController* editorScreenController): editorScreenController(editorScreenController) {}
762  virtual void performAction() {
763  auto draggingScreenController = editorScreenController->view->getPopUps()->getDraggingScreenController();
764  auto selectedTab = editorScreenController->getSelectedTab();
765  if (selectedTab == nullptr) {
766  editorScreenController->showInfoPopUp("Warning", "No tab opened to drop files into");
767  } else {
768  selectedTab->getTabView()->getTabController()->onDrop(
769  draggingScreenController->getPayload(),
770  draggingScreenController->getDragReleaseMouseX(),
771  draggingScreenController->getDragReleaseMouseY()
772  );
773  }
774  }
775  };
776  //
777  auto absoluteFileName = node->getValue();
778  auto imageSource = GUIParser::getEngineThemeProperties()->get("icon.type_" + FileDialogScreenController::getFileImageName(absoluteFileName) + "_big", "resources/engine/images/tdme_big.png");
779  auto xml = "<image width=\"auto\" height=\"auto\" src=\"" + imageSource + "\" />";
780  view->getPopUps()->getDraggingScreenController()->start(mouseX, mouseY, xml, "file:" + absoluteFileName, new OnDragReleaseAction(this));
781  }
782 }
783 
784 void EditorScreenController::openProject(const string& pathName) {
785  projectPath = pathName;
786  if (StringTools::endsWith(projectPath, "/") == true) {
787  projectPath = StringTools::substring(projectPath, 0, projectPath.size() - 1);
788  }
789  closeProject();
792  setRelativeProjectPath("resources");
793  startScanFiles();
794  //
795  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(false);
796  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(false);
797  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(false);
798  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(false);
799  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(false);
800  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(false);
801  //
802  Engine::getInstance()->loadTextures(pathName);
803  //
804  GUIParser::loadProjectThemeProperties(projectPath);
805 }
806 
808  class OnOpenProject: public virtual Action
809  {
810  public:
811  /**
812  * Public constructor
813  * @param editorScreenController editor screen controller
814  */
815  OnOpenProject(EditorScreenController* editorScreenController): editorScreenController(editorScreenController) {
816  }
817  // overridden methods
818  void performAction() override {
819  auto projectPath = editorScreenController->view->getPopUps()->getFileDialogScreenController()->getPathName();
820  editorScreenController->openProject(projectPath);
821  editorScreenController->view->getPopUps()->getFileDialogScreenController()->close();
822  }
823  private:
824  EditorScreenController* editorScreenController;
825  };
826 
828  ".",
829  "Open project from folder: ",
830  {},
831  string(),
832  true,
833  new OnOpenProject(this),
834  nullptr,
835  ".projects.filedialog.properties",
836  "."
837  );
838 }
839 
841  string xml;
842  xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escape("resources") + "\" value=\"" + GUIParser::escape("resources") + "\">\n";
843  scanProjectPaths(projectPath + "/resources", xml);
844  xml+= "</selectbox-parent-option>\n";
845  xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escape("shader") + "\" value=\"" + GUIParser::escape("shader") + "\">\n";
846  scanProjectPaths(projectPath + "/shader", xml);
847  xml+= "</selectbox-parent-option>\n";
848  xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escape("src") + "\" value=\"" + GUIParser::escape("src") + "\">\n";
849  scanProjectPaths(projectPath + "/src", xml);
850  xml+= "</selectbox-parent-option>\n";
851  try {
852  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathsScrollArea->getId()))->replaceSubNodes(xml, true);
853  } catch (Exception& exception) {
854  Console::print("EditorScreenController::scanProjectPaths(): An error occurred: " + string(exception.what()));
855  }
856 }
857 
858 void EditorScreenController::scanProjectPaths(const string& path, string& xml) {
859  class ListFilter : public virtual FileNameFilter {
860  public:
861  virtual ~ListFilter() {}
862 
863  bool accept(const string& pathName, const string& fileName) override {
864  if (fileName == ".") return false;
865  if (fileName == "..") return false;
866  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
867  //
868  return false;
869  }
870  };
871 
872  ListFilter listFilter;
873  vector<string> files;
874 
875  if (FileSystem::getInstance()->exists(path) == false) {
876  Console::println("EditorScreenController::scanProject(): Error: file does not exist: " + path);
877  } else
878  if (FileSystem::getInstance()->isPath(path) == false) {
879  if (listFilter.accept(".", path) == true) {
880  Console::println("EditorScreenController::scanProject(): Error: path is file" + path);
881  } else {
882  Console::println("EditorScreenController::scanProject(): Error: file exist, but does not match filter: " + path);
883  }
884  } else {
885  FileSystem::getInstance()->list(path, files, &listFilter);
886  for (const auto& fileName: files) {
887  auto relativePath = path + "/" + fileName;
888  if (StringTools::startsWith(relativePath, projectPath)) relativePath = StringTools::substring(relativePath, projectPath.size() + 1, relativePath.size());
889  if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
890  // no op for now
891  } else {
892  string innerXml;
893  scanProjectPaths(path + "/" + fileName, innerXml);
894  if (innerXml.empty() == false) {
895  xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escape(fileName) + "\" value=\"" + GUIParser::escape(relativePath) + "\">\n";
896  xml+= innerXml;
897  xml+= "</selectbox-parent-option>\n";
898  } else {
899  xml+= "<selectbox-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escape(fileName) + "\" value=\"" + GUIParser::escape(relativePath) + "\" />\n";
900  }
901  }
902  }
903  }
904 }
905 
906 void EditorScreenController::closeTab(const string& tabId) {
907  screenNode->removeNodeById(tabId, false);
908  screenNode->removeNodeById(tabId + "-content", false);
909  auto tabIt = tabViews.find(tabId);
910  if (tabIt != tabViews.end()) {
911  auto& tab = tabIt->second;
912  tab.getTabView()->dispose();
913  //
914  auto tabIdx = 0;
915  for (auto tab: tabViewVector) {
916  if (tab->getId() == tabId) break;
917  tabIdx++;
918  }
919  //
920  tabViews.erase(tabIt);
921  tabViewVector.erase(tabViewVector.begin() + tabIdx);
922  }
923  setDetailsContent(string());
924  setOutlinerContent(string());
925  //
928 }
929 
931  for (auto& [tabId, tab]: tabViews) {
932  screenNode->removeNodeById(tab.getId(), false);
933  screenNode->removeNodeById(tab.getId() + "-content", false);
934  tab.getTabView()->dispose();
935  }
936  tabViews.clear();
937  tabViewVector.clear();
938  setDetailsContent(string());
939  setOutlinerContent(string());
940  //
943 }
944 
946  stopScanFiles();
947  resetScanFiles();
949  closeTabs();
951  //
952  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(true);
953  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(true);
954  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(true);
955  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(true);
956  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(true);
957  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(true);
958 }
959 
961  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->clearSubNodes();
962 }
963 
965  stopScanFiles();
966  try {
967  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->clearSubNodes();
968  } catch (Exception& exception) {
969  Console::println("EditorScreenController::startScanFiles(): An error occurred: " + string(exception.what()));
970  }
971  scanFilesThread = make_unique<ScanFilesThread>(this, projectPath + "/" + relativeProjectPath, StringTools::toLowerCase(fileNameSearchTerm));
972  scanFilesThread->start();
973 }
974 
976  string scrollToNodeId;
977  string xml;
978  xml+= "<layout alignment=\"horizontal\">\n";
979  for (const auto& pendingFileEntity: pendingFileEntities) {
980  xml+= pendingFileEntity->buttonXML;
981  if (pendingFileEntity->scrollTo == true) scrollToNodeId = pendingFileEntity->id;
982  }
983  xml+= "</layout>\n";
984  //
985  try {
986  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->addSubNodes(xml, false);
987  if (scrollToNodeId.empty() == false) {
988  required_dynamic_cast<GUINode*>(screenNode->getNodeById(scrollToNodeId))->scrollToNodeX();
989  required_dynamic_cast<GUINode*>(screenNode->getNodeById(scrollToNodeId))->scrollToNodeY();
990  }
991  } catch (Exception& exception) {
992  Console::println("EditorScreenController::addPendingFileEntities(): An error occurred: " + string(exception.what()));
993  }
994  //
995  for (const auto& pendingFileEntity: pendingFileEntities) {
996  if (pendingFileEntity->thumbnailTexture == nullptr) continue;
997  if (screenNode->getNodeById(pendingFileEntity->id + "_texture_normal") == nullptr) continue;
998  try {
999  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_normal"))->setTexture(pendingFileEntity->thumbnailTexture);
1000  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_mouseover"))->setTexture(pendingFileEntity->thumbnailTexture);
1001  required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_clicked"))->setTexture(pendingFileEntity->thumbnailTexture);
1002  } catch (Exception& exception) {
1003  Console::println("EditorScreenController::addPendingFileEntities(): An error occurred: " + string(exception.what()));
1004  }
1005  if (pendingFileEntity->thumbnailTexture != nullptr) pendingFileEntity->thumbnailTexture->releaseReference();
1006  }
1007  pendingFileEntities.clear();
1008 }
1009 
1010 void EditorScreenController::setRelativeProjectPath(const string& relativeProjectPath) {
1011  this->relativeProjectPath = relativeProjectPath;
1012  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("selectbox_projectpaths"))->getController()->setValue(MutableString(relativeProjectPath));
1013 }
1014 
1016  if (scanFilesThread != nullptr) {
1017  scanFilesThread->stop();
1018  scanFilesThread->join();
1019  lockFileEntities();
1020  for (const auto& fileEntity: getFileEntities()) {
1021  if (fileEntity->thumbnailTexture != nullptr) fileEntity->thumbnailTexture->releaseReference();
1022  }
1023  getFileEntities().clear();
1025  scanFilesThread = nullptr;
1026  }
1027 }
1028 
1030  fileNameSearchTerm.clear();
1031  browseToFileName.clear();
1032  timeFileNameSearchTerm = -1LL;
1033  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setValue(MutableString());
1034 }
1035 
1037  stopScanFiles();
1038  resetScanFiles();
1039  browseToFileName.clear();
1041  startScanFiles();
1042 }
1043 
1044 void EditorScreenController::browseTo(const string& fileName) {
1045  stopScanFiles();
1046  resetScanFiles();
1047  auto newRelativeProjectPath = Tools::getPathName(fileName);
1048  if (StringTools::startsWith(newRelativeProjectPath, projectPath) == true) newRelativeProjectPath = StringTools::substring(newRelativeProjectPath, projectPath.size() + 1);
1049  browseToFileName = projectPath + "/" + newRelativeProjectPath + "/" + Tools::getFileName(fileName);
1050  setRelativeProjectPath(newRelativeProjectPath);
1051  startScanFiles();
1052 }
1053 
1055  class ListFilter : public virtual FileNameFilter {
1056  public:
1057  ListFilter(const string& searchTerm): searchTerm(searchTerm) {}
1058  virtual ~ListFilter() {}
1059 
1060  bool accept(const string& pathName, const string& fileName) override {
1061  if (fileName == ".") return false;
1062  if (fileName == "..") return false;
1063  //
1064  auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1065  //
1066  if (searchTerm.empty() == false && fileNameLowerCase.find(searchTerm) == string::npos) return false;
1067 
1068  // folders
1069  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
1070  // audio
1071  if (StringTools::endsWith(fileNameLowerCase, ".ogg") == true) return true;
1072  // markdown
1073  if (StringTools::endsWith(fileNameLowerCase, ".md") == true) return true;
1074  // license
1075  if (fileNameLowerCase == "license") return true;
1076  // code
1077  if (StringTools::endsWith(fileNameLowerCase, ".h") == true) return true;
1078  if (StringTools::endsWith(fileNameLowerCase, ".cpp") == true) return true;
1079  if (StringTools::endsWith(fileNameLowerCase, ".c") == true) return true;
1080  if (StringTools::endsWith(fileNameLowerCase, ".tscript") == true) return true;
1081  // fonts
1082  if (StringTools::endsWith(fileNameLowerCase, ".ttf") == true) return true;
1083  // images
1084  if (StringTools::endsWith(fileNameLowerCase, ".icns") == true) return true;
1085  if (StringTools::endsWith(fileNameLowerCase, ".ico") == true) return true;
1086  if (StringTools::endsWith(fileNameLowerCase, ".png") == true) return true;
1087  // video
1088  if (StringTools::endsWith(fileNameLowerCase, ".mpg") == true) return true;
1089  // models
1090  if (StringTools::endsWith(fileNameLowerCase, ".dae") == true) return true;
1091  if (StringTools::endsWith(fileNameLowerCase, ".fbx") == true) return true;
1092  if (StringTools::endsWith(fileNameLowerCase, ".glb") == true) return true;
1093  if (StringTools::endsWith(fileNameLowerCase, ".gltf") == true) return true;
1094  if (StringTools::endsWith(fileNameLowerCase, ".tm") == true) return true;
1095  // property files
1096  if (StringTools::endsWith(fileNameLowerCase, ".properties") == true) return true;
1097  // shader
1098  if (StringTools::endsWith(fileNameLowerCase, ".cl") == true) return true;
1099  if (StringTools::endsWith(fileNameLowerCase, ".frag") == true) return true;
1100  if (StringTools::endsWith(fileNameLowerCase, ".glsl") == true) return true;
1101  if (StringTools::endsWith(fileNameLowerCase, ".vert") == true) return true;
1102  // tdme empty
1103  if (StringTools::endsWith(fileNameLowerCase, ".tempty") == true) return true;
1104  // tdme trigger
1105  if (StringTools::endsWith(fileNameLowerCase, ".ttrigger") == true) return true;
1106  // tdme envmap
1107  if (StringTools::endsWith(fileNameLowerCase, ".tenvmap") == true) return true;
1108  // tdme decal
1109  if (StringTools::endsWith(fileNameLowerCase, ".tdecal") == true) return true;
1110  // tdme model
1111  if (StringTools::endsWith(fileNameLowerCase, ".tmodel") == true) return true;
1112  // tdme scene
1113  if (StringTools::endsWith(fileNameLowerCase, ".tscene") == true) return true;
1114  // tdme particle system
1115  if (StringTools::endsWith(fileNameLowerCase, ".tparticle") == true) return true;
1116  // tdme terrain
1117  if (StringTools::endsWith(fileNameLowerCase, ".tterrain") == true) return true;
1118  // xml
1119  if (StringTools::endsWith(fileNameLowerCase, ".xml") == true) return true;
1120  // nmake files
1121  if (StringTools::endsWith(fileNameLowerCase, ".nmake") == true) return true;
1122  if (StringTools::endsWith(fileNameLowerCase, ".nmake.main") == true) return true;
1123  // batch files
1124  if (StringTools::endsWith(fileNameLowerCase, ".bat") == true) return true;
1125  // bash files
1126  if (StringTools::endsWith(fileNameLowerCase, ".sh") == true) return true;
1127  if (StringTools::endsWith(fileNameLowerCase, ".bash") == true) return true;
1128  // files without ending
1129  if (fileName.rfind(".") == string::npos ||
1130  (fileName.rfind("/") != string::npos &&
1131  fileName.rfind(".") < fileName.rfind("/"))) {
1132  return true;
1133  }
1134  //
1135  return false;
1136  }
1137  private:
1138  string searchTerm;
1139  };
1140 
1141  ListFilter listFilter(searchTerm);
1142  vector<string> files;
1143 
1144  if (FileSystem::getInstance()->exists(pathName) == false) {
1145  Console::println("EditorScreenController::ScanFilesThread::run(): Error: file does not exist: " + pathName);
1146  } else
1147  if (FileSystem::getInstance()->isPath(pathName) == false) {
1148  if (listFilter.accept(".", pathName) == true) {
1149  Console::println("EditorScreenController::ScanFilesThread::run(): Error: path is file: " + pathName);
1150  } else {
1151  Console::println("EditorScreenController::ScanFilesThread::run(): Error: file exist, but does not match filter: " + pathName);
1152  }
1153  } else {
1154  FileSystem::getInstance()->list(pathName, files, &listFilter);
1155  // parent folder
1156  auto parentPathName = FileSystem::getInstance()->getPathName(pathName);
1157  if (editorScreenController->getProjectPath() != parentPathName) {
1158  string fileName = "..";
1159 
1160  //
1161  string templateSource = "button_template_thumbnail_nobackground.xml";
1162  string icon = "";
1163  string iconBig = "{$icon.type_folder_big}";
1164 
1165  //
1166  auto fileEntity = make_unique<FileEntity>();
1167  fileEntity->id = "projectpathfiles_file_" + GUIParser::escape(StringTools::replace(Tools::getFileName(fileName), '.', '_'));
1168  fileEntity->buttonXML =
1169  string() +
1170  "<button " +
1171  "id=\"" + fileEntity->id + "\" " +
1172  "value=\"" + GUIParser::escape(parentPathName) + "\" " +
1173  "template=\"" + templateSource + "\" " +
1174  "size=\"75\" " +
1175  "icon=\"" + GUIParser::escape(icon) + "\" " +
1176  "icon-big=\"" + GUIParser::escape(iconBig) + "\" " +
1177  "filename=\"" + GUIParser::escape(fileName) + "\" " +
1178  "/>\n";
1180  editorScreenController->getFileEntities().push_back(move(fileEntity));
1182  }
1183  for (const auto& fileName: files) {
1184  if (isStopRequested() == true) break;
1185 
1186  //
1187  auto absolutePath = pathName + "/" + fileName;
1188  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == false) continue;
1189 
1190  string templateSource = "button_template_thumbnail_nobackground.xml";
1191  string icon = "";
1192  string iconBig = "{$icon.type_folder_big}";
1193 
1194  //
1195  auto fileEntity = make_unique<FileEntity>();
1196  fileEntity->id = "projectpathfiles_file_" + GUIParser::escape(StringTools::replace(Tools::getFileName(fileName), '.', '_'));
1197 
1198  //
1199  string buttonOnInitialize;
1200  if (editorScreenController->browseToFileName.empty() == false && editorScreenController->browseToFileName == absolutePath) {
1201  fileEntity->scrollTo = true;
1202  buttonOnInitialize = "on-initialize=\"" + fileEntity->id + ".condition+=selected\" ";
1203  }
1204 
1205  fileEntity->buttonXML =
1206  string() +
1207  "<button " +
1208  "id=\"" + fileEntity->id + "\" " +
1209  "value=\"" + GUIParser::escape(absolutePath) + "\" " +
1210  "template=\"" + templateSource + "\" " +
1211  "size=\"75\" " +
1212  "icon=\"" + GUIParser::escape(icon) + "\" " +
1213  "icon-big=\"" + GUIParser::escape(iconBig) + "\" " +
1214  "filename=\"" + GUIParser::escape(fileName) + "\" " +
1215  buttonOnInitialize +
1216  "/>\n";
1218  editorScreenController->getFileEntities().push_back(move(fileEntity));
1220  }
1221  for (const auto& fileName: files) {
1222  if (isStopRequested() == true) break;
1223 
1224  auto absolutePath = pathName + "/" + fileName;
1225  if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) continue;
1226 
1227  //
1228  try {
1229  //
1230  auto image = FileDialogScreenController::getFileImageName(fileName);
1231  string icon = "{$icon.type_" + image + "}";
1232  string iconBig = "{$icon.type_" + image + "_big}";
1233  string typeColor = "{$color.type_" + image + "}";
1234 
1235  //
1236  auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1237 
1238  //
1239  string templateSource = "button_template_thumbnail.xml";
1240  Texture* thumbnailTexture = nullptr;
1241  vector<uint8_t> thumbnailPNGData;
1242  if (StringTools::endsWith(fileNameLowerCase, ".png") == true) {
1243  thumbnailTexture = TextureReader::read(pathName, fileName, false);
1244  } else
1245  if ((((StringTools::endsWith(fileNameLowerCase, ".tmodel") == true || StringTools::endsWith(fileNameLowerCase, ".tdecal") == true) && PrototypeReader::readThumbnail(pathName, fileName, thumbnailPNGData) == true) ||
1246  (StringTools::endsWith(fileNameLowerCase, ".tm") == true && FileSystem::getInstance()->getThumbnailAttachment(pathName, fileName, thumbnailPNGData) == true)) &&
1247  thumbnailPNGData.empty() == false) {
1248  static int thumbnailIdx = 0; // TODO: improve me
1249  thumbnailTexture = PNGTextureReader::read("tdme.editor.projectpathfiles." + to_string(thumbnailIdx++), thumbnailPNGData, false);
1250  }
1251  if (thumbnailTexture != nullptr) {
1252  auto textureWidth = thumbnailTexture->getTextureWidth();
1253  auto textureHeight = thumbnailTexture->getTextureHeight();
1254  auto scale = 1.0f;
1255  if (textureWidth > textureHeight) {
1256  scale = 128.0f / static_cast<float>(textureWidth);
1257  } else {
1258  scale = 128.0f / static_cast<float>(textureHeight);
1259  }
1260  auto scaledTextureWidth = static_cast<int>(static_cast<float>(textureWidth) * scale);
1261  auto scaledTextureHeight = static_cast<int>(static_cast<float>(textureHeight) * scale);
1262  if (textureWidth != scaledTextureWidth || textureHeight != scaledTextureHeight) {
1263  auto thumbnailTextureScaled = TextureReader::scale(thumbnailTexture, scaledTextureWidth, scaledTextureHeight);
1264  thumbnailTexture->releaseReference();
1265  thumbnailTexture = thumbnailTextureScaled;
1266  }
1267  iconBig.clear();
1268  }
1269  if (iconBig.empty() == false) icon.clear();
1270 
1271  //
1272  auto fileEntity = make_unique<FileEntity>();
1273  fileEntity->id = "projectpathfiles_file_" + GUIParser::escape(StringTools::replace(Tools::getFileName(fileName), '.', '_'));
1274 
1275  //
1276  string buttonOnInitialize;
1277  if (editorScreenController->browseToFileName.empty() == false && editorScreenController->browseToFileName == absolutePath) {
1278  fileEntity->scrollTo = true;
1279  buttonOnInitialize = "on-initialize=\"" + fileEntity->id + ".condition+=selected\" ";
1280  }
1281 
1282  fileEntity->buttonXML =
1283  string() +
1284  "<button " +
1285  "id=\"" + fileEntity->id + "\" " +
1286  "value=\"" + GUIParser::escape(absolutePath) + "\" " +
1287  "template=\"" + templateSource + "\" " +
1288  "size=\"75\" " +
1289  "icon=\"" + GUIParser::escape(icon) + "\" " +
1290  "icon-big=\"" + GUIParser::escape(iconBig) + "\" " +
1291  "filename=\"" + GUIParser::escape(fileName) + "\" " +
1292  "type-color=\"" + GUIParser::escape(typeColor) + "\" " +
1293  buttonOnInitialize +
1294  "/>\n";
1295 
1296  fileEntity->thumbnailTexture = thumbnailTexture;
1298  editorScreenController->getFileEntities().push_back(move(fileEntity));
1300  Thread::sleep(1LL);
1301  } catch (Exception& exception) {
1302  errorMessage = exception.what();
1303  error = true;
1304  Console::println("EditorScreenController::ScanFilesThread::run(): Error: " + errorMessage);
1305  }
1306  }
1307  }
1308  finished = true;
1309 }
1310 
1311 void EditorScreenController::onAddFile(const string& type) {
1312  class OnAddFile: public virtual Action
1313  {
1314  public:
1315  OnAddFile(EditorScreenController* editorScreenController, const string& type, const string& extension): editorScreenController(editorScreenController), type(type), extension(extension) {
1316  }
1317  // overridden methods
1318  void performAction() override {
1319  editorScreenController->addFile(
1320  editorScreenController->projectPath + "/" + editorScreenController->relativeProjectPath,
1321  (extension.empty() == true?
1322  editorScreenController->view->getPopUps()->getInputDialogScreenController()->getInputText():
1323  Tools::ensureFileExtension(editorScreenController->view->getPopUps()->getInputDialogScreenController()->getInputText(), extension)),
1324  type
1325  );
1326  editorScreenController->view->getPopUps()->getInputDialogScreenController()->close();
1327  }
1328  private:
1329  EditorScreenController* editorScreenController;
1330  string type;
1331  string extension;
1332  };
1333 
1334  //
1335  string extension;
1336  if (type != "folder") {
1337  if (type == "logic_script") extension = "tscript"; else
1338  if (type == "gui_script") extension = "tscript"; else
1339  if (type == "screen" || type == "template") extension = "xml"; else
1340  extension = "t" + type;
1341  }
1342 
1343  //
1345  string("Add ") + type + " to project: ",
1346  string("Untitled"),
1347  new OnAddFile(this, type, extension)
1348  );
1349 }
1350 
1351 void EditorScreenController::addFile(const string& pathName, const string& fileName, const string& type) {
1352  if (type == "folder") {
1353  try {
1354  FileSystem::getInstance()->createPath(pathName + "/" + fileName);
1355  browseTo(pathName + "/" + fileName);
1356  } catch (Exception& exception) {
1357  showInfoPopUp("Error", string() + "An error occurred: file type: " + type + ": " + exception.what());
1358  }
1359  } else
1360  if (type == "screen") {
1361  try {
1362  FileSystem::getInstance()->setContentFromString(
1363  pathName,
1364  fileName,
1365  StringTools::replace(
1366  FileSystem::getInstance()->getContentAsString("resources/engine/templates/gui", "screen.xml"),
1367  "{$screen-id}",
1368  Tools::removeFileExtension(fileName)
1369  )
1370  );
1371  browseTo(pathName + "/" + fileName);
1372  openFile(pathName + "/" + fileName);
1373  } catch (Exception& exception) {
1374  showInfoPopUp("Error", string() + "An error occurred: file type: " + type + ": " + exception.what());
1375  }
1376  } else
1377  if (type == "template") {
1378  try {
1379  FileSystem::getInstance()->setContentFromString(pathName, fileName, FileSystem::getInstance()->getContentAsString("resources/engine/templates/gui", "template.xml"));
1380  browseTo(pathName + "/" + fileName);
1381  openFile(pathName + "/" + fileName);
1382  } catch (Exception& exception) {
1383  showInfoPopUp("Error", string() + "An error occurred: file type: " + type + ": " + exception.what());
1384  }
1385  } else
1386  if (type == "logic_script") {
1387  try {
1388  FileSystem::getInstance()->setContentFromString(pathName, fileName, FileSystem::getInstance()->getContentAsString("resources/engine/templates/tscript", "logic_script_template.tscript"));
1389  browseTo(pathName + "/" + fileName);
1390  openFile(pathName + "/" + fileName);
1391  } catch (Exception& exception) {
1392  showInfoPopUp("Error", string() + "An error occurred: file type: " + type + ": " + exception.what());
1393  }
1394  } else
1395  if (type == "gui_script") {
1396  try {
1397  FileSystem::getInstance()->setContentFromString(pathName, fileName, FileSystem::getInstance()->getContentAsString("resources/engine/templates/tscript", "gui_script_template.tscript"));
1398  browseTo(pathName + "/" + fileName);
1399  openFile(pathName + "/" + fileName);
1400  } catch (Exception& exception) {
1401  showInfoPopUp("Error", string() + "An error occurred: file type: " + type + ": " + exception.what());
1402  }
1403  } else {
1404  unique_ptr<Prototype> prototype;
1405  unique_ptr<Scene> scene;
1406  if (type == "empty") {
1407  prototype = make_unique<Prototype>(
1408  Prototype::ID_NONE,
1409  Prototype_Type::EMPTY,
1410  Tools::removeFileExtension(fileName),
1411  Tools::removeFileExtension(fileName),
1412  pathName + "/" + fileName,
1413  "resources/engine/models/empty.tm",
1414  string(),
1415  ModelReader::read("resources/engine/models", "empty.tm") // TODO: exception
1416  );
1417  } else
1418  if (type == "trigger") {
1419  auto width = 1.0f;
1420  auto height = 1.0f;
1421  auto depth = 1.0f;
1422  auto boundingBox = BoundingBox(Vector3(-width / 2.0f, 0.0f, -depth / 2.0f), Vector3(+width / 2.0f, height, +depth / 2.0f));
1423  prototype = make_unique<Prototype>(
1424  Prototype::ID_NONE,
1425  Prototype_Type::TRIGGER,
1426  Tools::removeFileExtension(fileName),
1427  Tools::removeFileExtension(fileName),
1428  pathName + "/" + fileName,
1429  string(),
1430  string(),
1431  nullptr
1432  );
1433  prototype->addBoundingVolume(new PrototypeBoundingVolume(prototype.get()));
1434  prototype->getBoundingVolume(0)->setupAabb(boundingBox.getMin(), boundingBox.getMax());
1435  } else
1436  if (type == "envmap") {
1437  auto width = 1.0f;
1438  auto height = 1.0f;
1439  auto depth = 1.0f;
1440  auto boundingBox = BoundingBox(Vector3(-width / 2.0f, 0.0f, -depth / 2.0f), Vector3(+width / 2.0f, height, +depth / 2.0f));
1441  prototype = make_unique<Prototype>(
1442  Prototype::ID_NONE,
1443  Prototype_Type::ENVIRONMENTMAPPING,
1444  Tools::removeFileExtension(fileName),
1445  Tools::removeFileExtension(fileName),
1446  pathName + "/" + fileName,
1447  string(),
1448  string(),
1449  nullptr
1450  );
1451  prototype->addBoundingVolume(new PrototypeBoundingVolume(prototype.get()));
1452  prototype->getBoundingVolume(0)->setupAabb(boundingBox.getMin(), boundingBox.getMax());
1453  } else
1454  if (type == "decal") {
1455  auto width = 1.0f;
1456  auto height = 1.0f;
1457  auto depth = 1.0f;
1458  auto boundingBox = BoundingBox(Vector3(-width / 2.0f, 0.0f, -depth / 2.0f), Vector3(+width / 2.0f, height, +depth / 2.0f));
1459  prototype = make_unique<Prototype>(
1460  Prototype::ID_NONE,
1461  Prototype_Type::DECAL,
1462  Tools::removeFileExtension(fileName),
1463  Tools::removeFileExtension(fileName),
1464  pathName + "/" + fileName,
1465  string(),
1466  string(),
1467  nullptr
1468  );
1469  prototype->addBoundingVolume(new PrototypeBoundingVolume(prototype.get()));
1470  prototype->getBoundingVolume(0)->setupAabb(boundingBox.getMin(), boundingBox.getMax());
1471  } else
1472  if (type == "model") {
1473  prototype = make_unique<Prototype>(
1474  Prototype::ID_NONE,
1475  Prototype_Type::MODEL,
1476  Tools::removeFileExtension(fileName),
1477  Tools::removeFileExtension(fileName),
1478  pathName + "/" + fileName,
1479  "resources/engine/models/empty.tm",
1480  string(),
1481  ModelReader::read("resources/engine/models", "empty.tm") // TODO: exception
1482  );
1483  } else
1484  if (type == "terrain") {
1485  prototype = make_unique<Prototype>(
1486  Prototype::ID_NONE,
1487  Prototype_Type::TERRAIN,
1488  Tools::removeFileExtension(fileName),
1489  Tools::removeFileExtension(fileName),
1490  pathName + "/" + fileName,
1491  string(),
1492  string(),
1493  nullptr
1494  );
1495  } else
1496  if (type == "particle") {
1497  prototype = make_unique<Prototype>(
1498  Prototype::ID_NONE,
1499  Prototype_Type::PARTICLESYSTEM,
1500  Tools::removeFileExtension(fileName),
1501  Tools::removeFileExtension(fileName),
1502  pathName + "/" + fileName,
1503  string(),
1504  string(),
1505  nullptr
1506  );
1507  } else
1508  if (type == "scene") {
1509  scene = make_unique<Scene>(
1510  Tools::removeFileExtension(fileName),
1511  Tools::removeFileExtension(fileName)
1512  );
1513  }
1514  if (prototype != nullptr) {
1515  try {
1516  PrototypeWriter::write(pathName, fileName, prototype.get());
1517  browseTo(pathName + "/" + fileName);
1518  openFile(pathName + "/" + fileName);
1519  } catch (Exception& exception) {
1520  Console::println("EditorScreenController::addFile(): An error occurred: " + string(exception.what()));
1521  showInfoPopUp("Error", string() + "An error occurred: " + exception.what());
1522  }
1523  } else
1524  if (scene != nullptr) {
1525  try {
1526  SceneWriter::write(pathName, fileName, scene.get());
1527  browseTo(pathName + "/" + fileName);
1528  openFile(pathName + "/" + fileName);
1529  } catch (Exception& exception) {
1530  Console::println("EditorScreenController::addFile(): An error occurred: " + string(exception.what()));
1531  showInfoPopUp("Error", string() + "An error occurred: " + exception.what());
1532  }
1533  } else {
1534  showInfoPopUp("Error", string() + "Unknown file type: " + type);
1535  }
1536  }
1537 }
1538 
1540  auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
1541 
1542  //
1543  try {
1544  switch (fileType) {
1545  case FILETYPE_MODEL:
1546  {
1547  auto model = ModelReader::read(Tools::getPathName(absoluteFileName), Tools::getFileName(absoluteFileName));
1548  prototype = make_unique<Prototype>(
1549  Prototype::ID_NONE,
1550  Prototype_Type::MODEL,
1551  Tools::removeFileExtension(fileName),
1552  Tools::removeFileExtension(fileName),
1553  FileSystem::getInstance()->getPathName(absoluteFileName) + "/" + Tools::removeFileExtension(fileName) + ".tmodel",
1554  absoluteFileName,
1555  string(),
1556  model
1557  );
1558  break;
1559  }
1561  {
1562  prototype = unique_ptr<Prototype>(
1563  PrototypeReader::read(
1564  FileSystem::getInstance()->getPathName(absoluteFileName),
1565  FileSystem::getInstance()->getFileName(absoluteFileName)
1566  )
1567  );
1568  break;
1569  }
1571  {
1572  prototype = unique_ptr<Prototype>(
1573  PrototypeReader::read(
1574  FileSystem::getInstance()->getPathName(absoluteFileName),
1575  FileSystem::getInstance()->getFileName(absoluteFileName)
1576  )
1577  );
1578  break;
1579  }
1581  {
1582  scene = unique_ptr<Scene>(
1583  SceneReader::read(
1584  "resources/engine/scenes/envmap",
1585  "envmap.tscene"
1586  )
1587  );
1588  prototype = unique_ptr<Prototype>(
1589  PrototypeReader::read(
1590  FileSystem::getInstance()->getPathName(absoluteFileName),
1591  FileSystem::getInstance()->getFileName(absoluteFileName)
1592  )
1593  );
1594  break;
1595  }
1597  {
1598  prototype = unique_ptr<Prototype>(
1599  PrototypeReader::read(
1600  FileSystem::getInstance()->getPathName(absoluteFileName),
1601  FileSystem::getInstance()->getFileName(absoluteFileName)
1602  )
1603  );
1604  break;
1605  }
1607  {
1608  prototype = unique_ptr<Prototype>(
1609  PrototypeReader::read(
1610  FileSystem::getInstance()->getPathName(absoluteFileName),
1611  FileSystem::getInstance()->getFileName(absoluteFileName)
1612  )
1613  );
1614  break;
1615  }
1617  {
1618  prototype = unique_ptr<Prototype>(
1619  PrototypeReader::read(
1620  FileSystem::getInstance()->getPathName(absoluteFileName),
1621  FileSystem::getInstance()->getFileName(absoluteFileName)
1622  )
1623  );
1624  break;
1625  }
1627  {
1628  prototype = unique_ptr<Prototype>(
1629  PrototypeReader::read(
1630  FileSystem::getInstance()->getPathName(absoluteFileName),
1631  FileSystem::getInstance()->getFileName(absoluteFileName)
1632  )
1633  );
1634  break;
1635  }
1636  case FILETYPE_SCENE:
1637  {
1638  scene = unique_ptr<Scene>(
1639  SceneReader::read(
1640  FileSystem::getInstance()->getPathName(absoluteFileName),
1641  FileSystem::getInstance()->getFileName(absoluteFileName)
1642  )
1643  );
1644  break;
1645  }
1646  case FILETYPE_SCREEN_TEXT:
1647  {
1648  throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1649  }
1650  case FILETYPE_SOUND:
1651  {
1652  throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1653  }
1654  case FILETYPE_TEXTURE:
1655  {
1656  throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1657  }
1658  case FILETYPE_FONT:
1659  {
1660  throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1661  }
1662  case FILETYPE_TEXT:
1663  {
1664  throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1665  }
1666  default:
1667  throw ExceptionBase("Unknown file type.");
1668  }
1669  } catch (Exception& exception) {
1670  errorMessage = string(exception.what());
1671  Console::println("EditorScreenController::FileOpenThread::run(): An error occurred: " + errorMessage);
1672  error = true;
1673  }
1674 
1675  //
1676  finished = true;
1677 }
1678 
1680  auto selectedTabId = getSelectedTabId();
1681  auto idx = 0;
1682  for (auto tab: tabViewVector) {
1683  if (selectedTabId == tab->getId()) return idx;
1684  idx++;
1685  }
1686  return -1;
1687 }
1688 
1690  auto tab = getTabAt(idx);
1691  if (tab != nullptr && screenNode->getNodeById(tab->getId()) != nullptr) {
1692  tabs->getController()->setValue(MutableString(tab->getId()));
1693  return true;
1694  }
1695  return false;
1696 }
1697 
1698 bool EditorScreenController::selectTab(const string& tabId) {
1699  auto tab = getTab(tabId);
1700  if (tab != nullptr && screenNode->getNodeById(tab->getId()) != nullptr) {
1701  tabs->getController()->setValue(MutableString(tab->getId()));
1702  return true;
1703  }
1704  return false;
1705 }
1706 
1707 void EditorScreenController::openFile(const string& absoluteFileName) {
1708  // should never happen but still ...
1709  if (fileOpenThread != nullptr) {
1710  Console::println("EditorScreenController::openFile(): " + absoluteFileName + ": file open thread is already busy with opening a file");
1711  showInfoPopUp("Error", string() + "File open thread is already busy with opening a file");
1712  return;
1713  }
1714 
1715  // path
1716  if (FileSystem::getInstance()->isPath(absoluteFileName)) {
1717  stopScanFiles();
1718  resetScanFiles();
1719  setRelativeProjectPath(getRelativePath(absoluteFileName));
1720  startScanFiles();
1721  return;
1722  }
1723 
1724  //
1725  auto tabId = "tab_" + StringTools::replace(absoluteFileName, ".", "_");
1726  if (selectTab(tabId) == true) return;
1727  tabId = GUIParser::escape(tabId);
1728 
1729  //
1730  auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
1731  auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1732  FileType fileType = FILETYPE_UNKNOWN;
1733  if (StringTools::endsWith(fileNameLowerCase, ".xml") == true) {
1734  fileType = FILETYPE_SCREEN_TEXT;
1735  } else
1736  if (StringTools::endsWith(fileNameLowerCase, ".tempty") == true) {
1737  fileType = FILETYPE_EMPTYPROTOTYPE;
1738  } else
1739  if (StringTools::endsWith(fileNameLowerCase, ".ttrigger") == true) {
1740  fileType = FILETYPE_TRIGGERPROTOTYPE;
1741  } else
1742  if (StringTools::endsWith(fileNameLowerCase, ".tenvmap") == true) {
1743  fileType = FILETYPE_ENVMAPPROTOTYPE;
1744  } else
1745  if (StringTools::endsWith(fileNameLowerCase, ".tdecal") == true) {
1746  fileType = FILETYPE_DECALPROTOTYPE;
1747  } else
1748  if (StringTools::endsWith(fileNameLowerCase, ".tscene") == true) {
1749  fileType = FILETYPE_SCENE;
1750  } else
1751  if (StringTools::endsWith(fileNameLowerCase, ".tmodel") == true) {
1752  fileType = FILETYPE_MODELPROTOTYPE;
1753  } else
1754  if (StringTools::endsWith(fileNameLowerCase, ".tparticle") == true) {
1756  } else
1757  if (StringTools::endsWith(fileNameLowerCase, ".tterrain") == true) {
1758  fileType = FILETYPE_TERRAINPROTOTYPE;
1759  } else
1760  if (StringTools::endsWith(fileNameLowerCase, ".ttf") == true) {
1761  fileType = FILETYPE_FONT;
1762  } else
1763  if (StringTools::endsWith(fileNameLowerCase, ".ogg") == true) {
1764  fileType = FILETYPE_SOUND;
1765  } else
1766  if (StringTools::endsWith(fileNameLowerCase, ".mpg") == true) {
1767  fileType = FILETYPE_VIDEO;
1768  } else
1769  if (StringTools::endsWith(fileNameLowerCase, ".md") == true) {
1770  fileType = FILETYPE_MARKDOWN;
1771  } else
1772  if (fileNameLowerCase == "license" ||
1773  StringTools::endsWith(fileNameLowerCase, ".h") == true ||
1774  StringTools::endsWith(fileNameLowerCase, ".cpp") == true ||
1775  StringTools::endsWith(fileNameLowerCase, ".c") == true ||
1776  StringTools::endsWith(fileNameLowerCase, ".tscript") == true ||
1777  StringTools::endsWith(fileNameLowerCase, ".properties") == true ||
1778  StringTools::endsWith(fileNameLowerCase, ".cl") == true ||
1779  StringTools::endsWith(fileNameLowerCase, ".frag") == true ||
1780  StringTools::endsWith(fileNameLowerCase, ".glsl") == true ||
1781  StringTools::endsWith(fileNameLowerCase, ".vert") == true ||
1782  StringTools::endsWith(fileNameLowerCase, ".xml") == true ||
1783  StringTools::endsWith(fileNameLowerCase, ".nmake") == true ||
1784  StringTools::endsWith(fileNameLowerCase, ".nmake.main") == true ||
1785  StringTools::endsWith(fileNameLowerCase, ".bat") == true ||
1786  StringTools::endsWith(fileNameLowerCase, ".sh") == true ||
1787  StringTools::endsWith(fileNameLowerCase, ".bash") == true ||
1788  (fileName.rfind(".") == string::npos || (fileName.rfind("/") != string::npos && fileName.rfind(".") < fileName.rfind("/")))) {
1789  fileType = FILETYPE_TEXT;
1790  } else {
1791  for (const auto& extension: ModelReader::getModelExtensions()) {
1792  if (StringTools::endsWith(fileNameLowerCase, "." + extension) == true) {
1793  fileType = FILETYPE_MODEL;
1794  break;
1795  }
1796  }
1797  for (const auto& extension: TextureReader::getTextureExtensions()) {
1798  if (StringTools::endsWith(fileNameLowerCase, "." + extension) == true) {
1799  fileType = FILETYPE_TEXTURE;
1800  break;
1801  }
1802  }
1803  }
1804  if (fileType == FILETYPE_UNKNOWN) {
1805  showInfoPopUp("Error", "File format not yet supported");
1806  return;
1807  }
1808 
1809  //
1810  try {
1811  string icon;
1812  string colorType;
1814  TabView* tabView = nullptr;
1815  string viewPortTemplate;
1816  switch (fileType) {
1817  case FILETYPE_MODEL:
1818  {
1819  view->getPopUps()->getProgressBarScreenController()->show("Opening model as prototype ...", false);
1820  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1821  fileOpenThread->start();
1822  break;
1823  }
1825  {
1826  view->getPopUps()->getProgressBarScreenController()->show("Opening empty prototype ...", false);
1827  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1828  fileOpenThread->start();
1829  break;
1830  }
1832  {
1833  view->getPopUps()->getProgressBarScreenController()->show("Opening trigger prototype ...", false);
1834  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1835  fileOpenThread->start();
1836  break;
1837  }
1839  {
1840  view->getPopUps()->getProgressBarScreenController()->show("Opening environment map prototype ...", false);
1841  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1842  fileOpenThread->start();
1843  break;
1844  }
1846  {
1847  view->getPopUps()->getProgressBarScreenController()->show("Opening decal prototype ...", false);
1848  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1849  fileOpenThread->start();
1850  break;
1851  }
1853  {
1854  view->getPopUps()->getProgressBarScreenController()->show("Opening model prototype...", false);
1855  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1856  fileOpenThread->start();
1857  break;
1858  }
1860  {
1861  view->getPopUps()->getProgressBarScreenController()->show("Opening terrain prototype ...", false);
1862  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1863  fileOpenThread->start();
1864  break;
1865  }
1867  {
1868  view->getPopUps()->getProgressBarScreenController()->show("Opening particle system prototype ...", false);
1869  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1870  fileOpenThread->start();
1871  break;
1872  }
1873  case FILETYPE_SCENE:
1874  {
1875  view->getPopUps()->getProgressBarScreenController()->show("Opening scene ...", false);
1876  fileOpenThread = make_unique<FileOpenThread>(tabId, fileType, absoluteFileName);
1877  fileOpenThread->start();
1878  break;
1879  }
1880  case FILETYPE_SCREEN_TEXT:
1881  {
1882  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1883  break;
1884  }
1885  case FILETYPE_SOUND:
1886  {
1887  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1888  break;
1889  }
1890  case FILETYPE_TEXTURE:
1891  {
1892  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1893  break;
1894  }
1895  case FILETYPE_VIDEO:
1896  {
1897  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1898  break;
1899  }
1900  case FILETYPE_FONT:
1901  {
1902  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1903  break;
1904  }
1905  case FILETYPE_TEXT:
1906  {
1907  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1908  break;
1909  }
1910  case FILETYPE_MARKDOWN:
1911  {
1912  onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1913  break;
1914  }
1915  default:
1916  throw ExceptionBase("Unknown file type.");
1917  }
1918  } catch (Exception& exception) {
1919  Console::println("EditorScreenController::openFile(): An error occurred: " + string(exception.what()));
1922  showInfoPopUp("Error", "An error occurred: " + string(exception.what()));
1923  }
1924 }
1925 
1926 void EditorScreenController::onOpenFileFinish(const string& tabId, FileType fileType, const string& absoluteFileName, unique_ptr<Prototype> prototype, unique_ptr<Scene> scene) {
1927  auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
1928  auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1929 
1930  //
1931  try {
1932  string icon;
1933  string colorType;
1935  unique_ptr<TabView> tabView;
1936  string viewPortTemplate;
1937  switch (fileType) {
1938  case FILETYPE_MODEL:
1939  {
1940  icon = "{$icon.type_mesh}";
1941  colorType = "{$color.type_mesh}";
1943  tabView = make_unique<ModelEditorTabView>(view, tabId, prototype.release());
1944  viewPortTemplate = "template_viewport_scene.xml";
1945  break;
1946  }
1948  {
1949  icon = "{$icon.type_prototype}";
1950  colorType = "{$color.type_prototype}";
1952  tabView = make_unique<EmptyEditorTabView>(view, tabId, prototype.release());
1953  viewPortTemplate = "template_viewport_scene.xml";
1954  break;
1955  }
1957  {
1958  icon = "{$icon.type_prototype}";
1959  colorType = "{$color.type_prototype}";
1961  tabView = make_unique<TriggerEditorTabView>(view, tabId, prototype.release());
1962  viewPortTemplate = "template_viewport_scene.xml";
1963  break;
1964  }
1966  {
1967  icon = "{$icon.type_scene}";
1968  colorType = "{$color.type_scene}";
1970  tabView = make_unique<EnvMapEditorTabView>(view, tabId, scene.release(), prototype.release());
1971  viewPortTemplate = "template_viewport_scene.xml";
1972  break;
1973  }
1975  {
1976  icon = "{$icon.type_decal}";
1977  colorType = "{$color.type_prototype}";
1979  tabView = make_unique<DecalEditorTabView>(view, tabId, prototype.release());
1980  viewPortTemplate = "template_viewport_scene.xml";
1981  break;
1982  }
1984  {
1985  icon = "{$icon.type_prototype}";
1986  colorType = "{$color.type_prototype}";
1988  tabView = make_unique<ModelEditorTabView>(view, tabId, prototype.release());
1989  viewPortTemplate = "template_viewport_scene.xml";
1990  break;
1991  }
1993  {
1994  icon = "{$icon.type_terrain}";
1995  colorType = "{$color.type_terrain}";
1997  tabView = make_unique<TerrainEditorTabView>(view, tabId, prototype.release());
1998  viewPortTemplate = "template_viewport_terrain.xml";
1999  break;
2000  }
2002  {
2003  icon = "{$icon.type_particle}";
2004  colorType = "{$color.type_particle}";
2006  tabView = make_unique<ParticleSystemEditorTabView>(view, tabId, prototype.release());
2007  viewPortTemplate = "template_viewport_scene.xml";
2008  break;
2009  }
2010  case FILETYPE_SCENE:
2011  {
2012  icon = "{$icon.type_scene}";
2013  colorType = "{$color.type_scene}";
2015  tabView = make_unique<SceneEditorTabView>(view, tabId, scene.release());
2016  viewPortTemplate = "template_viewport_scene.xml";
2017  break;
2018  }
2019  case FILETYPE_SCREEN_TEXT:
2020  {
2021  string xmlRootNode;
2022  // try to read XML root node tag name
2023  try {
2024  xmlRootNode = GUIParser::getRootNode(
2025  FileSystem::getInstance()->getPathName(absoluteFileName),
2026  FileSystem::getInstance()->getFileName(absoluteFileName)
2027  );
2028  } catch (Exception& exception) {
2029  Console::println("EditorScreenController::openFile(): " + absoluteFileName + ": " + string(exception.what()));
2030  }
2031  // gui?
2032  if (xmlRootNode == "screen" || xmlRootNode == "template") {
2033  icon = "{$icon.type_gui}";
2034  colorType = "{$color.type_gui}";
2036  tabView = make_unique<UIEditorTabView>(view, tabId, screenNode, absoluteFileName);
2037  viewPortTemplate = "template_viewport_ui.xml";
2038  } else {
2039  // nope, xml
2040  icon = "{$icon.type_script}";
2041  colorType = "{$color.type_script}";
2042  auto text =
2043  FileSystem::getInstance()->getContentAsString(
2044  FileSystem::getInstance()->getPathName(absoluteFileName),
2045  FileSystem::getInstance()->getFileName(absoluteFileName)
2046  );
2047  auto screenNode = unique_ptr<GUIScreenNode>(
2048  GUIParser::parse(
2049  "resources/engine/gui/",
2050  "tab_text.xml",
2051  {{ "text", StringTools::replace(StringTools::replace(text, "[", "\\["), "]", "\\]") }}
2052  )
2053  );
2054  tabType = EditorTabView::TABTYPE_TEXT;
2055  tabView = make_unique<TextEditorTabView>(view, tabId, screenNode.release(), absoluteFileName);
2056  viewPortTemplate = "template_viewport_plain.xml";
2057  }
2058  break;
2059  }
2060  case FILETYPE_SOUND:
2061  {
2062  icon = "{$icon.type_sound}";
2063  colorType = "{$color.type_sound}";
2064  auto audioStream = make_unique<VorbisAudioStream>(
2065  tabId,
2066  FileSystem::getInstance()->getPathName(absoluteFileName),
2067  FileSystem::getInstance()->getFileName(absoluteFileName)
2068  );
2069  auto screenNode = unique_ptr<GUIScreenNode>(
2070  GUIParser::parse(
2071  "resources/engine/gui/",
2072  "tab_sound.xml"
2073  )
2074  );
2075  tabType = EditorTabView::TABTYPE_SOUND;
2076  tabView = make_unique<SoundTabView>(view, tabId, screenNode.release(), audioStream.release());
2077  viewPortTemplate = "template_viewport_plain.xml";
2078  break;
2079  }
2080  case FILETYPE_TEXTURE:
2081  {
2082  icon = "{$icon.type_texture}";
2083  colorType = "{$color.type_texture}";
2084  auto screenNode = unique_ptr<GUIScreenNode>(
2085  GUIParser::parse(
2086  "resources/engine/gui/",
2087  "tab_texture.xml",
2088  {{ "texture", absoluteFileName}}
2089  )
2090  );
2092  tabView = make_unique<TextureTabView>(view, tabId, screenNode.release());
2093  viewPortTemplate = "template_viewport_plain.xml";
2094  break;
2095  }
2096  case FILETYPE_VIDEO:
2097  {
2098  icon = "{$icon.type_texture}";
2099  colorType = "{$color.type_texture}";
2100  auto screenNode = unique_ptr<GUIScreenNode>(
2101  GUIParser::parse(
2102  "resources/engine/gui/",
2103  "tab_video.xml",
2104  {{ "video", absoluteFileName}}
2105  )
2106  );
2107  tabType = EditorTabView::TABTYPE_VIDEO;
2108  tabView = make_unique<VideoTabView>(view, tabId, screenNode.release());
2109  viewPortTemplate = "template_viewport_plain.xml";
2110  break;
2111  }
2112  case FILETYPE_FONT:
2113  {
2114  icon = "{$icon.type_font}";
2115  colorType = "{$color.type_font}";
2116  auto screenNode = unique_ptr<GUIScreenNode>(
2117  GUIParser::parse(
2118  "resources/engine/gui/",
2119  "tab_font.xml",
2120  {
2121  { "font", absoluteFileName },
2122  { "size", "20" }
2123  }
2124  )
2125  );
2126  tabType = EditorTabView::TABTYPE_FONT;
2127  tabView = make_unique<FontTabView>(view, tabId, screenNode.release());
2128  viewPortTemplate = "template_viewport_plain.xml";
2129  break;
2130  }
2131  case FILETYPE_TEXT:
2132  {
2133  auto hasVisualCode = StringTools::endsWith(fileNameLowerCase, ".tscript");
2134  icon = "{$icon.type_script}";
2135  colorType = "{$color.type_script}";
2136  auto text =
2137  FileSystem::getInstance()->getContentAsString(
2138  FileSystem::getInstance()->getPathName(absoluteFileName),
2139  FileSystem::getInstance()->getFileName(absoluteFileName)
2140  );
2141  auto screenNode = unique_ptr<GUIScreenNode>(
2142  GUIParser::parse(
2143  "resources/engine/gui/",
2144  hasVisualCode == true?"tab_visualcode.xml":"tab_text.xml",
2145  {{ "text", StringTools::replace(StringTools::replace(text, "[", "\\["), "]", "\\]") }}
2146  )
2147  );
2148  tabType = EditorTabView::TABTYPE_TEXT;
2149  tabView = make_unique<TextEditorTabView>(view, tabId, screenNode.release(), absoluteFileName);
2150  viewPortTemplate = hasVisualCode == true?"template_viewport_visualcode.xml":"template_viewport_plain.xml";
2151  break;
2152  }
2153  case FILETYPE_MARKDOWN:
2154  {
2155  icon = "{$icon.type_script}";
2156  colorType = "{$color.type_script}";
2157  vector<Markdown::TOCEntry> toc;
2158  auto screenNode = unique_ptr<GUIScreenNode>(
2159  GUIParser::parse(
2160  Markdown::createGUIXML(
2161  FileSystem::getInstance()->getPathName(absoluteFileName),
2162  FileSystem::getInstance()->getFileName(absoluteFileName),
2163  toc
2164  )
2165  )
2166  );
2168  tabView = make_unique<MarkdownTabView>(view, tabId, screenNode.release(), toc);
2169  viewPortTemplate = "template_viewport_plain.xml";
2170  break;
2171  }
2172  default:
2173  throw ExceptionBase("Unknown file type.");
2174  }
2175  //
2176  {
2177  string tabsHeaderXML = "<tab id=\"" + tabId + "\" image=\"" + GUIParser::escape(icon) + "\" type-color=\"" + GUIParser::escape(colorType) + "\" value=\"" + GUIParser::escape(absoluteFileName) + "\" text=\"" + GUIParser::escape(fileName) + "\" closeable=\"true\" />\n";
2178  try {
2179  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(tabsHeader->getId()))->addSubNodes(tabsHeaderXML, true);
2180  } catch (Exception& exception) {
2181  Console::println("EditorScreenController::onOpenFile(): An error occurred: " + string(exception.what()));
2182  }
2183  }
2184  {
2185  string tabsContentXML =
2186  "<tab-content tab-id=\"" + tabId + "\">\n" +
2187  " <template id=\"" + tabId + "_tab\" src=\"resources/engine/gui/" + viewPortTemplate + "\" />\n" +
2188  "</tab-content>\n";
2189  try {
2190  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(tabsContent->getId()))->addSubNodes(tabsContentXML, true);
2191  } catch (Exception& exception) {
2192  Console::println("EditorScreenController::onOpenFile(): An error occurred: " + string(exception.what()));
2193  }
2194  }
2195  //
2196  tabView->initialize();
2197  //
2198  // TODO: move me into GUIFrameBufferNode
2199  if (Engine::getInstance()->getGraphicsRendererType() != Renderer::RENDERERTYPE_VULKAN) {
2200  auto tabFrameBuffer = dynamic_cast<GUIImageNode*>(screenNode->getNodeById(tabId + "_tab_framebuffer"));
2201  if (tabFrameBuffer != nullptr) tabFrameBuffer->setTextureMatrix(Matrix3x3().identity().scale(Vector2(1.0f, -1.0f)));
2202  }
2203  tabViews[tabId] = EditorTabView(tabId, Tools::getFileName(absoluteFileName), tabType, tabView.release(), required_dynamic_cast<GUIImageNode*>(screenNode->getNodeById(tabId + "_tab_framebuffer")));
2204  tabViewVector.push_back(&tabViews[tabId]);
2206  } catch (Exception& exception) {
2207  Console::println("EditorScreenController::onOpenFileFinish(): An error occurred: " + string(exception.what()));
2210  showInfoPopUp("Error", "An error occurred: " + string(exception.what()));
2211  }
2212 
2213  //
2215 
2216  //
2219 }
2220 
2221 void EditorScreenController::storeOutlinerState(TabView::OutlinerState& outlinerState) {
2222  required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->determineExpandedParentOptionValues(outlinerState.expandedOutlinerParentOptionValues);
2223  outlinerState.value = required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->getValue();
2224  outlinerState.renderOffsetX = required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->getChildrenRenderOffsetX();
2225  outlinerState.renderOffsetY = required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->getChildrenRenderOffsetY();
2226 }
2227 
2228 void EditorScreenController::restoreOutlinerState(const TabView::OutlinerState& outlinerState) {
2229  required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->expandParentOptionsByValues(outlinerState.expandedOutlinerParentOptionValues);
2230  required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->setValue(outlinerState.value);
2231  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->setChildrenRenderOffsetX(outlinerState.renderOffsetX);
2232  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->setChildrenRenderOffsetY(outlinerState.renderOffsetY);
2233 }
2234 
2236  return outliner->getController()->getValue().getString();
2237 }
2238 
2239 void EditorScreenController::setOutlinerSelection(const string& newSelectionValue) {
2240  outliner->getController()->setValue(MutableString(newSelectionValue));
2241 }
2242 
2244  auto outlinerSelection = getOutlinerSelection();
2245  try {
2246  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->replaceSubNodes(xml, true);
2247  } catch (Exception& exception) {
2248  Console::println("EditorScreenController::setOutlinerContent(): An error occurred: " + string(exception.what()));
2249  }
2250  setOutlinerSelection(outlinerSelection);
2251 }
2252 
2254  try {
2255  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerAddDropDown->getId()))->replaceSubNodes(xml, true);
2256  } catch (Exception& exception) {
2257  Console::println("EditorScreenController::setOutlinerAddDropDownContent(): An error occurred: " + string(exception.what()));
2258  }
2259 }
2260 
2262  try {
2263  required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(detailsScrollarea->getId()))->replaceSubNodes(xml, true);
2264  } catch (Exception& exception) {
2265  Console::println("EditorScreenController::setDetailsContent(): An error occurred: " + string(exception.what()));
2266  }
2267 }
2268 
2270  return required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().has("fullscreen");
2271 }
2272 
2274  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_fullscreen"))->getController()->setDisabled(tabViews.empty() == true);
2275 }
2276 
2278  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("menu_view_tabs"))->clearSubNodes();
2279  //
2280  if (tabViewVector.empty() == true) return;
2281  auto tabIdx = 0;
2282  string xml = "<menu-separator />\n";
2283  for (auto tab: tabViewVector) {
2284  auto imageSource = GUIParser::getEngineThemeProperties()->get("icon.type_" + FileDialogScreenController::getFileImageName(tab->getName()), "resources/engine/images/tdme.png");
2285  xml+= "<menu-item image='" + imageSource + "' text='" + GUIParser::escape(tab->getName()) + "' id='menu_view_tab_" + to_string(tabIdx) + "' shortcut='Ctrl+" + to_string(tabIdx + 1) + "' />\n";
2286  tabIdx++;
2287  }
2288  try {
2289  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("menu_view_tabs"))->addSubNodes(xml, true);
2290  } catch (Exception& exception) {
2291  Console::println("EditorScreenController::updateTabsMenuEntries(): An error occurred: " + string(exception.what()));
2292  }
2293 }
2294 
2296  if (fullScreen == true) {
2297  auto selectedTab = getSelectedTab();
2298  if (selectedTab != nullptr) {
2299  Application::getApplication()->setFullScreen(true);
2300  fullScreenTabId = selectedTab->getId();
2301  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("fullscreen-content"))->moveSubNodes(
2302  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById(fullScreenTabId + "-content"))
2303  );
2304  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().add("fullscreen");
2305  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById(fullScreenTabId + "_tab_toolbar"))->getActiveConditions().add("fullscreen");
2306  //
2307  auto selectedTabNode = screenNode->getNodeById(fullScreenTabId + "_tab");
2308  fullScreenTabPadding = selectedTabNode->getPadding();
2309  selectedTabNode->getPadding().left = 0;
2310  selectedTabNode->getPadding().top = 0;
2311  selectedTabNode->getPadding().right = 0;
2312  selectedTabNode->getPadding().bottom = 0;
2313  }
2314  } else
2315  if (fullScreenTabId.empty() == false) {
2316  Application::getApplication()->setFullScreen(false);
2317  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById(fullScreenTabId + "-content"))->moveSubNodes(
2318  required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("fullscreen-content"))
2319  );
2320  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById(fullScreenTabId + "_tab_toolbar"))->getActiveConditions().remove("fullscreen");
2321  auto selectedTabNode = screenNode->getNodeById(fullScreenTabId + "_tab");
2322  selectedTabNode->getPadding() = fullScreenTabPadding;
2323  fullScreenTabId.clear();
2324  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().remove("fullscreen");
2325  }
2326 }
2327 
2329  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_scene_run"))->getController()->setDisabled(false);
2330  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_scene_stop"))->getController()->setDisabled(false);
2331 }
2332 
2334  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_scene_run"))->getController()->setDisabled(true);
2335  required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_scene_stop"))->getController()->setDisabled(true);
2336 }
2337 
2338 void EditorScreenController::getViewPort(GUINode* viewPortNode, int& left, int& top, int& width, int& height) {
2339  const auto& constraints = viewPortNode->getComputedConstraints();
2340  const auto& padding = viewPortNode->getPadding();
2341  left = constraints.left + constraints.alignmentLeft + constraints.contentAlignmentLeft;
2342  top = constraints.top + constraints.alignmentTop + constraints.contentAlignmentTop;
2343  width = constraints.width - (padding.left + padding.right);
2344  height = constraints.height - (padding.top + padding.bottom);
2345 }
2346 
2348  return tabs->getController()->getValue().getString();
2349 }
2350 
2352  auto now = Time::getCurrentMillis();
2353  if (timeFileNameSearchTerm != -1LL && now - timeFileNameSearchTerm >= 1000LL) {
2354  timeFileNameSearchTerm = -1LL;
2355  startScanFiles();
2356  }
2357  if (scanFilesThread != nullptr) {
2358  lockFileEntities();
2359  for (auto& fileEntity: getFileEntities()) {
2360  pendingFileEntities.push_back(move(fileEntity));
2361  if (pendingFileEntities.size() == 2) addPendingFileEntities();
2362  }
2363  getFileEntities().clear();
2364  if (scanFilesThread->isFinished() == true) {
2365  scanFilesThread->join();
2367  if (scanFilesThread->isError() == true) {
2368  if (scanFilesThread->getErrorMessage().empty() == true) {
2369  showInfoPopUp("Error", string() + "An error occurred: Unknown error");
2370  } else {
2371  showInfoPopUp("Error", string() + "An error occurred: " + scanFilesThread->getErrorMessage());
2372  }
2373  }
2374  scanFilesThread = nullptr;
2375  }
2377  }
2378  if (fileOpenThread != nullptr) {
2379  if (fileOpenThread->isFinished() == true) {
2380  fileOpenThread->join();
2381  if (fileOpenThread->isError() == true) {
2384  if (fileOpenThread->getErrorMessage().empty() == true) {
2385  showInfoPopUp("Error", string() + "An error occurred: Unknown error");
2386  } else {
2387  showInfoPopUp("Error", string() + "An error occurred: " + fileOpenThread->getErrorMessage());
2388  }
2389  } else {
2391  fileOpenThread->getTabId(),
2392  fileOpenThread->getFileType(),
2393  fileOpenThread->getAbsoluteFileName(),
2394  move(fileOpenThread->getPrototype()),
2395  move(fileOpenThread->getScene())
2396  );
2397  }
2398  fileOpenThread = nullptr;
2399  } else {
2401  }
2402  }
2403  //
2404  if (logUpdateRequired == true) {
2405  logUpdateRequired = false;
2406  //
2407  MutableString log;
2408  for (const auto& logMessage: logMessages) {
2409  log.append(StringTools::replace(StringTools::replace(logMessage, "[", "\\["), "]", "\\]"));
2410  log.append("\n");
2411  }
2412  logStyledTextNode->setText(log);
2413  //
2414  auto logScrollareaController = required_dynamic_cast<GUIScrollAreaController*>(logScrollarea->getController());
2415  if (logScrollareaController->isAtBottom() == true) logScrollareaController->scrollToBottom();
2416  }
2417 }
2418 
2419 bool EditorScreenController::isDropOnNode(int dropX, int dropY, const string& nodeId) {
2420  auto node = screenNode->getNodeById(nodeId);
2421  if (node == nullptr) return false;
2422  auto _node = node;
2423  while (_node != nullptr) {
2424  if (_node->isConditionsMet() == false || _node->isLayouted() == false) {
2425  return false;
2426  }
2427  _node = _node->getParentNode();
2428  }
2429  //
2430  auto gui = Engine::getInstance()->getGUI();
2431  // TODO: node->isCoordinateBelongingToNode() could check if layouted and conditions met
2432  return node->isCoordinateBelongingToNode(
2433  Vector2(
2434  gui->getScaledX(screenNode, dropX),
2435  gui->getScaledY(screenNode, dropY)
2436  )
2437  );
2438 }
2439 
2440 void EditorScreenController::onDrop(const vector<string>& paths) {
2441  // WIP
2443 }
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:41
Engine main class.
Definition: Engine.h:131
Frame buffer class.
Definition: FrameBuffer.h:22
Texture entity.
Definition: Texture.h:24
uint16_t getTextureHeight() const
Definition: Texture.h:211
uint16_t getTextureWidth() const
Definition: Texture.h:218
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
Prototype definition.
Definition: Prototype.h:55
Scene definition.
Definition: Scene.h:50
Interface to lighting shader program.
GUI parser.
Definition: GUIParser.h:40
GUI node controller base class.
virtual void setValue(const MutableString &value)=0
Set value.
virtual const MutableString & getValue()=0
GUI node base class.
Definition: GUINode.h:64
const string & getToolTip()
Definition: GUINode.h:346
GUIParentNode * getParentNode()
Definition: GUINode.h:332
GUINodeController * getController()
Definition: GUINode.h:661
GUINode_Padding & getPadding()
Definition: GUINode.h:398
const string & getId()
Definition: GUINode.h:339
bool isCoordinateBelongingToNode(const Vector2 &coordinate, Vector2 &nodeCoordinate)
Is coordinate belonging to node.
Definition: GUINode.h:575
GUINode_ComputedConstraints & getComputedConstraints()
Definition: GUINode.h:412
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 addContextMenuRequestListener(GUIContextMenuRequestListener *listener)
Add context menu request listener.
void addDragRequestListener(GUIDragRequestListener *listener)
Add drag request listener.
void addChangeListener(GUIChangeListener *listener)
Add change listener.
void addTooltipRequestListener(GUITooltipRequestListener *listener)
Add tooltip request listener.
void removeNodeById(const string &nodeId, bool resetScrollOffsets)
Remove GUI node by id.
void addActionListener(GUIActionListener *listener)
Add action listener.
void addFocusListener(GUIFocusListener *listener)
Add focus listener.
GUINode * getInnerNodeById(const string &nodeId)
Get inner GUI node by id.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
void setText(const MutableString &text)
Set text.
void setTextureMatrix(const Matrix3x3 &textureMatrix)
Set texture matrix.
Matrix3x3 class representing matrix3x3 mathematical structure and operations for 2d space.
Definition: Matrix3x3.h:20
Matrix3x3 & identity()
Creates identity matrix.
Definition: Matrix3x3.h:128
Matrix3x3 & scale(float scalar)
Scales by scalar.
Definition: Matrix3x3.h:146
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
File system singleton class.
Definition: FileSystem.h:17
Mutex implementation.
Definition: Mutex.h:19
Base class for threads.
Definition: Thread.h:20
bool isStopRequested()
Returns if stop has been requested.
Definition: Thread.h:77
void quit()
Request to exit the viewer.
Definition: Editor.cpp:96
static Editor * getInstance()
Definition: Editor.h:55
void show(int mouseX, int mouseY)
Shows the pop up.
void addMenuItem(const string &text, const string &id, Action *action=nullptr)
Add menu item.
void start(int mouseX, int mouseY, const string &xml, const string &payload, Action *onReleaseAction)
Show dragging screen and a dragging image from given source.
bool isDropOnNode(int dropX, int dropY, const string &nodeId)
Is drop on node.
EditorTabView * getTab(const string &tabId)
Returns editor tab view by given tab id.
void onContextMenuRequest(GUIElementNode *node, int mouseX, int mouseY) override
On context menu request.
void onOpenFile(const string &absoluteFileName)
On open file.
const string getRelativePath(const string &absoluteFileName)
Returns relative path within project path.
void setOutlinerSelection(const string &newSelectionValue)
Set outliner selection.
void browseTo(const string &fileName)
Browse to file name.
EditorTabView * getTabAt(int idx)
Get tab at given index.
void setOutlinerAddDropDownContent(const string &xml)
Set outliner add content.
void setOutlinerContent(const string &xml)
Set outliner content.
void restoreOutlinerState(const TabView::OutlinerState &outlinerState)
Restore outliner state.
void onChange(GUIElementNode *node) override
On change.
void addPendingFileEntities()
Add project path files pending file entities.
void setScreenCaption(const string &text)
Set screen caption.
void storeOutlinerState(TabView::OutlinerState &outlinerState)
Store outliner state.
void setRelativeProjectPath(const string &relativeProjectPath)
Set relative project path.
void onUnfocus(GUIElementNode *node) override
On unfocus.
void onTooltipCloseRequest() override
On tooltip close request.
void setDetailsContent(const string &xml)
Set details content.
void onDragRequest(GUIElementNode *node, int mouseX, int mouseY) override
On drag request.
void onFocus(GUIElementNode *node) override
On focus.
void showInfoPopUp(const string &caption, const string &message)
Show the information pop up / modal.
void onAction(GUIActionListenerType type, GUIElementNode *node) override
void onOpenFileFinish(const string &tabId, FileType fileType, const string &absoluteFileName, unique_ptr< Prototype > prototype, unique_ptr< Scene > scene)
On open file finish.
void getViewPort(GUINode *viewPortNode, int &left, int &top, int &width, int &height)
Get engine viewport constraints.
bool selectTab(const string &tabId)
Select tab with given id.
void addFile(const string &pathName, const string &fileName, const string &type)
On add file.
void openFile(const string &absoluteFileName)
Open file.
void onTooltipShowRequest(GUINode *node, int mouseX, int mouseY) override
On tooltip show request.
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 setDefaultCWD(const string &defaultCwd)
Set default current working directory.
static const string getFileImageName(const string &fileName)
Get file image name.
void show(const string &caption, const string &message)
Shows the pop up.
void show(const string &captionText, const string &inputText, Action *applyAction, Action *cancelAction=nullptr)
Shows the input dialog pop up.
void show(const string &message, bool showProgressBar=true)
Shows the pop up.
void show(int mouseX, int mouseY, const string &tooltip)
Show tooltip.
Pop ups controller accessor class.
Definition: PopUps.h:29
DraggingScreenController * getDraggingScreenController()
Definition: PopUps.h:138
AboutDialogScreenController * getAboutDialogScreenController()
Definition: PopUps.h:103
ImportDialogScreenController * getImportDialogScreenController()
Definition: PopUps.h:117
InputDialogScreenController * getInputDialogScreenController()
Definition: PopUps.h:68
FileDialogScreenController * getFileDialogScreenController()
Definition: PopUps.h:61
TooltipScreenController * getTooltipScreenController()
Definition: PopUps.h:131
ProgressBarScreenController * getProgressBarScreenController()
Definition: PopUps.h:82
ContextMenuScreenController * getContextMenuScreenController()
Definition: PopUps.h:96
InfoDialogScreenController * getInfoDialogScreenController()
Definition: PopUps.h:75
void addPrototype(Prototype *prototype)
Add prototype to scene.
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
MutableString & append(char c)
Append character.
const string & getString() const
Properties class, which helps out with storeing or loading key value pairs from/to property files.
Definition: Properties.h:23
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
Definition: Reference.h:38
String tools class.
Definition: StringTools.h:22
std::exception Exception
Exception base class.
Definition: Exception.h:18
GUI node padding entity.
File system file name filter interface.
Tab controller, which connects UI with logic.
Definition: TabController.h:34
Action Interface.
Definition: Action.h:11