Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 190 additions & 21 deletions src/XTMF2.GUI/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@
<SolidColorBrush x:Key="DlgPrimaryBtnBg">#FF00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="DlgPrimaryBtnFg">#FF000A0E</SolidColorBrush>
<SolidColorBrush x:Key="DlgPrimaryBtnHover">#CC00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="CtxBg">#F20A1120</SolidColorBrush>
<SolidColorBrush x:Key="CtxBorder">#AA00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="CtxFg">#FFF2FCFF</SolidColorBrush>
<SolidColorBrush x:Key="CtxHover">#3000D4FF</SolidColorBrush>
<SolidColorBrush x:Key="CtxPressed">#5200D4FF</SolidColorBrush>
<SolidColorBrush x:Key="CtxDisabled">#66A0B8C8</SolidColorBrush>
<SolidColorBrush x:Key="CtxSep">#5500D4FF</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarBg">#E60A1424</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarBorder">#AA00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarFg">#FFF2FCFF</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarHover">#3A00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarPressed">#5A00D4FF</SolidColorBrush>
<SolidColorBrush x:Key="NodeCardBg">#FF0E2238</SolidColorBrush>
<SolidColorBrush x:Key="NodeCardBorder">#FF00CCFF</SolidColorBrush>
</ResourceDictionary>

<ResourceDictionary x:Key="Light">
Expand All @@ -83,30 +97,23 @@
<SolidColorBrush x:Key="DlgPrimaryBtnBg">#FF0066CC</SolidColorBrush>
<SolidColorBrush x:Key="DlgPrimaryBtnFg">#FFFFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="DlgPrimaryBtnHover">#CC0066CC</SolidColorBrush>
<SolidColorBrush x:Key="CtxBg">#F7F4FAFF</SolidColorBrush>
<SolidColorBrush x:Key="CtxBorder">#AA0066CC</SolidColorBrush>
<SolidColorBrush x:Key="CtxFg">#FF001830</SolidColorBrush>
<SolidColorBrush x:Key="CtxHover">#220066CC</SolidColorBrush>
<SolidColorBrush x:Key="CtxPressed">#440066CC</SolidColorBrush>
<SolidColorBrush x:Key="CtxDisabled">#88637790</SolidColorBrush>
<SolidColorBrush x:Key="CtxSep">#550066CC</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarBg">#F2F7FFFF</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarBorder">#660066CC</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarFg">#FF001830</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarHover">#220066CC</SolidColorBrush>
<SolidColorBrush x:Key="MenuBarPressed">#3A0066CC</SolidColorBrush>
<SolidColorBrush x:Key="NodeCardBg">#FFFFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="NodeCardBorder">#FF0066BB</SolidColorBrush>
</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>

<!-- Forest Green Theme Colors -->
<ResourceDictionary x:Key="ForestGreen">
<Color x:Key="AccentColor">#2D5016</Color>
<Color x:Key="AccentColorLight">#4A7C2C</Color>
<Color x:Key="AccentColorDark">#1A3009</Color>
</ResourceDictionary>

<!-- Ruby Red Theme Colors -->
<ResourceDictionary x:Key="RubyRed">
<Color x:Key="AccentColor">#9B111E</Color>
<Color x:Key="AccentColorLight">#C41E3A</Color>
<Color x:Key="AccentColorDark">#6B0C15</Color>
</ResourceDictionary>

<!-- Sapphire Blue Theme Colors -->
<ResourceDictionary x:Key="SapphireBlue">
<Color x:Key="AccentColor">#0F52BA</Color>
<Color x:Key="AccentColorLight">#4169E1</Color>
<Color x:Key="AccentColorDark">#0A3A82</Color>
</ResourceDictionary>
</ResourceDictionary>
</Application.Resources>

Expand Down Expand Up @@ -150,6 +157,168 @@
<Setter Property="Background" Value="#5179F1"/>
</Style>

<!-- Neon context menus for both XAML-defined and code-generated menus -->
<Style Selector="ContextMenu">
<Setter Property="Background" Value="{DynamicResource CtxBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CtxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="4"/>
</Style>
<Style Selector="ContextMenu /template/ Border">
<Setter Property="BoxShadow" Value="0 8 22 0 #66000000, 0 0 14 1 #5500D4FF"/>
</Style>
<Style Selector="ContextMenu Separator">
<Setter Property="Background" Value="{DynamicResource CtxSep}"/>
<Setter Property="Margin" Value="6,4"/>
</Style>
<Style Selector="ContextMenu MenuItem">
<Setter Property="Foreground" Value="{DynamicResource CtxFg}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
<Style Selector="ContextMenu MenuItem /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ContextMenu MenuItem:pointerover">
<Setter Property="Background" Value="{DynamicResource CtxHover}"/>
</Style>
<Style Selector="ContextMenu MenuItem:selected">
<Setter Property="Background" Value="{DynamicResource CtxHover}"/>
</Style>
<Style Selector="ContextMenu MenuItem:pressed">
<Setter Property="Background" Value="{DynamicResource CtxPressed}"/>
</Style>
<Style Selector="ContextMenu MenuItem:disabled">
<Setter Property="Foreground" Value="{DynamicResource CtxDisabled}"/>
</Style>

<!-- Main window menu bar: same single-layer hover logic as context menus -->
<Style Selector="Menu.main-menu">
<Setter Property="Background" Value="{DynamicResource MenuBarBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource MenuBarBorder}"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="Padding" Value="6,3"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem">
<Setter Property="Foreground" Value="{DynamicResource MenuBarFg}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="12,5"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="MinHeight" Value="30"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem:pointerover">
<Setter Property="Background" Value="{DynamicResource MenuBarHover}"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem:selected">
<Setter Property="Background" Value="{DynamicResource MenuBarHover}"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem:pressed">
<Setter Property="Background" Value="{DynamicResource MenuBarPressed}"/>
</Style>
<Style Selector="Menu.main-menu > MenuItem:submenuopen">
<Setter Property="Background" Value="{DynamicResource MenuBarHover}"/>
</Style>
<Style Selector="Menu.main-menu MenuItem:disabled">
<Setter Property="Foreground" Value="{DynamicResource CtxDisabled}"/>
</Style>

<!-- Menu bar submenus are hosted in MenuFlyoutPresenter, not in the top Menu visual -->
<Style Selector="MenuFlyoutPresenter">
<Setter Property="Background" Value="{DynamicResource CtxBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CtxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="4"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem">
<Setter Property="Foreground" Value="{DynamicResource CtxFg}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem:pointerover">
<Setter Property="Background" Value="{DynamicResource CtxHover}"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem:selected">
<Setter Property="Background" Value="{DynamicResource CtxHover}"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem:pressed">
<Setter Property="Background" Value="{DynamicResource CtxPressed}"/>
</Style>
<Style Selector="MenuFlyoutPresenter MenuItem:disabled">
<Setter Property="Foreground" Value="{DynamicResource CtxDisabled}"/>
</Style>

<!-- Tooltips use the same popup palette as neon context menus -->
<Style Selector="ToolTip">
<Setter Property="Background" Value="{DynamicResource CtxBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CtxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="6"/>
<Setter Property="Padding" Value="8,6"/>
</Style>
<Style Selector="ToolTip TextBlock">
<Setter Property="Foreground" Value="{DynamicResource CtxFg}"/>
</Style>

<!-- Scroll surfaces keep tracks transparent and emphasize only the thumb -->
<Style Selector="ScrollViewer">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ScrollBar">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="ScrollBar:vertical">
<Setter Property="Width" Value="10"/>
</Style>
<Style Selector="ScrollBar:horizontal">
<Setter Property="Height" Value="10"/>
</Style>
<Style Selector="ScrollBar /template/ RepeatButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<Style Selector="ScrollBar /template/ Thumb">
<Setter Property="Background" Value="{DynamicResource DlgAccentMid}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgAccent}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="MinWidth" Value="10"/>
<Setter Property="MinHeight" Value="10"/>
</Style>
<Style Selector="ScrollBar /template/ Thumb /template/ Border">
<Setter Property="Background" Value="{DynamicResource DlgAccentMid}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgAccent}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="5"/>
</Style>
<Style Selector="ScrollBar:pointerover /template/ Thumb">
<Setter Property="Background" Value="{DynamicResource DlgAccent}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgPrimaryBtnBg}"/>
</Style>
<Style Selector="ScrollBar:pointerover /template/ Thumb /template/ Border">
<Setter Property="Background" Value="{DynamicResource DlgAccent}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgPrimaryBtnBg}"/>
</Style>
<Style Selector="ScrollBar:pressed /template/ Thumb">
<Setter Property="Background" Value="{DynamicResource DlgPrimaryBtnBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgPrimaryBtnBg}"/>
</Style>
<Style Selector="ScrollBar:pressed /template/ Thumb /template/ Border">
<Setter Property="Background" Value="{DynamicResource DlgPrimaryBtnBg}"/>
<Setter Property="BorderBrush" Value="{DynamicResource DlgPrimaryBtnBg}"/>
</Style>

<!-- ── Neon dialog theme: apply with Classes="neon-dialog" on any Window ── -->
<Style Selector="Window.neon-dialog">
<Setter Property="Background" Value="{DynamicResource DlgBg}"/>
Expand Down
46 changes: 11 additions & 35 deletions src/XTMF2.GUI/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,56 +154,32 @@ await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
/// <summary>
/// Change the application theme
/// </summary>
/// <param name="themeName">The theme to apply (Dark, Light, ForestGreen, RubyRed, SapphireBlue)</param>
/// <param name="themeName">The theme to apply (Dark or Light)</param>
public void ChangeTheme(string themeName)
{
switch (themeName)
{
case "Dark":
RequestedThemeVariant = ThemeVariant.Dark;
break;
case "Light":
case "ForestGreen":
case "RubyRed":
case "SapphireBlue":
// Colored themes use Light as the base
RequestedThemeVariant = ThemeVariant.Light;
break;
default:
RequestedThemeVariant = ThemeVariant.Dark;
break;
}
ApplyTheme(themeName);

// Save theme preference
SaveThemePreference(themeName);
SaveThemePreference(NormalizeThemeName(themeName));
}

private void LoadThemePreference()
{
// Load theme from settings
var savedTheme = Properties.Settings.Default.Theme ?? "Dark";
var savedTheme = NormalizeThemeName(Properties.Settings.Default.Theme);
ApplyTheme(savedTheme);
}

private void ApplyTheme(string themeName)
{
switch (themeName)
{
case "Dark":
RequestedThemeVariant = ThemeVariant.Dark;
break;
case "Light":
case "ForestGreen":
case "RubyRed":
case "SapphireBlue":
RequestedThemeVariant = ThemeVariant.Light;
break;
default:
RequestedThemeVariant = ThemeVariant.Dark;
break;
}
RequestedThemeVariant = NormalizeThemeName(themeName) == "Light"
? ThemeVariant.Light
: ThemeVariant.Dark;
}

public static string NormalizeThemeName(string? themeName)
=> themeName == "Light" ? "Light" : "Dark";

/// <summary>
/// Apply a theme without saving (for preview purposes)
/// </summary>
Expand All @@ -214,7 +190,7 @@ public void ApplyThemePreview(string themeName)

private void SaveThemePreference(string themeName)
{
Properties.Settings.Default.Theme = themeName;
Properties.Settings.Default.Theme = NormalizeThemeName(themeName);
Properties.Settings.Default.Save();
}
}
Loading
Loading