diff --git a/src/ElectronicPharmacy/Classes/UiThemeHelper.cs b/src/ElectronicPharmacy/Classes/UiThemeHelper.cs index 82b6b4b..22ba007 100644 --- a/src/ElectronicPharmacy/Classes/UiThemeHelper.cs +++ b/src/ElectronicPharmacy/Classes/UiThemeHelper.cs @@ -103,9 +103,19 @@ namespace Электронная_Фармация.Classes } else if (control is Panel || control is UserControl || control is TableLayoutPanel || control is SplitContainer) { - if (control.Tag as string != "keep-bg") + if (control.Tag as string == "keep-bg") + { + // preserve custom background + } + else if (control.Tag as string == "chrome-child") + { + control.BackColor = theme.BackgroundPrimary; + control.ForeColor = theme.TextPrimary; + } + else { control.BackColor = theme.BackgroundSecondary; + control.ForeColor = theme.TextPrimary; } } diff --git a/src/ElectronicPharmacy/Form1.UiShell.cs b/src/ElectronicPharmacy/Form1.UiShell.cs index 7048abb..da3ddd5 100644 --- a/src/ElectronicPharmacy/Form1.UiShell.cs +++ b/src/ElectronicPharmacy/Form1.UiShell.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; using Elfisa.UI.Controls; +using Elfisa.UI.Helpers; using Elfisa.UI.Loading; using Elfisa.UI.Notifications; using Elfisa.UI.Theming; @@ -112,6 +113,7 @@ namespace Электронная_Фармация }); _appHeader.ItemSelected += OnAppHeaderItemSelected; + _documentTabStrip.ThemeToggleClicked += OnThemeToggleClicked; _documentTabStrip.TabSelected += OnDocumentTabSelected; _documentTabStrip.TabClosed += OnDocumentTabClosed; _documentTabStrip.TabCloseAllRequested += OnDocumentTabCloseAll; @@ -133,14 +135,41 @@ namespace Электронная_Фармация _documentTabMenu.Items.Add(_documentCloseTabMenuItem); _documentTabMenu.Items.Add(_documentCloseAllTabsMenuItem); - ThemeManager.ThemeChanged += (_, __) => _themeService.Apply(this); + ThemeManager.ThemeChanged += (_, __) => + { + UiThemeHelper.ApplyToControlTree(this); + UpdateThemeToggleState(); + WindowChromeHelper.ApplyTitleBarTheme(this, ThemeManager.Colors); + }; + + HandleCreated += (_, __) => WindowChromeHelper.ApplyTitleBarTheme(this, ThemeManager.Colors); + } + + private void UpdateThemeToggleState() + { + if (_documentTabStrip != null) + { + _documentTabStrip.IsDarkTheme = ThemeManager.IsDarkProductivityActive; + } + } + + private void OnThemeToggleClicked(object sender, EventArgs e) + { + ThemeManager.ToggleProductivityTheme(); + Settings.Default.UseDarkTheme = ThemeManager.IsDarkProductivityActive; + Settings.Default.Save(); + UpdateThemeToggleState(); } partial void FinalizeModernShell() { - ThemeManager.CurrentVariant = ThemeVariant.PharmaTrust; + ThemeManager.CurrentVariant = Settings.Default.UseDarkTheme + ? ThemeVariant.DarkProductivity + : ThemeVariant.PharmaTrust; _themeService.Initialize(this); + UpdateThemeToggleState(); UiThemeHelper.ApplyToControlTree(this); + WindowChromeHelper.ApplyTitleBarTheme(this, ThemeManager.Colors); RefreshCurrentUserStatus(); } diff --git a/src/ElectronicPharmacy/HelpForms/HF_Registration.cs b/src/ElectronicPharmacy/HelpForms/HF_Registration.cs index 27784e0..15eb8c7 100644 --- a/src/ElectronicPharmacy/HelpForms/HF_Registration.cs +++ b/src/ElectronicPharmacy/HelpForms/HF_Registration.cs @@ -12,6 +12,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using Электронная_Фармация.Classes; using System.Net.Http; +using Elfisa.UI.Helpers; +using Elfisa.UI.Theming; namespace Электронная_Фармация.HelpForms { @@ -20,6 +22,7 @@ namespace Электронная_Фармация.HelpForms public HF_Registration() { InitializeComponent(); + Shown += (_, __) => WindowChromeHelper.ApplyTitleBarTheme(this, ThemeManager.Colors); } string login= Settings.Default.stringLogin.ToString(); @@ -91,7 +94,7 @@ namespace Электронная_Фармация.HelpForms private void HF_Registration_Load(object sender, EventArgs e) { UiThemeHelper.ApplyToControlTree(this); - panel1.BackColor = Elfisa.UI.Theming.ThemeManager.Colors.TitleBarBottom; + WindowChromeHelper.ApplyDialogChrome(this, panel1, label3); txtLogin.Text = login; txtPassword.Text = password; txtLocationId.Text = Settings.Default.LocationId ?? string.Empty; diff --git a/src/ElectronicPharmacy/Program.cs b/src/ElectronicPharmacy/Program.cs index a8be127..4dcc9e3 100644 --- a/src/ElectronicPharmacy/Program.cs +++ b/src/ElectronicPharmacy/Program.cs @@ -1,6 +1,5 @@ using System; using System.Windows.Forms; -using Elfisa.UI.Theming; namespace Электронная_Фармация { @@ -11,7 +10,6 @@ namespace Электронная_Фармация { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - ThemeManager.CurrentVariant = ThemeVariant.PharmaTrust; Application.Run(new ElectroPharmacy()); } } diff --git a/src/ElectronicPharmacy/Properties/Settings.Designer.cs b/src/ElectronicPharmacy/Properties/Settings.Designer.cs index c9b1cff..e0ea4f7 100644 --- a/src/ElectronicPharmacy/Properties/Settings.Designer.cs +++ b/src/ElectronicPharmacy/Properties/Settings.Designer.cs @@ -107,5 +107,17 @@ namespace Электронная_Фармация.Properties { } } + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool UseDarkTheme { + get { + return ((bool)(this["UseDarkTheme"])); + } + set { + this["UseDarkTheme"] = value; + } + } + } } diff --git a/src/ElectronicPharmacy/Properties/Settings.settings b/src/ElectronicPharmacy/Properties/Settings.settings index 17ec4d6..d747674 100644 --- a/src/ElectronicPharmacy/Properties/Settings.settings +++ b/src/ElectronicPharmacy/Properties/Settings.settings @@ -23,5 +23,8 @@ + + False + \ No newline at end of file diff --git a/src/Elfisa.UI/Controls/ModernDataGridView.cs b/src/Elfisa.UI/Controls/ModernDataGridView.cs index 0cbfc82..2f45d86 100644 --- a/src/Elfisa.UI/Controls/ModernDataGridView.cs +++ b/src/Elfisa.UI/Controls/ModernDataGridView.cs @@ -8,6 +8,7 @@ namespace Elfisa.UI.Controls public class ModernDataGridView : DataGridView { private ThemeColors _theme; + private int? _hoverRowIndex; public ModernDataGridView() { @@ -24,6 +25,7 @@ namespace Elfisa.UI.Controls ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single; DoubleBuffered = true; + CellFormatting += OnGridCellFormatting; ApplyTheme(ThemeManager.Colors); } @@ -64,30 +66,73 @@ namespace Elfisa.UI.Controls Font = theme.FontRegular13, Padding = new Padding(12, 0, 12, 0) }; - Invalidate(); + Invalidate(true); + } + + private void OnGridCellFormatting(object sender, DataGridViewCellFormattingEventArgs e) + { + if (e.RowIndex < 0 || e.ColumnIndex < 0) + { + return; + } + + var theme = _theme ?? ThemeManager.Colors; + var row = Rows[e.RowIndex]; + + if (row.Selected) + { + e.CellStyle.BackColor = theme.GridRowSelected; + e.CellStyle.ForeColor = theme.GridRowSelectedText; + } + else if (_hoverRowIndex == e.RowIndex) + { + e.CellStyle.BackColor = theme.GridRowHover; + e.CellStyle.ForeColor = theme.TextPrimary; + } + else if (e.RowIndex % 2 == 1) + { + e.CellStyle.BackColor = theme.GridRowAlternate; + e.CellStyle.ForeColor = theme.TextPrimary; + } + else + { + e.CellStyle.BackColor = theme.GridRowBackground; + e.CellStyle.ForeColor = theme.TextPrimary; + } + + e.CellStyle.SelectionBackColor = theme.GridRowSelected; + e.CellStyle.SelectionForeColor = theme.GridRowSelectedText; + e.CellStyle.Font = theme.FontRegular13; } protected override void OnCellMouseEnter(DataGridViewCellEventArgs e) { base.OnCellMouseEnter(e); - if (e.RowIndex >= 0 && e.RowIndex != CurrentCell?.RowIndex) + if (e.RowIndex < 0 || e.RowIndex == _hoverRowIndex) { - var theme = _theme ?? ThemeManager.Colors; - Rows[e.RowIndex].DefaultCellStyle.BackColor = theme.GridRowHover; + return; } + + var previous = _hoverRowIndex; + _hoverRowIndex = e.RowIndex; + if (previous.HasValue) + { + InvalidateRow(previous.Value); + } + + InvalidateRow(e.RowIndex); } protected override void OnCellMouseLeave(DataGridViewCellEventArgs e) { base.OnCellMouseLeave(e); - if (e.RowIndex >= 0) + if (e.RowIndex < 0 || _hoverRowIndex != e.RowIndex) { - var theme = _theme ?? ThemeManager.Colors; - var isAlt = e.RowIndex % 2 == 1; - Rows[e.RowIndex].DefaultCellStyle.BackColor = isAlt - ? theme.GridRowAlternate - : theme.GridRowBackground; + return; } + + _hoverRowIndex = null; + InvalidateRow(e.RowIndex); } } } diff --git a/src/Elfisa.UI/Controls/ModernDocumentTabStrip.cs b/src/Elfisa.UI/Controls/ModernDocumentTabStrip.cs index 132565d..20ed68a 100644 --- a/src/Elfisa.UI/Controls/ModernDocumentTabStrip.cs +++ b/src/Elfisa.UI/Controls/ModernDocumentTabStrip.cs @@ -27,10 +27,29 @@ namespace Elfisa.UI.Controls private ThemeColors _theme; private string _activeTabId; private string _hoverTabId; + private bool _themeToggleHover; + private bool _isDarkTheme; + private Rectangle _themeToggleRect = Rectangle.Empty; public event EventHandler TabSelected; public event EventHandler TabClosed; public event EventHandler TabCloseAllRequested; + public event EventHandler ThemeToggleClicked; + + public bool IsDarkTheme + { + get => _isDarkTheme; + set + { + if (_isDarkTheme == value) + { + return; + } + + _isDarkTheme = value; + Invalidate(_themeToggleRect); + } + } private readonly ContextMenuStrip _contextMenu; private readonly ToolStripMenuItem _closeTabMenuItem; @@ -62,6 +81,13 @@ namespace Elfisa.UI.Controls _contextMenu = new ContextMenuStrip(); _contextMenu.Items.Add(_closeTabMenuItem); _contextMenu.Items.Add(_closeAllTabsMenuItem); + Resize += (_, __) => UpdateThemeToggleRect(); + } + + private void UpdateThemeToggleRect() + { + const int size = 26; + _themeToggleRect = new Rectangle(Width - size - 10, (Height - size) / 2, size, size); } public IReadOnlyList Tabs => _tabs; @@ -140,6 +166,7 @@ namespace Elfisa.UI.Controls public void ApplyTheme(ThemeColors theme) { _theme = theme; + UpdateThemeToggleRect(); Invalidate(); } @@ -168,6 +195,8 @@ namespace Elfisa.UI.Controls const int minTabWidth = 140; const int gap = 8; const int closeSize = 18; + const int toggleReserve = 44; + var maxTabRight = Math.Max(10, Width - toggleReserve); using (var textFont = theme.FontSemibold14 ?? new Font("Segoe UI", 10f, FontStyle.Bold)) using (var closeFont = new Font("Segoe MDL2 Assets", 10f, FontStyle.Regular)) @@ -176,6 +205,11 @@ namespace Elfisa.UI.Controls { var textSize = TextRenderer.MeasureText(tab.Title, textFont); var tabWidth = Math.Max(minTabWidth, textSize.Width + 48); + if (x + tabWidth > maxTabRight) + { + break; + } + var tabRect = new Rectangle(x, tabTop, tabWidth, tabHeight); _hitAreas[tab.Id] = tabRect; @@ -232,6 +266,41 @@ namespace Elfisa.UI.Controls x += tabWidth + gap; } } + + DrawThemeToggle(g, theme); + } + + private void DrawThemeToggle(Graphics g, ThemeColors theme) + { + if (_themeToggleRect.IsEmpty) + { + UpdateThemeToggleRect(); + } + + var fill = _themeToggleHover + ? GraphicsExtensions.Blend(theme.SurfaceElevated, theme.AccentPrimarySoft, 0.45f) + : theme.Surface; + using (var fillBrush = new SolidBrush(fill)) + { + GraphicsExtensions.FillRoundedRectangle(g, fillBrush, _themeToggleRect, theme.CornerRadiusSmall); + } + + using (var pen = new Pen(_themeToggleHover ? theme.AccentPrimaryBorder : theme.Border, 1f)) + { + GraphicsExtensions.DrawRoundedRectangle(g, pen, _themeToggleRect, theme.CornerRadiusSmall); + } + + var glyph = _isDarkTheme ? "\uE706" : "\uE708"; + using (var iconFont = new Font("Segoe MDL2 Assets", 11f)) + { + TextRenderer.DrawText( + g, + glyph, + iconFont, + _themeToggleRect, + theme.TextSecondary, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine); + } } protected override void OnPaintBackground(PaintEventArgs e) @@ -245,6 +314,12 @@ namespace Elfisa.UI.Controls return; } + if (_themeToggleRect.Contains(e.Location)) + { + ThemeToggleClicked?.Invoke(this, EventArgs.Empty); + return; + } + var tabId = HitTestClose(e.Location); if (!string.IsNullOrEmpty(tabId)) { @@ -270,13 +345,23 @@ namespace Elfisa.UI.Controls Invalidate(); } + var toggleHover = _themeToggleRect.Contains(e.Location); + if (toggleHover != _themeToggleHover) + { + _themeToggleHover = toggleHover; + Invalidate(_themeToggleRect); + } + + Cursor = toggleHover || !string.IsNullOrEmpty(hovered) ? Cursors.Hand : Cursors.Default; base.OnMouseMove(e); } protected override void OnMouseLeave(EventArgs e) { _hoverTabId = null; - Invalidate(); + _themeToggleHover = false; + Invalidate(_themeToggleRect); + Cursor = Cursors.Default; base.OnMouseLeave(e); } diff --git a/src/Elfisa.UI/Helpers/WindowChromeHelper.cs b/src/Elfisa.UI/Helpers/WindowChromeHelper.cs new file mode 100644 index 0000000..6ca4fb9 --- /dev/null +++ b/src/Elfisa.UI/Helpers/WindowChromeHelper.cs @@ -0,0 +1,117 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Elfisa.UI.Theming; + +namespace Elfisa.UI.Helpers +{ + public static class WindowChromeHelper + { + private const int DwmwaUseImmersiveDarkMode = 20; + private const int DwmwaUseImmersiveDarkModeLegacy = 19; + private const int DwmwaCaptionColor = 35; + private const int DwmwaTextColor = 36; + + private const uint SwpNomove = 0x0002; + private const uint SwpNosize = 0x0001; + private const uint SwpNozorder = 0x0004; + private const uint SwpFramechanged = 0x0020; + + [DllImport("dwmapi.dll", PreserveSig = true)] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref int pvAttribute, int cbAttribute); + + [DllImport("dwmapi.dll", PreserveSig = true)] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref uint pvAttribute, int cbAttribute); + + [DllImport("user32.dll", SetLastError = true)] + private static extern bool SetWindowPos( + IntPtr hWnd, + IntPtr hWndInsertAfter, + int x, + int y, + int cx, + int cy, + uint uFlags); + + public static void ApplyTitleBarTheme(Form form, ThemeColors theme) + { + if (form == null || theme == null || !form.IsHandleCreated) + { + return; + } + + var isDark = theme.Mode == ThemeMode.Dark; + var useDarkMode = isDark ? 1 : 0; + TrySetInt(form.Handle, DwmwaUseImmersiveDarkMode, useDarkMode); + TrySetInt(form.Handle, DwmwaUseImmersiveDarkModeLegacy, useDarkMode); + + var caption = isDark ? theme.TitleBarTop : Color.White; + var text = isDark ? Color.White : Color.Black; + + TrySetUInt(form.Handle, DwmwaCaptionColor, ColorToDwm(caption)); + TrySetUInt(form.Handle, DwmwaTextColor, ColorToDwm(text)); + + RefreshNonClientArea(form); + } + + public static void ApplyThemedDialogHeader(Panel headerPanel, Label headerLabel, ThemeColors theme) + { + if (theme == null) + { + return; + } + + var isDark = theme.Mode == ThemeMode.Dark; + if (headerPanel != null) + { + headerPanel.BackColor = isDark ? theme.TitleBarTop : Color.White; + } + + if (headerLabel != null) + { + headerLabel.ForeColor = isDark ? Color.White : Color.Black; + } + } + + public static void ApplyDialogChrome(Form form, Panel headerPanel = null, Label headerLabel = null) + { + if (form == null) + { + return; + } + + var theme = ThemeManager.Colors; + ApplyThemedDialogHeader(headerPanel, headerLabel, theme); + + if (form.IsHandleCreated) + { + ApplyTitleBarTheme(form, theme); + } + else + { + form.HandleCreated += (_, __) => ApplyTitleBarTheme(form, ThemeManager.Colors); + } + } + + private static uint ColorToDwm(Color color) + { + return (uint)(color.R | (color.G << 8) | (color.B << 16)); + } + + private static void RefreshNonClientArea(Form form) + { + SetWindowPos(form.Handle, IntPtr.Zero, 0, 0, 0, 0, SwpNomove | SwpNosize | SwpNozorder | SwpFramechanged); + } + + private static void TrySetInt(IntPtr handle, int attribute, int value) + { + DwmSetWindowAttribute(handle, attribute, ref value, sizeof(int)); + } + + private static void TrySetUInt(IntPtr handle, int attribute, uint value) + { + DwmSetWindowAttribute(handle, attribute, ref value, sizeof(uint)); + } + } +} diff --git a/src/Elfisa.UI/Theming/DarkProductivityPalette.cs b/src/Elfisa.UI/Theming/DarkProductivityPalette.cs new file mode 100644 index 0000000..915b18d --- /dev/null +++ b/src/Elfisa.UI/Theming/DarkProductivityPalette.cs @@ -0,0 +1,83 @@ +using System.Drawing; + +namespace Elfisa.UI.Theming +{ + /// + /// Вариант H — Dark Productivity (ui-ux-pro-max: indigo accents, dark surfaces). + /// Макет: elfisa-design/desktop/variant-h-dark-productivity.html + /// + public sealed class DarkProductivityPalette : IThemePalette + { + public ThemeVariant Variant => ThemeVariant.DarkProductivity; + + public ThemeColors Colors { get; } = new ThemeColors + { + Name = "Dark Productivity", + Mode = ThemeMode.Dark, + BackgroundPrimary = Color.FromArgb(17, 24, 39), + BackgroundSecondary = Color.FromArgb(15, 23, 42), + Surface = Color.FromArgb(31, 41, 55), + SurfaceElevated = Color.FromArgb(37, 47, 63), + Border = Color.FromArgb(55, 65, 81), + BorderSubtle = Color.FromArgb(45, 55, 72), + TextPrimary = Color.FromArgb(243, 244, 246), + TextSecondary = Color.FromArgb(209, 213, 219), + TextMuted = Color.FromArgb(156, 163, 175), + TextOnAccent = Color.White, + AccentPrimary = Color.FromArgb(79, 70, 229), + AccentPrimaryHover = Color.FromArgb(67, 56, 202), + AccentPrimaryPressed = Color.FromArgb(55, 48, 163), + AccentPrimarySoft = Color.FromArgb(30, 27, 75), + AccentPrimaryBorder = Color.FromArgb(129, 140, 248), + AccentSecondary = Color.FromArgb(55, 65, 81), + Success = Color.FromArgb(52, 211, 153), + SuccessSoft = Color.FromArgb(6, 78, 59), + Warning = Color.FromArgb(251, 191, 36), + WarningSoft = Color.FromArgb(66, 32, 6), + Danger = Color.FromArgb(239, 68, 68), + DangerSoft = Color.FromArgb(69, 26, 26), + Info = Color.FromArgb(129, 140, 248), + InfoSoft = Color.FromArgb(30, 27, 75), + TitleBarTop = Color.FromArgb(15, 23, 42), + TitleBarBottom = Color.FromArgb(30, 27, 75), + NavBackground = Color.FromArgb(26, 35, 50), + CartHeaderBackground = Color.FromArgb(37, 47, 63), + ToolbarBackground = Color.FromArgb(26, 35, 50), + SectionHeaderBackground = Color.FromArgb(55, 65, 81), + SidebarBackground = Color.FromArgb(17, 24, 39), + SidebarItem = Color.FromArgb(156, 163, 175), + SidebarItemHover = Color.FromArgb(37, 48, 68), + SidebarItemActive = Color.FromArgb(79, 70, 229), + SidebarItemActiveText = Color.White, + GridHeaderBackground = Color.FromArgb(55, 65, 81), + GridHeaderForeground = Color.FromArgb(243, 244, 246), + GridRowBackground = Color.FromArgb(17, 24, 39), + GridRowAlternate = Color.FromArgb(31, 41, 55), + GridRowHover = Color.FromArgb(37, 48, 68), + GridRowSelected = Color.FromArgb(79, 70, 229), + GridRowSelectedText = Color.White, + GridBorder = Color.FromArgb(45, 55, 72), + InputBackground = Color.FromArgb(17, 24, 39), + InputBorder = Color.FromArgb(55, 65, 81), + InputBorderFocus = Color.FromArgb(129, 140, 248), + OverlayScrim = Color.FromArgb(180, 0, 0, 0), + Shadow = Color.FromArgb(115, 0, 0, 0), + ScrollbarThumb = Color.FromArgb(75, 85, 99), + ScrollbarTrack = Color.FromArgb(26, 35, 50), + CornerRadiusSmall = 6, + CornerRadiusMedium = 8, + GridRowHeight = 36, + GridHeaderHeight = 34 + }; + + public DarkProductivityPalette() + { + Colors.FontRegular12 = new Font("Segoe UI", 12f); + Colors.FontRegular13 = new Font("Segoe UI", 13f); + Colors.FontRegular14 = new Font("Segoe UI", 14f); + Colors.FontSemibold14 = new Font("Segoe UI Semibold", 14f); + Colors.FontSemibold16 = new Font("Segoe UI Semibold", 16f); + Colors.FontBold18 = new Font("Segoe UI", 18f, FontStyle.Bold); + } + } +} diff --git a/src/Elfisa.UI/Theming/ThemeManager.cs b/src/Elfisa.UI/Theming/ThemeManager.cs index 5d6e702..d9edcfb 100644 --- a/src/Elfisa.UI/Theming/ThemeManager.cs +++ b/src/Elfisa.UI/Theming/ThemeManager.cs @@ -13,7 +13,8 @@ namespace Elfisa.UI.Theming { ThemeVariant.LightOffice, new LightOfficePalette() }, { ThemeVariant.DarkRider, new DarkRiderPalette() }, { ThemeVariant.DarkFluent, new DarkFluentPalette() }, - { ThemeVariant.FluentWin11, new FluentWin11Palette() } + { ThemeVariant.FluentWin11, new FluentWin11Palette() }, + { ThemeVariant.DarkProductivity, new DarkProductivityPalette() } }; private static ThemeVariant _currentVariant = ThemeVariant.FluentWin11; @@ -40,7 +41,17 @@ namespace Elfisa.UI.Theming public static ThemeMode CurrentMode => Colors.Mode; public static IReadOnlyList AvailableVariants { get; } = - new[] { ThemeVariant.PharmaTrust, ThemeVariant.Apotheca, ThemeVariant.ClinicalPro, ThemeVariant.LightOffice, ThemeVariant.DarkRider, ThemeVariant.DarkFluent, ThemeVariant.FluentWin11 }; + new[] + { + ThemeVariant.PharmaTrust, + ThemeVariant.Apotheca, + ThemeVariant.ClinicalPro, + ThemeVariant.LightOffice, + ThemeVariant.DarkRider, + ThemeVariant.DarkFluent, + ThemeVariant.FluentWin11, + ThemeVariant.DarkProductivity + }; public static string GetVariantDisplayName(ThemeVariant variant) { @@ -52,5 +63,14 @@ namespace Elfisa.UI.Theming var next = ((int)CurrentVariant + 1) % AvailableVariants.Count; CurrentVariant = AvailableVariants[next]; } + + public static bool IsDarkProductivityActive => CurrentVariant == ThemeVariant.DarkProductivity; + + public static void ToggleProductivityTheme() + { + CurrentVariant = IsDarkProductivityActive + ? ThemeVariant.PharmaTrust + : ThemeVariant.DarkProductivity; + } } } diff --git a/src/Elfisa.UI/Theming/ThemeRenderer.cs b/src/Elfisa.UI/Theming/ThemeRenderer.cs index ff02593..9d4f107 100644 --- a/src/Elfisa.UI/Theming/ThemeRenderer.cs +++ b/src/Elfisa.UI/Theming/ThemeRenderer.cs @@ -1,3 +1,4 @@ +using System.Drawing; using System.Windows.Forms; using Elfisa.UI.Controls; @@ -13,6 +14,20 @@ namespace Elfisa.UI.Theming private static void ApplyRecursive(Control control, ThemeColors colors) { + if (control.Tag as string == "keep-bg") + { + ApplyChildren(control, colors); + return; + } + + if (control.Tag as string == "chrome-child") + { + control.BackColor = colors.BackgroundPrimary; + control.ForeColor = colors.TextPrimary; + ApplyChildren(control, colors); + return; + } + if (control is Form form) { form.BackColor = colors.BackgroundPrimary; @@ -90,6 +105,43 @@ namespace Elfisa.UI.Theming { uploadPanel.ApplyTheme(colors); } + else if (control is DataGridView gridView) + { + gridView.EnableHeadersVisualStyles = false; + gridView.BackgroundColor = colors.GridRowBackground; + gridView.GridColor = colors.GridBorder; + gridView.ColumnHeadersDefaultCellStyle.BackColor = colors.GridHeaderBackground; + gridView.ColumnHeadersDefaultCellStyle.ForeColor = colors.GridHeaderForeground; + gridView.DefaultCellStyle.BackColor = colors.GridRowBackground; + gridView.DefaultCellStyle.ForeColor = colors.TextPrimary; + gridView.DefaultCellStyle.SelectionBackColor = colors.GridRowSelected; + gridView.DefaultCellStyle.SelectionForeColor = colors.GridRowSelectedText; + gridView.AlternatingRowsDefaultCellStyle.BackColor = colors.GridRowAlternate; + } + else if (control is CheckBox checkBox) + { + checkBox.ForeColor = colors.TextPrimary; + checkBox.BackColor = Color.Transparent; + } + else if (control is NumericUpDown numericUpDown) + { + numericUpDown.BackColor = colors.InputBackground; + numericUpDown.ForeColor = colors.TextPrimary; + } + else if (control is TextBox legacyTextBox) + { + legacyTextBox.BackColor = colors.InputBackground; + legacyTextBox.ForeColor = colors.TextPrimary; + } + else if (control is TabControl tabControl) + { + tabControl.BackColor = colors.BackgroundSecondary; + tabControl.ForeColor = colors.TextPrimary; + } + else if (control is SplitContainer splitContainer) + { + splitContainer.BackColor = colors.BackgroundSecondary; + } else if (control.Tag as string == "toolbar") { control.BackColor = colors.ToolbarBackground; @@ -100,11 +152,6 @@ namespace Elfisa.UI.Theming } else if (control is Panel || control is UserControl || control is TableLayoutPanel || control is FlowLayoutPanel) { - if (control.Tag as string == "chrome-child" || control.Tag as string == "keep-bg") - { - return; - } - control.BackColor = colors.BackgroundSecondary; control.ForeColor = colors.TextPrimary; } @@ -117,6 +164,11 @@ namespace Elfisa.UI.Theming } } + ApplyChildren(control, colors); + } + + private static void ApplyChildren(Control control, ThemeColors colors) + { foreach (Control child in control.Controls) { ApplyRecursive(child, colors); diff --git a/src/Elfisa.UI/Theming/ThemeVariant.cs b/src/Elfisa.UI/Theming/ThemeVariant.cs index 01ce683..c171870 100644 --- a/src/Elfisa.UI/Theming/ThemeVariant.cs +++ b/src/Elfisa.UI/Theming/ThemeVariant.cs @@ -8,7 +8,8 @@ namespace Elfisa.UI.Theming LightOffice = 3, DarkRider = 4, DarkFluent = 5, - FluentWin11 = 6 + FluentWin11 = 6, + DarkProductivity = 7 } public enum ThemeMode