ProjectWindow.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using BansheeEngine;
  5. namespace BansheeEditor
  6. {
  7. internal enum ProjectViewType
  8. {
  9. Grid64, Grid48, Grid32, List16
  10. }
  11. internal sealed class ProjectWindow : EditorWindow
  12. {
  13. private class ContentInfo
  14. {
  15. public ContentInfo(ProjectWindow window, ProjectViewType viewType)
  16. {
  17. GUIPanel parentPanel = window.scrollAreaPanel;
  18. GUIPanel contentPanel = parentPanel.AddPanel(1);
  19. overlay = parentPanel.AddPanel(0);
  20. underlay = parentPanel.AddPanel(2);
  21. main = contentPanel.AddLayoutY();
  22. if (viewType == ProjectViewType.List16)
  23. {
  24. tileSize = 16;
  25. gridLayout = false;
  26. }
  27. else
  28. {
  29. switch (viewType)
  30. {
  31. case ProjectViewType.Grid64:
  32. tileSize = 64;
  33. break;
  34. case ProjectViewType.Grid48:
  35. tileSize = 48;
  36. break;
  37. case ProjectViewType.Grid32:
  38. tileSize = 32;
  39. break;
  40. }
  41. gridLayout = true;
  42. }
  43. this.window = window;
  44. }
  45. public GUILayout main;
  46. public GUIPanel overlay;
  47. public GUIPanel underlay;
  48. public ProjectWindow window;
  49. public int tileSize;
  50. public bool gridLayout;
  51. }
  52. private class ElementEntry
  53. {
  54. // Note: Order of these is relevant
  55. enum UnderlayState
  56. {
  57. None, Hovered, Selected, Pinged
  58. }
  59. public string path;
  60. public GUITexture icon;
  61. public GUILabel label;
  62. public Rect2I bounds;
  63. private GUITexture underlay;
  64. private ContentInfo info;
  65. private UnderlayState underlayState;
  66. public ElementEntry(ContentInfo info, GUILayout parent, LibraryEntry entry)
  67. {
  68. GUILayout entryLayout;
  69. if (info.gridLayout)
  70. entryLayout = parent.AddLayoutY();
  71. else
  72. entryLayout = parent.AddLayoutX();
  73. SpriteTexture iconTexture = GetIcon(entry);
  74. icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit,
  75. true, GUIOption.FixedHeight(info.tileSize), GUIOption.FixedWidth(info.tileSize));
  76. label = null;
  77. if (info.gridLayout)
  78. {
  79. label = new GUILabel(entry.Name, EditorStyles.MultiLineLabel,
  80. GUIOption.FixedWidth(info.tileSize), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
  81. }
  82. else
  83. {
  84. label = new GUILabel(entry.Name);
  85. }
  86. entryLayout.AddElement(icon);
  87. entryLayout.AddElement(label);
  88. this.info = info;
  89. this.path = entry.Path;
  90. this.bounds = new Rect2I();
  91. this.underlay = null;
  92. }
  93. public void Initialize()
  94. {
  95. bounds = icon.Bounds;
  96. Rect2I labelBounds = label.Bounds;
  97. bounds.x = MathEx.Min(bounds.x, labelBounds.x);
  98. bounds.y = MathEx.Min(bounds.y, labelBounds.y);
  99. bounds.width = MathEx.Max(bounds.x + bounds.width,
  100. labelBounds.x + labelBounds.width) - bounds.x;
  101. bounds.height = MathEx.Max(bounds.y + bounds.height,
  102. labelBounds.y + labelBounds.height) - bounds.y;
  103. ProjectWindow hoistedWindow = info.window;
  104. string hoistedPath = path;
  105. GUIButton overlayBtn = new GUIButton("", EditorStyles.Blank);
  106. overlayBtn.Bounds = bounds;
  107. overlayBtn.OnClick += () => hoistedWindow.OnEntryClicked(hoistedPath);
  108. overlayBtn.OnDoubleClick += () => hoistedWindow.OnEntryDoubleClicked(hoistedPath);
  109. overlayBtn.SetContextMenu(info.window.entryContextMenu);
  110. info.overlay.AddElement(overlayBtn);
  111. }
  112. public Rect2I Bounds
  113. {
  114. get { return bounds; }
  115. }
  116. public void MarkAsCut(bool enable)
  117. {
  118. if (enable)
  119. icon.SetTint(CUT_COLOR);
  120. else
  121. icon.SetTint(Color.White);
  122. }
  123. public void MarkAsSelected(bool enable)
  124. {
  125. if ((int)underlayState > (int) UnderlayState.Selected)
  126. return;
  127. if (enable)
  128. {
  129. CreateUnderlay();
  130. underlay.SetTint(SELECTION_COLOR);
  131. }
  132. else
  133. ClearUnderlay();
  134. underlayState = UnderlayState.Selected;
  135. }
  136. public void MarkAsPinged(bool enable)
  137. {
  138. if ((int)underlayState > (int)UnderlayState.Pinged)
  139. return;
  140. if (enable)
  141. {
  142. CreateUnderlay();
  143. underlay.SetTint(PING_COLOR);
  144. }
  145. else
  146. ClearUnderlay();
  147. underlayState = UnderlayState.Pinged;
  148. }
  149. public void MarkAsHovered(bool enable)
  150. {
  151. if ((int)underlayState > (int)UnderlayState.Hovered)
  152. return;
  153. if (enable)
  154. {
  155. CreateUnderlay();
  156. underlay.SetTint(HOVER_COLOR);
  157. }
  158. else
  159. ClearUnderlay();
  160. underlayState = UnderlayState.Hovered;
  161. }
  162. private void ClearUnderlay()
  163. {
  164. if (underlay != null)
  165. {
  166. underlay.Destroy();
  167. underlay = null;
  168. }
  169. underlayState = UnderlayState.None;
  170. }
  171. private void CreateUnderlay()
  172. {
  173. if (underlay == null)
  174. {
  175. underlay = new GUITexture(Builtin.WhiteTexture);
  176. underlay.Bounds = Bounds;
  177. info.underlay.AddElement(underlay);
  178. }
  179. }
  180. private static SpriteTexture GetIcon(LibraryEntry entry)
  181. {
  182. if (entry.Type == LibraryEntryType.Directory)
  183. {
  184. return EditorBuiltin.FolderIcon;
  185. }
  186. else
  187. {
  188. FileEntry fileEntry = (FileEntry)entry;
  189. switch (fileEntry.ResType)
  190. {
  191. case ResourceType.Font:
  192. return EditorBuiltin.FontIcon;
  193. case ResourceType.Mesh:
  194. return EditorBuiltin.MeshIcon;
  195. case ResourceType.Texture:
  196. return EditorBuiltin.TextureIcon;
  197. case ResourceType.PlainText:
  198. return null; // TODO
  199. case ResourceType.ScriptCode:
  200. return null; // TODO
  201. case ResourceType.SpriteTexture:
  202. return null; // TODO
  203. case ResourceType.Shader:
  204. return null; // TODO
  205. case ResourceType.Material:
  206. return null; // TODO
  207. }
  208. }
  209. return null;
  210. }
  211. }
  212. private const int GRID_ENTRY_SPACING = 15;
  213. private const int LIST_ENTRY_SPACING = 7;
  214. private const int MAX_LABEL_HEIGHT = 50;
  215. private const int DRAG_SCROLL_HEIGHT = 50;
  216. private const int DRAG_SCROLL_AMOUNT_PER_SECOND = 200;
  217. private static readonly Color PING_COLOR = Color.BansheeOrange;
  218. private static readonly Color SELECTION_COLOR = Color.DarkCyan;
  219. private static readonly Color HOVER_COLOR = new Color(Color.DarkCyan.r, Color.DarkCyan.g, Color.DarkCyan.b, 0.5f);
  220. private static readonly Color CUT_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.5f);
  221. private bool hasContentFocus = false;
  222. private bool HasContentFocus { get { return HasFocus && hasContentFocus; } } // TODO - This is dummy and never set
  223. private ProjectViewType viewType = ProjectViewType.Grid64;
  224. private string currentDirectory = "";
  225. private List<string> selectionPaths = new List<string>();
  226. private string pingPath = "";
  227. private string hoverHighlightPath = "";
  228. private GUIScrollArea contentScrollArea;
  229. private GUIPanel scrollAreaPanel;
  230. private GUIButton optionsButton;
  231. private ContextMenu entryContextMenu;
  232. private ProjectDropTarget dropTarget;
  233. private List<ElementEntry> entries = new List<ElementEntry>();
  234. private Dictionary<string, ElementEntry> entryLookup = new Dictionary<string, ElementEntry>();
  235. private GUITexture pingUnderlay;
  236. private int autoScrollAmount;
  237. // Cut/Copy/Paste
  238. private List<string> copyPaths = new List<string>();
  239. private List<string> cutPaths = new List<string>();
  240. internal ProjectViewType ViewType
  241. {
  242. get { return viewType; }
  243. set { viewType = value; Refresh(); }
  244. }
  245. [MenuItem("Windows/Project", ButtonModifier.Ctrl, ButtonCode.P)]
  246. private static void OpenProjectWindow()
  247. {
  248. OpenWindow<ProjectWindow>();
  249. }
  250. private void OnInitialize()
  251. {
  252. ProjectLibrary.OnEntryAdded += OnEntryChanged;
  253. ProjectLibrary.OnEntryRemoved += OnEntryChanged;
  254. GUILayoutY contentLayout = GUI.AddLayoutY();
  255. GUILayoutX searchBarLayout = contentLayout.AddLayoutX();
  256. GUITextField searchField = new GUITextField();
  257. searchField.OnChanged += OnSearchChanged;
  258. GUIButton clearSearchBtn = new GUIButton("C");
  259. clearSearchBtn.OnClick += ClearSearch;
  260. clearSearchBtn.SetWidth(40);
  261. optionsButton = new GUIButton("O");
  262. optionsButton.OnClick += OpenOptionsWindow;
  263. optionsButton.SetWidth(40);
  264. searchBarLayout.AddElement(searchField);
  265. searchBarLayout.AddElement(clearSearchBtn);
  266. searchBarLayout.AddElement(optionsButton);
  267. // TODO - Add search bar + options button with drop-down
  268. // TODO - Add directory bar + home button
  269. contentScrollArea = new GUIScrollArea(GUIOption.FlexibleWidth(), GUIOption.FlexibleHeight());
  270. contentLayout.AddElement(contentScrollArea);
  271. entryContextMenu = new ContextMenu();
  272. entryContextMenu.AddItem("Cut", CutSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.X));
  273. entryContextMenu.AddItem("Copy", CopySelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.C));
  274. entryContextMenu.AddItem("Duplicate", DuplicateSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.D));
  275. entryContextMenu.AddItem("Paste", PasteToSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.V));
  276. dropTarget = new ProjectDropTarget(this);
  277. dropTarget.Bounds = contentScrollArea.Bounds;
  278. dropTarget.OnStart += DoOnDragStart;
  279. dropTarget.OnDrag += DoOnDragMove;
  280. dropTarget.OnLeave += DoOnDragLeave;
  281. dropTarget.OnDrop += DoOnDragDropped;
  282. Reset();
  283. }
  284. private ElementEntry FindElementAt(Vector2I windowPos)
  285. {
  286. Rect2I scrollBounds = contentScrollArea.Bounds;
  287. Vector2I scrollPos = windowPos;
  288. scrollPos.x -= scrollBounds.x;
  289. scrollPos.y -= scrollBounds.y;
  290. foreach (var element in entries)
  291. {
  292. if (element.bounds.Contains(scrollPos))
  293. return element;
  294. }
  295. return null;
  296. }
  297. private void DoOnDragStart(Vector2I windowPos)
  298. {
  299. ElementEntry underCursorElem = FindElementAt(windowPos);
  300. if (underCursorElem == null)
  301. return;
  302. if (!selectionPaths.Contains(underCursorElem.path))
  303. Select(new List<string> { underCursorElem.path });
  304. ResourceDragDropData dragDropData = new ResourceDragDropData(selectionPaths.ToArray());
  305. DragDrop.StartDrag(dragDropData);
  306. }
  307. private void DoOnDragMove(Vector2I windowPos)
  308. {
  309. ElementEntry underCursorElem = FindElementAt(windowPos);
  310. if (underCursorElem == null)
  311. {
  312. if (!string.IsNullOrEmpty(hoverHighlightPath))
  313. {
  314. ElementEntry previousUnderCursorElem;
  315. if (entryLookup.TryGetValue(hoverHighlightPath, out previousUnderCursorElem))
  316. previousUnderCursorElem.MarkAsHovered(false);
  317. }
  318. hoverHighlightPath = "";
  319. }
  320. else
  321. {
  322. if (underCursorElem.path != hoverHighlightPath)
  323. {
  324. if (!string.IsNullOrEmpty(hoverHighlightPath))
  325. {
  326. ElementEntry previousUnderCursorElem;
  327. if (entryLookup.TryGetValue(hoverHighlightPath, out previousUnderCursorElem))
  328. previousUnderCursorElem.MarkAsHovered(false);
  329. }
  330. hoverHighlightPath = underCursorElem.path;
  331. underCursorElem.MarkAsHovered(true);
  332. }
  333. }
  334. Rect2I scrollAreaBounds = contentScrollArea.Bounds;
  335. int scrollAreaTop = scrollAreaBounds.y;
  336. int scrollAreaBottom = scrollAreaBounds.y + scrollAreaBounds.height;
  337. if (windowPos.y > scrollAreaTop && windowPos.y <= (scrollAreaTop + DRAG_SCROLL_HEIGHT))
  338. autoScrollAmount = -DRAG_SCROLL_AMOUNT_PER_SECOND;
  339. else if (windowPos.y >= (scrollAreaBottom - DRAG_SCROLL_HEIGHT) && windowPos.y < scrollAreaBottom)
  340. autoScrollAmount = DRAG_SCROLL_AMOUNT_PER_SECOND;
  341. else
  342. autoScrollAmount = 0;
  343. }
  344. private void DoOnDragLeave()
  345. {
  346. if (!string.IsNullOrEmpty(hoverHighlightPath))
  347. {
  348. ElementEntry previousUnderCursorElem;
  349. if (entryLookup.TryGetValue(hoverHighlightPath, out previousUnderCursorElem))
  350. previousUnderCursorElem.MarkAsHovered(false);
  351. }
  352. hoverHighlightPath = "";
  353. }
  354. private void DoOnDragDropped(Vector2I windowPos, string[] paths)
  355. {
  356. string destinationFolder = currentDirectory;
  357. ElementEntry underCursorElement = FindElementAt(windowPos);
  358. if (underCursorElement != null)
  359. {
  360. LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
  361. if (entry != null && entry.Type == LibraryEntryType.Directory)
  362. destinationFolder = entry.Path;
  363. }
  364. if (paths != null)
  365. {
  366. foreach (var path in paths)
  367. {
  368. if (PathEx.IsPartOf(destinationFolder, path) || PathEx.Compare(path, destinationFolder))
  369. continue;
  370. string destination = Path.Combine(destinationFolder, Path.GetFileName(path));
  371. ProjectLibrary.Move(path, destination, true);
  372. }
  373. }
  374. }
  375. public void Ping(Resource resource)
  376. {
  377. if (!string.IsNullOrEmpty(pingPath))
  378. {
  379. ElementEntry entry;
  380. if (entryLookup.TryGetValue(pingPath, out entry))
  381. entry.MarkAsPinged(false);
  382. }
  383. if (resource != null)
  384. pingPath = ProjectLibrary.GetPath(resource);
  385. else
  386. pingPath = "";
  387. if (!string.IsNullOrEmpty(pingPath))
  388. {
  389. ElementEntry entry;
  390. if (entryLookup.TryGetValue(pingPath, out entry))
  391. entry.MarkAsPinged(true);
  392. ScrollToEntry(pingPath);
  393. }
  394. }
  395. private void Select(List<string> paths)
  396. {
  397. if (selectionPaths != null)
  398. {
  399. foreach (var path in selectionPaths)
  400. {
  401. ElementEntry entry;
  402. if (entryLookup.TryGetValue(path, out entry))
  403. entry.MarkAsSelected(false);
  404. }
  405. }
  406. selectionPaths = paths;
  407. if (selectionPaths != null)
  408. {
  409. foreach (var path in selectionPaths)
  410. {
  411. ElementEntry entry;
  412. if (entryLookup.TryGetValue(path, out entry))
  413. entry.MarkAsSelected(true);
  414. }
  415. }
  416. Ping(null);
  417. }
  418. private void EnterDirectory(string directory)
  419. {
  420. currentDirectory = directory;
  421. Ping(null);
  422. Select(new List<string>());
  423. Refresh();
  424. }
  425. private void Cut(IEnumerable<string> sourcePaths)
  426. {
  427. foreach (var path in cutPaths)
  428. {
  429. ElementEntry entry;
  430. if (entryLookup.TryGetValue(path, out entry))
  431. entry.MarkAsCut(false);
  432. }
  433. cutPaths.Clear();
  434. cutPaths.AddRange(sourcePaths);
  435. foreach (var path in cutPaths)
  436. {
  437. ElementEntry entry;
  438. if (entryLookup.TryGetValue(path, out entry))
  439. entry.MarkAsCut(true);
  440. }
  441. copyPaths.Clear();
  442. }
  443. private void Copy(IEnumerable<string> sourcePaths)
  444. {
  445. copyPaths.Clear();
  446. copyPaths.AddRange(sourcePaths);
  447. foreach (var path in cutPaths)
  448. {
  449. ElementEntry entry;
  450. if (entryLookup.TryGetValue(path, out entry))
  451. entry.MarkAsCut(false);
  452. }
  453. cutPaths.Clear();
  454. }
  455. private void Duplicate(IEnumerable<string> sourcePaths)
  456. {
  457. foreach (var source in sourcePaths)
  458. {
  459. int idx = 0;
  460. string destination;
  461. do
  462. {
  463. destination = source + "_" + idx;
  464. idx++;
  465. } while (!ProjectLibrary.Exists(destination));
  466. ProjectLibrary.Copy(source, destination);
  467. }
  468. }
  469. private void Paste(string destinationFolder)
  470. {
  471. if (copyPaths.Count > 0)
  472. {
  473. for (int i = 0; i < copyPaths.Count; i++)
  474. {
  475. string destination = Path.Combine(destinationFolder, Path.GetFileName(copyPaths[i]));
  476. ProjectLibrary.Copy(copyPaths[i], destination, true);
  477. }
  478. Refresh();
  479. }
  480. else if (cutPaths.Count > 0)
  481. {
  482. for (int i = 0; i < cutPaths.Count; i++)
  483. {
  484. string destination = Path.Combine(destinationFolder, Path.GetFileName(cutPaths[i]));
  485. ProjectLibrary.Move(cutPaths[i], destination, true);
  486. }
  487. cutPaths.Clear();
  488. Refresh();
  489. }
  490. }
  491. private void EditorUpdate()
  492. {
  493. if (HasContentFocus)
  494. {
  495. if (Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl))
  496. {
  497. if (Input.IsButtonUp(ButtonCode.C))
  498. {
  499. CopySelection();
  500. }
  501. else if (Input.IsButtonUp(ButtonCode.X))
  502. {
  503. CutSelection();
  504. }
  505. else if (Input.IsButtonUp(ButtonCode.D))
  506. {
  507. DuplicateSelection();
  508. }
  509. else if (Input.IsButtonUp(ButtonCode.V))
  510. {
  511. PasteToSelection();
  512. }
  513. }
  514. }
  515. if (autoScrollAmount != 0)
  516. {
  517. Rect2I contentBounds = contentScrollArea.ContentBounds;
  518. float scrollPct = DRAG_SCROLL_AMOUNT_PER_SECOND / (float)contentBounds.height;
  519. contentScrollArea.VerticalScroll += scrollPct;
  520. }
  521. dropTarget.Update();
  522. }
  523. private void OnEntryChanged(string entry)
  524. {
  525. Refresh();
  526. }
  527. private void ScrollToEntry(string path)
  528. {
  529. Rect2I contentBounds = scrollAreaPanel.Bounds;
  530. Rect2I scrollAreaBounds = contentScrollArea.ContentBounds;
  531. ElementEntry entryGUI;
  532. if (!entryLookup.TryGetValue(path, out entryGUI))
  533. return;
  534. Rect2I entryBounds = entryGUI.icon.Bounds;
  535. float percent = (entryBounds.x - scrollAreaBounds.height * 0.5f) / contentBounds.height;
  536. percent = MathEx.Clamp01(percent);
  537. contentScrollArea.VerticalScroll = percent;
  538. }
  539. private void Refresh()
  540. {
  541. DirectoryEntry entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
  542. if (entry == null)
  543. {
  544. Reset();
  545. return;
  546. }
  547. if (scrollAreaPanel != null)
  548. scrollAreaPanel.Destroy();
  549. entries.Clear();
  550. entryLookup.Clear();
  551. scrollAreaPanel = contentScrollArea.Layout.AddPanel();
  552. ContentInfo contentInfo = new ContentInfo(this, viewType);
  553. Rect2I scrollBounds = contentScrollArea.Bounds;
  554. LibraryEntry[] childEntries = entry.Children;
  555. if (childEntries.Length == 0)
  556. return;
  557. if (viewType == ProjectViewType.List16)
  558. {
  559. int tileSize = 16;
  560. for (int i = 0; i < childEntries.Length; i++)
  561. {
  562. ElementEntry guiEntry = new ElementEntry(contentInfo, contentInfo.main, childEntries[i]);
  563. entries.Add(guiEntry);
  564. entryLookup[guiEntry.path] = guiEntry;
  565. if (i != childEntries.Length - 1)
  566. contentInfo.main.AddSpace(LIST_ENTRY_SPACING);
  567. }
  568. contentInfo.main.AddFlexibleSpace();
  569. }
  570. else
  571. {
  572. int tileSize = 64;
  573. switch (viewType)
  574. {
  575. case ProjectViewType.Grid64: tileSize = 64; break;
  576. case ProjectViewType.Grid48: tileSize = 48; break;
  577. case ProjectViewType.Grid32: tileSize = 32; break;
  578. }
  579. GUILayoutX rowLayout = contentInfo.main.AddLayoutX();
  580. rowLayout.AddFlexibleSpace();
  581. int elemSize = tileSize + GRID_ENTRY_SPACING;
  582. int elemsPerRow = (scrollBounds.width - GRID_ENTRY_SPACING*2)/elemSize;
  583. int elemsInRow = 0;
  584. for (int i = 0; i < childEntries.Length; i++)
  585. {
  586. if (elemsInRow == elemsPerRow && elemsInRow > 0)
  587. {
  588. rowLayout = contentInfo.main.AddLayoutX();
  589. contentInfo.main.AddSpace(GRID_ENTRY_SPACING);
  590. rowLayout.AddFlexibleSpace();
  591. elemsInRow = 0;
  592. }
  593. ElementEntry guiEntry = new ElementEntry(contentInfo, rowLayout, childEntries[i]);
  594. entries.Add(guiEntry);
  595. entryLookup[guiEntry.path] = guiEntry;
  596. rowLayout.AddFlexibleSpace();
  597. elemsInRow++;
  598. }
  599. int extraElements = elemsPerRow - elemsInRow;
  600. for (int i = 0; i < extraElements; i++)
  601. {
  602. rowLayout.AddSpace(tileSize);
  603. rowLayout.AddFlexibleSpace();
  604. }
  605. contentInfo.main.AddFlexibleSpace();
  606. }
  607. for (int i = 0; i < entries.Count; i++)
  608. {
  609. ElementEntry guiEntry = entries[i];
  610. guiEntry.Initialize();
  611. if (cutPaths.Contains(guiEntry.path))
  612. guiEntry.MarkAsCut(true);
  613. if (selectionPaths.Contains(guiEntry.path))
  614. guiEntry.MarkAsSelected(true);
  615. else if (pingPath == guiEntry.path)
  616. guiEntry.MarkAsPinged(true);
  617. }
  618. Rect2I contentBounds = contentInfo.main.Bounds;
  619. GUIButton catchAll = new GUIButton("", EditorStyles.Blank);
  620. catchAll.Bounds = contentBounds;
  621. catchAll.OnClick += OnCatchAllClicked;
  622. catchAll.SetContextMenu(entryContextMenu);
  623. contentInfo.underlay.AddElement(catchAll);
  624. }
  625. private void OnEntryClicked(string path)
  626. {
  627. Select(new List<string> { path });
  628. Selection.resourcePaths = new string[] {path};
  629. }
  630. private void OnEntryDoubleClicked(string path)
  631. {
  632. LibraryEntry entry = ProjectLibrary.GetEntry(path);
  633. if (entry != null && entry.Type == LibraryEntryType.Directory)
  634. {
  635. EnterDirectory(path);
  636. }
  637. }
  638. private void OnCatchAllClicked()
  639. {
  640. Select(new List<string> { });
  641. Selection.resourcePaths = new string[] { };
  642. }
  643. private void CutSelection()
  644. {
  645. if (selectionPaths.Count > 0)
  646. Cut(selectionPaths);
  647. }
  648. private void CopySelection()
  649. {
  650. if (selectionPaths.Count > 0)
  651. Copy(selectionPaths);
  652. }
  653. private void DuplicateSelection()
  654. {
  655. if (selectionPaths.Count > 0)
  656. Duplicate(selectionPaths);
  657. }
  658. private void PasteToSelection()
  659. {
  660. DirectoryEntry selectedDirectory = null;
  661. if (selectionPaths.Count == 1)
  662. {
  663. LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
  664. if (entry != null && entry.Type == LibraryEntryType.Directory)
  665. selectedDirectory = (DirectoryEntry) entry;
  666. }
  667. if(selectedDirectory != null)
  668. Paste(selectedDirectory.Path);
  669. else
  670. Paste(currentDirectory);
  671. }
  672. private void OnSearchChanged(string newValue)
  673. {
  674. // TODO
  675. }
  676. private void ClearSearch()
  677. {
  678. // TODO
  679. }
  680. private void OpenOptionsWindow()
  681. {
  682. Vector2I openPosition;
  683. Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
  684. openPosition.x = buttonBounds.x + buttonBounds.width / 2;
  685. openPosition.y = buttonBounds.y + buttonBounds.height / 2;
  686. ProjectDropDown dropDown = DropDownWindow.Open<ProjectDropDown>(this, openPosition);
  687. dropDown.SetParent(this);
  688. }
  689. private void Reset()
  690. {
  691. currentDirectory = ProjectLibrary.Root.Path;
  692. Refresh();
  693. }
  694. protected override void WindowResized(int width, int height)
  695. {
  696. base.WindowResized(width, height);
  697. Refresh();
  698. dropTarget.Bounds = contentScrollArea.Bounds;
  699. }
  700. }
  701. internal class ProjectDropDown : DropDownWindow
  702. {
  703. private ProjectWindow parent;
  704. public ProjectDropDown()
  705. :base(150, 30)
  706. { }
  707. internal void SetParent(ProjectWindow parent)
  708. {
  709. this.parent = parent;
  710. GUIToggleGroup group = new GUIToggleGroup();
  711. GUIToggle list16 = new GUIToggle("16", group, EditorStyles.Button, GUIOption.FixedWidth(30));
  712. GUIToggle grid32 = new GUIToggle("32", group, EditorStyles.Button, GUIOption.FixedWidth(30));
  713. GUIToggle grid48 = new GUIToggle("48", group, EditorStyles.Button, GUIOption.FixedWidth(30));
  714. GUIToggle grid64 = new GUIToggle("64", group, EditorStyles.Button, GUIOption.FixedWidth(30));
  715. ProjectViewType activeType = parent.ViewType;
  716. switch (activeType)
  717. {
  718. case ProjectViewType.List16:
  719. list16.ToggleOn();
  720. break;
  721. case ProjectViewType.Grid32:
  722. grid32.ToggleOn();
  723. break;
  724. case ProjectViewType.Grid48:
  725. grid48.ToggleOn();
  726. break;
  727. case ProjectViewType.Grid64:
  728. grid64.ToggleOn();
  729. break;
  730. }
  731. list16.OnToggled += (active) =>
  732. {
  733. if (active)
  734. ChangeViewType(ProjectViewType.List16);
  735. };
  736. grid32.OnToggled += (active) =>
  737. {
  738. if (active)
  739. ChangeViewType(ProjectViewType.Grid32);
  740. };
  741. grid48.OnToggled += (active) =>
  742. {
  743. if (active)
  744. ChangeViewType(ProjectViewType.Grid48);
  745. };
  746. grid64.OnToggled += (active) =>
  747. {
  748. if (active)
  749. ChangeViewType(ProjectViewType.Grid64);
  750. };
  751. GUILayoutY vertLayout = GUI.AddLayoutY();
  752. vertLayout.AddFlexibleSpace();
  753. GUILayoutX contentLayout = vertLayout.AddLayoutX();
  754. contentLayout.AddFlexibleSpace();
  755. contentLayout.AddElement(list16);
  756. contentLayout.AddElement(grid32);
  757. contentLayout.AddElement(grid48);
  758. contentLayout.AddElement(grid64);
  759. contentLayout.AddFlexibleSpace();
  760. vertLayout.AddFlexibleSpace();
  761. }
  762. private void ChangeViewType(ProjectViewType viewType)
  763. {
  764. parent.ViewType = viewType;
  765. }
  766. }
  767. }