set text editor theme on startup and change

This commit is contained in:
Matt Parker
2026-01-31 14:16:25 +10:00
parent 11c5bf2bcb
commit ccf55440ed
8 changed files with 58 additions and 8 deletions

View File

@@ -63,6 +63,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
public override void _Ready() public override void _Ready()
{ {
UpdateEditorThemeForCurrentTheme();
SyntaxHighlighter = _syntaxHighlighter; SyntaxHighlighter = _syntaxHighlighter;
_popupMenu = GetNode<PopupMenu>("CodeFixesMenu"); _popupMenu = GetNode<PopupMenu>("CodeFixesMenu");
_aboveCanvasItem = GetNode<CanvasItem>("%AboveCanvasItem"); _aboveCanvasItem = GetNode<CanvasItem>("%AboveCanvasItem");
@@ -80,6 +81,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
SymbolLookup += OnSymbolLookup; SymbolLookup += OnSymbolLookup;
LinesEditedFrom += OnLinesEditedFrom; LinesEditedFrom += OnLinesEditedFrom;
GlobalEvents.Instance.SolutionAltered.Subscribe(OnSolutionAltered); GlobalEvents.Instance.SolutionAltered.Subscribe(OnSolutionAltered);
GodotGlobalEvents.Instance.TextEditorThemeChanged.Subscribe(UpdateEditorThemeAsync);
SetCodeRegionTags("#region", "#endregion"); SetCodeRegionTags("#region", "#endregion");
//AddGitGutter(); //AddGitGutter();
} }
@@ -162,6 +164,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
_currentFile?.FileDeleted.Unsubscribe(OnFileDeleted); _currentFile?.FileDeleted.Unsubscribe(OnFileDeleted);
_projectDiagnosticsObserveDisposable?.Dispose(); _projectDiagnosticsObserveDisposable?.Dispose();
GlobalEvents.Instance.SolutionAltered.Unsubscribe(OnSolutionAltered); GlobalEvents.Instance.SolutionAltered.Unsubscribe(OnSolutionAltered);
GodotGlobalEvents.Instance.TextEditorThemeChanged.Unsubscribe(UpdateEditorThemeAsync);
if (_currentFile is not null) _openTabsFileManager.CloseFile(_currentFile); if (_currentFile is not null) _openTabsFileManager.CloseFile(_currentFile);
} }

View File

@@ -0,0 +1,29 @@
using Godot;
using SharpIDE.Godot.Features.IdeSettings;
namespace SharpIDE.Godot.Features.CodeEditor;
public partial class SharpIdeCodeEdit
{
private static readonly StringName ThemeInfoStringName = "ThemeInfo";
private static readonly StringName IsLight1OrDark2StringName = "IsLight1OrDark2";
private void UpdateEditorThemeForCurrentTheme()
{
var ideTheme = Singletons.AppState.IdeSettings.Theme;
UpdateEditorTheme(ideTheme);
}
// Only async for the EventWrapper subscription
private Task UpdateEditorThemeAsync(LightOrDarkTheme lightOrDarkTheme)
{
UpdateEditorTheme(lightOrDarkTheme);
return Task.CompletedTask;
}
private void UpdateEditorTheme(LightOrDarkTheme lightOrDarkTheme)
{
_syntaxHighlighter.UpdateThemeColorCache(lightOrDarkTheme);
SyntaxHighlighter = null;
SyntaxHighlighter = _syntaxHighlighter; // Reassign to trigger redraw
}
}

View File

@@ -0,0 +1 @@
uid://fk3w6vud5tlx

View File

@@ -1,4 +1,6 @@
namespace SharpIDE.Godot.Features.IdeSettings; using System.Text.Json.Serialization;
namespace SharpIDE.Godot.Features.IdeSettings;
public class AppState public class AppState
{ {
@@ -13,9 +15,12 @@ public class IdeSettings
public string? DebuggerExecutablePath { get; set; } public string? DebuggerExecutablePath { get; set; }
public bool DebuggerUseSharpDbg { get; set; } = true; public bool DebuggerUseSharpDbg { get; set; } = true;
public float UiScale { get; set; } = 1.0f; public float UiScale { get; set; } = 1.0f;
public string Theme { get; set; } = "Dark"; public LightOrDarkTheme Theme { get; set; } = LightOrDarkTheme.Dark;
} }
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum LightOrDarkTheme { Light, Dark }
public record RecentSln public record RecentSln
{ {
public required string Name { get; set; } public required string Name { get; set; }

View File

@@ -1,4 +1,5 @@
using Godot; using Godot;
using SharpIDE.Godot.Features.IdeSettings;
namespace SharpIDE.Godot.Features.Settings; namespace SharpIDE.Godot.Features.Settings;
@@ -9,15 +10,15 @@ public static class SetTheme
private static readonly Theme DarkTheme = ResourceLoader.Load<Theme>("uid://epmt8kq6efrs"); private static readonly Theme DarkTheme = ResourceLoader.Load<Theme>("uid://epmt8kq6efrs");
private static readonly Color DarkThemeClearColor = new Color("4d4d4d"); private static readonly Color DarkThemeClearColor = new Color("4d4d4d");
public static void SetIdeTheme(this Node node, string theme) public static void SetIdeTheme(this Node node, LightOrDarkTheme theme)
{ {
var rootWindow = node.GetTree().GetRoot(); var rootWindow = node.GetTree().GetRoot();
if (theme is "Light") if (theme is LightOrDarkTheme.Light)
{ {
RenderingServer.Singleton.SetDefaultClearColor(LightThemeClearColor); RenderingServer.Singleton.SetDefaultClearColor(LightThemeClearColor);
rootWindow.Theme = LightTheme; rootWindow.Theme = LightTheme;
} }
else if (theme is "Dark") else if (theme is LightOrDarkTheme.Dark)
{ {
RenderingServer.Singleton.SetDefaultClearColor(DarkThemeClearColor); RenderingServer.Singleton.SetDefaultClearColor(DarkThemeClearColor);
rootWindow.Theme = DarkTheme; rootWindow.Theme = DarkTheme;

View File

@@ -0,0 +1 @@
uid://qs50t6nvwar1

View File

@@ -1,4 +1,5 @@
using Godot; using Godot;
using SharpIDE.Godot.Features.IdeSettings;
namespace SharpIDE.Godot.Features.Settings; namespace SharpIDE.Godot.Features.Settings;
@@ -28,7 +29,7 @@ public partial class SettingsWindow : Window
_uiScaleSpinBox.Value = Singletons.AppState.IdeSettings.UiScale; _uiScaleSpinBox.Value = Singletons.AppState.IdeSettings.UiScale;
_debuggerFilePathLineEdit.Text = Singletons.AppState.IdeSettings.DebuggerExecutablePath; _debuggerFilePathLineEdit.Text = Singletons.AppState.IdeSettings.DebuggerExecutablePath;
_debuggerUseSharpDbgCheckButton.ButtonPressed = Singletons.AppState.IdeSettings.DebuggerUseSharpDbg; _debuggerUseSharpDbgCheckButton.ButtonPressed = Singletons.AppState.IdeSettings.DebuggerUseSharpDbg;
var themeOptionIndex = _themeOptionButton.GetOptionIndexOrNullForString(Singletons.AppState.IdeSettings.Theme); var themeOptionIndex = _themeOptionButton.GetOptionIndexOrNullForString(Singletons.AppState.IdeSettings.Theme.ToString());
if (themeOptionIndex is not null) _themeOptionButton.Selected = themeOptionIndex.Value; if (themeOptionIndex is not null) _themeOptionButton.Selected = themeOptionIndex.Value;
} }
@@ -54,7 +55,14 @@ public partial class SettingsWindow : Window
private void OnThemeItemSelected(long index) private void OnThemeItemSelected(long index)
{ {
var selectedTheme = _themeOptionButton.GetItemText((int)index); var selectedTheme = _themeOptionButton.GetItemText((int)index);
Singletons.AppState.IdeSettings.Theme = selectedTheme; var lightOrDarkTheme = selectedTheme switch
this.SetIdeTheme(selectedTheme); {
"Light" => LightOrDarkTheme.Light,
"Dark" => LightOrDarkTheme.Dark,
_ => throw new InvalidOperationException($"Unknown theme selected: {selectedTheme}")
};
Singletons.AppState.IdeSettings.Theme = lightOrDarkTheme;
this.SetIdeTheme(lightOrDarkTheme);
GodotGlobalEvents.Instance.TextEditorThemeChanged.InvokeParallelFireAndForget(lightOrDarkTheme);
} }
} }

View File

@@ -2,6 +2,7 @@
using SharpIDE.Application.Features.Events; using SharpIDE.Application.Features.Events;
using SharpIDE.Application.Features.SolutionDiscovery; using SharpIDE.Application.Features.SolutionDiscovery;
using SharpIDE.Godot.Features.BottomPanel; using SharpIDE.Godot.Features.BottomPanel;
using SharpIDE.Godot.Features.IdeSettings;
namespace SharpIDE.Godot; namespace SharpIDE.Godot;
@@ -13,4 +14,5 @@ public class GodotGlobalEvents
public EventWrapper<bool, Task> BottomPanelVisibilityChangeRequested { get; } = new(_ => Task.CompletedTask); public EventWrapper<bool, Task> BottomPanelVisibilityChangeRequested { get; } = new(_ => Task.CompletedTask);
public EventWrapper<SharpIdeFile, SharpIdeFileLinePosition?, Task> FileSelected { get; } = new((_, _) => Task.CompletedTask); public EventWrapper<SharpIdeFile, SharpIdeFileLinePosition?, Task> FileSelected { get; } = new((_, _) => Task.CompletedTask);
public EventWrapper<SharpIdeFile, SharpIdeFileLinePosition?, Task> FileExternallySelected { get; } = new((_, _) => Task.CompletedTask); public EventWrapper<SharpIdeFile, SharpIdeFileLinePosition?, Task> FileExternallySelected { get; } = new((_, _) => Task.CompletedTask);
public EventWrapper<LightOrDarkTheme, Task> TextEditorThemeChanged { get; } = new(_ => Task.CompletedTask);
} }