diff --git a/BeefLibs/Beefy2D/src/widgets/Widget.bf b/BeefLibs/Beefy2D/src/widgets/Widget.bf index 16523e26..3b5a7a6a 100644 --- a/BeefLibs/Beefy2D/src/widgets/Widget.bf +++ b/BeefLibs/Beefy2D/src/widgets/Widget.bf @@ -811,19 +811,29 @@ namespace Beefy.widgets public static bool HandleTab(int dir, List tabWidgets) { + Widget wantFocus = null; + + if (tabWidgets.IsEmpty) + return false; + for (int32 idx = 0; idx < tabWidgets.Count; idx++) { Widget widget = tabWidgets[idx]; if (widget.mHasFocus) { var nextWidget = tabWidgets[(idx + tabWidgets.Count + dir) % tabWidgets.Count]; - nextWidget.SetFocus(); - if (var editWidget = nextWidget as EditWidget) - editWidget.mEditWidgetContent.SelectAll(); - return true; + wantFocus = nextWidget; + break; } } - return false; + + if (wantFocus == null) + wantFocus = tabWidgets[0]; + + wantFocus.SetFocus(); + if (var editWidget = wantFocus as EditWidget) + editWidget.mEditWidgetContent.SelectAll(); + return true; } } } diff --git a/BeefLibs/corlib/src/System/IO/FolderBrowserDialog.bf b/BeefLibs/corlib/src/System/IO/FolderBrowserDialog.bf index ad462895..06888003 100644 --- a/BeefLibs/corlib/src/System/IO/FolderBrowserDialog.bf +++ b/BeefLibs/corlib/src/System/IO/FolderBrowserDialog.bf @@ -43,7 +43,6 @@ namespace System.IO public void Reset() { - //mRootFolder = .Default; mSelectedPath.Clear(); mDescriptionText.Clear(); mSelectedPathNeedsCheck = false; diff --git a/BeefLibs/corlib/src/System/String.bf b/BeefLibs/corlib/src/System/String.bf index a5ec0a32..1cac9e59 100644 --- a/BeefLibs/corlib/src/System/String.bf +++ b/BeefLibs/corlib/src/System/String.bf @@ -838,6 +838,7 @@ namespace System public void Append(String str, int offset, int length) { Debug.Assert((uint)offset <= (uint)str.mLength); + Debug.Assert(length >= 0); Debug.Assert((uint)offset + (uint)length <= (uint)str.mLength); Append(str.Ptr + offset, length); } diff --git a/BeefySysLib/FileHandleStream.cpp b/BeefySysLib/FileHandleStream.cpp index be536ecc..7f4a9557 100644 --- a/BeefySysLib/FileHandleStream.cpp +++ b/BeefySysLib/FileHandleStream.cpp @@ -55,12 +55,12 @@ bool FileHandleStream::Eof() ::SetFilePointer(mFileHandle, 0, 0, FILE_END); return mVFilePos >= (int)::SetFilePointer(mFileHandle, 0, 0, FILE_CURRENT); } - return ::SetFilePointer(mFileHandle, 0, 0, FILE_CURRENT) != ::GetFileSize(mFileHandle, NULL); + return ::SetFilePointer(mFileHandle, 0, 0, FILE_CURRENT) >= ::GetFileSize(mFileHandle, NULL); } int FileHandleStream::GetSize() -{ - return ::GetFileSize(mFileHandle, NULL);; +{ + return ::GetFileSize(mFileHandle, NULL); } void FileHandleStream::Read(void* ptr, int size) diff --git a/IDE/BeefProj.toml b/IDE/BeefProj.toml index 74f1336d..e339ea8b 100644 --- a/IDE/BeefProj.toml +++ b/IDE/BeefProj.toml @@ -27,7 +27,7 @@ TargetDirectory = "$(WorkspaceDir)/dist" TargetName = "BeefIDE_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib" CLibType = "Dynamic" -DebugCommandArguments = "-workspace=c:\\beef\\ide -dbgCompileDump" +DebugCommandArguments = "-workspace=c:\\beef\\BeefTools\\LogViewer" DebugWorkingDirectory = "c:\\Beef\\IDE\\Tests\\EmptyTest" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] @@ -56,7 +56,7 @@ TargetName = "BeefIDE_d2" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib BeefySysLib64_d.lib wsock32.lib" CLibType = "Dynamic" BeefLibType = "DynamicDebug" -DebugCommandArguments = "-proddir=C:\\Beef\\IDE\\mintest -dbgCompileDump" +DebugCommandArguments = "-workspace=c:\\_beef\\testapp" DebugWorkingDirectory = "$(ProjectDir)\\dist" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] diff --git a/IDE/mintest/src/main3.bf b/IDE/mintest/src/main3.bf index 5d016bcb..7c042f08 100644 --- a/IDE/mintest/src/main3.bf +++ b/IDE/mintest/src/main3.bf @@ -114,7 +114,7 @@ class Blurg public static void Hey() { - function void() func = null; + } } diff --git a/IDE/src/FileWatcher.bf b/IDE/src/FileWatcher.bf index 250859ee..b48bd5fe 100644 --- a/IDE/src/FileWatcher.bf +++ b/IDE/src/FileWatcher.bf @@ -84,7 +84,19 @@ namespace IDE void FileChanged(String filePath, String newPath, WatcherChangeTypes changeType) { - if (changeType == .Renamed) + bool isDirectory = filePath.EndsWith(Path.DirectorySeparatorChar); + + var newPath; + if (isDirectory) + { + if (newPath.EndsWith(Path.DirectorySeparatorChar)) + { + newPath = scope:: String(); + newPath.Append(@newPath, 0, @newPath.Length - 1); + } + } + + if ((changeType == .Renamed) && (!isDirectory)) { // ALWAYS interpret 'file rename' notifications as a delete of filePath and a create of newPath // A manual rename in the IDE will have manually processed the rename before we get here, so @@ -258,7 +270,7 @@ namespace IDE if (newName != null) { var newFullPath = new String(); - Path.GetDirectoryPath(fullPath, newFullPath); + newFullPath.Append(fileSystemWatcher.Directory); newFullPath.Append(Path.DirectorySeparatorChar); newFullPath.Append(newName); queuedFileChange.mNewFileName = newFullPath; @@ -363,7 +375,19 @@ namespace IDE CheckFileCreated(newName); } else - QueueFileChanged(fileSystemWatcher, oldName, newName, .Renamed); + { + var newFilePath = scope String(); + GetPath(newName, newFilePath); + + if (Directory.Exists(newFilePath)) + { + let dirOldName = scope String()..Concat(oldName, Path.DirectorySeparatorChar); + let dirNewName = scope String()..Concat(newName, Path.DirectorySeparatorChar); + QueueFileChanged(fileSystemWatcher, dirOldName, dirNewName, .Renamed); + } + else + QueueFileChanged(fileSystemWatcher, oldName, newName, .Renamed); + } } }); fileSystemWatcher.OnError.Add(new () => QueueFileChanged(fileSystemWatcher, null, null, .Failed)); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 45e34fed..cc488d3e 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -321,6 +321,8 @@ namespace IDE None, File, Workspace, + NewWorkspace, + NewWorkspaceOrProject, CrashDump, DebugSession } @@ -766,7 +768,7 @@ namespace IDE mWorkspace.mName = new String(); Path.GetFileName(mWorkspace.mDir, mWorkspace.mName); - LoadWorkspace(); + LoadWorkspace(.OpenOrNew); FinishShowingNewWorkspace(); DeleteAndNullify!(mDeferredOpenFileName); @@ -1646,6 +1648,10 @@ namespace IDE bool SaveWorkspaceUserData(bool showErrors = true) { + // Don't save if we didn't finish creating the workspace + if (mWorkspace.mNeedsCreate) + return false; + if (mWorkspace.IsDebugSession) { bool hasUnsavedProjects = false; @@ -1740,35 +1746,9 @@ namespace IDE { if (!mWorkspace.IsSingleFileWorkspace) { - #if !CLI if (mWorkspace.mDir == null) { - /*SaveFileDialog dialog = scope .(); - dialog.ValidateNames = true; - dialog.DefaultExt = ".toml"; - dialog.SetFilter("Beef projects (BeefProj.toml)|BeefProj.toml"); - dialog.FileName = "BeefProj.toml"; - if (dialog.ShowDialog(GetActiveWindow()).GetValueOrDefault() != .OK) - return false; - - bool matches = false; - if (dialog.FileNames.Count == 1) - { - String fileName = scope .(); - Path.GetFileName(dialog.FileNames[0], fileName); - matches = fileName == "BeefProj.toml"; - } - - if (!matches) - { - Fail("Workspace name must be 'BeefProj.toml'"); - return false; - } - - mWorkspace.mDir = new String(); - Path.GetDirectoryPath(dialog.FileNames[0], mWorkspace.mDir);*/ - let activeWindow = GetActiveWindow(); FolderBrowserDialog folderDialog = scope FolderBrowserDialog(); @@ -1960,7 +1940,7 @@ namespace IDE ProjectOptionsChanged(project, false); } - public void CreateProject(String projName, String projDir, Project.TargetType targetType) + public Project CreateProject(String projName, String projDir, Project.TargetType targetType) { Project project = new Project(); project.mProjectName.Set(projName); @@ -1982,6 +1962,7 @@ namespace IDE mWorkspace.ClearProjectNameCache(); CurrentWorkspaceConfigChanged(); + return project; } void StopDebugging() @@ -2175,7 +2156,7 @@ namespace IDE return .Err; } - protected void LoadWorkspace() + protected void LoadWorkspace(BeefVerb verb) { scope AutoBeefPerf("IDEApp.LoadWorkspace"); @@ -2210,11 +2191,11 @@ namespace IDE LoadFailed(); return; case .FileError: // Assume 'file not found' - if (mVerb == .OpenOrNew) + if (verb == .OpenOrNew) { isNew = true; } - else if (mVerb == .New) + else if (verb == .New) { isNew = true; wantSave = true; @@ -2257,6 +2238,9 @@ namespace IDE project.mProjectPath.Set(mWorkspace.mDir); Utils.GetDirWithSlash(project.mProjectPath); project.mProjectPath.Append("BeefProj.toml"); + //project.FinishCreate(); + + project.FinishCreate(false); var verSpec = new VerSpecRecord(); verSpec.SetSemVer("*"); @@ -2922,7 +2906,7 @@ namespace IDE [IDECommand] public void Cmd_NewWorkspace() { - OpenWorkspace(); + mDeferredOpen = .NewWorkspaceOrProject; } [IDECommand] @@ -3107,7 +3091,7 @@ namespace IDE textPanel.ShowQuickFind(isReplace); else { - if (let activeWindow = GetActiveWindow() as WidgetWindow) + if (let activeWindow = GetActiveWindow()) { var widget = activeWindow.mFocusWidget; while (widget != null) @@ -3207,7 +3191,7 @@ namespace IDE } else { - if (let activeWindow = GetActiveWindow() as WidgetWindow) + if (let activeWindow = GetActiveWindow()) { var widget = activeWindow.mFocusWidget; while (widget != null) @@ -5030,11 +5014,16 @@ namespace IDE return null; } - public BFWindow GetActiveWindow() + public WidgetWindow GetActiveWindow() { for (let window in mWindows) if (window.mHasFocus) - return window; + { + var result = window; + while ((result.mWindowFlags.HasFlag(.Modal)) && (result.mParent != null)) + result = result.mParent; + return result as WidgetWindow; + } return mMainWindow; } @@ -5621,6 +5610,10 @@ namespace IDE if (showType == SourceShowType.Temp) { + let prevAutoClose = tabbedView.mAutoClose; + defer { tabbedView.mAutoClose = prevAutoClose; } + tabbedView.mAutoClose = false; + if (tabbedView.mRightTab != null) { CloseDocument(tabbedView.mRightTab.mContent); @@ -9147,7 +9140,7 @@ namespace IDE }); ((DarkButton)dlg.mButtons[0]).Label = "Open Link"; - dlg.PopupWindow(GetActiveWindow() as WidgetWindow); + dlg.PopupWindow(GetActiveWindow()); MessageBeep(.Error); #endif } @@ -9637,13 +9630,13 @@ namespace IDE { mWorkspace.mName = new String(); Path.GetFileName(mWorkspace.mDir, mWorkspace.mName); - LoadWorkspace(); + LoadWorkspace(mVerb); } else if (mWorkspace.IsSingleFileWorkspace) { mWorkspace.mName = new String(); Path.GetFileNameWithoutExtension(mWorkspace.mCompositeFile.mFilePath, mWorkspace.mName); - LoadWorkspace(); + LoadWorkspace(mVerb); } if ((mRunningTestScript) || (!LoadWorkspaceUserData())) @@ -11358,6 +11351,117 @@ namespace IDE DeleteAndNullify!(mDeferredUserRequest); } + void UpdateDeferredOpens() + { + void DoDeferredOpen(DeferredOpenKind openKind) + { + switch (openKind) + { + case .NewWorkspaceOrProject: + var dialog = ThemeFactory.mDefault.CreateDialog("Create Workspace?", + "Do you want to create an empty workspace or a new project?"); + dialog.AddButton("Empty Workspace", new (evt) => + { + mDeferredOpen = .NewWorkspace; + }); + dialog.AddButton("New Project", new (evt) => + { + CloseWorkspace(); + FinishShowingNewWorkspace(); + Cmd_NewProject(); + }); + dialog.PopupWindow(GetActiveWindow()); + case .NewWorkspace: + + if (mDeferredOpenFileName != null) + { + let directoryPath = scope String(); + Path.GetDirectoryPath(mDeferredOpenFileName, directoryPath); + + if (File.Exists(mDeferredOpenFileName)) + { + var dialog = ThemeFactory.mDefault.CreateDialog("Already Exists", + scope String()..AppendF("A Beef workspace already exists at '{}'. Do you want to open it?", directoryPath), + DarkTheme.sDarkTheme.mIconWarning); + dialog.mDefaultButton = dialog.AddButton("Yes", new (evt) => + { + DoOpenWorkspace(); + }); + dialog.AddButton("No", new (evt) => + { + DeleteAndNullify!(mDeferredOpenFileName); + }); + dialog.PopupWindow(GetActiveWindow()); + return; + } + else if (!IDEUtils.IsDirectoryEmpty(directoryPath)) + { + var dialog = ThemeFactory.mDefault.CreateDialog("Already Exists", + scope String()..AppendF("A non-empty directory already exists at '{}'. Are you sure you want to create a workspace there?", directoryPath), + DarkTheme.sDarkTheme.mIconWarning); + dialog.mDefaultButton = dialog.AddButton("Yes", new (evt) => + { + DoOpenWorkspace(); + }); + dialog.AddButton("No", new (evt) => + { + DeleteAndNullify!(mDeferredOpenFileName); + }); + dialog.PopupWindow(GetActiveWindow()); + return; + } + } + + DoOpenWorkspace(); + if (mDeferredOpen != .None) + mDeferredOpen = _; + case .Workspace: + DoOpenWorkspace(); + case .CrashDump: + DoOpenCrashDump(); + default: + } + } + + var deferredOpen = mDeferredOpen; + mDeferredOpen = .None; + switch (deferredOpen) + { + case .File: + DoOpenFile(); + case .CrashDump: + DoOpenCrashDump(); + case .Workspace, .NewWorkspace, .NewWorkspaceOrProject: + + if ((mDeferredOpenFileName == null) && (deferredOpen == .Workspace)) + { + DoDeferredOpen(_); + break; + } + + if (CheckCloseWorkspace(mMainWindow, + new () => + { + DoDeferredOpen(_); + }, + new () => + { + DoDeferredOpen(_); + }, + new () => + { + DeleteAndNullify!(mDeferredOpenFileName); + } + )) + { + DoDeferredOpen(_); + } + case .DebugSession: + DoOpenDebugSession(); + default: + } + } + public override void Update(bool batchStart) { scope AutoBeefPerf("IDEApp.Update"); @@ -11473,55 +11577,7 @@ namespace IDE if (mBfResolveSystem != null) mBfResolveSystem.PerfZoneEnd(); - void DoDeferredOpen(DeferredOpenKind openKind) - { - switch (openKind) - { - case .Workspace: - DoOpenWorkspace(); - case .CrashDump: - DoOpenCrashDump(); - default: - } - } - - var deferredOpen = mDeferredOpen; - mDeferredOpen = .None; - switch (deferredOpen) - { - case .File: - DoOpenFile(); - case .CrashDump: - DoOpenCrashDump(); - case .Workspace: - - if (mDeferredOpenFileName == null) - { - DoDeferredOpen(_); - break; - } - - if (CheckCloseWorkspace(mMainWindow, - new () => - { - DoDeferredOpen(_); - }, - new () => - { - DoDeferredOpen(_); - }, - new () => - { - DeleteAndNullify!(mDeferredOpenFileName); - } - )) - { - DoDeferredOpen(_); - } - case .DebugSession: - DoOpenDebugSession(); - default: - } + UpdateDeferredOpens(); mHaveSourcesChangedInternallySinceLastCompile = false; WithSourceViewPanels(scope (sourceViewPanel) => diff --git a/IDE/src/IDEUtils.bf b/IDE/src/IDEUtils.bf index 8df248b7..645c98b8 100644 --- a/IDE/src/IDEUtils.bf +++ b/IDE/src/IDEUtils.bf @@ -71,6 +71,15 @@ namespace IDE return true; } + public static bool IsDirectoryEmpty(StringView dirPath) + { + for (let entry in Directory.Enumerate(scope String()..AppendF("{}/*.*", dirPath), .Directories | .Files)) + { + return false; + } + return true; + } + public static bool FixFilePath(String filePath) { return FixFilePath(filePath, cNativeSlash, cOtherSlash); diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index c9adff3b..c9442bd8 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -391,13 +391,6 @@ namespace IDE public class ProjectFolder : ProjectFileItem { - public enum AutoIncludeKind - { - Default, - Always, - Never - } - public List mChildItems = new List() ~ { for (var projectItem in mChildItems) @@ -551,7 +544,7 @@ namespace IDE data.Add("Type", (mIncludeKind == .Ignore) ? "IgnoreFolder" : "Folder"); base.Serialize(data); if (mAutoInclude != (mIncludeKind == .Auto)) - data.Add("AutoInclude", mAutoInclude); + data.ConditionalAdd("AutoInclude", mAutoInclude, true); } if (!mChildItems.IsEmpty) { @@ -598,12 +591,12 @@ namespace IDE //var outer = data.Current; - bool autoInclude = data.GetBool("AutoInclude"); + bool doPopulate = false; + + bool autoInclude = data.GetBool("AutoInclude", true); if ((autoInclude) && (!mAutoInclude)) - { - mAutoInclude = true; - Populate(mPath); - } + doPopulate = true; + mAutoInclude = autoInclude; for (data.Enumerate("Items")) { @@ -670,6 +663,9 @@ namespace IDE projectItem.mPath = path; AddChild(projectItem); } + + if (doPopulate) + Populate(mPath); } public void Populate(String relDir) @@ -703,7 +699,11 @@ namespace IDE String dirName = scope String(); fileEntry.GetFileName(dirName); - if (dirName == "build") + // Why was this here? + /*if (dirName == "build") + continue;*/ + + if (mChildMap.ContainsKey(dirName)) continue; let newRelDir = scope String(relDir); @@ -1925,16 +1925,22 @@ namespace IDE mRootFolder.StartWatching(); } - public void FinishCreate() + public void FinishCreate(bool allowCreateDir = true) { - var path = scope String(); - mRootFolder.GetFullImportPath(path); - Directory.CreateDirectory(path).IgnoreError(); if (!mRootFolder.mIsWatching) { String fullPath = scope String(); mRootFolder.GetFullImportPath(fullPath); - Directory.CreateDirectory(fullPath).IgnoreError(); + if (Directory.Exists(fullPath)) + { + mRootFolder.Populate("src"); + } + else if (!allowCreateDir) + { + return; + } + else + Directory.CreateDirectory(fullPath).IgnoreError(); mRootFolder.StartWatching(); } mNeedsCreate = false; diff --git a/IDE/src/ui/NewProjectDialog.bf b/IDE/src/ui/NewProjectDialog.bf index 11271414..b2fdee5e 100644 --- a/IDE/src/ui/NewProjectDialog.bf +++ b/IDE/src/ui/NewProjectDialog.bf @@ -7,6 +7,7 @@ using Beefy; using Beefy.gfx; using Beefy.theme.dark; using Beefy.widgets; +using Beefy.theme; namespace IDE.ui { @@ -33,8 +34,14 @@ namespace IDE.ui mWidth = GS!(320); mHeight = GS!(200); } - - bool CreateProject() + + enum CreateFlags + { + None, + NonEmptyDirOkay = 1, + } + + bool CreateProject(CreateFlags createFlags = .None) { var app = IDEApp.sApp; String projName = scope String(); @@ -44,6 +51,13 @@ namespace IDE.ui mDirectoryEdit.GetText(projDirectory); projDirectory.Trim(); + if (projName.IsEmpty) + { + while ((projDirectory.EndsWith('/')) || (projDirectory.EndsWith('\\'))) + projDirectory.RemoveFromEnd(1); + Path.GetFileName(projDirectory, projName); + } + bool isNameValid = projName.Length > 0; for (int32 i = 0; i < projName.Length; i++) { @@ -75,6 +89,24 @@ namespace IDE.ui return false; } } + else + { + if ((!createFlags.HasFlag(.NonEmptyDirOkay)) && (!IDEUtils.IsDirectoryEmpty(projDirectory))) + { + var dialog = ThemeFactory.mDefault.CreateDialog("Create Project?", + scope String()..AppendF("The selected directory '{}' is not empty. Are you sure you want to create a project there?", projDirectory), DarkTheme.sDarkTheme.mIconWarning); + dialog.AddButton("Yes", new (evt) => + { + CreateProject(createFlags | .NonEmptyDirOkay); + }); + dialog.AddButton("No", new (evt) => + { + mDirectoryEdit.SetFocus(); + }); + dialog.PopupWindow(mWidgetWindow); + return false; + } + } String projectFilePath = scope String()..Append(projDirectory, "/BeefProj.toml"); if (File.Exists(projectFilePath)) @@ -93,7 +125,28 @@ namespace IDE.ui } IDEUtils.FixFilePath(projDirectory); - app.CreateProject(projName, projDirectory, targetType); + + Project project = null; + + // If we don't yet have a workspace then create one now... + if (!app.mWorkspace.IsInitialized) + { + app.mWorkspace.mDir = new String(projDirectory); + app.mWorkspace.mName = new String(projName); + + app.[Friend]LoadWorkspace(.OpenOrNew); + app.[Friend]FinishShowingNewWorkspace(false); + + project = app.mWorkspace.FindProject(projName); + if (project != null) + { + project.mGeneralOptions.mTargetType = targetType; + project.FinishCreate(); + } + } + + if (project == null) + project = app.CreateProject(projName, projDirectory, targetType); app.mWorkspace.SetChanged(); @@ -116,7 +169,7 @@ namespace IDE.ui { mDefaultButton = AddButton("Create", new (evt) => { if (!CreateProject()) evt.mCloseDialog = false; }); mEscButton = AddButton("Cancel", new (evt) => Close()); - mNameEdit = AddEdit("NewProject"); + mNameEdit = AddEdit(""); mNameEdit.mOnContentChanged.Add(new (dlg) => { UpdateProjectDir(); diff --git a/IDE/src/ui/PathEditWidget.bf b/IDE/src/ui/PathEditWidget.bf index 964c5e0a..d5e7f6a4 100644 --- a/IDE/src/ui/PathEditWidget.bf +++ b/IDE/src/ui/PathEditWidget.bf @@ -127,7 +127,7 @@ namespace IDE.ui if (nextSlash != -1) selStr.Append(editText, startSlash + 1, nextSlash - startSlash - 1); else - selStr.Append(editText, startSlash + 1, cursorPos - startSlash - 1); + selStr.Append(editText, startSlash + 1, Math.Max(cursorPos - startSlash - 1, 0)); String info = scope .(); info.Append("uncertain\n"); diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index 18e24778..a2b8ae0d 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -415,6 +415,8 @@ namespace IDE.ui { None = 0, ApplyAutoToChildren = 1, + ClearAutoItems = 2, + FullTraversal = 4, } public void RehupFolder(ProjectFolder projectFolder, RehupFlags rehupFlags = .None) @@ -429,7 +431,7 @@ namespace IDE.ui var dirPath = scope String(); projectFolder.GetFullImportPath(dirPath); - bool clearAutoItems = (!rehupFlags.HasFlag(.ApplyAutoToChildren)) && (projectFolder.mIncludeKind == .Auto); + bool clearAutoItems = (!rehupFlags.HasFlag(.ApplyAutoToChildren)) && (projectFolder.mAutoInclude); // && (rehupFlags.HasFlag(.ClearAutoItems)); HashSet foundAutoItems = scope .(); for (let fileEntry in Directory.EnumerateFiles(dirPath)) @@ -482,6 +484,8 @@ namespace IDE.ui projectItem.mIncludeKind = .Auto; if (projectItem.mIncludeKind == .Auto) RehupFolder(childProjectFolder, rehupFlags); + if ((clearAutoItems) && (projectItem.mIncludeKind == .Auto)) + foundAutoItems.Add(projectItem); } continue; } @@ -501,6 +505,11 @@ namespace IDE.ui childProjectFolder.mAutoInclude = true; projectFolder.AddChild(childProjectFolder); + if (clearAutoItems) + { + foundAutoItems.Add(childProjectFolder); + } + AddProjectItem(childProjectFolder); RehupFolder(childProjectFolder, rehupFlags); @@ -516,11 +525,19 @@ namespace IDE.ui for (int childIdx = projectFolder.mChildItems.Count - 1; childIdx >= 0; childIdx--) { var child = projectFolder.mChildItems[childIdx]; + + if (((rehupFlags.HasFlag(.ApplyAutoToChildren)) && (child.mIncludeKind == .Manual)) || ((clearAutoItems) && (child.mIncludeKind == .Auto) && (!foundAutoItems.Contains(child)))) { var listItem = mProjectToListViewMap[child]; DoDeleteItem(listItem, null, true); + continue; + } + + if ((rehupFlags.HasFlag(.FullTraversal)) && (child.mIncludeKind == .Manual) && (var childProjectFolder = child as ProjectFolder)) + { + RehupFolder(childProjectFolder, rehupFlags); } } } @@ -583,7 +600,7 @@ namespace IDE.ui dialog.mDefaultButton = dialog.AddButton("OK", new (evt) => DoNewClass(folder, evt)); dialog.mEscButton = dialog.AddButton("Cancel"); dialog.AddEdit("Unnamed"); - dialog.PopupWindow(mWidgetWindow); + dialog.PopupWindow(gApp.GetActiveWindow()); } void DoNewClass(ProjectFolder folder, DialogEvent evt) @@ -596,6 +613,8 @@ namespace IDE.ui return; let project = folder.mProject; + if (project.mNeedsCreate) + project.FinishCreate(); String relFileName = scope String(className, ".bf"); String fullFilePath = scope String(); @@ -680,6 +699,11 @@ namespace IDE.ui if (rightProjectItem == null) return 1; + if ((leftProjectItem.mParentFolder == null) && (rightProjectItem.mParentFolder == null)) + { + return String.Compare(leftProjectItem.mProject.mProjectName, rightProjectItem.mProject.mProjectName, true); + } + return ProjectItem.Compare(leftProjectItem, rightProjectItem); } @@ -811,7 +835,7 @@ namespace IDE.ui fileDialog.Multiselect = true; fileDialog.InitialDirectory = fullDir; fileDialog.ValidateNames = true; - mWidgetWindow.PreModalChild(); + gApp.GetActiveWindow().PreModalChild(); if (fileDialog.ShowDialog(gApp.GetActiveWindow()).GetValueOrDefault() == .OK) { if (mSelectedParentItem.mOpenButton != null) @@ -1291,7 +1315,7 @@ namespace IDE.ui aDialog.mDefaultButton = aDialog.AddButton("Yes", new (evt) => RemoveSelectedItems(false)); aDialog.mEscButton = aDialog.AddButton("No"); - aDialog.PopupWindow(mWidgetWindow); + aDialog.PopupWindow(gApp.GetActiveWindow()); } } else if((fileCount > 0) || (folderCount > 0)) @@ -1345,7 +1369,7 @@ namespace IDE.ui RemoveSelectedItems(true); }); aDialog.mEscButton = aDialog.AddButton("Cancel"); - aDialog.PopupWindow(mWidgetWindow); + aDialog.PopupWindow(gApp.GetActiveWindow()); } } } @@ -1591,7 +1615,7 @@ namespace IDE.ui Sort(); } ~ delete oldValue); - dialog.PopupWindow(mWidgetWindow); + dialog.PopupWindow(gApp.GetActiveWindow()); didRename = false; } @@ -1712,7 +1736,7 @@ namespace IDE.ui fileDialog.ValidateNames = true; fileDialog.DefaultExt = ".toml"; fileDialog.SetFilter("Beef projects (BeefProj.toml)|BeefProj.toml|All files (*.*)|*.*"); - mWidgetWindow.PreModalChild(); + gApp.GetActiveWindow().PreModalChild(); if (fileDialog.ShowDialog(gApp.GetActiveWindow()).GetValueOrDefault() == .OK) { for (String origProjFilePath in fileDialog.FileNames) @@ -1734,13 +1758,13 @@ namespace IDE.ui public void ShowProjectProperties(Project project) { var projectProperties = new ProjectProperties(project); - projectProperties.PopupWindow(mWidgetWindow); + projectProperties.PopupWindow(gApp.GetActiveWindow()); } public void ShowWorkspaceProperties() { var workspaceProperties = new WorkspaceProperties(); - workspaceProperties.PopupWindow(mWidgetWindow); + workspaceProperties.PopupWindow(gApp.GetActiveWindow()); } public void RehupProjects() @@ -1768,7 +1792,7 @@ namespace IDE.ui { var newProjectDialog = new NewProjectDialog(); newProjectDialog.Init(); - newProjectDialog.PopupWindow(mWidgetWindow); + newProjectDialog.PopupWindow(gApp.GetActiveWindow()); } protected override void ShowRightClickMenu(Widget relWidget, float x, float y) @@ -1832,6 +1856,55 @@ namespace IDE.ui if ((projectItem != null) && (!handled)) { Menu item = null; + + if (isProject) + { + item = menu.AddItem("Set as Startup Project"); + item.mOnMenuItemSelected.Add(new (item) => + { + var projectItem = GetSelectedProjectItem(); + if (projectItem != null) + SetAsStartupProject(projectItem.mProject); + }); + + item = menu.AddItem("Lock Project"); + if (projectItem.mProject.mLocked) + item.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check); + item.mOnMenuItemSelected.Add(new (item) => + { + var projectItem = GetSelectedProjectItem(); + if (projectItem != null) + { + projectItem.mProject.mLocked = !projectItem.mProject.mLocked; + gApp.mWorkspace.SetChanged(); + } + }); + + item = menu.AddItem("Refresh"); + item.mOnMenuItemSelected.Add(new (item) => + { + var projectItem = GetSelectedProjectItem(); + if (projectItem != null) + { + let project = projectItem.mProject; + if (project.mNeedsCreate) + { + project.FinishCreate(false); + RebuildUI(); + } + else + { + if (project.mRootFolder.mIsWatching) + project.mRootFolder.StopWatching(); + project.mRootFolder.StartWatching(); + RehupFolder(project.mRootFolder, .FullTraversal); + } + } + }); + + menu.AddItem(); + } + if ((projectItem != null) && (!isProject)) { item = menu.AddItem("Remove ..."); @@ -1933,7 +2006,7 @@ namespace IDE.ui RehupFolder(projectFolder); } }); - dialog.PopupWindow(mWidgetWindow); + dialog.PopupWindow(gApp.GetActiveWindow()); } else RehupFolder(projectFolder); @@ -1988,17 +2061,8 @@ namespace IDE.ui var process = scope SpawnedProcess(); process.Start(psi).IgnoreError(); }); - } - if (isProject) - { - item = menu.AddItem("Set as Startup Project"); - item.mOnMenuItemSelected.Add(new (item) => - { - var projectItem = GetSelectedProjectItem(); - if (projectItem != null) - SetAsStartupProject(projectItem.mProject); - }); + menu.AddItem(); } //menu.AddItem(); @@ -2026,19 +2090,7 @@ namespace IDE.ui if (isProject) { - item = menu.AddItem("Lock Project"); - if (projectItem.mProject.mLocked) - item.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check); - item.mOnMenuItemSelected.Add(new (item) => - { - var projectItem = GetSelectedProjectItem(); - if (projectItem != null) - { - projectItem.mProject.mLocked = !projectItem.mProject.mLocked; - gApp.mWorkspace.SetChanged(); - } - }); - + menu.AddItem(); item = menu.AddItem("Properties..."); item.mOnMenuItemSelected.Add(new (item) => { @@ -2047,7 +2099,6 @@ namespace IDE.ui ShowProjectProperties(projectItem.mProject); }); } - } /*else if (!handled) { @@ -2070,7 +2121,6 @@ namespace IDE.ui mMenuWidget = null; }); - //menuWidget.mWidgetWindow.mWindowClosedHandler.Add(new => DeselectFolder); } void ListViewItemClicked(MouseEvent theEvent) diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 43cc5cb1..0dc38c05 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -1315,6 +1315,9 @@ namespace IDE.ui { var editWidgetContent = (SourceEditWidgetContent)mEditWidget.Content; + if (mWidgetWindow == null) + return; + bool wantOpen = (autocompleteInfo.Length > 0); if ((editWidgetContent.mAutoComplete != null) && (editWidgetContent.mAutoComplete.mIsAsync) && (editWidgetContent.mAutoComplete.mInvokeWidget != null))