From bd048e2fe693a7905a55f11a00b1223a80d15b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Thu, 9 Jun 2022 12:25:48 +0200 Subject: [PATCH] Bookmark folders, Drag & Drop --- IDE/src/BookmarkManager.bf | 344 +++++++++++++++++++++++++----- IDE/src/Commands.bf | 2 + IDE/src/IDEApp.bf | 96 ++++++--- IDE/src/ui/BookmarksPanel.bf | 380 +++++++++++++++++++++++++--------- IDE/src/ui/SourceViewPanel.bf | 36 ++-- 5 files changed, 670 insertions(+), 188 deletions(-) diff --git a/IDE/src/BookmarkManager.bf b/IDE/src/BookmarkManager.bf index 83ddafc9..dc0bcd5b 100644 --- a/IDE/src/BookmarkManager.bf +++ b/IDE/src/BookmarkManager.bf @@ -52,38 +52,153 @@ namespace IDE public String mTitle ~ delete _; public String mNotes ~ delete _; public bool mIsDisabled; + public BookmarkFolder mFolder; } + public class BookmarkFolder + { + /// The title of the bookmark-folder that will be visible in the bookmark-panel + public String mTitle ~ delete _; + + public List mBookmarkList = new List() ~ + { + for (var bookmark in mBookmarkList) + bookmark.Kill(); + + gApp.mDebugger.mBreakpointsChangedDelegate(); + + delete _; + }; + + /// Gets or Sets whether every bookmark in this folder is disabled or not. + public bool IsDisabled + { + get + { + for (var bookmark in mBookmarkList) + if (!bookmark.mIsDisabled) + return false; + + return true; + } + set + { + for (var bookmark in mBookmarkList) + bookmark.mIsDisabled = value; + + gApp.mBookmarksPanel.mBookmarksDirty = true; + } + } + + /// Adds the given bookmark to this folder. If needed, removes it from its old folder. + public void AddBookmark(Bookmark bookmark) + { + if (bookmark.mFolder != null) + { + bookmark.mFolder.mBookmarkList.Remove(bookmark); + } + mBookmarkList.Add(bookmark); + bookmark.mFolder = this; + + //gApp.mBookmarksPanel.mBookmarksDirty = true; + } + } + public class BookmarkManager { - public List mBookmarkList = new List() ~ - { - for (var bookmark in mBookmarkList) - bookmark.Kill(); - delete _; - }; + public BookmarkFolder mRootFolder = new .(); + public List mBookmarkFolders = new .() {mRootFolder} ~ DeleteContainerAndItems!(_); + + private int mBookmarkCount; + + /// Index of the folder that was navigated to last + public int32 mFolderIdx; + /// Index of the bookmark (inside of its folder) that was navigated to last public int32 mBookmarkIdx; + /// Number of bookmarks created, used to generate the names. private int32 _createdBookmarks; - + /// Number of folders created, used to generate the names. + private int32 _createdFolders; + + /// Gets or sets whether all bookmarks are disabled or not. public bool AllBookmarksDisabled { get { - for (Bookmark b in mBookmarkList) + for (var folder in mBookmarkFolders) { - if (!b.mIsDisabled) + if (!folder.IsDisabled) return false; } return true; } + set + { + for (var folder in mBookmarkFolders) + { + folder.IsDisabled = value; + } + + gApp.mBookmarksPanel.mBookmarksDirty = true; + } + } + + /** + * Creates a new bookmark folder + * @param title The title of the bookmark + * @returns the newly created BookmarkFolder + */ + public BookmarkFolder CreateFolder(String title = null) + { + mBookmarkIdx = -1; + + BookmarkFolder folder = new .(); + + if (title == null) + folder.mTitle = new $"Folder {_createdFolders++}"; + else + folder.mTitle = new String(title); + + mBookmarkFolders.Add(folder); + + gApp.mBookmarksPanel.mBookmarksDirty = true; + + return folder; } - public Bookmark CreateBookmark(String fileName, int wantLineNum, int wantColumn, bool isDisabled = false, String title = null) + /// Deletes the given bookmark folder and all bookmarks inside it. + public void DeleteFolder(BookmarkFolder folder) { - mBookmarkIdx = (int32)mBookmarkList.Count; - _createdBookmarks++; + int folderIdx = mBookmarkFolders.IndexOf(folder); + + mBookmarkFolders.Remove(folder); + + delete folder; + + // Select the previous folder + if (mFolderIdx == folderIdx) + folderIdx--; + if (mFolderIdx >= mBookmarkFolders.Count) + mFolderIdx = (int32)mBookmarkFolders.Count - 1; + + // Select last bookmark inside the newly selected folder + if (mBookmarkIdx >= mBookmarkFolders[mFolderIdx].mBookmarkList.Count) + mBookmarkIdx = (int32)mBookmarkFolders[mFolderIdx].mBookmarkList.Count - 1; + + gApp.mBookmarksPanel.mBookmarksDirty = true; + } + + public Bookmark CreateBookmark(String fileName, int wantLineNum, int wantColumn, bool isDisabled = false, String title = null, BookmarkFolder folder = null) + { + var folder; + + folder = folder ?? mRootFolder; + + mFolderIdx = (int32)mBookmarkFolders.IndexOf(folder); + + mBookmarkIdx = (int32)folder.mBookmarkList.Count; Bookmark bookmark = new Bookmark(); bookmark.mFileName = new String(fileName); @@ -96,92 +211,223 @@ namespace IDE bookmark.mTitle = new String(title); bookmark.mIsDisabled = isDisabled; - - mBookmarkList.Add(bookmark); + + folder.AddBookmark(bookmark); gApp.mDebugger.mBreakpointsChangedDelegate(); - //gApp.mBookmarksPanel.UpdateBookmarks(); gApp.mBookmarksPanel.mBookmarksDirty = true; + mBookmarkCount++; + return bookmark; } + /** Moves the bookmark to the specified folder. + * @param bookmark The bookmark to move. + * @param folder The folder to which the bookmark will be moved. + * @param insertBefore If null the bookmark will be added at the end of the folder. Otherwise it will be inserted before the specified bookmark. + */ + public void MoveBookmarkToFolder(Bookmark bookmark, BookmarkFolder folder, Bookmark insertBefore = null) + { + if (bookmark.mFolder != null) + { + bookmark.mFolder.mBookmarkList.Remove(bookmark); + } + + if (insertBefore == null) + folder.mBookmarkList.Add(bookmark); + else + { + Debug.Assert(folder == insertBefore.mFolder, "Insert before must be in folder."); + + int index = folder.mBookmarkList.IndexOf(insertBefore); + + folder.mBookmarkList.Insert(index, bookmark); + } + + bookmark.mFolder = folder; + + FixupIndices(); + + gApp.mBookmarksPanel.mBookmarksDirty = true; + } + + enum Placement + { + Before, + After + } + + public void MoveFolder(BookmarkFolder folder, Placement place = .After, BookmarkFolder target = null) + { + if (folder == target) + return; + + if (mBookmarkFolders.Contains(folder)) + mBookmarkFolders.Remove(folder); + + if (target == null) + { + mBookmarkFolders.Add(folder); + } + else + { + int index = mBookmarkFolders.IndexOf(target); + + if (place == .After) + index++; + + mBookmarkFolders.Insert(index, folder); + } + + FixupIndices(); + + gApp.mBookmarksPanel.mBookmarksDirty = true; + } + + /// Make sure that the bookmark and folder indices are valid. + private void FixupIndices() + { + if (mBookmarkIdx <= 0 || mBookmarkIdx >= mBookmarkFolders[mFolderIdx].mBookmarkList.Count) + { + mBookmarkIdx = 0; + + // Don't have an empty folder selected + if (mBookmarkFolders[mFolderIdx].mBookmarkList.Count == 0) + mFolderIdx = 0; + } + } + public void DeleteBookmark(Bookmark bookmark) { - int idx = mBookmarkList.IndexOf(bookmark); - mBookmarkList.RemoveAt(idx); - if (mBookmarkIdx == idx) - mBookmarkIdx--; - if (mBookmarkIdx >= mBookmarkList.Count) - mBookmarkIdx = (int32)mBookmarkList.Count - 1; - gApp.mDebugger.mBreakpointsChangedDelegate(); + BookmarkFolder folder = bookmark.mFolder; + + folder.mBookmarkList.Remove(bookmark); + + FixupIndices(); + + gApp.mDebugger.mBreakpointsChangedDelegate(); bookmark.Kill(); - //gApp.mBookmarksPanel.UpdateBookmarks(); gApp.mBookmarksPanel.mBookmarksDirty = true; + + mBookmarkCount--; } public void Clear() { - for (var bookmark in mBookmarkList) - bookmark.Kill(); - mBookmarkList.Clear(); + for (var folder in mBookmarkFolders) + { + for (var bookmark in folder.mBookmarkList) + bookmark.Kill(); + folder.mBookmarkList.Clear(); + } + ClearAndDeleteItems!(mBookmarkFolders); + + mRootFolder = new BookmarkFolder(); + mBookmarkFolders.Add(mRootFolder); + + mFolderIdx = 0; mBookmarkIdx = 0; gApp.mDebugger.mBreakpointsChangedDelegate(); - //gApp.mBookmarksPanel.UpdateBookmarks(); gApp.mBookmarksPanel.mBookmarksDirty = true; } - public void PrevBookmark() + public void PrevBookmark(bool currentFolderOnly = false) { - if (mBookmarkList.Count == 0) - return; + if (mBookmarkCount == 0) + return; - int32 currentIdx = mBookmarkIdx; + int32 currentFolderIdx = mFolderIdx; + int32 currentBookmarkIdx = mBookmarkIdx; - Bookmark prevBookmark; + Bookmark nextBookmark = null; repeat { - mBookmarkIdx++; - if (mBookmarkIdx >= mBookmarkList.Count) - mBookmarkIdx = 0; - - prevBookmark = mBookmarkList[mBookmarkIdx]; + mBookmarkIdx++; + + if (mBookmarkIdx >= mBookmarkFolders[mFolderIdx].mBookmarkList.Count) + { + if (!currentFolderOnly) + { + mFolderIdx++; + + if (mFolderIdx >= mBookmarkFolders.Count) + { + // wrap to first folder + mFolderIdx = 0; + } + } + + // Select first bookmark in current folder (or -1 if there is no bookmark) + mBookmarkIdx = mBookmarkFolders[mFolderIdx].mBookmarkList.IsEmpty ? -1 : 0; + } + + if (mBookmarkIdx >= 0) + nextBookmark = mBookmarkFolders[mFolderIdx].mBookmarkList[mBookmarkIdx]; + else + nextBookmark = null; } // skip disabled bookmarks, stop when we reach starting point - while (prevBookmark.mIsDisabled && (currentIdx != mBookmarkIdx)); + while ((nextBookmark == null || nextBookmark.mIsDisabled) && ((currentFolderIdx != mFolderIdx) || (currentBookmarkIdx != mBookmarkIdx) && mBookmarkIdx != -1)); - GotoBookmark(prevBookmark); + // If nextBookmark is disabled no bookmark is enabled. + if (nextBookmark != null && !nextBookmark.mIsDisabled) + GotoBookmark(nextBookmark); } - public void NextBookmark() + public void NextBookmark(bool currentFolderOnly = false) { - if (mBookmarkList.Count == 0) - return; + if (mBookmarkCount == 0) + return; - int32 currentIdx = mBookmarkIdx; + int32 currentFolderIdx = mFolderIdx; + int32 currentBookmarkIdx = mBookmarkIdx; - Bookmark nextBookmark; + Bookmark nextBookmark = null; repeat { mBookmarkIdx--; - if (mBookmarkIdx < 0) - mBookmarkIdx = (int32)mBookmarkList.Count - 1; - nextBookmark = mBookmarkList[mBookmarkIdx]; + if (mBookmarkIdx < 0) + { + if (!currentFolderOnly) + { + mFolderIdx--; + + if (mFolderIdx < 0) + { + // wrap to last folder + mFolderIdx = (int32)mBookmarkFolders.Count - 1; + } + } + + // Select last bookmark in current folder + mBookmarkIdx = (int32)mBookmarkFolders[mFolderIdx].mBookmarkList.Count - 1; + } + + if (mBookmarkIdx >= 0) + nextBookmark = mBookmarkFolders[mFolderIdx].mBookmarkList[mBookmarkIdx]; + else + nextBookmark = null; } // skip disabled bookmarks, stop when we reach starting point - while (nextBookmark.mIsDisabled && (currentIdx != mBookmarkIdx)); + while ((nextBookmark == null || nextBookmark.mIsDisabled) && ((currentFolderIdx != mFolderIdx) || (currentBookmarkIdx != mBookmarkIdx) && mBookmarkIdx != -1)); - GotoBookmark(nextBookmark); + // If nextBookmark is disabled no bookmark is enabled. + if (nextBookmark != null && !nextBookmark.mIsDisabled) + GotoBookmark(nextBookmark); } public void GotoBookmark(Bookmark bookmark) { + mFolderIdx = (int32)mBookmarkFolders.IndexOf(bookmark.mFolder); + mBookmarkIdx = (int32)bookmark.mFolder.mBookmarkList.IndexOf(bookmark); + gApp.ShowSourceFileLocation(bookmark.mFileName, -1, -1, bookmark.mLineNum, bookmark.mColumn, LocatorType.Smart); } } diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 57e1ff8c..f493b56e 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -196,6 +196,8 @@ namespace IDE Add("Autocomplete", new => gApp.Cmd_ShowAutoComplete, .None); Add("Bookmark Next", new => gApp.Cmd_NextBookmark, .Editor); Add("Bookmark Prev", new => gApp.Cmd_PrevBookmark, .Editor); + Add("Bookmark Next in Folder", new => gApp.Cmd_NextBookmarkInFolder, .Editor); + Add("Bookmark Prev in Folder", new => gApp.Cmd_PrevBookmarkInFolder, .Editor); Add("Bookmark Toggle", new => gApp.Cmd_ToggleBookmark, .Editor); Add("Bookmark Clear", new => gApp.Cmd_ClearBookmarks, .Editor); Add("Break All", new => gApp.[Friend]Cmd_Break); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 3073285a..5a86eeb0 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -1896,26 +1896,37 @@ namespace IDE } } } - - using (sd.CreateArray("Bookmarks")) + + using (sd.CreateArray("BookmarkFolders")) { - for (var bookmark in mBookmarkManager.mBookmarkList) - { - if (bookmark.mFileName != null) + for (var folder in mBookmarkManager.mBookmarkFolders) + { + using (sd.CreateObject()) { - using (sd.CreateObject()) - { - String relPath = scope .(); - mWorkspace.GetWorkspaceRelativePath(bookmark.mFileName, relPath); - sd.Add("File", relPath); - sd.Add("Line", bookmark.mLineNum); - sd.Add("Column", bookmark.mColumn); - sd.Add("Title", bookmark.mTitle); - if (bookmark.mIsDisabled) - sd.Add("Disabled", true); - } - } - } + sd.Add("Title", folder.mTitle); + + using (sd.CreateArray("Bookmarks")) + { + for (var bookmark in folder.mBookmarkList) + { + if (bookmark.mFileName != null) + { + using (sd.CreateObject()) + { + String relPath = scope .(); + mWorkspace.GetWorkspaceRelativePath(bookmark.mFileName, relPath); + sd.Add("File", relPath); + sd.Add("Line", bookmark.mLineNum); + sd.Add("Column", bookmark.mColumn); + sd.Add("Title", bookmark.mTitle); + if (bookmark.mIsDisabled) + sd.Add("Disabled", true); + } + } + } + } + } + } } using (sd.CreateObject("DebuggerDisplayTypes")) @@ -3308,22 +3319,33 @@ namespace IDE breakpoint.SetThreadId(0); } } - - for (var _bookmark in data.Enumerate("Bookmarks")) + + for (var _bookmarkFolder in data.Enumerate("BookmarkFolders")) { - String relPath = scope String(); - data.GetString("File", relPath); - IDEUtils.FixFilePath(relPath); - String absPath = scope String(); - mWorkspace.GetWorkspaceAbsPath(relPath, absPath); - int32 lineNum = data.GetInt("Line"); - int32 column = data.GetInt("Column"); String title = scope String(); data.GetString("Title", title); - bool isDisabled = data.GetBool("Disabled", false); + BookmarkFolder folder = null; - mBookmarkManager.CreateBookmark(absPath, lineNum, column, isDisabled, title); + if (!String.IsNullOrWhiteSpace(title)) + folder = mBookmarkManager.CreateFolder(title); + + for (var _bookmark in data.Enumerate("Bookmarks")) + { + String relPath = scope String(); + data.GetString("File", relPath); + IDEUtils.FixFilePath(relPath); + String absPath = scope String(); + mWorkspace.GetWorkspaceAbsPath(relPath, absPath); + int32 lineNum = data.GetInt("Line"); + int32 column = data.GetInt("Column"); + String bookmarkTitle = scope String(); + data.GetString("Title", bookmarkTitle); + + bool isDisabled = data.GetBool("Disabled", false); + + mBookmarkManager.CreateBookmark(absPath, lineNum, column, isDisabled, bookmarkTitle, folder); + } } for (var referenceId in data.Enumerate("DebuggerDisplayTypes")) @@ -3952,13 +3974,25 @@ namespace IDE [IDECommand] public void Cmd_PrevBookmark() { - mBookmarkManager.PrevBookmark(); + mBookmarkManager.PrevBookmark(false); + } + + [IDECommand] + public void Cmd_PrevBookmarkInFolder() + { + mBookmarkManager.PrevBookmark(true); } [IDECommand] public void Cmd_NextBookmark() { - mBookmarkManager.NextBookmark(); + mBookmarkManager.NextBookmark(false); + } + + [IDECommand] + public void Cmd_NextBookmarkInFolder() + { + mBookmarkManager.NextBookmark(true); } [IDECommand] diff --git a/IDE/src/ui/BookmarksPanel.bf b/IDE/src/ui/BookmarksPanel.bf index 63d03542..9d6234f7 100644 --- a/IDE/src/ui/BookmarksPanel.bf +++ b/IDE/src/ui/BookmarksPanel.bf @@ -5,34 +5,78 @@ using System; using System.Collections; using Beefy.theme; using Beefy.events; +using System.Diagnostics; namespace IDE.ui { + public class BookmarksListView : IDEListView + { + protected override ListViewItem CreateListViewItem() + { + return new BookmarksListViewItem(); + } + protected override void SetScaleData() + { + base.SetScaleData(); + mIconX = GS!(200); + mOpenButtonX = GS!(0); + mLabelX = GS!(0); + //mChildIndent = GS!(16); + mHiliteOffset = GS!(-2); + } + } + + public class BookmarksListViewItem : IDEListViewItem + { + public Object RefObject; + public String BookmarkLine ~ delete _; + + public float mLabelOffsetFolder = GS!(16); + public float mLabelOffsetBookmark = GS!(0); + + public override void RehupScale(float oldScale, float newScale) + { + base.RehupScale(oldScale, newScale); + + mLabelOffsetFolder = GS!(16); + mLabelOffsetBookmark = GS!(0); + } + + protected override float GetLabelOffset() + { + if (RefObject is BookmarkFolder) + { + return mLabelOffsetFolder; + } + + return mLabelOffsetBookmark; + } + + public void Goto() + { + if (Bookmark bookmark = RefObject as Bookmark) + { + gApp.mBookmarkManager.GotoBookmark(bookmark); + } + } + } + class BookmarksPanel : Panel { - public class BookmarksListView : IDEListView - { - protected override ListViewItem CreateListViewItem() - { - return new BookmarksListViewItem(); - } - } - - public class BookmarksListViewItem : IDEListViewItem - { - public Bookmark Bookmark; - public String BookmarkLine ~ delete _; - - public void Goto() - { - gApp.mBookmarkManager.GotoBookmark(Bookmark); - } - } + public DarkButton mCreateBookmarkFolder; public BookmarksListView mBookmarksLV; public this() { + mCreateBookmarkFolder = new DarkButton(); + mCreateBookmarkFolder.Label = "New Folder"; + mCreateBookmarkFolder.mOnMouseClick.Add(new (args) => + { + gApp.mBookmarkManager.CreateFolder(); + }); + AddWidget(mCreateBookmarkFolder); + mBookmarksLV = new .(); mBookmarksLV.mOnEditDone.Add(new => HandleEditDone); @@ -44,6 +88,9 @@ namespace IDE.ui mBookmarksLV.AddColumn(400, "File"); mBookmarksLV.AddColumn(120, "Line"); + mBookmarksLV.mOnDragEnd.Add(new => BookmarksLV_OnDragEnd); + mBookmarksLV.mOnDragUpdate.Add(new => BookmarksLV_OnDragUpdate); + mBookmarksLV.mOnItemMouseDown.Add(new (item, x, y, btnNum, btnCount) => { if ((btnNum == 0) && (btnCount == 2)) @@ -58,55 +105,160 @@ namespace IDE.ui mBookmarksLV.mOnKeyDown.Add(new => BookmarksLV_OnKeyDown); AddWidget(mBookmarksLV); - } private void BookmarksLV_OnKeyDown(KeyDownEvent event) { - if (event.mKeyCode == KeyCode.Delete) + if (event.mKeyCode == KeyCode.Delete) { - DeleteSelectedItem(); + DeleteSelectedItems(); } ListViewKeyDown_ShowMenu(event); } + + public override void RehupScale(float oldScale, float newScale) + { + mBookmarksLV.mOpenButtonX = GS!(4); + base.RehupScale(oldScale, newScale); + } + + private void BookmarksLV_OnDragUpdate(DragEvent evt) + { + var dragKind = evt.mDragKind; + evt.mDragKind = .None; + + var dragSource = evt.mSender as BookmarksListViewItem; + var dragTarget = evt.mDragTarget as BookmarksListViewItem; + + // Folders can only be dragged onto other folders + if (dragSource.RefObject is BookmarkFolder && (!dragTarget.RefObject is BookmarkFolder)) + return; + + if (dragSource == null) + return; + if (dragTarget == null) + return; + + evt.mDragKind = .After; + + if ((dragTarget.mLabel == "") && (dragKind == .After)) + dragKind = .Before; + + if (dragKind == .None) + return; + evt.mDragKind = dragKind; + } + + private void BookmarksLV_OnDragEnd(DragEvent theEvent) + { + if (theEvent.mDragKind == .None) + return; + + if (theEvent.mDragTarget is BookmarksListViewItem) + { + var source = (BookmarksListViewItem)theEvent.mSender; + var target = (BookmarksListViewItem)theEvent.mDragTarget; + + if (source.mListView == target.mListView) + { + if (source == target) + return; + + List selectedItems = scope .(); + mBookmarksLV.GetRoot().WithSelectedItems(scope [&] (selectedItem) => + { + selectedItems.Add((BookmarksListViewItem)selectedItem); + }); + + for (BookmarksListViewItem item in selectedItems) + { + if (var sourceBookmark = item.RefObject as Bookmark) + { + if (var targetBookmark = target.RefObject as Bookmark) + { + if (theEvent.mDragKind == .After) + { + int index = targetBookmark.mFolder.mBookmarkList.IndexOf(targetBookmark); + index++; + + Bookmark prevBookmark = null; + + if (index < targetBookmark.mFolder.mBookmarkList.Count) + { + prevBookmark = targetBookmark.mFolder.mBookmarkList[index]; + } + + gApp.mBookmarkManager.MoveBookmarkToFolder(sourceBookmark, targetBookmark.mFolder, prevBookmark); + } + else if (theEvent.mDragKind == .Before) + { + gApp.mBookmarkManager.MoveBookmarkToFolder(sourceBookmark, targetBookmark.mFolder, targetBookmark); + } + } + else if (var targetFolder = target.RefObject as BookmarkFolder) + { + if (theEvent.mDragKind == .Before) + { + // Drop before folder -> Drop to root + gApp.mBookmarkManager.MoveBookmarkToFolder(sourceBookmark, gApp.mBookmarkManager.mRootFolder); + } + else if (theEvent.mDragKind == .After || theEvent.mDragKind == .Inside) + { + gApp.mBookmarkManager.MoveBookmarkToFolder(sourceBookmark, targetFolder); + } + } + } + else if (var sourceFolder = item.RefObject as BookmarkFolder) + { + if (var targetFolder = target.RefObject as BookmarkFolder) + { + if (theEvent.mDragKind == .Before) + { + gApp.mBookmarkManager.MoveFolder(sourceFolder, .Before, targetFolder); + } + else if (theEvent.mDragKind == .After) + { + gApp.mBookmarkManager.MoveFolder(sourceFolder, .After, targetFolder); + } + } + } + } + } + } + } /// Tries to rename the currently selected bookmark public void TryRenameItem() { ListViewItem selectedItem = mBookmarksLV.GetRoot().FindFirstSelectedItem(); + RenameItem(selectedItem); } - public void DeleteSelectedItem() + private void HandleEditDone(EditWidget editWidget, bool cancelled) { - ListViewItem selectedItem = mBookmarksLV.GetRoot().FindFirstSelectedItem(); - if (var bookmarkItem = selectedItem as BookmarksListViewItem) - { - gApp.mBookmarkManager.DeleteBookmark(bookmarkItem.Bookmark); - } - } + String newValue = scope String(); + editWidget.GetText(newValue); + newValue.Trim(); - private void HandleEditDone(EditWidget editWidget, bool cancelled) - { - String newValue = scope String(); - editWidget.GetText(newValue); - newValue.Trim(); - ListViewItem listViewItem = mBookmarksLV.mEditingItem; if (var item = listViewItem as BookmarksListViewItem) { - item.Bookmark.mTitle.Clear(); - item.Bookmark.mTitle.Append(newValue); - listViewItem.Label = item.Bookmark.mTitle; + if (var bookmark = item.RefObject as Bookmark) + { + bookmark.mTitle.Clear(); + bookmark.mTitle.Append(newValue); + listViewItem.Label = bookmark.mTitle; + } + else if (var folder = item.RefObject as BookmarkFolder) + { + folder.mTitle.Clear(); + folder.mTitle.Append(newValue); + listViewItem.Label = folder.mTitle; + } } - - } - - public ~this() - { - } protected override void ShowRightClickMenu(Widget relWidget, float x, float y) @@ -118,7 +270,7 @@ namespace IDE.ui if (listView.GetRoot().FindFirstSelectedItem() != null) { Menu menu = new Menu(); - Menu anItem; + Menu anItem; anItem = menu.AddItem("Delete"); anItem.mOnMenuItemSelected.Add(new (item) => { @@ -126,19 +278,21 @@ namespace IDE.ui { if (var bookmarkItem = item as BookmarksListViewItem) { - gApp.mBookmarkManager.DeleteBookmark(bookmarkItem.Bookmark); + if (var bookmark = bookmarkItem.RefObject as Bookmark) + gApp.mBookmarkManager.DeleteBookmark(bookmark); + else if (var folder = bookmarkItem.RefObject as BookmarkFolder) + gApp.mBookmarkManager.DeleteFolder(folder); } }); - }); - anItem = menu.AddItem("Rename"); + anItem = menu.AddItem("Rename"); anItem.mOnMenuItemSelected.Add(new (item) => - { + { var selectedItem = mBookmarksLV.GetRoot().FindFirstSelectedItem(); if (selectedItem != null) - RenameItem(selectedItem); - }); + RenameItem(selectedItem); + }); menu.AddItem(); @@ -146,58 +300,55 @@ namespace IDE.ui { anItem = menu.AddItem("Enable all Bookmarks"); anItem.mOnMenuItemSelected.Add(new (item) => - { - for (Bookmark b in gApp.mBookmarkManager.mBookmarkList) - { - b.mIsDisabled = false; - } - mBookmarksDirty = true; - }); + { + gApp.mBookmarkManager.AllBookmarksDisabled = false; + }); } else { anItem = menu.AddItem("Disable all Bookmarks"); anItem.mOnMenuItemSelected.Add(new (item) => - { - for (Bookmark b in gApp.mBookmarkManager.mBookmarkList) - { - b.mIsDisabled = true; - } - mBookmarksDirty = true; - }); + { + gApp.mBookmarkManager.AllBookmarksDisabled = true; + }); } MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu); menuWidget.Init(relWidget, x, y); } } - + void EditListViewItem(ListViewItem listViewItem) { mBookmarksLV.EditListViewItem(listViewItem); } - void RenameItem(ListViewItem listViewItem) - { - EditListViewItem(listViewItem); - } + void RenameItem(ListViewItem listViewItem) + { + if (listViewItem != null) + EditListViewItem(listViewItem); + } public override void Serialize(StructuredData data) { - base.Serialize(data); + base.Serialize(data); - data.Add("Type", "BookmarksPanel"); + data.Add("Type", "BookmarksPanel"); } - + public override void Resize(float x, float y, float width, float height) { base.Resize(x, y, width, height); - mBookmarksLV.Resize(0, 0, width, height); + + float buttonWidth = GS!(140); + float buttonHeight = GS!(22); + mCreateBookmarkFolder.Resize(0, 0, buttonWidth, buttonHeight); + + mBookmarksLV.Resize(0, buttonHeight, width, Math.Max(mHeight - buttonHeight, 0)); } public void Clear() { - } public bool mBookmarksDirty; @@ -217,66 +368,109 @@ namespace IDE.ui root.Clear(); - for (Bookmark bookmark in gApp.mBookmarkManager.mBookmarkList) + for (BookmarkFolder folder in gApp.mBookmarkManager.mBookmarkFolders) { - BookmarksListViewItem listViewItem = (.)root.CreateChildItem(); - SetupListViewItem(listViewItem, bookmark); + bool isRoot = (folder == IDEApp.sApp.mBookmarkManager.mRootFolder); + + BookmarksListViewItem FolderItem = null; + + if (!isRoot) + { + FolderItem = (BookmarksListViewItem)root.CreateChildItem(); + SetupListViewItemFolder(FolderItem, folder); + } + else + { + FolderItem = (BookmarksListViewItem)root; + } + + for (Bookmark bookmark in folder.mBookmarkList) + { + var listViewItem = (BookmarksListViewItem)(FolderItem.CreateChildItem()); + SetupListViewItem(listViewItem, bookmark); + } } mBookmarksDirty = false; } + private void SetupListViewItemFolder(BookmarksListViewItem listViewItem, BookmarkFolder folder) + { + listViewItem.AllowDragging = true; + + listViewItem.RefObject = folder; + + var subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(0); + + DarkCheckBox cb = new DarkCheckBox(); + cb.Checked = !folder.IsDisabled; + cb.Resize(GS!(-16), 0, GS!(22), GS!(22)); + cb.mOnValueChanged.Add(new () => + { + folder.IsDisabled = !cb.Checked; + }); + subViewItem.AddWidget(cb); + + subViewItem.Label = folder.mTitle; + subViewItem.Resize(GS!(22), 0, 0, 0); + } + private void SetupListViewItem(BookmarksListViewItem listViewItem, Bookmark bookmark) { - listViewItem.Bookmark = bookmark; + listViewItem.AllowDragging = true; + + listViewItem.RefObject = bookmark; var subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(0); DarkCheckBox cb = new DarkCheckBox(); cb.Checked = !bookmark.mIsDisabled; cb.Resize(GS!(-16), 0, GS!(22), GS!(22)); - cb.mOnValueChanged.Add(new () => { - bookmark.mIsDisabled = !cb.Checked; - }); + cb.mOnValueChanged.Add(new () => + { + bookmark.mIsDisabled = !cb.Checked; + }); subViewItem.AddWidget(cb); subViewItem.Label = bookmark.mTitle; subViewItem.Resize(GS!(22), 0, 0, 0); - subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(1); - subViewItem.Label = bookmark.mFileName; + subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(1); + subViewItem.Label = bookmark.mFileName; // Internally lines are 0-based -> add one for display listViewItem.BookmarkLine = new $"{bookmark.mLineNum + 1}"; - subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(2); - subViewItem.Label = listViewItem.BookmarkLine; + subViewItem = (DarkListViewItem)listViewItem.GetOrCreateSubItem(2); + subViewItem.Label = listViewItem.BookmarkLine; } public override void KeyDown(KeyCode keyCode, bool isRepeat) { mBookmarksLV.KeyDown(keyCode, isRepeat); - + base.KeyDown(keyCode, isRepeat); } private void DeleteSelectedItems() { var root = mBookmarksLV.GetRoot(); - List selectedItems = scope List(); + List selectedItems = scope List(); root.WithSelectedItems(scope (listViewItem) => - { - selectedItems.Add(listViewItem); - }); + { + selectedItems.Add(listViewItem); + }); // Go through in reverse, to process children before their parents for (int itemIdx = selectedItems.Count - 1; itemIdx >= 0; itemIdx--) { BookmarksListViewItem item = (.)selectedItems[itemIdx]; - if (item.Bookmark != null) - gApp.mBookmarkManager.DeleteBookmark(item.Bookmark); + if (var bookmark = item.RefObject as Bookmark) + gApp.mBookmarkManager.DeleteBookmark(bookmark); + else if (var folder = item.RefObject as BookmarkFolder) + gApp.mBookmarkManager.DeleteFolder(folder); } } } -} \ No newline at end of file +} diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 81c56e65..2a7316d6 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -3171,16 +3171,19 @@ namespace IDE.ui mTrackedTextElementViewList = new List(); if (mFilePath == null) return mTrackedTextElementViewList; - - for (var bookmark in IDEApp.sApp.mBookmarkManager.mBookmarkList) - { - if (Path.Equals(bookmark.mFileName, findFileName)) - { - var bookmarkView = new TrackedTextElementView(bookmark); - UpdateTrackedElementView(bookmarkView); - mTrackedTextElementViewList.Add(bookmarkView); - } - } + + for (var folder in IDEApp.sApp.mBookmarkManager.mBookmarkFolders) + { + for (var bookmark in folder.mBookmarkList) + { + if (Path.Equals(bookmark.mFileName, findFileName)) + { + var bookmarkView = new TrackedTextElementView(bookmark); + UpdateTrackedElementView(bookmarkView); + mTrackedTextElementViewList.Add(bookmarkView); + } + } + } for (var breakpoint in debugManager.mBreakpointList) { @@ -4393,11 +4396,14 @@ namespace IDE.ui bool hadBookmark = false; - WithTrackedElementsAtCursor(IDEApp.sApp.mBookmarkManager.mBookmarkList, scope [&] (bookmark) => - { - bookmarkManager.DeleteBookmark(bookmark); - hadBookmark = true; - }); + for (var folder in IDEApp.sApp.mBookmarkManager.mBookmarkFolders) + { + WithTrackedElementsAtCursor(folder.mBookmarkList, scope [&] (bookmark) => + { + bookmarkManager.DeleteBookmark(bookmark); + hadBookmark = true; + }); + } if (!hadBookmark) {