TDME2 1.9.121
EditorScreenController.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <string>
5#include <unordered_set>
6#include <vector>
7
8#include <tdme/tdme.h>
23#include <tdme/engine/Engine.h>
33#include <tdme/gui/GUI.h>
34#include <tdme/gui/GUIParser.h>
70
71using std::remove;
72using std::string;
73using std::unordered_set;
74using std::vector;
75
137
138EditorScreenController::EditorScreenController(EditorView* view): fileEntitiesMutex("fileentities-mutex")
139{
140 this->view = view;
141}
142
144{
145 // TODO
146}
147
149{
150 return screenNode;
151}
152
154{
155 try {
156 screenNode = GUIParser::parse("resources/engine/gui", "screen_editor.xml");
161 projectPathsScrollArea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_projectpaths_scrollarea"));
162 projectPathFilesScrollArea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_projectpathfiles_scrollarea"));
163 tabs = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs"));
164 tabsHeader = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs-header"));
165 tabsContent = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("tabs-content"));
166 outliner = required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("selectbox_outliner"));
167 outlinerScrollarea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_outliner_scrollarea"));
168 detailsScrollarea = required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("selectbox_details_scrollarea"));
169 outlinerAddDropDown = required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"));
170
171 //
172 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(true);
173 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(true);
174 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(true);
175 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(true);
176 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(true);
177 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(true);
178
179 //
181 } catch (Exception& exception) {
182 Console::print(string("EditorScreenController::initialize(): An error occurred: "));
183 Console::println(string(exception.what()));
184 }
185}
186
188{
190}
191
193{
194}
195
197{
199}
200
201void EditorScreenController::showErrorPopUp(const string& caption, const string& message)
202{
203 view->getPopUps()->getInfoDialogScreenController()->show(caption, message);
204}
205
207{
208 if (node->getId() == "projectpathfiles_search") {
210 timeFileNameSearchTerm = Time::getCurrentMillis();
211 } else
212 if (node->getId() == "selectbox_projectpaths") {
213 fileNameSearchTerm.clear();
218 } else
219 if (node->getId() == "dropdown_projectlibrary_add") {
221 }
222 // forward onValueChanged to active tab tab controller
223 auto selectedTab = getSelectedTab();
224 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onValueChanged(node);
225}
226
228{
230 if (node->getId() == "menu_file_open") {
232 } else
233 if (node->getId() == "menu_file_save") {
235 } else
236 if (node->getId() == "menu_file_saveas") {
238 } else
239 if (node->getId() == "menu_file_saveall") {
241 } else
242 if (node->getId() == "menu_view_fullscreen") {
243 setFullScreen(isFullScreen() == false?true:false);
244 } else
245 if (node->getId() == "menu_help_about") {
247 } else
248 if (StringTools::startsWith(node->getId(), "projectpathfiles_file_") == true) {
249 onOpenFile(required_dynamic_cast<GUIElementNode*>(node)->getValue());
250 } else
251 if (StringTools::startsWith(node->getId(), "tab_viewport_") == true) {
252 string tabIdToClose;
253 for (auto& tabsIt: tabViews) {
254 auto& tab = tabsIt.second;
255 if (StringTools::startsWith(node->getId(), tab.getId() + "_close") == true) {
256 tabIdToClose = tab.getId();
257 Console::println("EditorScreenController::onActionPerformed(): close tab: " + tab.getId());
258 }
259 }
260 if (tabIdToClose.empty() == false) {
261 //
262 class CloseTabAction: public Action {
263 private:
264 EditorScreenController* editorScreenController;
265 string tabIdToClose;
266 public:
267 CloseTabAction(EditorScreenController* editorScreenController, const string& tabIdToClose): editorScreenController(editorScreenController), tabIdToClose(tabIdToClose) {}
268 virtual void performAction() {
269 editorScreenController->screenNode->removeNodeById(tabIdToClose, false);
270 editorScreenController->screenNode->removeNodeById(tabIdToClose + "-content", false);
271 auto tabIt = editorScreenController->tabViews.find(tabIdToClose);
272 if (tabIt == editorScreenController->tabViews.end()) {
273 Console::println("CloseTabAction::performAction(): close tab: " + tabIdToClose + ": not found");
274 } else {
275 auto& tab = tabIt->second;
276 tab.getTabView()->dispose();
277 delete tab.getTabView();
278 editorScreenController->tabViews.erase(tabIt);
279 }
280 editorScreenController->setDetailsContent(string());
281 editorScreenController->setOutlinerContent(string());
282 //
283 editorScreenController->updateFullScreenMenuEntry();
284 }
285 };
286 Engine::getInstance()->enqueueAction(new CloseTabAction(this, tabIdToClose));
287 }
288 } else
289 if (node->getId() == "menu_file_quit") {
291 }
292 }
293 // forward onActionPerformed to active tab tab controller
294 auto selectedTab = getSelectedTab();
295 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onActionPerformed(type, node);
296}
297
299 // forward onFocus to active tab tab controller
300 auto selectedTab = getSelectedTab();
301 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onFocus(node);
302}
303
305 // forward onFocus to active tab tab controller
306 auto selectedTab = getSelectedTab();
307 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onUnfocus(node);
308}
309
311 if (StringTools::startsWith(node->getId(), "projectpathfiles_file_") == true) {
312 auto absoluteFileName = required_dynamic_cast<GUIElementNode*>(node)->getValue();
313 auto selectedTab = getSelectedTab();
314 if (selectedTab == nullptr) return;
315 switch (selectedTab->getType()) {
317 break;
319 {
320 // clear
322
323 // load
324 class OnAddToSceneAction: public virtual Action
325 {
326 public:
327 void performAction() override {
328 auto currentTab = editorScreenController->getSelectedTab();
329 if (currentTab == nullptr) return;
330 SceneEditorTabView* sceneEditorTabView = dynamic_cast<SceneEditorTabView*>(currentTab->getTabView());
331 if (sceneEditorTabView == nullptr) return;
332 try {
333 auto prototype = PrototypeReader::read(
334 Tools::getPathName(absoluteFileName),
335 Tools::getFileName(absoluteFileName)
336 );
337 sceneEditorTabView->addPrototype(prototype);
338 } catch (Exception& exception) {
339 Console::println(string("OnAddToSceneAction::performAction(): An error occurred: ") + exception.what());;
340 editorScreenController->showErrorPopUp("Warning", (string(exception.what())));
341 }
342 }
343 OnAddToSceneAction(EditorScreenController* editorScreenController, const string& absoluteFileName): editorScreenController(editorScreenController), absoluteFileName(absoluteFileName) {
344 }
345 private:
346 EditorScreenController* editorScreenController;
347 string absoluteFileName;
348 };
349 view->getPopUps()->getContextMenuScreenController()->addMenuItem("Add to scene", "contextmenu_addtoscene", new OnAddToSceneAction(this, absoluteFileName));
350
351 //
352 view->getPopUps()->getContextMenuScreenController()->show(mouseX, mouseY);
353 }
354 break;
356 break;
358 break;
360 break;
361 default: break;
362 }
363 }
364 // forward onContextMenuRequested to active tab tab controller
365 auto selectedTab = getSelectedTab();
366 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->onContextMenuRequested(node, mouseX, mouseY);
367}
368
369void EditorScreenController::openProject(const string& path) {
370 projectPath = path;
371 if (StringTools::endsWith(projectPath, "/") == true) {
372 projectPath = StringTools::substring(projectPath, 0, projectPath.size() - 1);
373 }
374 Console::println("EditorScreenController::openProject(): " + projectPath);
375 closeProject();
378 setRelativeProjectPath("resources");
380 //
381 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(false);
382 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(false);
383 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(false);
384 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(false);
385 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(false);
386 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(false);
387 //
388 GUIParser::loadProjectThemeProperties(projectPath);
389}
390
392 class OnOpenProject: public virtual Action
393 {
394 public:
395 // overriden methods
396 void performAction() override {
397 auto projectPath = editorScreenController->view->getPopUps()->getFileDialogScreenController()->getPathName();
398 editorScreenController->openProject(projectPath);
399 editorScreenController->view->getPopUps()->getFileDialogScreenController()->close();
400 }
401
402 /**
403 * Public constructor
404 * @param editorScreenController editor screen controller
405 */
406 OnOpenProject(EditorScreenController* editorScreenController): editorScreenController(editorScreenController) {
407 }
408
409 private:
410 EditorScreenController* editorScreenController;
411 };
412
414 string(),
415 "Open project from folder: ",
416 {},
417 string(),
418 true,
419 new OnOpenProject(this),
420 nullptr,
421 ".projects.filedialog.properties",
422 "."
423 );
424}
425
427 string xml;
428 xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escapeQuotes("resources") + "\" value=\"" + GUIParser::escapeQuotes("resources") + "\">\n";
429 scanProjectPaths(projectPath + "/resources", xml);
430 xml+= "</selectbox-parent-option>\n";
431 xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escapeQuotes("shader") + "\" value=\"" + GUIParser::escapeQuotes("shader") + "\">\n";
432 scanProjectPaths(projectPath + "/shader", xml);
433 xml+= "</selectbox-parent-option>\n";
434 xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escapeQuotes("src") + "\" value=\"" + GUIParser::escapeQuotes("src") + "\">\n";
435 scanProjectPaths(projectPath + "/src", xml);
436 xml+= "</selectbox-parent-option>\n";
437 try {
438 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathsScrollArea->getId()))->replaceSubNodes(xml, true);
439 } catch (Exception& exception) {
440 Console::print(string("EditorScreenController::scanProjectPaths(): An error occurred: "));
441 Console::println(string(exception.what()));
442 }
443}
444
445void EditorScreenController::scanProjectPaths(const string& path, string& xml) {
446 class ListFilter : public virtual FileNameFilter {
447 public:
448 virtual ~ListFilter() {}
449
450 bool accept(const string& pathName, const string& fileName) override {
451 if (fileName == ".") return false;
452 if (fileName == "..") return false;
453 if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
454 //
455 return false;
456 }
457 };
458
459 ListFilter listFilter;
460 vector<string> files;
461
462 if (FileSystem::getInstance()->fileExists(path) == false) {
463 Console::println("EditorScreenController::scanProject(): Error: file does not exist: " + path);
464 } else
465 if (FileSystem::getInstance()->isPath(path) == false) {
466 if (listFilter.accept(".", path) == true) {
467 Console::println("EditorScreenController::scanProject(): Error: path is file" + path);
468 } else {
469 Console::println("EditorScreenController::scanProject(): Error: file exist, but does not match filter: " + path);
470 }
471 } else {
472 FileSystem::getInstance()->list(path, files, &listFilter);
473 for (auto fileName: files) {
474 auto relativePath = path + "/" + fileName;
475 if (StringTools::startsWith(relativePath, projectPath)) relativePath = StringTools::substring(relativePath, projectPath.size() + 1, relativePath.size());
476 if (FileSystem::getInstance()->isPath(path + "/" + fileName) == false) {
477 // no op for now
478 } else {
479 string innerXml;
480 scanProjectPaths(path + "/" + fileName, innerXml);
481 if (innerXml.empty() == false) {
482 xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escapeQuotes(fileName) + "\" value=\"" + GUIParser::escapeQuotes(relativePath) + "\">\n";
483 xml+= innerXml;
484 xml+= "</selectbox-parent-option>\n";
485 } else {
486 xml+= "<selectbox-option image=\"resources/engine/images/folder.png\" text=\"" + GUIParser::escapeQuotes(fileName) + "\" value=\"" + GUIParser::escapeQuotes(relativePath) + "\" />\n";
487 }
488 }
489 }
490 }
491}
492
494 for (auto& tabsIt: tabViews) {
495 auto& tab = tabsIt.second;
496 screenNode->removeNodeById(tab.getId(), false);
497 screenNode->removeNodeById(tab.getId() + "-content", false);
498 tab.getTabView()->dispose();
499 delete tab.getTabView();
500 }
501 tabViews.clear();
502 setDetailsContent(string());
503 setOutlinerContent(string());
504 //
506}
507
511 closeTabs();
513 //
514 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectlibrary_import"))->getController()->setDisabled(true);
515 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpathfiles_search"))->getController()->setDisabled(true);
516 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("projectpaths_search"))->getController()->setDisabled(true);
517 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_projectlibrary_add"))->getController()->setDisabled(true);
518 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("dropdown_outliner_add"))->getController()->setDisabled(true);
519 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("outliner_search"))->getController()->setDisabled(true);
520}
521
523 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->clearSubNodes();
524}
525
528 try {
529 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->clearSubNodes();
530 } catch (Exception& exception) {
531 Console::print(string("EditorScreenController::startScanFiles(): An error occurred: "));
532 Console::println(string(exception.what()));
533 }
534 Console::println("EditorScreenController::startScanFiles()");
535 scanFilesThread = new ScanFilesThread(this, projectPath + "/" + relativeProjectPath, StringTools::toLowerCase(fileNameSearchTerm));
537}
538
540 string xml;
541 xml+= "<layout alignment=\"horizontal\">\n";
542 for (auto pendingFileEntity: pendingFileEntities) {
543 xml+= pendingFileEntity->buttonXML;
544 }
545 xml+= "</layout>\n";
546 //
547 try {
548 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(projectPathFilesScrollArea->getId()))->addSubNodes(xml, false);
549 } catch (Exception& exception) {
550 Console::print(string("EditorScreenController::addPendingFileEntities(): An error occurred: "));
551 Console::println(string(exception.what()));
552 }
553 //
554 for (auto pendingFileEntity: pendingFileEntities) {
555 if (pendingFileEntity->thumbnailTexture == nullptr) continue;
556 if (screenNode->getNodeById(pendingFileEntity->id + "_texture_normal") == nullptr) continue;
557 try {
558 required_dynamic_cast<GUITextureNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_normal"))->setTexture(pendingFileEntity->thumbnailTexture);
559 required_dynamic_cast<GUITextureNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_mouseover"))->setTexture(pendingFileEntity->thumbnailTexture);
560 required_dynamic_cast<GUITextureNode*>(screenNode->getNodeById(pendingFileEntity->id + "_texture_clicked"))->setTexture(pendingFileEntity->thumbnailTexture);
561 } catch (Exception& exception) {
562 Console::print(string("EditorScreenController::addPendingFileEntities(): An error occurred: "));
563 Console::println(string(exception.what()));
564 }
565 if (pendingFileEntity->thumbnailTexture != nullptr) pendingFileEntity->thumbnailTexture->releaseReference();
566 delete pendingFileEntity;
567 }
568 pendingFileEntities.clear();
569}
570
571void EditorScreenController::setRelativeProjectPath(const string& relativeProjectPath) {
572 this->relativeProjectPath = relativeProjectPath;
573 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("selectbox_projectpaths"))->getController()->setValue(MutableString(relativeProjectPath));
574}
575
577 Console::println("EditorScreenController::stopScanFiles()");
578 if (scanFilesThread != nullptr) {
582 for (auto fileEntity: getFileEntities()) {
583 if (fileEntity->thumbnailTexture != nullptr) fileEntity->thumbnailTexture->releaseReference();
584 delete fileEntity;
585 }
586 getFileEntities().clear();
588 delete scanFilesThread;
589 scanFilesThread = nullptr;
590 }
591}
592
594 class ListFilter : public virtual FileNameFilter {
595 public:
596 ListFilter(const string& searchTerm): searchTerm(searchTerm) {}
597 virtual ~ListFilter() {}
598
599 bool accept(const string& pathName, const string& fileName) override {
600 if (fileName == ".") return false;
601 if (fileName == "..") return false;
602 //
603 auto fileNameLowerCase = StringTools::toLowerCase(fileName);
604 //
605 if (searchTerm.empty() == false && fileNameLowerCase.find(searchTerm) == string::npos) return false;
606
607 // folders
608 if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) return true;
609 // audio
610 if (StringTools::endsWith(fileNameLowerCase, ".ogg") == true) return true;
611 // code
612 if (StringTools::endsWith(fileNameLowerCase, ".h") == true) return true;
613 if (StringTools::endsWith(fileNameLowerCase, ".cpp") == true) return true;
614 // fonts
615 if (StringTools::endsWith(fileNameLowerCase, ".fnt") == true) return true;
616 // images
617 if (StringTools::endsWith(fileNameLowerCase, ".icns") == true) return true;
618 if (StringTools::endsWith(fileNameLowerCase, ".ico") == true) return true;
619 if (StringTools::endsWith(fileNameLowerCase, ".png") == true) return true;
620 // models
621 if (StringTools::endsWith(fileNameLowerCase, ".dae") == true) return true;
622 if (StringTools::endsWith(fileNameLowerCase, ".fbx") == true) return true;
623 if (StringTools::endsWith(fileNameLowerCase, ".glb") == true) return true;
624 if (StringTools::endsWith(fileNameLowerCase, ".tm") == true) return true;
625 // property files
626 if (StringTools::endsWith(fileNameLowerCase, ".properties") == true) return true;
627 // shader
628 if (StringTools::endsWith(fileNameLowerCase, ".cl") == true) return true;
629 if (StringTools::endsWith(fileNameLowerCase, ".frag") == true) return true;
630 if (StringTools::endsWith(fileNameLowerCase, ".glsl") == true) return true;
631 if (StringTools::endsWith(fileNameLowerCase, ".vert") == true) return true;
632 // tdme empty
633 if (StringTools::endsWith(fileNameLowerCase, ".tempty") == true) return true;
634 // tdme trigger
635 if (StringTools::endsWith(fileNameLowerCase, ".ttrigger") == true) return true;
636 // tdme envmap
637 if (StringTools::endsWith(fileNameLowerCase, ".tenvmap") == true) return true;
638 // tdme model
639 if (StringTools::endsWith(fileNameLowerCase, ".tmodel") == true) return true;
640 // tdme scene
641 if (StringTools::endsWith(fileNameLowerCase, ".tscene") == true) return true;
642 // tdme particle system
643 if (StringTools::endsWith(fileNameLowerCase, ".tparticle") == true) return true;
644 // tdme terrain
645 if (StringTools::endsWith(fileNameLowerCase, ".tterrain") == true) return true;
646 // tdme script
647 if (StringTools::endsWith(fileNameLowerCase, ".tscript") == true) return true;
648 // xml
649 if (StringTools::endsWith(fileNameLowerCase, ".xml") == true) return true;
650 // files without ending
651 if (fileName.rfind(".") == string::npos ||
652 (fileName.rfind("/") != string::npos &&
653 fileName.rfind(".") < fileName.rfind("/"))) {
654 return true;
655 }
656 //
657 return false;
658 }
659 private:
660 string searchTerm;
661 };
662
663 ListFilter listFilter(searchTerm);
664 vector<string> files;
665
666 if (FileSystem::getInstance()->fileExists(pathName) == false) {
667 Console::println("EditorScreenController::ScanFilesThread::run(): Error: file does not exist: " + pathName);
668 } else
669 if (FileSystem::getInstance()->isPath(pathName) == false) {
670 if (listFilter.accept(".", pathName) == true) {
671 Console::println("EditorScreenController::ScanFilesThread::run(): Error: path is file: " + pathName);
672 } else {
673 Console::println("EditorScreenController::ScanFilesThread::run(): Error: file exist, but does not match filter: " + pathName);
674 }
675 } else {
676 FileSystem::getInstance()->list(pathName, files, &listFilter);
677 // parent folder
678 Console::println("'" + editorScreenController->getProjectPath() + "' vs '" + pathName + "'");
679 auto parentPathName = FileSystem::getInstance()->getPathName(pathName);
680 if (editorScreenController->getProjectPath() != parentPathName) {
681 string fileName = "..";
682
683 //
684 string templateSource = "button_template_thumbnail_nobackground.xml";
685 string icon = "";
686 string iconBig = "{$icon.type_folder_big}";
687
688 //
689 auto fileEntity = new FileEntity();
690 fileEntity->id = "projectpathfiles_file_" + GUIParser::escapeQuotes(Tools::getFileName(fileName));
691 fileEntity->buttonXML =
692 string() +
693 "<button " +
694 "id=\"" + fileEntity->id + "\" " +
695 "value=\"" + GUIParser::escapeQuotes(parentPathName) + "\" " +
696 "template=\"" + templateSource + "\" " +
697 "size=\"75\" " +
698 "icon=\"" + GUIParser::escapeQuotes(icon) + "\" " +
699 "icon-big=\"" + GUIParser::escapeQuotes(iconBig) + "\" " +
700 "filename=\"" + GUIParser::escapeQuotes(fileName) + "\" " +
701 "/>\n";
703 editorScreenController->getFileEntities().push_back(fileEntity);
705 Thread::sleep(1LL);
706 }
707 for (auto fileName: files) {
708 if (isStopRequested() == true) break;
709
710 //
711 auto absolutePath = pathName + "/" + fileName;
712 if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == false) continue;
713
714 string templateSource = "button_template_thumbnail_nobackground.xml";
715 string icon = "";
716 string iconBig = "{$icon.type_folder_big}";
717
718 //
719 auto fileEntity = new FileEntity();
720 fileEntity->id = "projectpathfiles_file_" + GUIParser::escapeQuotes(Tools::getFileName(fileName));
721 fileEntity->buttonXML =
722 string() +
723 "<button " +
724 "id=\"" + fileEntity->id + "\" " +
725 "value=\"" + GUIParser::escapeQuotes(absolutePath) + "\" " +
726 "template=\"" + templateSource + "\" " +
727 "size=\"75\" " +
728 "icon=\"" + GUIParser::escapeQuotes(icon) + "\" " +
729 "icon-big=\"" + GUIParser::escapeQuotes(iconBig) + "\" " +
730 "filename=\"" + GUIParser::escapeQuotes(fileName) + "\" " +
731 "/>\n";
733 editorScreenController->getFileEntities().push_back(fileEntity);
735 Thread::sleep(1LL);
736 }
737 for (auto fileName: files) {
738 if (isStopRequested() == true) break;
739
740 auto absolutePath = pathName + "/" + fileName;
741 if (FileSystem::getInstance()->isPath(pathName + "/" + fileName) == true) continue;
742
743 //
744 try {
745 //
747 string icon = "{$icon.type_" + image + "}";
748 string iconBig = "{$icon.type_" + image + "_big}";
749 string typeColor = "{$color.type_" + image + "}";
750
751 //
752 auto fileNameLowerCase = StringTools::toLowerCase(fileName);
753
754 //
755 string templateSource = "button_template_thumbnail_texture.xml";
756 Texture* thumbnailTexture = nullptr;
757 vector<uint8_t> thumbnailPNGData;
758 if (StringTools::endsWith(fileNameLowerCase, ".png") == true) {
759 thumbnailTexture = TextureReader::read(pathName, fileName, false);
760 } else
761 if (((StringTools::endsWith(fileNameLowerCase, ".tmodel") == true && PrototypeReader::readThumbnail(pathName, fileName, thumbnailPNGData) == true) ||
762 (StringTools::endsWith(fileNameLowerCase, ".tm") == true && FileSystem::getInstance()->getThumbnailAttachment(pathName, fileName, thumbnailPNGData) == true)) &&
763 thumbnailPNGData.empty() == false) {
764 static int thumbnailIdx = 0; // TODO: improve me
765 thumbnailTexture = TextureReader::readPNG("tdme.editor.projectpathfiles." + to_string(thumbnailIdx++), thumbnailPNGData, false);
766 } else {
767 // no valid thumbnail texture
768 templateSource = "button_template_thumbnail.xml";
769 }
770 if (thumbnailTexture != nullptr) {
771 auto textureWidth = thumbnailTexture->getTextureWidth();
772 auto textureHeight = thumbnailTexture->getTextureHeight();
773 auto scale = 1.0f;
774 if (textureWidth > textureHeight) {
775 scale = 128.0f / static_cast<float>(textureWidth);
776 } else {
777 scale = 128.0f / static_cast<float>(textureHeight);
778 }
779 auto scaledTextureWidth = static_cast<int>(static_cast<float>(textureWidth) * scale);
780 auto scaledTextureHeight = static_cast<int>(static_cast<float>(textureHeight) * scale);
781 if (textureWidth != scaledTextureWidth || textureHeight != scaledTextureHeight) {
782 auto thumbnailTextureScaled = TextureReader::scale(thumbnailTexture, scaledTextureWidth, scaledTextureHeight);
783 thumbnailTexture->releaseReference();
784 thumbnailTextureScaled->acquireReference();
785 thumbnailTexture = thumbnailTextureScaled;
786 }
787 iconBig.clear();
788 }
789 if (iconBig.empty() == false) icon.clear();
790
791 //
792 auto fileEntity = new FileEntity();
793 fileEntity->id = "projectpathfiles_file_" + GUIParser::escapeQuotes(Tools::getFileName(fileName));
794 fileEntity->buttonXML =
795 string() +
796 "<button " +
797 "id=\"" + fileEntity->id + "\" " +
798 "value=\"" + GUIParser::escapeQuotes(absolutePath) + "\" " +
799 "template=\"" + templateSource + "\" " +
800 "size=\"75\" " +
801 "icon=\"" + GUIParser::escapeQuotes(icon) + "\" " +
802 "icon-big=\"" + GUIParser::escapeQuotes(iconBig) + "\" " +
803 "filename=\"" + GUIParser::escapeQuotes(fileName) + "\" " +
804 "type-color=\"" + GUIParser::escapeQuotes(typeColor) + "\" " +
805 "/>\n";
806 fileEntity->thumbnailTexture = thumbnailTexture;
808 editorScreenController->getFileEntities().push_back(fileEntity);
810 Thread::sleep(1LL);
811 } catch (Exception& exception) {
812 errorMessage = exception.what();
813 error = true;
814 Console::println("EditorScreenController::ScanFilesThread::run(): Error: " + errorMessage);
815 }
816 }
817 }
818 finished = true;
819}
820
821void EditorScreenController::onAddFile(const string& type) {
822 class OnAddFile: public virtual Action
823 {
824 public:
825 // overriden methods
826 void performAction() override {
827 editorScreenController->addFile(
828 editorScreenController->view->getPopUps()->getFileDialogScreenController()->getPathName(),
829 Tools::ensureFileEnding(editorScreenController->view->getPopUps()->getFileDialogScreenController()->getFileName(), string("t") + type),
830 type
831 );
832 editorScreenController->view->getPopUps()->getFileDialogScreenController()->close();
833 }
834 OnAddFile(EditorScreenController* editorScreenController, const string& type): editorScreenController(editorScreenController), type(type) {
835 }
836 private:
837 EditorScreenController* editorScreenController;
838 string type;
839 };
840
843 string("Add ") + type + " to project: ",
844 { string("t") + type },
845 string("Untitled") + "." + "t" + type,
846 true,
847 new OnAddFile(this, type)
848 );
849
850}
851
852void EditorScreenController::addFile(const string& pathName, const string& fileName, const string& type) {
853 Prototype* prototype = nullptr;
854 Scene* scene = nullptr;
855 if (type == "empty") {
856 prototype = new Prototype(
857 Prototype::ID_NONE,
858 Prototype_Type::EMPTY,
859 Tools::removeFileEnding(fileName),
860 Tools::removeFileEnding(fileName),
861 pathName + "/" + fileName,
862 "resources/engine/models/empty.tm",
863 string(),
864 ModelReader::read("resources/engine/models", "empty.tm"), // TODO: exception
865 Vector3(0.0f, 0.0f, 0.0f)
866 );
867 } else
868 if (type == "trigger") {
869 auto width = 1.0f;
870 auto height = 1.0f;
871 auto depth = 1.0f;
872 auto boundingBox = new BoundingBox(Vector3(-width / 2.0f, 0.0f, -depth / 2.0f), Vector3(+width / 2.0f, height, +depth / 2.0f));
873 prototype = new Prototype(
874 Prototype::ID_NONE,
875 Prototype_Type::TRIGGER,
876 Tools::removeFileEnding(fileName),
877 Tools::removeFileEnding(fileName),
878 pathName + "/" + fileName,
879 string(),
880 string(),
881 nullptr,
882 Vector3()
883 );
884 prototype->addBoundingVolume(0, new PrototypeBoundingVolume(0, prototype));
885 prototype->getBoundingVolume(0)->setupAabb(boundingBox->getMin(), boundingBox->getMax());
886 } else
887 if (type == "envmap") {
888 auto width = 1.0f;
889 auto height = 1.0f;
890 auto depth = 1.0f;
891 auto boundingBox = new BoundingBox(Vector3(-width / 2.0f, 0.0f, -depth / 2.0f), Vector3(+width / 2.0f, height, +depth / 2.0f));
892 prototype = new Prototype(
893 Prototype::ID_NONE,
894 Prototype_Type::ENVIRONMENTMAPPING,
895 Tools::removeFileEnding(fileName),
896 Tools::removeFileEnding(fileName),
897 pathName + "/" + fileName,
898 string(),
899 string(),
900 nullptr,
901 Vector3()
902 );
903 prototype->addBoundingVolume(0, new PrototypeBoundingVolume(0, prototype));
904 prototype->getBoundingVolume(0)->setupAabb(boundingBox->getMin(), boundingBox->getMax());
905 } else
906 if (type == "model") {
907 prototype = new Prototype(
908 Prototype::ID_NONE,
909 Prototype_Type::MODEL,
910 Tools::removeFileEnding(fileName),
911 Tools::removeFileEnding(fileName),
912 pathName + "/" + fileName,
913 "resources/engine/models/empty.tm",
914 string(),
915 ModelReader::read("resources/engine/models", "empty.tm"), // TODO: exception
916 Vector3(0.0f, 0.0f, 0.0f)
917 );
918 } else
919 if (type == "terrain") {
920 prototype = new Prototype(
921 Prototype::ID_NONE,
922 Prototype_Type::TERRAIN,
923 Tools::removeFileEnding(fileName),
924 Tools::removeFileEnding(fileName),
925 pathName + "/" + fileName,
926 string(),
927 string(),
928 nullptr,
929 Vector3()
930 );
931 } else
932 if (type == "particle") {
933 prototype = new Prototype(
934 Prototype::ID_NONE,
935 Prototype_Type::PARTICLESYSTEM,
936 Tools::removeFileEnding(fileName),
937 Tools::removeFileEnding(fileName),
938 pathName + "/" + fileName,
939 string(),
940 string(),
941 nullptr,
942 Vector3()
943 );
944 } else
945 if (type == "scene") {
946 scene = new Scene(
947 Tools::removeFileEnding(fileName),
948 Tools::removeFileEnding(fileName)
949 );
950 }
951 if (prototype != nullptr) {
952 try {
953 PrototypeWriter::write(pathName, fileName, prototype);
954 openFile(pathName + "/" + fileName);
955 } catch (Exception& exception) {
956 Console::print(string("EditorScreenController::addFile(): An error occurred: "));
957 Console::println(string(exception.what()));
958 showErrorPopUp("Error", string() + "An error occurred: " + exception.what());
959 }
960 } else
961 if (scene != nullptr) {
962 try {
963 SceneWriter::write(pathName, fileName, scene);
964 openFile(pathName + "/" + fileName);
965 } catch (Exception& exception) {
966 Console::print(string("EditorScreenController::addFile(): An error occurred: "));
967 Console::println(string(exception.what()));
968 showErrorPopUp("Error", string() + "An error occurred: " + exception.what());
969 }
970 } else {
971 showErrorPopUp("Error", string() + "Unknown file type: " + type);
972 }
973}
974
976 auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
977
978 //
979 try {
980 switch (fileType) {
981 case FILETYPE_MODEL:
982 {
983 auto model = ModelReader::read(Tools::getPathName(absoluteFileName), Tools::getFileName(absoluteFileName));
984 prototype = new Prototype(
985 Prototype::ID_NONE,
986 Prototype_Type::MODEL,
987 Tools::removeFileEnding(fileName),
988 Tools::removeFileEnding(fileName),
989 FileSystem::getInstance()->getPathName(absoluteFileName) + "/" + Tools::removeFileEnding(fileName) + ".tmodel",
990 absoluteFileName,
991 string(),
992 model,
993 Vector3(0.0f, 0.0f, 0.0f)
994 );
995 break;
996 }
998 {
999 prototype = PrototypeReader::read(
1000 FileSystem::getInstance()->getPathName(absoluteFileName),
1001 FileSystem::getInstance()->getFileName(absoluteFileName)
1002 );
1003 break;
1004 }
1006 {
1007 prototype = PrototypeReader::read(
1008 FileSystem::getInstance()->getPathName(absoluteFileName),
1009 FileSystem::getInstance()->getFileName(absoluteFileName)
1010 );
1011 break;
1012 }
1014 {
1015 scene = SceneReader::read(
1016 "resources/engine/scenes/envmap",
1017 "envmap.tscene"
1018 );
1019 prototype = PrototypeReader::read(
1020 FileSystem::getInstance()->getPathName(absoluteFileName),
1021 FileSystem::getInstance()->getFileName(absoluteFileName)
1022 );
1023 break;
1024 }
1026 {
1027 prototype = PrototypeReader::read(
1028 FileSystem::getInstance()->getPathName(absoluteFileName),
1029 FileSystem::getInstance()->getFileName(absoluteFileName)
1030 );
1031 break;
1032 }
1034 {
1035 prototype = PrototypeReader::read(
1036 FileSystem::getInstance()->getPathName(absoluteFileName),
1037 FileSystem::getInstance()->getFileName(absoluteFileName)
1038 );
1039 break;
1040 }
1042 {
1043 prototype = PrototypeReader::read(
1044 FileSystem::getInstance()->getPathName(absoluteFileName),
1045 FileSystem::getInstance()->getFileName(absoluteFileName)
1046 );
1047 break;
1048 }
1049 case FILETYPE_SCENE:
1050 {
1051 scene = SceneReader::read(
1052 FileSystem::getInstance()->getPathName(absoluteFileName),
1053 FileSystem::getInstance()->getFileName(absoluteFileName)
1054 );
1055 break;
1056 }
1058 {
1059 throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1060 }
1061 case FILETYPE_SOUND:
1062 {
1063 throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1064 }
1065 case FILETYPE_TEXTURE:
1066 {
1067 throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1068 }
1069 case FILETYPE_FONT:
1070 {
1071 throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1072 }
1073 case FILETYPE_TEXT:
1074 {
1075 throw ExceptionBase("File type not supported by EditorScreenController::FileOpenThread");
1076 }
1077 default:
1078 throw ExceptionBase("Unknown file type.");
1079 }
1080 } catch (Exception& exception) {
1081 Console::print(string("EditorScreenController::FileOpenThread::run(): An error occurred: "));
1082 Console::println(string(exception.what()));
1083 errorMessage = string(exception.what());
1084 error = true;
1085 }
1086
1087 //
1088 finished = true;
1089}
1090
1091void EditorScreenController::openFile(const string& absoluteFileName) {
1092 Console::println("EditorScreenController::onOpenFile(): " + absoluteFileName);
1093
1094 // should never happen but still ...
1095 if (fileOpenThread != nullptr) {
1096 Console::println("EditorScreenController::onOpenFile(): " + absoluteFileName + ": file open thread is already busy with opening a file");
1097 showErrorPopUp("Error", string() + "File open thread is already busy with opening a file");
1098 return;
1099 }
1100
1101 // path
1102 if (FileSystem::getInstance()->isPath(absoluteFileName)) {
1103 fileNameSearchTerm.clear();
1105 stopScanFiles();
1106 setRelativeProjectPath(StringTools::substring(absoluteFileName, projectPath.size() + 1));
1108 return;
1109 }
1110
1111 //
1112 auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
1113 auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1114 FileType fileType = FILETYPE_UNKNOWN;
1115 if (StringTools::endsWith(fileNameLowerCase, ".xml") == true) {
1116 fileType = FILETYPE_SCREEN_TEXT;
1117 } else
1118 if (StringTools::endsWith(fileNameLowerCase, ".tempty") == true) {
1119 fileType = FILETYPE_EMPTYPROTOTYPE;
1120 } else
1121 if (StringTools::endsWith(fileNameLowerCase, ".ttrigger") == true) {
1122 fileType = FILETYPE_TRIGGERPROTOTYPE;
1123 } else
1124 if (StringTools::endsWith(fileNameLowerCase, ".tenvmap") == true) {
1125 fileType = FILETYPE_ENVMAPPROTOTYPE;
1126 } else
1127 if (StringTools::endsWith(fileNameLowerCase, ".tscene") == true) {
1128 fileType = FILETYPE_SCENE;
1129 } else
1130 if (StringTools::endsWith(fileNameLowerCase, ".tmodel") == true) {
1131 fileType = FILETYPE_MODELPROTOTYPE;
1132 } else
1133 if (StringTools::endsWith(fileNameLowerCase, ".tparticle") == true) {
1135 } else
1136 if (StringTools::endsWith(fileNameLowerCase, ".tterrain") == true) {
1137 fileType = FILETYPE_TERRAINPROTOTYPE;
1138 } else
1139 if (StringTools::endsWith(fileNameLowerCase, ".fnt") == true) {
1140 fileType = FILETYPE_FONT;
1141 } else
1142 if (StringTools::endsWith(fileNameLowerCase, ".ogg") == true) {
1143 fileType = FILETYPE_SOUND;
1144 } else
1145 if (StringTools::endsWith(fileNameLowerCase, ".h") == true ||
1146 StringTools::endsWith(fileNameLowerCase, ".cpp") == true ||
1147 StringTools::endsWith(fileNameLowerCase, ".c") == true ||
1148 StringTools::endsWith(fileNameLowerCase, ".properties") == true ||
1149 StringTools::endsWith(fileNameLowerCase, ".cl") == true ||
1150 StringTools::endsWith(fileNameLowerCase, ".frag") == true ||
1151 StringTools::endsWith(fileNameLowerCase, ".glsl") == true ||
1152 StringTools::endsWith(fileNameLowerCase, ".vert") == true ||
1153 StringTools::endsWith(fileNameLowerCase, ".xml") == true ||
1154 (fileName.rfind(".") == string::npos || (fileName.rfind("/") != string::npos && fileName.rfind(".") < fileName.rfind("/")))) {
1155 fileType = FILETYPE_TEXT;
1156 } else {
1157 for (auto& extension: ModelReader::getModelExtensions()) {
1158 if (StringTools::endsWith(fileNameLowerCase, "." + extension) == true) {
1159 fileType = FILETYPE_MODEL;
1160 break;
1161 }
1162 }
1163 for (auto& extension: TextureReader::getTextureExtensions()) {
1164 if (StringTools::endsWith(fileNameLowerCase, "." + extension) == true) {
1165 fileType = FILETYPE_TEXTURE;
1166 break;
1167 }
1168 }
1169 }
1170 if (fileType == FILETYPE_UNKNOWN) {
1171 showErrorPopUp("Error", "File format not yet supported");
1172 return;
1173 }
1174
1175 //
1176 auto tabId = "tab_viewport_" + StringTools::replace(absoluteFileName, ".", "_");
1177 tabId = StringTools::replace(tabId, "/", "_");
1178 if (screenNode->getNodeById(tabId) != nullptr) {
1180 return;
1181 }
1182 tabId = GUIParser::escapeQuotes(tabId);
1183
1184 //
1185 try {
1186 string icon;
1187 string colorType;
1189 TabView* tabView = nullptr;
1190 string viewPortTemplate;
1191 switch (fileType) {
1192 case FILETYPE_MODEL:
1193 {
1194 view->getPopUps()->getProgressBarScreenController()->show("Opening model as prototype ...", false);
1195 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1197 break;
1198 }
1200 {
1201 view->getPopUps()->getProgressBarScreenController()->show("Opening empty prototype ...", false);
1202 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1204 break;
1205 }
1207 {
1208 view->getPopUps()->getProgressBarScreenController()->show("Opening trigger prototype ...", false);
1209 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1211 break;
1212 }
1214 {
1215 view->getPopUps()->getProgressBarScreenController()->show("Opening environment map prototype ...", false);
1216 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1218 break;
1219 }
1221 {
1222 view->getPopUps()->getProgressBarScreenController()->show("Opening model prototype...", false);
1223 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1225 break;
1226 }
1228 {
1229 view->getPopUps()->getProgressBarScreenController()->show("Opening terrain prototype ...", false);
1230 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1232 break;
1233 }
1235 {
1236 view->getPopUps()->getProgressBarScreenController()->show("Opening particle system prototype ...", false);
1237 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1239 break;
1240 }
1241 case FILETYPE_SCENE:
1242 {
1243 view->getPopUps()->getProgressBarScreenController()->show("Opening scene ...", false);
1244 fileOpenThread = new FileOpenThread(tabId, fileType, absoluteFileName);
1246 break;
1247 }
1249 {
1250 onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1251 break;
1252 }
1253 case FILETYPE_SOUND:
1254 {
1255 onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1256 break;
1257 }
1258 case FILETYPE_TEXTURE:
1259 {
1260 onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1261 break;
1262 }
1263 case FILETYPE_FONT:
1264 {
1265 onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1266 break;
1267 }
1268 case FILETYPE_TEXT:
1269 {
1270 onOpenFileFinish(tabId, fileType, absoluteFileName, nullptr, nullptr);
1271 break;
1272 }
1273 default:
1274 throw ExceptionBase("Unknown file type.");
1275 }
1276 } catch (Exception& exception) {
1277 Console::print(string("EditorScreenController::onOpenFile(): An error occurred: "));
1278 Console::println(string(exception.what()));
1279 showErrorPopUp("Error", string() + "An error occurred: " + exception.what());
1280 }
1281}
1282
1283void EditorScreenController::onOpenFileFinish(const string& tabId, FileType fileType, const string& absoluteFileName, Prototype* prototype, Scene* scene) {
1284 auto fileName = FileSystem::getInstance()->getFileName(absoluteFileName);
1285 auto fileNameLowerCase = StringTools::toLowerCase(fileName);
1286
1287 //
1288 try {
1289 string icon;
1290 string colorType;
1292 TabView* tabView = nullptr;
1293 string viewPortTemplate;
1294 switch (fileType) {
1295 case FILETYPE_MODEL:
1296 {
1297 icon = "{$icon.type_mesh}";
1298 colorType = "{$color.type_mesh}";
1300 tabView = new ModelEditorTabView(view, tabId, prototype);
1301 viewPortTemplate = "template_viewport_scene.xml";
1302 break;
1303 }
1305 {
1306 icon = "{$icon.type_prototype}";
1307 colorType = "{$color.type_prototype}";
1309 tabView = new EmptyEditorTabView(view, tabId, prototype);
1310 viewPortTemplate = "template_viewport_scene.xml";
1311 break;
1312 }
1314 {
1315 icon = "{$icon.type_prototype}";
1316 colorType = "{$color.type_prototype}";
1318 tabView = new TriggerEditorTabView(view, tabId, prototype);
1319 viewPortTemplate = "template_viewport_scene.xml";
1320 break;
1321 }
1323 {
1324 icon = "{$icon.type_scene}";
1325 colorType = "{$color.type_scene}";
1327 tabView = new EnvMapEditorTabView(view, tabId, scene, prototype);
1328 viewPortTemplate = "template_viewport_scene.xml";
1329 break;
1330 }
1332 {
1333 icon = "{$icon.type_prototype}";
1334 colorType = "{$color.type_prototype}";
1336 tabView = new ModelEditorTabView(view, tabId, prototype);
1337 viewPortTemplate = "template_viewport_scene.xml";
1338 break;
1339 }
1341 {
1342 icon = "{$icon.type_terrain}";
1343 colorType = "{$color.type_terrain}";
1345 tabView = new TerrainEditorTabView(view, tabId, prototype);
1346 viewPortTemplate = "template_viewport_terrain.xml";
1347 break;
1348 }
1350 {
1351 icon = "{$icon.type_particle}";
1352 colorType = "{$color.type_particle}";
1354 tabView = new ParticleSystemEditorTabView(view, tabId, prototype);
1355 viewPortTemplate = "template_viewport_scene.xml";
1356 break;
1357 }
1358 case FILETYPE_SCENE:
1359 {
1360 icon = "{$icon.type_scene}";
1361 colorType = "{$color.type_scene}";
1363 tabView = new SceneEditorTabView(view, tabId, scene);
1364 viewPortTemplate = "template_viewport_scene.xml";
1365 break;
1366 }
1368 {
1369 try {
1370 icon = "{$icon.type_gui}";
1371 colorType = "{$color.type_gui}";
1372 auto screenNode = GUIParser::parse(
1373 FileSystem::getInstance()->getPathName(absoluteFileName),
1374 FileSystem::getInstance()->getFileName(absoluteFileName)
1375 );
1377 tabView = new UIEditorTabView(view, tabId, screenNode);
1378 viewPortTemplate = "template_viewport_ui.xml";
1379 } catch (Exception &exception) {
1380 Console::println("EditorScreenController::openFile(): " + absoluteFileName + ": " + exception.what());
1381 icon = "{$icon.type_script}";
1382 colorType = "{$color.type_script}";
1383 auto text = StringTools::replace(
1384 FileSystem::getInstance()->getContentAsString(
1385 FileSystem::getInstance()->getPathName(absoluteFileName),
1386 FileSystem::getInstance()->getFileName(absoluteFileName)
1387 ),
1388 "\t",
1389 " "
1390 );
1391 auto screenNode = GUIParser::parse(
1392 "resources/engine/gui/",
1393 "tab_text.xml",
1394 {{ "text", StringTools::replace(StringTools::replace(text, "[", "\\["), "]", "\\]") }}
1395 );
1397 tabView = new TextEditorTabView(view, tabId, screenNode, StringTools::substring(fileNameLowerCase, fileNameLowerCase.rfind('.') + 1, fileNameLowerCase.size()));
1398 viewPortTemplate = "template_viewport_plain.xml";
1399 }
1400 break;
1401 }
1402 case FILETYPE_SOUND:
1403 {
1404 icon = "{$icon.type_sound}";
1405 colorType = "{$color.type_sound}";
1406 auto audioStream = new VorbisAudioStream(
1407 tabId,
1408 FileSystem::getInstance()->getPathName(absoluteFileName),
1409 FileSystem::getInstance()->getFileName(absoluteFileName)
1410 );
1411 auto screenNode = GUIParser::parse(
1412 "resources/engine/gui/",
1413 "tab_sound.xml"
1414 );
1416 tabView = new SoundTabView(view, tabId, screenNode, audioStream);
1417 viewPortTemplate = "template_viewport_plain.xml";
1418 break;
1419 }
1420 case FILETYPE_TEXTURE:
1421 {
1422 icon = "{$icon.type_texture}";
1423 colorType = "{$color.type_texture}";
1424 auto screenNode = GUIParser::parse(
1425 "resources/engine/gui/",
1426 "tab_texture.xml",
1427 {{ "texture", absoluteFileName}}
1428
1429 );
1431 tabView = new TextureTabView(view, tabId, screenNode);
1432 viewPortTemplate = "template_viewport_plain.xml";
1433 break;
1434 }
1435 case FILETYPE_FONT:
1436 {
1437 icon = "{$icon.type_font}";
1438 colorType = "{$color.type_font}";
1439 auto screenNode = GUIParser::parse(
1440 "resources/engine/gui/",
1441 "tab_font.xml",
1442 {{ "font", absoluteFileName }}
1443 );
1445 tabView = new FontTabView(view, tabId, screenNode);
1446 viewPortTemplate = "template_viewport_plain.xml";
1447 break;
1448 }
1449 case FILETYPE_TEXT:
1450 {
1451 icon = "{$icon.type_script}";
1452 colorType = "{$color.type_script}";
1453 auto text = StringTools::replace(
1454 FileSystem::getInstance()->getContentAsString(
1455 FileSystem::getInstance()->getPathName(absoluteFileName),
1456 FileSystem::getInstance()->getFileName(absoluteFileName)
1457 ),
1458 "\t",
1459 " "
1460 );
1461 auto screenNode = GUIParser::parse(
1462 "resources/engine/gui/",
1463 "tab_text.xml",
1464 {{ "text", StringTools::replace(StringTools::replace(text, "[", "\\["), "]", "\\]") }}
1465 );
1467 tabView = new TextEditorTabView(view, tabId, screenNode, StringTools::substring(fileNameLowerCase, fileNameLowerCase.rfind('.') + 1, fileNameLowerCase.size()));
1468 viewPortTemplate = "template_viewport_plain.xml";
1469 break;
1470 }
1471 default:
1472 throw ExceptionBase("Unknown file type.");
1473 }
1474 //
1475 {
1476 string tabsHeaderXML = "<tab id=\"" + tabId + "\" image=\"" + GUIParser::escapeQuotes(icon) + "\" type-color=\"" + GUIParser::escapeQuotes(colorType) + "\" value=\"" + GUIParser::escapeQuotes(absoluteFileName) + "\" text=\"" + GUIParser::escapeQuotes(fileName) + "\" closeable=\"true\" />\n";
1477 try {
1478 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(tabsHeader->getId()))->addSubNodes(tabsHeaderXML, true);
1479 } catch (Exception& exception) {
1480 Console::print(string("EditorScreenController::onOpenFile(): An error occurred: "));
1481 Console::println(string(exception.what()));
1482 }
1483 }
1484 {
1485 string tabsContentXML =
1486 "<tab-content tab-id=\"" + tabId + "\">\n" +
1487 " <template id=\"" + tabId + "_tab\" src=\"resources/engine/gui/" + viewPortTemplate + "\" />\n" +
1488 "</tab-content>\n";
1489 try {
1490 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(tabsContent->getId()))->addSubNodes(tabsContentXML, true);
1491 } catch (Exception& exception) {
1492 Console::print(string("EditorScreenController::onOpenFile(): An error occurred: "));
1493 Console::println(string(exception.what()));
1494 }
1495 }
1496 //
1497 tabView->initialize();
1498 //
1499 // TODO: move me into GUIFrameBufferNode
1500 if (Engine::getInstance()->getGraphicsRendererType() != Renderer::RENDERERTYPE_VULKAN) {
1501 required_dynamic_cast<GUIFrameBufferNode*>(screenNode->getNodeById(tabId + "_tab_framebuffer"))->setTextureMatrix((new Matrix2D3x3())->identity().scale(Vector2(1.0f, -1.0f)));
1502 }
1503 tabViews[tabId] = EditorTabView(tabId, tabType, tabView, required_dynamic_cast<GUIFrameBufferNode*>(screenNode->getNodeById(tabId + "_tab_framebuffer")));
1505 } catch (Exception& exception) {
1506 Console::print(string("EditorScreenController::onOpenFileFinish(): An error occurred: "));
1507 Console::println(string(exception.what()));
1508 showErrorPopUp("Error", string() + "An error occurred: " + exception.what());
1509 }
1510
1511 //
1513
1514 //
1516}
1517
1518void EditorScreenController::storeOutlinerState(TabView::OutlinerState& outlinerState) {
1519 required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->determineExpandedParentOptionValues(outlinerState.expandedOutlinerParentOptionValues);
1520 outlinerState.value = required_dynamic_cast<GUISelectBoxController*>(screenNode->getNodeById("selectbox_outliner")->getController())->getValue();
1521 outlinerState.renderOffsetX = required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById("selectbox_outliner_scrollarea"))->getChildrenRenderOffsetX();
1522 outlinerState.renderOffsetY = required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById("selectbox_outliner_scrollarea"))->getChildrenRenderOffsetY();
1523}
1524
1525void EditorScreenController::restoreOutlinerState(const TabView::OutlinerState& outlinerState) {
1526 required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->setValue(outlinerState.value);
1527 required_dynamic_cast<GUISelectBoxController*>(outliner->getController())->expandParentOptionsByValues(outlinerState.expandedOutlinerParentOptionValues);
1528 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->setChildrenRenderOffsetX(outlinerState.renderOffsetX);
1529 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->setChildrenRenderOffsetY(outlinerState.renderOffsetY);
1530}
1531
1533 try {
1535 } catch (Exception& exception) {
1536 Console::print(string("EditorScreenController::getOutlinerSelection(): An error occurred: "));
1537 Console::println(string(exception.what()));
1538 }
1539 return string();
1540}
1541
1542void EditorScreenController::setOutlinerSelection(const string& newSelectionValue) {
1543 try {
1544 outliner->getController()->setValue(MutableString(newSelectionValue));
1545 } catch (Exception& exception) {
1546 Console::print(string("EditorScreenController::setOutlinerSelection(): An error occurred: "));
1547 Console::println(string(exception.what()));
1548 }
1549}
1550
1552 try {
1553 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerScrollarea->getId()))->replaceSubNodes(xml, true);
1554 } catch (Exception& exception) {
1555 Console::print(string("EditorScreenController::setOutlinerContent(): An error occurred: "));
1556 Console::println(string(exception.what()));
1557 }
1558}
1559
1561 try {
1562 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(outlinerAddDropDown->getId()))->replaceSubNodes(xml, true);
1563 } catch (Exception& exception) {
1564 Console::print(string("EditorScreenController::setOutlinerAddDropDownContent(): An error occurred: "));
1565 Console::println(string(exception.what()));
1566 }
1567}
1568
1570 try {
1571 required_dynamic_cast<GUIParentNode*>(screenNode->getInnerNodeById(detailsScrollarea->getId()))->replaceSubNodes(xml, true);
1572 } catch (Exception& exception) {
1573 Console::print(string("EditorScreenController::setDetailsContent(): An error occurred: "));
1574 Console::println(string(exception.what()));
1575 }
1576}
1577
1579 return required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().has("fullscreen");
1580}
1581
1583 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("menu_view_fullscreen"))->getController()->setDisabled(tabViews.empty() == true);
1584}
1585
1587 if (fullScreen == true) {
1588 auto selectedTab = getSelectedTab();
1589 if (selectedTab != nullptr) {
1590 Application::getApplication()->setFullScreen(true);
1591 fullScreenTabId = selectedTab->getId();
1592 required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("fullscreen-content"))->moveNodes(
1593 required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById(fullScreenTabId + "-content"))
1594 );
1595 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().add("fullscreen");
1596 }
1597 } else
1598 if (fullScreenTabId.empty() == false) {
1599 Application::getApplication()->setFullScreen(false);
1600 required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById(fullScreenTabId + "-content"))->moveNodes(
1601 required_dynamic_cast<GUIParentNode*>(screenNode->getNodeById("fullscreen-content"))
1602 );
1603 fullScreenTabId.clear();
1604 required_dynamic_cast<GUIElementNode*>(screenNode->getNodeById("screen_editor_screen"))->getActiveConditions().remove("fullscreen");
1605 }
1606}
1607
1609 // forward save to active tab tab controller
1610 auto selectedTab = getSelectedTab();
1611 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->save();
1612}
1613
1615 // forward saveAs to active tab tab controller
1616 auto selectedTab = getSelectedTab();
1617 if (selectedTab != nullptr) selectedTab->getTabView()->getTabController()->saveAs();
1618}
1619
1621 // forward saveAs to active tab tab controller
1622 for (auto& tabViewIt: tabViews) {
1623 auto& tab = tabViewIt.second;
1624 tab.getTabView()->getTabController()->save();
1625 }
1626}
1627
1628void EditorScreenController::getViewPort(GUINode* viewPortNode, int& left, int& top, int& width, int& height) {
1629 auto& constraints = viewPortNode->getComputedConstraints();
1630 auto& padding = viewPortNode->getPadding();
1631 left = constraints.left + constraints.alignmentLeft + constraints.contentAlignmentLeft;
1632 top = constraints.top + constraints.alignmentTop + constraints.contentAlignmentTop;
1633 width = constraints.width - (padding.left + padding.right);
1634 height = constraints.height - (padding.top + padding.bottom);
1635}
1636
1638 return tabs->getController()->getValue().getString();
1639}
1640
1642 auto now = Time::getCurrentMillis();
1643 if (timeFileNameSearchTerm != -1LL && now - timeFileNameSearchTerm >= 1000LL) {
1646 }
1647 if (scanFilesThread != nullptr) {
1649 for (auto fileEntity: getFileEntities()) {
1650 pendingFileEntities.push_back(fileEntity);
1652 }
1653 getFileEntities().clear();
1654 if (scanFilesThread->isFinished() == true) {
1657 if (scanFilesThread->isError() == true) {
1658 if (scanFilesThread->getErrorMessage().empty() == true) {
1659 showErrorPopUp("Error", string() + "An error occurred: Unknown error");
1660 } else {
1661 showErrorPopUp("Error", string() + "An error occurred: " + scanFilesThread->getErrorMessage());
1662 }
1663 }
1664 delete scanFilesThread;
1665 scanFilesThread = nullptr;
1666 }
1668 }
1669 if (fileOpenThread != nullptr) {
1670 if (fileOpenThread->isFinished() == true) {
1672 if (fileOpenThread->isError() == true) {
1673 if (fileOpenThread->getErrorMessage().empty() == true) {
1674 showErrorPopUp("Error", string() + "An error occurred: Unknown error");
1675 } else {
1676 showErrorPopUp("Error", string() + "An error occurred: " + fileOpenThread->getErrorMessage());
1677 }
1678 } else {
1685 );
1686 }
1687 delete fileOpenThread;
1688 fileOpenThread = nullptr;
1689 } else {
1691 }
1692 }
1693}
Engine main class.
Definition: Engine.h:122
Frame buffer class.
Definition: FrameBuffer.h:21
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:25
void setupAabb(const Vector3 &min, const Vector3 &max)
Setup bounding volume bounding box.
Prototype definition.
Definition: Prototype.h:49
bool addBoundingVolume(int idx, PrototypeBoundingVolume *prototypeBoundingVolume)
Add bounding volume at given index.
Definition: Prototype.cpp:71
PrototypeBoundingVolume * getBoundingVolume(int idx)
Get bounding volume at given index.
Definition: Prototype.h:223
Scene definition.
Definition: Scene.h:41
GUI parser.
Definition: GUIParser.h:39
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:63
GUINode_Padding & getPadding()
Definition: GUINode.h:373
const string & getId()
Definition: GUINode.h:329
GUINode_ComputedConstraints & getComputedConstraints()
Definition: GUINode.h:387
GUINodeController * getController()
Definition: GUINode.h:586
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:43
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:57
void addContextMenuRequestListener(GUIContextMenuRequestListener *listener)
Add context menu request listener.
void addChangeListener(GUIChangeListener *listener)
Add change listener.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
void removeNodeById(const string &nodeId, bool resetScrollOffsets)
Remove GUI node by id.
void addActionListener(GUIActionListener *listener)
Add action listener.
GUINode * getInnerNodeById(const string &nodeId)
Get inner GUI node by id.
void addFocusListener(GUIFocusListener *listener)
Add focus listener.
3x3 2D Matrix class
Definition: Matrix2D3x3.h:22
2D vector 2 class
Definition: Vector2.h:19
3D vector 3 class
Definition: Vector3.h:22
File system singleton class.
Definition: FileSystem.h:14
Mutex implementation.
Definition: Mutex.h:27
Base class for threads.
Definition: Thread.h:26
void start()
Starts this objects thread.
Definition: Thread.cpp:65
void join()
Blocks caller thread until this thread has been terminated.
Definition: Thread.cpp:55
void stop()
Requests that this thread should be stopped.
Definition: Thread.cpp:94
bool isStopRequested()
Returns if stop has been requested.
Definition: Thread.cpp:98
static TDMEEditor * getInstance()
Definition: TDMEEditor.h:53
void quit()
Request to exit the viewer.
Definition: TDMEEditor.cpp:82
void addMenuItem(const string &text, const string &id, Action *action=nullptr)
Add menu item.
void onOpenFile(const string &absoluteFileName)
On open file.
void setOutlinerSelection(const string &newSelectionValue)
Set outliner selection.
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 addPendingFileEntities()
Add project path files pending file entities.
void setScreenCaption(const string &text)
Set screen caption.
void onContextMenuRequested(GUIElementNode *node, int mouseX, int mouseY) override
On mouse over.
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 onValueChanged(GUIElementNode *node) override
On value changed.
void setDetailsContent(const string &xml)
Set details content.
void onActionPerformed(GUIActionListenerType type, GUIElementNode *node) override
void onFocus(GUIElementNode *node) override
On focus.
void showErrorPopUp(const string &caption, const string &message)
Shows the error pop up.
void onOpenFileFinish(const string &tabId, FileType fileType, const string &absoluteFileName, Prototype *prototype, Scene *scene)
On open file finish.
void getViewPort(GUINode *viewPortNode, int &left, int &top, int &width, int &height)
Get engine viewport constraints.
void addFile(const string &pathName, const string &fileName, const string &type)
On add file.
void openFile(const string &absoluteFileName)
Open file.
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 &message, bool showProgressBar=true)
Shows the pop up.
Pop ups controller accessor class.
Definition: PopUps.h:19
AboutDialogScreenController * getAboutDialogScreenController()
Definition: PopUps.h:77
FileDialogScreenController * getFileDialogScreenController()
Definition: PopUps.h:42
ProgressBarScreenController * getProgressBarScreenController()
Definition: PopUps.h:56
ContextMenuScreenController * getContextMenuScreenController()
Definition: PopUps.h:70
InfoDialogScreenController * getInfoDialogScreenController()
Definition: PopUps.h:49
void addPrototype(Prototype *prototype)
Add prototype to scene.
Console class.
Definition: Console.h:26
Exception base class.
Definition: ExceptionBase.h:20
Mutable string class.
Definition: MutableString.h:16
const string & getString() const
void releaseReference()
releases a reference, thus decrementing the counter and delete it if reference counter is zero
Definition: Reference.cpp:20
String tools class.
Definition: StringTools.h:20
std::exception Exception
Exception base class.
Definition: Exception.h:19
File system file name filter interface.
Tab controller, which connects UI with logic.
Definition: TabController.h:23
virtual void initialize()=0
Initiates the view.
Action Interface.
Definition: Action.h:12