UIProjectFrame.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicEditor
  4. #include "AtomicEditor.h"
  5. #include <TurboBadger/tb_select.h>
  6. #include <Atomic/UI/TBUI.h>
  7. #include <Atomic/IO/Log.h>
  8. #include <Atomic/IO/FileSystem.h>
  9. #include <Atomic/Resource/ResourceEvents.h>
  10. #include "../AEEditor.h"
  11. #include "../Project/AEProject.h"
  12. #include "UIListView.h"
  13. #include "UIProjectFrame.h"
  14. #include "../Project/ProjectUtils.h"
  15. #include "UI/Modal/UIModalOps.h"
  16. using namespace tb;
  17. namespace AtomicEditor
  18. {
  19. ProjectFrame::ProjectFrame(Context* context) :
  20. AEWidget(context)
  21. {
  22. TBUI* tbui = GetSubsystem<TBUI>();
  23. tbui->LoadResourceFile(delegate_, "AtomicEditor/editor/ui/projectframe.tb.txt");
  24. delegate_->SetID(TBIDC("projectframe_delegate"));
  25. delegate_->SetGravity(WIDGET_GRAVITY_TOP_BOTTOM);
  26. // folders
  27. TBLayout* foldercontainer = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("foldercontainer"));
  28. assert(foldercontainer);
  29. folderList_ = new ListView(context_, "folderList_");
  30. TBWidgetDelegate* folderListWD = folderList_->GetWidgetDelegate();
  31. folderListWD->SetID(TBIDC("folerList_delegate"));
  32. folderListWD->SetGravity(WIDGET_GRAVITY_ALL);
  33. foldercontainer->AddChild(folderListWD);
  34. SubscribeToEvent(E_FILECHANGED, HANDLER(ProjectFrame, HandleFileChanged));
  35. }
  36. ProjectFrame::~ProjectFrame()
  37. {
  38. }
  39. void ProjectFrame::Refresh()
  40. {
  41. String cfolder = currentContentFolder_;
  42. currentContentFolder_ = "";
  43. SelectCurrentContentFolder(cfolder);
  44. }
  45. void ProjectFrame::HandleFileChanged(StringHash eventType, VariantMap& eventData)
  46. {
  47. // Don't currently do anything here
  48. /*
  49. using namespace FileChanged;
  50. const String& fileName = eventData[P_FILENAME].GetString();
  51. const String& resourceName = eventData[P_RESOURCENAME].GetString();
  52. */
  53. }
  54. void ProjectFrame::ScanDirForFolders(Vector<String>& dirs, const String& fullPath)
  55. {
  56. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  57. Vector<String> _dirs;
  58. fileSystem->ScanDir(_dirs, fullPath, "", SCAN_DIRS, false);
  59. for (unsigned i = 0; i < _dirs.Size(); i++)
  60. {
  61. const String& dir = _dirs[i];
  62. if (dir == "." || dir == ".." || dir.EndsWith("/..") || dir.EndsWith("/."))
  63. continue;
  64. dirs.Push(dir);
  65. }
  66. }
  67. void ProjectFrame::RecursiveAddFolder(ListViewItem* parent, const String& fullpath, const String& folderName)
  68. {
  69. TBID id = TBIDC(fullpath.CString());
  70. tbidToFolder_[id] = fullpath;
  71. ListViewItem* child = parent->AddChild(folderName.CString(), "Folder.icon", TBIDC(fullpath.CString()));
  72. Vector<String> dirs;
  73. ScanDirForFolders(dirs, fullpath);
  74. for (unsigned i = 0; i < dirs.Size(); i++)
  75. {
  76. const String& dir = dirs[i];
  77. RecursiveAddFolder(child, AddTrailingSlash(fullpath + dir), dir);
  78. }
  79. }
  80. void ProjectFrame::Clear()
  81. {
  82. currentContentFolder_ = "";
  83. tbidToContent_.Clear();
  84. tbidToContentFolder_.Clear();
  85. tbidToFolder_.Clear();
  86. TBLayout* container = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("contentcontainer"));
  87. assert(container);
  88. folderList_->DeleteAllItems();
  89. container->DeleteAllChildren();
  90. }
  91. void ProjectFrame::RefreshFolders()
  92. {
  93. Editor* editor = GetSubsystem<Editor>();
  94. Project* project = editor->GetProject();
  95. tbidToFolder_.Clear();
  96. String resourcePath = project->GetResourcePath();
  97. currentContentFolder_ = resourcePath;
  98. TBID id = TBID(resourcePath.CString());
  99. tbidToFolder_[id] = resourcePath;
  100. folderList_->DeleteAllItems();
  101. ListViewItem* resources = folderList_->AddItem("Resources", "Folder.icon", id);
  102. Vector<String> dirs;
  103. ScanDirForFolders(dirs, resourcePath);
  104. for (unsigned i = 0; i < dirs.Size(); i++)
  105. {
  106. const String& dir = dirs[i];
  107. RecursiveAddFolder(resources, AddTrailingSlash(resourcePath + dir), dir);
  108. }
  109. resources->SetExpanded(true);
  110. RefreshContent(resourcePath);
  111. }
  112. void ProjectFrame::ScanContentDirForContent(Vector<String>& folders, Vector<String>& content, const String& fullPath)
  113. {
  114. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  115. folders.Clear();
  116. content.Clear();
  117. Vector<String> _folders;
  118. fileSystem->ScanDir(_folders, fullPath, "", SCAN_DIRS, false);
  119. for (unsigned i = 0; i < _folders.Size(); i++)
  120. {
  121. const String& dir = _folders[i];
  122. if (dir == "." || dir == ".." || dir.EndsWith("/..") || dir.EndsWith("/."))
  123. continue;
  124. folders.Push(dir);
  125. }
  126. fileSystem->ScanDir(content, fullPath, "", SCAN_FILES, false);
  127. }
  128. TBLayout* ProjectFrame::CreateButtonLayout(const String& fullpath, const String& text)
  129. {
  130. Editor* editor = GetSubsystem<Editor>();
  131. Project* project = editor->GetProject();
  132. FileSystem* fs = GetSubsystem<FileSystem>();
  133. String pathName, fileName, extension;
  134. SplitPath(fullpath, pathName, fileName, extension);
  135. TBID bitmapID = TBIDC("Folder.icon");
  136. if (fs->FileExists(fullpath))
  137. bitmapID = TBIDC("FileBitmap");
  138. if (extension.Length())
  139. {
  140. if (extension == ".js")
  141. {
  142. if (project->IsComponentsDirOrFile(fullpath))
  143. {
  144. bitmapID = TBIDC("ComponentBitmap");
  145. }
  146. else
  147. {
  148. bitmapID = TBIDC("JavascriptBitmap");
  149. }
  150. }
  151. }
  152. TBLayout* blayout = new TBLayout();
  153. TBWidget* spacer = new TBWidget();
  154. spacer->SetRect(TBRect(0, 0, 8, 8));
  155. blayout->AddChild(spacer);
  156. TBButton* button = new TBButton();
  157. button->SetGravity(WIDGET_GRAVITY_LEFT);
  158. TBSkinImage* image = new TBSkinImage(bitmapID);
  159. image->SetRect(TBRect(0, 0, 16, 16));
  160. image->SetGravity(WIDGET_GRAVITY_RIGHT);
  161. blayout->AddChild(image);
  162. button->SetID(TBIDC(fullpath.CString()));
  163. button->SetText(text.CString());
  164. button->SetSkinBg(TBIDC("TBButton.flat"));
  165. blayout->AddChild(button);
  166. return blayout;
  167. }
  168. void ProjectFrame::RefreshContent(const String& fullpath)
  169. {
  170. Editor* editor = GetSubsystem<Editor>();
  171. Project* project = editor->GetProject();
  172. currentContentFolder_ = fullpath;
  173. tbidToContent_.Clear();
  174. tbidToContentFolder_.Clear();
  175. Vector<String> folders;
  176. Vector<String> content;
  177. ScanContentDirForContent(folders, content, fullpath);
  178. TBLayout* container = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("contentcontainer"));
  179. assert(container);
  180. container->DeleteAllChildren();
  181. if (fullpath != project->GetResourcePath())
  182. {
  183. TBButton* button = new TBButton();
  184. button->SetGravity(WIDGET_GRAVITY_LEFT);
  185. button->SetText("..");
  186. button->SetID(TBIDC(".."));
  187. button->SetSkinBg(TBIDC("TBButton.flat"));
  188. container->AddChild(button);
  189. }
  190. for (unsigned i = 0; i < folders.Size(); i++)
  191. {
  192. String contentID = AddTrailingSlash(fullpath + folders[i]);
  193. container->AddChild(CreateButtonLayout(contentID, folders[i]));
  194. tbidToContentFolder_[TBIDC(contentID.CString())] = contentID;
  195. }
  196. for (unsigned i = 0; i < content.Size(); i++)
  197. {
  198. String contentID = fullpath + content[i];
  199. container->AddChild(CreateButtonLayout(contentID, content[i]));
  200. tbidToContent_[TBIDC(contentID.CString())] = contentID;
  201. }
  202. }
  203. bool ProjectFrame::OnEvent(const TBWidgetEvent &ev)
  204. {
  205. if (!ev.target)
  206. return false;
  207. TBID id = ev.target->GetID();
  208. if (ev.type == EVENT_TYPE_CLICK)
  209. {
  210. // context menu
  211. if (ev.target->GetID() == TBIDC("contextmenu"))
  212. {
  213. return OnContextMenuEvent(ev);
  214. }
  215. // we clicked the folder list
  216. if (ev.target->GetID() == TBID("folderList_"))
  217. {
  218. TBSelectList* list = (TBSelectList*) ev.target;
  219. TBID tbid = list->GetSelectedItemID();
  220. if (tbidToFolder_.Contains(tbid))
  221. {
  222. SelectCurrentContentFolder(tbidToFolder_[tbid]);
  223. }
  224. }
  225. else
  226. {
  227. if (ev.target->GetID() == TBIDC(".."))
  228. {
  229. String parentPath = GetParentPath(currentContentFolder_);
  230. SelectCurrentContentFolder(parentPath);
  231. return true;
  232. }
  233. // see if we clicked a folder in the content area
  234. else if (tbidToContentFolder_.Contains(ev.target->GetID()))
  235. {
  236. String path = tbidToContentFolder_[ev.target->GetID()];
  237. SelectCurrentContentFolder(path);
  238. }
  239. else if (tbidToContent_.Contains(ev.target->GetID()))
  240. {
  241. // we clicked some content
  242. String contentPath = tbidToContent_[ev.target->GetID()];
  243. Editor* editor = GetSubsystem<Editor>();
  244. editor->EditResource(contentPath);
  245. }
  246. }
  247. return false;
  248. }
  249. if (ev.type == EVENT_TYPE_RIGHT_POINTER_UP)
  250. {
  251. TBPoint pos_in_root(ev.target_x, ev.target_y);
  252. if (tbidToFolder_.Contains(ev.target->GetID()))
  253. {
  254. // right click folder
  255. String folder = tbidToFolder_[ev.target->GetID()];
  256. CreateFolderContextMenu(AddTrailingSlash(folder), pos_in_root.x, pos_in_root.y);
  257. }
  258. else if (tbidToContent_.Contains(ev.target->GetID()))
  259. {
  260. // right click content
  261. String content = tbidToContent_[ev.target->GetID()];
  262. CreateContentContextMenu(content, pos_in_root.x, pos_in_root.y);
  263. }
  264. else
  265. {
  266. if (folderList_->GetRootList()->IsAncestorOf(ev.target))
  267. {
  268. // right click in folder area
  269. CreateFolderContainerContextMenu(pos_in_root.x, pos_in_root.y);
  270. }
  271. else
  272. {
  273. TBScrollContainer* container = delegate_->GetWidgetByIDAndType<TBScrollContainer>(TBIDC("contentcontainerscroll"));
  274. if (container->IsAncestorOf(ev.target))
  275. {
  276. CreateContentContainerContextMenu(pos_in_root.x, pos_in_root.y);
  277. }
  278. }
  279. }
  280. return true;
  281. }
  282. return false;
  283. }
  284. void ProjectFrame::SelectCurrentContentFolder(const String& folder)
  285. {
  286. folderList_->SelectItemByID(TBIDC(folder.CString()));
  287. if (currentContentFolder_ != folder)
  288. RefreshContent(folder);
  289. }
  290. // Context Menus
  291. bool ProjectFrame::OnContextMenuEvent(const TBWidgetEvent &ev)
  292. {
  293. UIModalOps* ops = GetSubsystem<UIModalOps>();
  294. if (ev.ref_id == TBIDC("reveal_in_finder"))
  295. {
  296. ProjectUtils* utils = GetSubsystem<ProjectUtils>();
  297. utils->RevealInFinder(contextMenuPath_);
  298. }
  299. else if (ev.ref_id == TBIDC("create_component"))
  300. {
  301. ops->ShowCreateComponent(contextMenuPath_);
  302. }
  303. else if (ev.ref_id == TBIDC("create_script"))
  304. {
  305. ops->ShowCreateScript(contextMenuPath_);
  306. }
  307. else if (ev.ref_id == TBIDC("new_folder"))
  308. {
  309. ops->ShowNewFolder(contextMenuPath_);
  310. }
  311. else if (ev.ref_id == TBIDC("delete"))
  312. {
  313. ops->ShowResourceDelete(contextMenuPath_);
  314. }
  315. return true;
  316. }
  317. void ProjectFrame::CreateFolderContextMenu(const String& folder, int x, int y)
  318. {
  319. contextMenuPath_ = "";
  320. Editor* editor = GetSubsystem<Editor>();
  321. Project* project = editor->GetProject();
  322. TBMenuWindow *menu = new TBMenuWindow(delegate_, TBIDC("contextmenu"));
  323. TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
  324. TBGenericStringItem* item = new TBGenericStringItem("Create Folder", TBIDC("new_folder"));
  325. item->SetSkinImage(TBIDC("FolderCreateBitmap"));
  326. source->AddItem(item);
  327. if (project->IsComponentsDirOrFile(folder))
  328. {
  329. source->AddItem(new TBGenericStringItem("-"));
  330. item = new TBGenericStringItem("Create Component", TBIDC("create_component"));
  331. item->SetSkinImage(TBIDC("ComponentBitmap"));
  332. source->AddItem(item);
  333. }
  334. else if (project->IsScriptsDirOrFile(folder))
  335. {
  336. source->AddItem(new TBGenericStringItem("-"));
  337. item = new TBGenericStringItem("Create Script", TBIDC("create_script"));
  338. item->SetSkinImage(TBIDC("JavascriptBitmap"));
  339. source->AddItem(item);
  340. }
  341. else if (project->IsModulesDirOrFile(folder))
  342. {
  343. source->AddItem(new TBGenericStringItem("-"));
  344. item = new TBGenericStringItem("Create Module", TBIDC("create_module"));
  345. item->SetSkinImage(TBIDC("JavascriptBitmap"));
  346. source->AddItem(item);
  347. }
  348. source->AddItem(new TBGenericStringItem("-"));
  349. item = new TBGenericStringItem("Reveal in Finder", TBIDC("reveal_in_finder"));
  350. item->SetSkinImage(TBIDC("MagnifierBitmap"));
  351. source->AddItem(item);
  352. source->AddItem(new TBGenericStringItem("-"));
  353. item = new TBGenericStringItem("Delete Folder", TBIDC("delete"));
  354. item->SetSkinImage(TBIDC("FolderDeleteBitmap"));
  355. source->AddItem(item);
  356. menu->Show(source, TBPopupAlignment(TBPoint(x, y)), -1);
  357. contextMenuPath_ = folder;
  358. }
  359. void ProjectFrame::CreateContentContextMenu(const String& content, int x, int y)
  360. {
  361. contextMenuPath_ = "";
  362. TBMenuWindow *menu = new TBMenuWindow(delegate_, TBIDC("contextmenu"));
  363. TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
  364. source->AddItem(new TBGenericStringItem("Delete", TBIDC("delete")));
  365. source->AddItem(new TBGenericStringItem("-"));
  366. source->AddItem(new TBGenericStringItem("Reveal in Finder", TBIDC("reveal_in_finder")));
  367. menu->Show(source, TBPopupAlignment(TBPoint(x, y)), -1);
  368. contextMenuPath_ = content;
  369. }
  370. void ProjectFrame::CreateFolderContainerContextMenu(int x, int y)
  371. {
  372. contextMenuPath_ = "";
  373. TBMenuWindow *menu = new TBMenuWindow(delegate_, TBIDC("contextmenu"));
  374. TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
  375. source->AddItem(new TBGenericStringItem("Create Folder", TBIDC("new_folder")));
  376. source->AddItem(new TBGenericStringItem("-"));
  377. source->AddItem(new TBGenericStringItem("Reveal in Finder", TBIDC("reveal_in_finder")));
  378. menu->Show(source, TBPopupAlignment(TBPoint(x, y)), -1);
  379. contextMenuPath_ = currentContentFolder_;
  380. }
  381. void ProjectFrame::CreateContentContainerContextMenu(int x, int y)
  382. {
  383. contextMenuPath_ = "";
  384. Editor* editor = GetSubsystem<Editor>();
  385. Project* project = editor->GetProject();
  386. TBMenuWindow *menu = new TBMenuWindow(delegate_, TBIDC("contextmenu"));
  387. TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
  388. TBGenericStringItem* item = new TBGenericStringItem("Create Folder", TBIDC("new_folder"));
  389. item->SetSkinImage(TBIDC("Folder.icon"));
  390. source->AddItem(item);
  391. if (project->IsComponentsDirOrFile(currentContentFolder_))
  392. {
  393. source->AddItem(new TBGenericStringItem("-"));
  394. item = new TBGenericStringItem("Create Component", TBIDC("create_component"));
  395. item->SetSkinImage(TBIDC("ComponentBitmap"));
  396. source->AddItem(item);
  397. }
  398. else if (project->IsScriptsDirOrFile(currentContentFolder_))
  399. {
  400. source->AddItem(new TBGenericStringItem("-"));
  401. item = new TBGenericStringItem("Create Script", TBIDC("create_script"));
  402. item->SetSkinImage(TBIDC("JavascriptBitmap"));
  403. source->AddItem(item);
  404. }
  405. else if (project->IsModulesDirOrFile(currentContentFolder_))
  406. {
  407. source->AddItem(new TBGenericStringItem("-"));
  408. item = new TBGenericStringItem("Create Module", TBIDC("create_module"));
  409. item->SetSkinImage(TBIDC("JavascriptBitmap"));
  410. source->AddItem(item);
  411. }
  412. source->AddItem(new TBGenericStringItem("-"));
  413. source->AddItem(new TBGenericStringItem("Reveal in Finder", TBIDC("reveal_in_finder")));
  414. menu->Show(source, TBPopupAlignment(TBPoint(x, y)), -1);
  415. contextMenuPath_ = currentContentFolder_;
  416. }
  417. }