// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using System.Windows.Forms.VisualStyles; namespace System.Windows.Forms.ButtonInternal; internal class ButtonDarkModeAdapter : ButtonBaseAdapter { private readonly ButtonDarkModeRendererBase _buttonDarkModeRenderer; internal ButtonDarkModeAdapter(ButtonBase control) : base(control) { _buttonDarkModeRenderer = control.FlatStyle switch { FlatStyle.Standard => new FlatButtonDarkModeRenderer(), FlatStyle.Flat => new FlatButtonDarkModeRenderer(), FlatStyle.Popup => new PopupButtonDarkModeRenderer(), FlatStyle.System => new SystemButtonDarkModeRenderer(), _ => throw new ArgumentOutOfRangeException(nameof(control)) }; } private ButtonDarkModeRendererBase ButtonDarkModeRenderer => _buttonDarkModeRenderer; private Color GetButtonTextColor(IDeviceContext deviceContext, PushButtonState state) { Color textColor; if (Control.ForeColor != Forms.Control.DefaultForeColor) { textColor = new ColorOptions(deviceContext, Control.ForeColor, Control.BackColor) { Enabled = Control.Enabled }.Calculate().WindowText; if (IsHighContrastHighlighted()) { textColor = SystemColors.HighlightText; } } else { textColor = ButtonDarkModeRenderer.GetTextColor(state, Control.IsDefault); } return textColor; } private Color GetButtonBackColor(PushButtonState state) { Color backColor; if (Control.BackColor != Forms.Control.DefaultBackColor) { backColor = Control.BackColor; if (IsHighContrastHighlighted()) { backColor = SystemColors.HighlightText; } } else { backColor = ButtonDarkModeRenderer.GetBackgroundColor(state, Control.IsDefault); } return backColor; } internal override void PaintUp(PaintEventArgs e, CheckState state) { try { // Use GraphicsInternal for better performance (GDI+ best practice) var g = e.GraphicsInternal; var smoothingMode = g.SmoothingMode; g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias; LayoutData layout = CommonLayout().Layout(); PushButtonState pushButtonState = ToPushButtonState(state, Control.Enabled); ButtonDarkModeRenderer.RenderButton( g, Control.ClientRectangle, Control.FlatStyle, pushButtonState, Control.IsDefault, Control.Focused, Control.ShowFocusCues, Control.Parent?.BackColor ?? Control.BackColor, GetButtonBackColor(pushButtonState), _ => PaintImage(e, layout), () => PaintField( e, layout, PaintDarkModeRender(e).Calculate(), GetButtonTextColor(e, pushButtonState), drawFocus: false) ); g.SmoothingMode = smoothingMode; } catch (Exception) { // Handle exceptions gracefully, possibly logging them or showing a message Debug.Assert(false, "Exception in PaintUp: Unable to render button in dark mode."); } } internal override void PaintDown(PaintEventArgs e, CheckState state) { try { // Use GraphicsInternal for better performance (GDI+ best practice) var g = e.GraphicsInternal; var smoothingMode = g.SmoothingMode; g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias; LayoutData layout = CommonLayout().Layout(); ButtonDarkModeRenderer.RenderButton( g, Control.ClientRectangle, Control.FlatStyle, PushButtonState.Pressed, Control.IsDefault, Control.Focused, Control.ShowFocusCues, Control.Parent?.BackColor ?? Control.BackColor, GetButtonBackColor(PushButtonState.Pressed), _ => PaintImage(e, layout), () => PaintField( e, layout, PaintDarkModeRender(e).Calculate(), GetButtonTextColor(e, PushButtonState.Pressed), drawFocus: false) ); g.SmoothingMode = smoothingMode; } catch (Exception) { // Handle exceptions gracefully, possibly logging them or showing a message Debug.Assert(false, "Exception in PaintDown: Unable to render button in dark mode."); } } internal override void PaintOver(PaintEventArgs e, CheckState state) { try { // Use GraphicsInternal for better performance (GDI+ best practice) var g = e.GraphicsInternal; var smoothingMode = g.SmoothingMode; g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias; LayoutData layout = CommonLayout().Layout(); ButtonDarkModeRenderer.RenderButton( g, Control.ClientRectangle, Control.FlatStyle, PushButtonState.Hot, Control.IsDefault, Control.Focused, Control.ShowFocusCues, Control.Parent?.BackColor ?? Control.BackColor, GetButtonBackColor(PushButtonState.Hot), _ => PaintImage(e, layout), () => PaintField( e, layout, PaintDarkModeRender(e).Calculate(), GetButtonTextColor(e, PushButtonState.Hot), drawFocus: false) ); g.SmoothingMode = smoothingMode; } catch (Exception ex) { Debug.Assert(false, $"Exception in PaintOver: {ex.Message}"); } } protected override LayoutOptions Layout(PaintEventArgs e) => CommonLayout(); private new LayoutOptions CommonLayout() { LayoutOptions layout = base.CommonLayout(); layout.FocusOddEvenFixup = false; layout.ShadowedText = false; return layout; } private ColorOptions PaintDarkModeRender(IDeviceContext deviceContext) => new(deviceContext, Control.ForeColor, Control.BackColor) { Enabled = Control.Enabled }; private static PushButtonState ToPushButtonState(CheckState state, bool enabled) => !enabled ? PushButtonState.Disabled : state switch { CheckState.Unchecked => PushButtonState.Normal, CheckState.Checked => PushButtonState.Pressed, CheckState.Indeterminate => PushButtonState.Hot, _ => PushButtonState.Normal }; }