From ecfe838ad4563d37c1be291c561b3f813a7dbb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Tue, 8 Jul 2025 19:35:40 +0200 Subject: [PATCH] Added basic central popup service and way to highlight settings. --- .../src/CodeEditors/RiderIdeAdapter.bf | 22 +++ .../src/EditWindows/ContentBrowserWindow.bf | 2 +- GlitchyEditor/src/EditWindows/PopupService.bf | 83 ++++++++++++ GlitchyEditor/src/Editor.bf | 11 ++ GlitchyEditor/src/EditorLayer.bf | 127 ++++++++---------- GlitchyEditor/src/SettingsWindow.bf | 70 +++++++++- GlitchyEngine/src/Settings.bf | 10 +- 7 files changed, 246 insertions(+), 79 deletions(-) create mode 100644 GlitchyEditor/src/EditWindows/PopupService.bf diff --git a/GlitchyEditor/src/CodeEditors/RiderIdeAdapter.bf b/GlitchyEditor/src/CodeEditors/RiderIdeAdapter.bf index 9c7e1a3..6e646b5 100644 --- a/GlitchyEditor/src/CodeEditors/RiderIdeAdapter.bf +++ b/GlitchyEditor/src/CodeEditors/RiderIdeAdapter.bf @@ -2,6 +2,10 @@ using System; using System.Diagnostics; using GlitchyEngine; using System.Collections; +using System.IO; +using System.IO; +using GlitchyEditor.EditWindows; +using ImGui; namespace GlitchyEditor.CodeEditors; @@ -29,6 +33,23 @@ class RiderIdeAdapter : IIdeAdapter String solutionPath = scope .(); Editor.Instance.CurrentProject.PathInProject(solutionPath, scope $"{Editor.Instance.CurrentProject.Name}.sln"); + if (!File.Exists(solutionPath)) + { + Log.EngineLogger.Error("Could not find solution file?"); + return; + } + + if (!File.Exists(Application.Instance.Settings.ScriptSettings.RiderPath)) + { + Editor.Instance.ShowSettings(); + Editor.Instance.SettingsWindow.HighlightSetting("Tools", "Rider path"); + + PopupService.Instance.ShowMessageBox("Rider not found.", + "The rider path could not be found. Please select the correct path."); + + return; + } + ProcessStartInfo startInfo = scope .(); startInfo.SetFileName(Application.Instance.Settings.ScriptSettings.RiderPath); startInfo.SetArguments(solutionPath); @@ -36,3 +57,4 @@ class RiderIdeAdapter : IIdeAdapter scope SpawnedProcess().Start(startInfo); } } + diff --git a/GlitchyEditor/src/EditWindows/ContentBrowserWindow.bf b/GlitchyEditor/src/EditWindows/ContentBrowserWindow.bf index 6373130..c8386bb 100644 --- a/GlitchyEditor/src/EditWindows/ContentBrowserWindow.bf +++ b/GlitchyEditor/src/EditWindows/ContentBrowserWindow.bf @@ -1199,7 +1199,7 @@ namespace GlitchyEditor.EditWindows } } - /// Shows the context menu for the given file/folder. + /// Shows the context menu for the selected files and directories. private void ShowItemContextMenu() { bool singleEntry = _selectedFiles.Count == 1; diff --git a/GlitchyEditor/src/EditWindows/PopupService.bf b/GlitchyEditor/src/EditWindows/PopupService.bf new file mode 100644 index 0000000..d1cac96 --- /dev/null +++ b/GlitchyEditor/src/EditWindows/PopupService.bf @@ -0,0 +1,83 @@ +using System; +using ImGui; +using System.Collections; +using GlitchyEngine; +namespace GlitchyEditor.EditWindows; + +class Popup +{ + public String Title ~ delete _; + public ImGui.WindowFlags WindowFlags; + + public delegate void(out bool) Render ~ delete _; + + public this(StringView title, delegate void(out bool) render, ImGui.WindowFlags flags) + { + Title = new String(title); + Render = render; + WindowFlags = flags; + } +} + +class PopupService +{ + private static PopupService _service = new PopupService() ~ delete _; + + public static PopupService Instance => _service; + + private append List _popups = .() ~ ClearAndDeleteItems(_); + + public void OpenPopup(StringView popupTitle, delegate void(out bool) render, ImGui.WindowFlags flags = .AlwaysAutoResize | .NoSavedSettings | .NoResize) + { + Popup popup = new Popup(popupTitle, render, flags); + _popups.Add(popup); + + Log.EngineLogger.Info($"Opened {popupTitle}"); + } + + public void ShowMessageBox(StringView title, StringView message) + { + String messageCopy = new String(message); + + OpenPopup(title, new (close) => + { + close = false; + + ImGui.NewLine(); + + ImGui.TextUnformatted(messageCopy); + + ImGui.NewLine(); + + if (ImGui.Button("Ok")) + { + delete messageCopy; + close = true; + } + } + ); + } + + public void ImGuiDraw() + { + for (Popup popup in _popups) + { + ImGui.OpenPopup(popup.Title); + + let center = ImGui.GetWindowViewport().GetCenter(); + ImGui.SetNextWindowPos(center, .Appearing, .(0.5f, 0.5f)); + if (ImGui.BeginPopupModal(popup.Title, null, popup.WindowFlags)) + { + popup.Render(let close); + if (close) + { + ImGui.CloseCurrentPopup(); + @popup.Remove(); + delete popup; + } + + ImGui.EndPopup(); + } + } + } +} \ No newline at end of file diff --git a/GlitchyEditor/src/Editor.bf b/GlitchyEditor/src/Editor.bf index 77b250a..6882a0a 100644 --- a/GlitchyEditor/src/Editor.bf +++ b/GlitchyEditor/src/Editor.bf @@ -27,6 +27,7 @@ namespace GlitchyEditor private InspectorWindow _inspectorWindow ~ delete _; private AssetViewer _assetViewer ~ delete _; private LogWindow _logWindow ~ delete _; + private SettingsWindow _settingsWindow ~ delete _; private List _windows = new .() ~ DeleteContainerAndItems!(_); @@ -67,6 +68,7 @@ namespace GlitchyEditor public InspectorWindow InspectorWindow => _inspectorWindow; public AssetViewer AssetViewer => _assetViewer; public LogWindow LogWindow => _logWindow; + public SettingsWindow SettingsWindow => _settingsWindow; public EditorCamera* CurrentCamera { get; set; } @@ -108,10 +110,13 @@ namespace GlitchyEditor _inspectorWindow = new InspectorWindow(this); _assetViewer = new AssetViewer((.)Application.Get().ContentManager); _logWindow = new LogWindow(); + _settingsWindow = new SettingsWindow(); } public void Update() { + PopupService.Instance.ImGuiDraw(); + _sceneViewportWindow.Show(); _gameViewportWindow.Show(); _entityHierarchyWindow.Show(); @@ -120,6 +125,7 @@ namespace GlitchyEditor _inspectorWindow.Show(); _assetViewer.Show(); _logWindow.Show(); + _settingsWindow.Show(); for (ClosableWindow window in _windows) window.Show(); @@ -135,5 +141,10 @@ namespace GlitchyEditor _windows.Remove(closableWindow); delete closableWindow; } + + public void ShowSettings() + { + _settingsWindow.Open = true; + } } } diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 90aaa59..626d209 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -63,8 +63,6 @@ namespace GlitchyEditor RenderTargetGroup _editorViewportTarget ~ _.ReleaseRef(); RenderTargetGroup _gameViewportTarget ~ _.ReleaseRef(); - SettingsWindow _settingsWindow = new .() ~ delete _; - ProjectUserSettings _projectUserSettings; EditorCamera _camera ~ _.Dispose(); @@ -656,91 +654,83 @@ namespace GlitchyEditor return .Ok; } - /// If set to true, the popup for creating a new project will be shown. - private bool _openCreateProjectModal; - - private void ShowCreateNewProjectModal() + public void OpenCreateNewProjectModal() { + PopupService.Instance.OpenPopup("Create new Project", new => ShowCreateNewProjectModal); + } + + private void ShowCreateNewProjectModal(out bool close) + { + close = false; + static char8[128] projectNameBuffer = .(); - static char8[256] projectDirectoryBuffer = .(); - - if (_openCreateProjectModal) - { - ImGui.OpenPopup("Create new Project"); - _openCreateProjectModal = false; - - projectNameBuffer = .(); - } + static char8[1024] projectDirectoryBuffer = .(); // Always center this window when appearing var center = ImGui.GetMainViewport().GetCenter(); ImGui.SetNextWindowPos(center, .Appearing, .(0.5f, 0.5f)); - if (ImGui.BeginPopupModal("Create new Project", null, .AlwaysAutoResize)) + ImGui.TextUnformatted("Project Name:"); + ImGui.InputText("##projectName", &projectNameBuffer, projectNameBuffer.Count - 1); + + StringView projectName = StringView(&projectNameBuffer); + + if (projectName.IsWhiteSpace) { - ImGui.TextUnformatted("Project Name:"); - ImGui.InputText("##projectName", &projectNameBuffer, projectNameBuffer.Count - 1); - - StringView projectName = StringView(&projectNameBuffer); + ImGui.TextColored(.(1, 0, 0, 1), "Project Name required!"); + } - if (projectName.IsWhiteSpace) + ImGui.NewLine(); + + ImGui.TextUnformatted("Directory:"); + ImGui.InputText("##directory", &projectDirectoryBuffer, projectDirectoryBuffer.Count - 1); + ImGui.SameLine(); + + if (ImGui.Button("...")) + { + FolderBrowserDialog folderDialog = scope FolderBrowserDialog(); + Result result = folderDialog.ShowDialog(); + + if (result case .Ok(let dialogResult) && dialogResult case .OK) { - ImGui.TextColored(.(1, 0, 0, 1), "Project Name required!"); + folderDialog.SelectedPath.CopyTo(projectDirectoryBuffer); } + } - ImGui.NewLine(); + StringView directory = StringView(&projectDirectoryBuffer); - ImGui.TextUnformatted("Directory:"); - ImGui.InputText("##directory", &projectDirectoryBuffer, projectDirectoryBuffer.Count - 1); - ImGui.SameLine(); + String target = scope String(); + Path.Combine(target, directory, projectName); + + ImGui.NewLine(); - if (ImGui.Button("...")) - { - FolderBrowserDialog folderDialog = scope FolderBrowserDialog(); - Result result = folderDialog.ShowDialog(); + ImGui.Text($"The Project will be in:\n{target}"); - if (result case .Ok(let dialogResult) && dialogResult case .OK) - { - folderDialog.SelectedPath.CopyTo(projectDirectoryBuffer); - } - } + if (Directory.Exists(target) && !Directory.IsEmpty(target)) + { + ImGui.TextColored(.(1, 1, 0, 1), "The directory is not empty!"); + } - StringView directory = StringView(&projectDirectoryBuffer); + ImGui.NewLine(); - String target = scope String(); - Path.Combine(target, directory, projectName); - - ImGui.NewLine(); + ImGui.BeginDisabled(directory.IsWhiteSpace || projectName.IsWhiteSpace); - ImGui.Text($"The Project will be in:\n{target}"); + if (ImGui.Button("Create")) + { + Result result = CreateNewProject(target, projectName); - if (Directory.Exists(target) && !Directory.IsEmpty(target)) - { - ImGui.TextColored(.(1, 1, 0, 1), "The directory is not empty!"); - } + if (result case .Ok) + close = true; - ImGui.NewLine(); + } - ImGui.BeginDisabled(directory.IsWhiteSpace || projectName.IsWhiteSpace); + ImGui.EndDisabled(); - if (ImGui.Button("Create")) - { - Result result = CreateNewProject(target, projectName); + ImGui.SameLine(); - if (result case .Ok) - ImGui.CloseCurrentPopup(); - } - - ImGui.EndDisabled(); - - ImGui.SameLine(); - - if (ImGui.Button("Cancel")) - { - ImGui.CloseCurrentPopup(); - } - - ImGui.EndPopup(); + if (ImGui.Button("Cancel")) + { + close = true; } } @@ -1209,9 +1199,6 @@ namespace GlitchyEditor _editor.Update(); - _settingsWindow.Show(); - ShowCreateNewProjectModal(); - return false; } @@ -1479,7 +1466,7 @@ namespace GlitchyEditor ImGui.Separator(); if (ImGui.MenuItem("Create new Project...", "Ctrl+ALT+N")) - _openCreateProjectModal = true; + OpenCreateNewProjectModal(); if (ImGui.MenuItem("Open Project...", "Ctrl+ALT+O")) ShowOpenProjectDialog(); @@ -1493,7 +1480,7 @@ namespace GlitchyEditor ImGui.Separator(); if (ImGui.MenuItem("Settings")) - _settingsWindow.Open = true; + Editor.Instance.SettingsWindow.Open = true; ImGui.Separator(); @@ -1611,7 +1598,7 @@ namespace GlitchyEditor case .N: if (alt) // "Create new Project..." - _openCreateProjectModal = true; + OpenCreateNewProjectModal(); else // "New Scene" CreateAndOpenNewScene(); diff --git a/GlitchyEditor/src/SettingsWindow.bf b/GlitchyEditor/src/SettingsWindow.bf index 95d89b8..fec1330 100644 --- a/GlitchyEditor/src/SettingsWindow.bf +++ b/GlitchyEditor/src/SettingsWindow.bf @@ -4,6 +4,8 @@ using GlitchyEngine; using System; using System.Collections; using System.Reflection; +using GlitchyEngine.Math; +using System.IO; namespace GlitchyEditor { @@ -15,13 +17,15 @@ namespace GlitchyEditor public String Name ~ delete _; public String FieldName ~ delete _; public StringView Tooltip; + public SettingEditor EditorType; - public this(StringView name, StringView fieldName, Object settingsObject, StringView tooltip) + public this(StringView name, StringView fieldName, Object settingsObject, StringView tooltip, SettingEditor editorType) { Name = new String(name); FieldName = new String(fieldName); SettingsObject = settingsObject; Tooltip = tooltip; + EditorType = editorType; } } @@ -38,9 +42,9 @@ namespace GlitchyEditor Header = new String(header); } - public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null, StringView tooltip = "") + public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null, StringView tooltip = "", SettingEditor editorType = .Default) { - Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject, tooltip); + Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject, tooltip, editorType); _bindings.Add(binding); } } @@ -91,7 +95,7 @@ namespace GlitchyEditor if (settingResult case .Ok(let settingInfo)) { - AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container, settingInfo.Tooltip); + AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container, settingInfo.Tooltip, settingInfo.EditorMode); } Result containerResult = field.GetCustomAttribute(); @@ -112,11 +116,22 @@ namespace GlitchyEditor } } - void AddSetting(String categoryName, String name, StringView fieldName, Object container, StringView tooltip) + void AddSetting(String categoryName, String name, StringView fieldName, Object container, StringView tooltip, SettingEditor settingEditor) { Category category = AddCategory(categoryName); - category.AddSetting(name, fieldName, container, tooltip); + category.AddSetting(name, fieldName, container, tooltip, settingEditor); + } + + private String _tabToSelect = new String() ~ delete _; + private String _SettingToHighlight = new String() ~ delete _; + private float _timeToHighlight; + + public void HighlightSetting(StringView tabName, StringView settingName = "") + { + _tabToSelect.Set(tabName); + _SettingToHighlight.Set(settingName); + _timeToHighlight = 10; } protected override void InternalShow() @@ -131,7 +146,15 @@ namespace GlitchyEditor for (Category category in _categories.Values) { - if (ImGui.BeginTabItem(category.Header)) + ImGui.TabItemFlags flags = .None; + + if (_tabToSelect == category.Header) + { + flags |= .SetSelected; + _tabToSelect.Clear(); + } + + if (ImGui.BeginTabItem(category.Header, null, flags)) { ShowCategory(category); ImGui.EndTabItem(); @@ -260,6 +283,7 @@ namespace GlitchyEditor _settingsChanged = true; case typeof(String): + String value = GetSettingValue!(); char8[256] buffer = .(); @@ -275,6 +299,38 @@ namespace GlitchyEditor _settingsChanged = true; } + + /*if (setting.EditorType == .FilePath) + { + ImGui.SameLine(); + + if (ImGui.Button("...")) + { + OpenFileDialog ofd = scope .(); + ofd.InitialDirectory = value; + ofd.SetFilter("All Files (*.*)|*.*"); + ofd.Multiselect = false; + + if (ofd.ShowDialog() case .Ok(let result) && result == .OK) + { + SetSettingValue!(new String(ofd.FileNames[0])); + } + } + }*/ + } + + if (setting.Name == _SettingToHighlight) + { + let min = (float2)ImGui.GetItemRectMin() - 2; + let max = (float2)ImGui.GetItemRectMax() + 2; + + ImGui.DrawRect((.)min, (.)max, (.)ColorRGBA.Yellow); + + _timeToHighlight -= Application.Instance.GameTime.DeltaTime; + if (_timeToHighlight < 0) + { + _SettingToHighlight.Clear(); + } } /*if (fieldInfo.FieldType.IsEnum) diff --git a/GlitchyEngine/src/Settings.bf b/GlitchyEngine/src/Settings.bf index e7cc89c..7ae9753 100644 --- a/GlitchyEngine/src/Settings.bf +++ b/GlitchyEngine/src/Settings.bf @@ -17,6 +17,12 @@ namespace GlitchyEngine { } + enum SettingEditor + { + case Default; + case Path;//(bool MultiSelect, bool OpenFolderDialog, StringView Filter); + } + /// Fields with this Attribute will be exposed as settings. [AttributeUsage(.Field, .ReflectAttribute)] struct SettingAttribute : Attribute @@ -24,12 +30,14 @@ namespace GlitchyEngine public String Category; public String Name; public String Tooltip; + public SettingEditor EditorMode; - public this(String category, String name, String tooltip = "") + public this(String category, String name, String tooltip = "", SettingEditor editorMode = .Default) { Category = category; Name = name; Tooltip = tooltip; + EditorMode = editorMode; } }