From a112fcc64a49033746f9369419d37871b9ce38ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Mon, 14 Aug 2023 22:10:27 +0200 Subject: [PATCH] Automatic switch between Player <-> Editor Tabs + Allow Editor to inject into Settings --- GlitchyEditor/src/EditorLayer.bf | 29 ++++ GlitchyEditor/src/EditorSettings.bf | 47 +++++++ GlitchyEditor/src/SettingsWindow.bf | 209 ++++++++++++++++------------ GlitchyEngine/src/Settings.bf | 10 +- 4 files changed, 203 insertions(+), 92 deletions(-) create mode 100644 GlitchyEditor/src/EditorSettings.bf diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 2d96ad1..2173d0a 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -711,6 +711,20 @@ namespace GlitchyEditor #endregion Project Management #region Scene Management + + /// Focuses the Play window, so that its tab will be shown. + private void SwitchToPlayWindow() + { + let window = ImGui.FindWindowByName(GameViewportWindow.s_WindowTitle); + ImGui.FocusWindow(window); + } + + /// Focuses the Editor window, so that its tab will be shown. + private void SwitchToEditorWindow() + { + let window = ImGui.FindWindowByName(EditorViewportWindow.s_WindowTitle); + ImGui.FocusWindow(window); + } /// Starts the play mode for the current scene private void OnScenePlay() @@ -728,6 +742,9 @@ namespace GlitchyEditor } _editor.CurrentScene = _activeScene; + + if (Application.Instance.Settings.EditorSettings.SwitchToPlayerOnPlay) + SwitchToPlayWindow(); } /// Starts the physics simulation mode for the current scene @@ -746,18 +763,27 @@ namespace GlitchyEditor } _editor.CurrentScene = _activeScene; + + if (Application.Instance.Settings.EditorSettings.SwitchToPlayerOnSimulate) + SwitchToPlayWindow(); } /// Pauses the scene private void OnScenePause() { _isPaused = true; + + if (Application.Instance.Settings.EditorSettings.SwitchToEditorOnPause) + SwitchToEditorWindow(); } /// Resumes the simulation / game private void OnSceneResume() { _isPaused = false; + + if (Application.Instance.Settings.EditorSettings.SwitchToPlayerOnResume) + SwitchToPlayWindow(); } /// Requests execution of a single simulation / game tick @@ -792,6 +818,9 @@ namespace GlitchyEditor */ GameViewportSizeChanged(null, _editor.GameViewportWindow.ViewportSize); } + + if (Application.Instance.Settings.EditorSettings.SwitchToEditorOnStop) + SwitchToEditorWindow(); } /// Stops the scene and cleans up the subsystems to allow loading another scene. diff --git a/GlitchyEditor/src/EditorSettings.bf b/GlitchyEditor/src/EditorSettings.bf new file mode 100644 index 0000000..cbd894b --- /dev/null +++ b/GlitchyEditor/src/EditorSettings.bf @@ -0,0 +1,47 @@ +using System; +using GlitchyEngine; +using Bon; +using GlitchyEditor; +using System.Collections; + +namespace GlitchyEngine +{ + extension Settings + { + [SettingContainer, BonInclude] + public readonly EditorSettings EditorSettings = new .() ~ delete _; + + public this() + { + OnApplySettings.Add(new (s, e) => EditorSettings.Apply()); + } + } +} + +namespace GlitchyEditor; + +[Reflect] +class EditorSettings +{ + [Setting("Editor", "Switch to Player on play", "If checked the editor will automatically switch to the \"Play\" window after starting the game."), BonInclude] + public bool SwitchToPlayerOnPlay = true; + + [Setting("Editor", "Switch to Player on simulate", "If checked the editor will automatically switch to the \"Play\" window after starting the simulation."), BonInclude] + public bool SwitchToPlayerOnSimulate = true; + + [Setting("Editor", "Switch to Player on continue", "If checked the editor will automatically switch to the \"Play\" window when the game is continued after pausing."), BonInclude] + public bool SwitchToPlayerOnResume = false; + + [Setting("Editor", "Switch to Editor on stop", "If checked the editor will automatically switch to the \"Editor\" window after stopping the game."), BonInclude] + public bool SwitchToEditorOnStop = true; + + [Setting("Editor", "Switch to Editor on pause", "If checked the editor will automatically switch to the \"Editor\" window when the game is being paused."), BonInclude] + public bool SwitchToEditorOnPause = false; + + // + //public readonly List RecentProjects = new .() ~ delete _; + + public void Apply() + { + } +} \ No newline at end of file diff --git a/GlitchyEditor/src/SettingsWindow.bf b/GlitchyEditor/src/SettingsWindow.bf index a279ec5..7452c3a 100644 --- a/GlitchyEditor/src/SettingsWindow.bf +++ b/GlitchyEditor/src/SettingsWindow.bf @@ -14,12 +14,14 @@ namespace GlitchyEditor public Object SettingsObject; public String Name ~ delete _; public String FieldName ~ delete _; + public StringView Tooltip; - public this(StringView name, StringView fieldName, Object settingsObject) + public this(StringView name, StringView fieldName, Object settingsObject, StringView tooltip) { Name = new String(name); FieldName = new String(fieldName); SettingsObject = settingsObject; + Tooltip = tooltip; } } @@ -36,9 +38,9 @@ namespace GlitchyEditor Header = new String(header); } - public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null) + public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null, StringView tooltip = "") { - Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject); + Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject, tooltip); _bindings.Add(binding); } } @@ -89,7 +91,7 @@ namespace GlitchyEditor if (settingResult case .Ok(let settingInfo)) { - AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container); + AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container, settingInfo.Tooltip); } Result containerResult = field.GetCustomAttribute(); @@ -110,11 +112,11 @@ namespace GlitchyEditor } } - void AddSetting(String categoryName, String name, StringView fieldName, Object container) + void AddSetting(String categoryName, String name, StringView fieldName, Object container, StringView tooltip) { Category category = AddCategory(categoryName); - category.AddSetting(name, fieldName, container); + category.AddSetting(name, fieldName, container, tooltip); } protected override void InternalShow() @@ -131,90 +133,7 @@ namespace GlitchyEditor { if (ImGui.BeginTabItem(category.Header)) { - ImGui.Columns(2); - defer ImGui.Columns(1); - ImGui.SetColumnWidth(0, 100); - - for (Binding setting in category._bindings) - { - ImGui.TextUnformatted(setting.Name); - - ImGui.NextColumn(); - - Type settingsObjectType = setting.SettingsObject.GetType(); - - Result result = settingsObjectType.GetField(setting.FieldName); - - if (result case .Err) - { - ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f)); - ImGui.Text($"Field {setting.FieldName} not found."); - ImGui.PopStyleColor(); - - continue; - } - - FieldInfo fieldInfo = result.Get(); - - Type fieldType = fieldInfo.FieldType; - - mixin GetSettingValue() - { - var error = fieldInfo.GetValue(setting.SettingsObject, var value); - - if (error case .Err(let err)) - { - Log.EngineLogger.Error($"Could not get value of setting {setting.FieldName}. Error: {err}"); - - ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f)); - ImGui.Text($"Could not get value of setting {setting.FieldName}. Error: {err}"); - ImGui.PopStyleColor(); - - break; - } - - value - } - - mixin SetSettingValue(T value) - { - var error = fieldInfo.SetValue(setting.SettingsObject, value); - - if (error case .Err(let err)) - { - Log.EngineLogger.Error($"Could not set value of setting {setting.FieldName}. Error: {err}"); - } - } - - switch (fieldType) - { - case typeof(int32): - int32 value = GetSettingValue!(); - - if (!ImGui.InputInt(scope $"##{setting.Name}", &value)) - break; - - SetSettingValue!(value); - - _settingsChanged = true; - case typeof(String): - String value = GetSettingValue!(); - - char8[256] buffer = .(); - - value.CopyTo(buffer); - - if (ImGui.InputText(scope $"##{setting.Name}", &buffer, buffer.Count)) - { - value..Clear().Append(&buffer); - - _settingsChanged = true; - } - } - - ImGui.NextColumn(); - } - + ShowCategory(category); ImGui.EndTabItem(); } } @@ -249,5 +168,115 @@ namespace GlitchyEditor _open = false; } } + + private void ShowCategory(Category category) + { + if (ImGui.BeginTable("SettingsTable", 2, .SizingFixedFit | .RowBg)) + { + ImGui.TableSetupColumn("Settings"); + ImGui.TableSetupColumn("Values", .WidthStretch); + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(1); + ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x); + + for (Binding setting in category._bindings) + { + ImGui.TableNextRow(); + + ImGui.TableNextColumn(); + + // Name of setting + ImGui.TextUnformatted(setting.Name); + + if (!setting.Tooltip.IsWhiteSpace) + ImGui.AttachTooltip(setting.Tooltip); + + ImGui.TableNextColumn(); + + Type settingsObjectType = setting.SettingsObject.GetType(); + + Result result = settingsObjectType.GetField(setting.FieldName); + + if (result case .Err) + { + ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f)); + ImGui.Text($"Field {setting.FieldName} not found."); + ImGui.PopStyleColor(); + + continue; + } + + FieldInfo fieldInfo = result.Get(); + + Type fieldType = fieldInfo.FieldType; + + mixin GetSettingValue() + { + var error = fieldInfo.GetValue(setting.SettingsObject, var value); + + if (error case .Err(let err)) + { + Log.EngineLogger.Error($"Could not get value of setting {setting.FieldName}. Error: {err}"); + + ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f)); + ImGui.Text($"Could not get value of setting {setting.FieldName}. Error: {err}"); + ImGui.PopStyleColor(); + + break; + } + + value + } + + mixin SetSettingValue(T value) + { + var error = fieldInfo.SetValue(setting.SettingsObject, value); + + if (error case .Err(let err)) + { + Log.EngineLogger.Error($"Could not set value of setting {setting.FieldName}. Error: {err}"); + } + } + + switch (fieldType) + { + case typeof(bool): + let value = GetSettingValue!(); + + if (!ImGui.Checkbox(scope $"##{setting.Name}", &value)) + break; + + SetSettingValue!(value); + + _settingsChanged = true; + case typeof(int32): + int32 value = GetSettingValue!(); + + if (!ImGui.InputInt(scope $"##{setting.Name}", &value)) + break; + + SetSettingValue!(value); + + _settingsChanged = true; + case typeof(String): + String value = GetSettingValue!(); + + char8[256] buffer = .(); + + value.CopyTo(buffer); + + if (ImGui.InputText(scope $"##{setting.Name}", &buffer, buffer.Count)) + { + value..Clear().Append(&buffer); + + _settingsChanged = true; + } + } + } + + ImGui.EndTable(); + } + } } } \ No newline at end of file diff --git a/GlitchyEngine/src/Settings.bf b/GlitchyEngine/src/Settings.bf index c5ff25d..66b26fe 100644 --- a/GlitchyEngine/src/Settings.bf +++ b/GlitchyEngine/src/Settings.bf @@ -23,11 +23,13 @@ namespace GlitchyEngine { public String Category; public String Name; + public String Tooltip; - public this(String category, String name) + public this(String category, String name, String tooltip = "") { Category = category; Name = name; + Tooltip = tooltip; } } @@ -38,6 +40,8 @@ namespace GlitchyEngine [SettingContainer, BonInclude] public readonly ImGuiSettings ImGuiSettings = new .() ~ delete _; #endif + [BonIgnore] + public Event OnApplySettings = .() ~ _.Dispose(); /* [BonInclude] @@ -57,6 +61,8 @@ namespace GlitchyEngine ImGuiSettings.Apply(); #endif + OnApplySettings.Invoke(this, .Empty); + /*for (let settings in _userSettings) { settings.Apply(); @@ -119,7 +125,7 @@ namespace GlitchyEngine public void Apply() { - Application.Get().[Friend]_imGuiLayer.SettingsInvalid = true; + Application.Instance.[Friend]_imGuiLayer.SettingsInvalid = true; } } #endif