Skip to content

Commit

Permalink
Added more XML comments and refactored the IsDarkModeEnabled logic a …
Browse files Browse the repository at this point in the history
…bit.
  • Loading branch information
KlausLoeffelmann committed Mar 18, 2024
1 parent f1333eb commit 6870067
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 102 deletions.
36 changes: 36 additions & 0 deletions src/System.Windows.Forms/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
static System.Windows.Forms.Application.DefaultDarkMode.get -> System.Windows.Forms.DarkMode
static System.Windows.Forms.Application.EnvironmentDarkMode.get -> System.Windows.Forms.DarkMode
static System.Windows.Forms.Application.IsDarkModeEnabled.get -> bool
static System.Windows.Forms.Application.SetDefaultDarkMode(System.Windows.Forms.DarkMode darkMode) -> bool
System.Windows.Forms.Control.DarkMode.get -> System.Windows.Forms.DarkMode
System.Windows.Forms.Control.DarkMode.set -> void
Expand All @@ -17,7 +18,42 @@ System.Windows.Forms.Form.WindowCornerPreference.Default = 0 -> System.Windows.F
System.Windows.Forms.Form.WindowCornerPreference.DoNotRound = 1 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.Round = 2 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.Form.WindowCornerPreference.RoundSmall = 3 -> System.Windows.Forms.Form.WindowCornerPreference
System.Windows.Forms.ThemedSystemColors
System.Windows.Forms.ThemedSystemColors.ThemedSystemColors() -> void
virtual System.Windows.Forms.Control.DarkModeSupported.get -> bool
virtual System.Windows.Forms.Control.DefaultDarkMode.get -> System.Windows.Forms.DarkMode
virtual System.Windows.Forms.Control.IsDarkModeEnabled.get -> bool
virtual System.Windows.Forms.Control.SetDarkModeCore(System.Windows.Forms.DarkMode darkModeSetting) -> bool
virtual System.Windows.Forms.ThemedSystemColors.ActiveBorder.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ActiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ActiveCaptionText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.AppWorkspace.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonFace.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonHighlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ButtonShadow.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Control.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlDark.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlDarkDark.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlLight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlLightLight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ControlText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Desktop.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GradientActiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GradientInactiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.GrayText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Highlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.HighlightText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.HotTrack.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveBorder.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveCaption.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InactiveCaptionText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Info.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.InfoText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Menu.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuBar.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuHighlight.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.MenuText.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.ScrollBar.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.Window.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.WindowFrame.get -> System.Drawing.Color
virtual System.Windows.Forms.ThemedSystemColors.WindowText.get -> System.Drawing.Color
11 changes: 7 additions & 4 deletions src/System.Windows.Forms/src/System/Windows/Forms/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,12 @@ public static DarkMode EnvironmentDarkMode
}
}

internal static bool IsDarkModeEnabled => SystemInformation.HighContrast
? false
: DefaultDarkMode switch
/// <summary>
/// Gets a value indicating whether the application is running in a dark mode context.
/// Note: We're never using dark mode in a high contrast context.
/// </summary>
public static bool IsDarkModeEnabled => !SystemInformation.HighContrast
&& DefaultDarkMode switch
{
DarkMode.Enabled => true,
DarkMode.Disabled => false,
Expand All @@ -329,7 +332,7 @@ public static DarkMode EnvironmentDarkMode
}
};

internal static ThemedSystemColors SystemColors
public static ThemedSystemColors SystemColors
=> IsDarkModeEnabled
? DarkThemedSystemColors.DefaultInstance
: LightThemedSystemColors.DefaultInstance;
Expand Down
133 changes: 75 additions & 58 deletions src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,13 @@ public ControlBindingsCollection DataBindings
}
}

/// <summary>
/// Gets or sets the dark mode for the control.
/// </summary>
/// <value>
/// The dark mode for the control. The default value is <see cref="DarkMode.Inherits"/>. This property is ambient.
/// Deriving classes should override <see cref="SetDarkModeCore(DarkMode)"/> to implement their own dark-mode detection logic.
/// </value>
public DarkMode DarkMode
{
get
Expand All @@ -1777,17 +1784,25 @@ private bool ShouldSerializeDarkMode()
private void ResetDarkMode()
=> DarkMode = DefaultDarkMode;

/// <summary>
/// Tests, if the control is currently in dark mode. This property is ambient. Inherited controls can return false,
/// to prevent their base classes to apply their dark-mode logic, and can still test for dark-mode by calling base.IsDarkModeEnabled.
/// </summary>
protected virtual bool IsDarkModeEnabled
{
get
{
if (Properties.ContainsObject(s_isDarkModeEnabledProperty))
if (Properties.ContainsObject(s_darkModeProperty))
{
return (bool)Properties.GetObject(s_isDarkModeEnabledProperty)!;
// If we inherit, it's the parent's dark-mode, otherwise it's the value we have.
return (DarkMode == DarkMode.Inherits
&& (ParentInternal?.IsDarkModeEnabled ?? false))
|| DarkMode == DarkMode.Enabled;
}
else
{
return ParentInternal?.IsDarkModeEnabled ?? SetDarkModeCore(DarkMode.Inherits);
// We're ambient: It's either the parent's or the application's dark-mode.
return ParentInternal?.IsDarkModeEnabled ?? Application.IsDarkModeEnabled;
}
}
}
Expand Down Expand Up @@ -1824,48 +1839,21 @@ DarkMode.Enabled or
}
}

protected virtual bool SetDarkModeCore(DarkMode darkModeSetting)
{
bool wasDarkModeEnabled = Properties.ContainsObject(s_isDarkModeEnabledProperty)
? (bool)Properties.GetObject(s_isDarkModeEnabledProperty)!
: false;

bool isDarkMode = darkModeSetting switch
{
DarkMode.Enabled => true,
DarkMode.Disabled => false,

// Only DarkModeSettings.Inherits remains:
_ => Parent?.IsDarkModeEnabled ?? IsApplicationDarkMode()
};

// Has the dark mode changed?
if (wasDarkModeEnabled ^ isDarkMode)
{
Properties.SetObject(s_isDarkModeEnabledProperty, isDarkMode);
// TODO: We need to raise BackColor/FontColor changed, if the respective Colors are ambient.
// OnIsDarkModeEnabledChanged();
}

return isDarkMode;

static bool IsApplicationDarkMode()
{
bool isDark = Application.DefaultDarkMode switch
{
DarkMode.Enabled => true,
DarkMode.Inherits => Application.EnvironmentDarkMode is DarkMode.Enabled ? true : false,
_ => false
};

return isDark;
}
}
/// <summary>
/// Inherited classes should override this method to implement their own dark-mode changed logic, if they need it.
/// </summary>
/// <param name="darkModeSetting">A value of type <see cref="DarkMode"/> with the new dark-mode setting.</param>
/// <returns><see langword="true"/>, if the setting succeeded, otherwise <see langword="false"/>.</returns>
protected virtual bool SetDarkModeCore(DarkMode darkModeSetting) => true;

/// <summary>
/// Determines whether the control supports dark mode.
/// </summary>
/// <returns><see langword="true"/>, if the control supports dark mode; otherwise, <see langword="false"/>.</returns>
protected virtual bool DarkModeSupported
=> Application.EnvironmentDarkMode != DarkMode.NotSupported;

protected virtual DarkMode DefaultDarkMode => DarkMode.Inherits;
private static DarkMode DefaultDarkMode => DarkMode.Inherits;

/// <summary>
/// The default BackColor of a generic top-level Control. Subclasses may have
Expand Down Expand Up @@ -7850,23 +7838,52 @@ protected virtual void OnHandleCreated(EventArgs e)

if (IsDarkModeEnabled)
{
if (this is (Button
or Label
or GroupBox
or Panel
or SplitterPanel
or ListBox
or CheckedListBox
or MaskedTextBox
or NumericUpDown
or CheckBox
or RadioButton
or TreeView
or DataGridView
or TextBox
or RichTextBox
or TabControl
or Form))
if (this is

// Controls with four levels of inheritance, sorted alphabetically by type name
DomainUpDown // Inherits from UpDownBase, ContainerControl, ScrollableControl, Control
or NumericUpDown // Inherits from UpDownBase, ContainerControl, ScrollableControl, Control

// Controls with three levels of inheritance, sorted alphabetically by type name
or CheckedListBox // Inherits from ListBox, ListControl, Control
or Form // Excluded - too invasive.
or FlowLayoutPanel // Inherits from Panel, ScrollableControl, Control
or SplitContainer // Inherits from ContainerControl, ScrollableControl, Control
or TabPage // Inherits from Panel, ScrollableControl, Control
or TableLayoutPanel // Inherits from Panel, ScrollableControl, Control

// Controls with 2 levels of inheritance, sorted alphabetically by type name
// or ComboBox // Excluded - directly handled.
or ListBox // Inherits from ListControl, Control

or Button // Inherits from ButtonBase, Control
or CheckBox // Inherits from ButtonBase, Control
or MaskedTextBox // Inherits from TextBoxBase, Control
or Panel // Inherits from ScrollableControl, Control
or RadioButton // Inherits from ButtonBase, Control
or RichTextBox // Inherits from TextBoxBase, Control
or TextBox // Inherits from TextBoxBase, Control

// Base classes and controls with direct inheritance from Control, sorted alphabetically by type name
// or ButtonBase // Excluded - probably too invasive.
or DateTimePicker // Inherits from Control
or GroupBox // Inherits from Control directly, but behaves like a container
or HScrollBar // Inherits from ScrollBar, Control
or Label // Inherits from Control
or LinkLabel // Inherits from Label, Control
// or ListView // Excluded - directly handled.
or MonthCalendar // Inherits from Control
or PictureBox // Inherits from Control
or ProgressBar // Inherits from Control
// or ScrollableControl // Excluded - probably too invasive.
// or TextBoxBase // Excluded - probably too invasive.
or TrackBar // Inherits from Control
or TreeView // Inherits from Control
// or UpDownBase // Excluded - probably too invasive.
or VScrollBar // Inherits from ScrollBar, Control

// Base class for all UI controls in WinForms
or Control)
{
_ = PInvoke.SetWindowTheme(HWND, "DarkMode_Explorer", null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ public enum DarkMode
NotSupported = 0,

/// <summary>
/// The setting for the current dark mode context is inherited from the parent context.
/// The setting for the current dark mode context is inherited from the parent context.
/// </summary>
Inherits = 1,

/// <summary>
/// Dark mode for the current context is enabled.
/// Dark mode for the current context is enabled.
/// </summary>
Enabled = 2,

/// <summary>
/// Dark mode the current context is disabled.
/// Dark mode the current context is disabled.
/// </summary>
Disabled = 3
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

namespace System.Windows.Forms
{
/// <summary>
/// This is a temporary list of the light color palette that is used when the system is in "normal light mode".
/// It's purely for testing purposes and will most likely be removed once the system colors are available.
/// </summary>
internal class ForcedLightThemedSystemColors : ThemedSystemColors
{
private static ForcedLightThemedSystemColors? s_instance;
Expand Down
Loading

0 comments on commit 6870067

Please sign in to comment.