Browse Source

Author manual Light/Dark brushes for the surfaces ILSpy paints itself

Simple theme ships no Dark resource dictionary, so flipping
RequestedThemeVariant alone is a no-op against any surface whose
brushes are hardcoded or pulled from a Simple key. We can't swap
themes (Simple is the deliberate visual identity), but we can layer
our own ThemeDictionaries on top so the surfaces ILSpy owns directly
respond to View > Theme.

Introduce a single block of Light / Dark brush pairs under
Application.Resources.ThemeDictionaries (App.axaml), then route the
hardcoded brushes in the editor view, the toolbar, the zoom overlay,
and tooltips through DynamicResource lookups against those keys.

Surfaces wired:
- Decompiler text view background and wait-adorner overlay.
- Main toolbar background, bottom border, separator hairlines,
  combobox border, and the disabled-button content fills.
- Zoom-buttons overlay background and border.
- Tooltips (background, foreground, border) via a Style selector
  since Simple paints them via hardcoded setters that don't expose
  a brush key.

Simple-themed chrome (menu, tree, scrollbars, status bar, dock
splitters) remains Light in both variants. That's partial dark mode
by design -- covering it requires either swapping to Fluent (which
costs the Simple visual identity, and a separate test showed the
chrome regressing under Fluent) or redeclaring every Simple resource
key per variant, which is a much larger effort. Follow-ups will
extend coverage one surface at a time.

Light values match what each file shipped (no visible diff in the
default theme). Dark values follow the VS-style palette:
  editor       #1E1E1E
  toolbar      #2D2D30  border  #3F3F46
  tooltip      #252526  border  #3F3F46  foreground #DCDCDC
  zoom overlay #E01E1E1E with translucent gray border

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 1 month ago
parent
commit
7c7c17ca77
  1. 51
      ILSpy/App.axaml
  2. 4
      ILSpy/TextView/DecompilerTextView.axaml
  3. 4
      ILSpy/TextView/ZoomButtons.axaml
  4. 12
      ILSpy/Views/MainToolBar.axaml

51
ILSpy/App.axaml

@ -19,6 +19,46 @@
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Resources> <Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<!-- Light / Dark variant brushes for the surfaces ILSpy paints directly
(the editor canvas and the toolbar chrome). The Simple theme itself
ships no Dark resource dictionary, so chrome painted by Simple (menu,
scrollbars, tree, status bar) stays Light regardless of the user's
theme choice. Intentional, partial dark mode targeting only the
surfaces a reader spends most time looking at. -->
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ILSpy.EditorBackground" Color="#FFFFE1" />
<SolidColorBrush x:Key="ILSpy.EditorWaitAdornerBackground" Color="#80FFFFFF" />
<SolidColorBrush x:Key="ILSpy.ToolbarBackground" Color="White" />
<SolidColorBrush x:Key="ILSpy.ToolbarBorder" Color="#FFA9B0B7" />
<SolidColorBrush x:Key="ILSpy.ToolbarSeparator" Color="#FFC8CDD3" />
<SolidColorBrush x:Key="ILSpy.ToolbarComboBoxBorder" Color="#FFCCCEDB" />
<SolidColorBrush x:Key="ILSpy.ToolbarDisabledFill" Color="#22000000" />
<SolidColorBrush x:Key="ILSpy.ToolbarDisabledBorder" Color="#33000000" />
<SolidColorBrush x:Key="ILSpy.ZoomButtonsBackground" Color="#E0FFFFE1" />
<SolidColorBrush x:Key="ILSpy.ZoomButtonsBorder" Color="#80808080" />
<SolidColorBrush x:Key="ILSpy.TooltipBackground" Color="#FFFFE1" />
<SolidColorBrush x:Key="ILSpy.TooltipForeground" Color="Black" />
<SolidColorBrush x:Key="ILSpy.TooltipBorder" Color="#FF767676" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ILSpy.EditorBackground" Color="#1E1E1E" />
<SolidColorBrush x:Key="ILSpy.EditorWaitAdornerBackground" Color="#A0000000" />
<SolidColorBrush x:Key="ILSpy.ToolbarBackground" Color="#2D2D30" />
<SolidColorBrush x:Key="ILSpy.ToolbarBorder" Color="#3F3F46" />
<SolidColorBrush x:Key="ILSpy.ToolbarSeparator" Color="#3F3F46" />
<SolidColorBrush x:Key="ILSpy.ToolbarComboBoxBorder" Color="#3F3F46" />
<SolidColorBrush x:Key="ILSpy.ToolbarDisabledFill" Color="#22FFFFFF" />
<SolidColorBrush x:Key="ILSpy.ToolbarDisabledBorder" Color="#33FFFFFF" />
<SolidColorBrush x:Key="ILSpy.ZoomButtonsBackground" Color="#E01E1E1E" />
<SolidColorBrush x:Key="ILSpy.ZoomButtonsBorder" Color="#80A0A0A0" />
<SolidColorBrush x:Key="ILSpy.TooltipBackground" Color="#252526" />
<SolidColorBrush x:Key="ILSpy.TooltipForeground" Color="#DCDCDC" />
<SolidColorBrush x:Key="ILSpy.TooltipBorder" Color="#3F3F46" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<!-- Every dockable owns its view (IDockableViewOwner): the dock chrome must render one <!-- Every dockable owns its view (IDockableViewOwner): the dock chrome must render one
view per dockable identity, not one per slot, or two panes sharing a ToolDock slot view per dockable identity, not one per slot, or two panes sharing a ToolDock slot
(e.g. Analyzer + Debug Steps both Bottom-aligned) render each other's content. This (e.g. Analyzer + Debug Steps both Bottom-aligned) render each other's content. This
@ -46,6 +86,7 @@
translucent accent matches MainToolBar.axaml's button hover treatment. --> translucent accent matches MainToolBar.axaml's button hover treatment. -->
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="#330078D7" /> <SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="#330078D7" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="#660078D7" /> <SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="#660078D7" />
</ResourceDictionary>
</Application.Resources> </Application.Resources>
<Application.DataTemplates> <Application.DataTemplates>
@ -67,6 +108,16 @@
<Setter Property="(recycling:ControlRecyclingDataTemplate.ControlRecycling)" Value="{StaticResource ControlRecyclingKey}" /> <Setter Property="(recycling:ControlRecyclingDataTemplate.ControlRecycling)" Value="{StaticResource ControlRecyclingKey}" />
</Style> </Style>
<!-- Tooltips: Simple theme paints them with hardcoded fills that don't respond to
RequestedThemeVariant. Restyle ToolTip so background, foreground, and border
route through our ILSpy.Tooltip* brushes and swap with the active theme. -->
<Style Selector="ToolTip">
<Setter Property="Background" Value="{DynamicResource ILSpy.TooltipBackground}" />
<Setter Property="Foreground" Value="{DynamicResource ILSpy.TooltipForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ILSpy.TooltipBorder}" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<!-- Suppress the column header's hover / pressed fill while the user is interacting <!-- Suppress the column header's hover / pressed fill while the user is interacting
with content INSIDE the header (e.g. typing into a per-column filter TextBox). with content INSIDE the header (e.g. typing into a per-column filter TextBox).
Without this, clicking the TextBox briefly flashes the header background blue — Without this, clicking the TextBox briefly flashes the header background blue —

4
ILSpy/TextView/DecompilerTextView.axaml

@ -17,11 +17,11 @@
<textView:DecompilerTextEditor Name="Editor" <textView:DecompilerTextEditor Name="Editor"
IsReadOnly="True" IsReadOnly="True"
ShowLineNumbers="True" ShowLineNumbers="True"
Background="#FFFFE1" Background="{DynamicResource ILSpy.EditorBackground}"
FontFamily="Consolas, Menlo, Monospace" FontFamily="Consolas, Menlo, Monospace"
FontSize="13" /> FontSize="13" />
<Border Name="WaitAdorner" <Border Name="WaitAdorner"
Background="#80FFFFFF" Background="{DynamicResource ILSpy.EditorWaitAdornerBackground}"
IsVisible="{Binding IsDecompiling}"> IsVisible="{Binding IsDecompiling}">
<Grid ColumnDefinitions="*,Auto,*"> <Grid ColumnDefinitions="*,Auto,*">
<StackPanel Grid.Column="1" <StackPanel Grid.Column="1"

4
ILSpy/TextView/ZoomButtons.axaml

@ -3,7 +3,9 @@
x:Class="ILSpy.TextView.ZoomButtons" x:Class="ILSpy.TextView.ZoomButtons"
HorizontalAlignment="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Margin="0,0,12,12"> Margin="0,0,12,12">
<Border Background="#E0FFFFE1" BorderBrush="#80808080" BorderThickness="1" <Border Background="{DynamicResource ILSpy.ZoomButtonsBackground}"
BorderBrush="{DynamicResource ILSpy.ZoomButtonsBorder}"
BorderThickness="1"
CornerRadius="3" Padding="2"> CornerRadius="3" Padding="2">
<StackPanel Orientation="Horizontal" Spacing="2"> <StackPanel Orientation="Horizontal" Spacing="2">
<Button Name="MinusButton" Content="&#8722;" Width="22" Height="22" <Button Name="MinusButton" Content="&#8722;" Width="22" Height="22"

12
ILSpy/Views/MainToolBar.axaml

@ -97,8 +97,8 @@
<Setter Property="Cursor" Value="Arrow" /> <Setter Property="Cursor" Value="Arrow" />
</Style> </Style>
<Style Selector="StackPanel#ToolbarRoot > Button:disabled /template/ ContentPresenter, StackPanel#ToolbarRoot > ToggleButton:disabled /template/ ContentPresenter"> <Style Selector="StackPanel#ToolbarRoot > Button:disabled /template/ ContentPresenter, StackPanel#ToolbarRoot > ToggleButton:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="#22000000" /> <Setter Property="Background" Value="{DynamicResource ILSpy.ToolbarDisabledFill}" />
<Setter Property="BorderBrush" Value="#33000000" /> <Setter Property="BorderBrush" Value="{DynamicResource ILSpy.ToolbarDisabledBorder}" />
</Style> </Style>
<!-- Default Fluent SplitButton paints both halves with an opaque dark fill on press <!-- Default Fluent SplitButton paints both halves with an opaque dark fill on press
(looks black against our white toolbar). Replace with the toolbar accent palette (looks black against our white toolbar). Replace with the toolbar accent palette
@ -125,7 +125,7 @@
<Setter Property="Width" Value="1" /> <Setter Property="Width" Value="1" />
<Setter Property="Height" Value="18" /> <Setter Property="Height" Value="18" />
<Setter Property="Margin" Value="4,3" /> <Setter Property="Margin" Value="4,3" />
<Setter Property="Background" Value="#FFC8CDD3" /> <Setter Property="Background" Value="{DynamicResource ILSpy.ToolbarSeparator}" />
</Style> </Style>
<!-- Keep the combos flush with the buttons; soften the default border so it sits <!-- Keep the combos flush with the buttons; soften the default border so it sits
@ -136,7 +136,7 @@
<Setter Property="MinHeight" Value="22" /> <Setter Property="MinHeight" Value="22" />
<Setter Property="Padding" Value="6,1" /> <Setter Property="Padding" Value="6,1" />
<Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="BorderBrush" Value="#FFCCCEDB" /> <Setter Property="BorderBrush" Value="{DynamicResource ILSpy.ToolbarComboBoxBorder}" />
</Style> </Style>
<!-- The Simple theme's ComboBox template (this project uses Avalonia.Themes.Simple, <!-- The Simple theme's ComboBox template (this project uses Avalonia.Themes.Simple,
not Fluent) places a separate ToggleButton named "toggle" in the chevron column not Fluent) places a separate ToggleButton named "toggle" in the chevron column
@ -168,9 +168,9 @@
</Style> </Style>
</UserControl.Styles> </UserControl.Styles>
<Border BorderThickness="0,0,0,1" BorderBrush="#FFA9B0B7" <Border BorderThickness="0,0,0,1" BorderBrush="{DynamicResource ILSpy.ToolbarBorder}"
MinHeight="29" Padding="3" MinHeight="29" Padding="3"
Background="White"> Background="{DynamicResource ILSpy.ToolbarBackground}">
<StackPanel Name="ToolbarRoot" Orientation="Horizontal"> <StackPanel Name="ToolbarRoot" Orientation="Horizontal">
<!-- Navigation: Back / Forward as web-browser-style split buttons. The primary half <!-- Navigation: Back / Forward as web-browser-style split buttons. The primary half
navigates one step; the chevron drops a menu of recent history entries built on navigates one step; the chevron drops a menu of recent history entries built on

Loading…
Cancel
Save