Add Dark Productivity theme with native title bar and auth dialog chrome.
Persist theme choice in settings, fix grid row colors on theme switch, and apply DWM caption styling to the main window and authorization dialog. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2e1b13fde6
commit
7ed8822bd4
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,5 +23,8 @@
|
||||
<Setting Name="RegionId" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="UseDarkTheme" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<string> TabSelected;
|
||||
public event EventHandler<string> 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<DocumentTabInfo> 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);
|
||||
}
|
||||
|
||||
|
||||
117
src/Elfisa.UI/Helpers/WindowChromeHelper.cs
Normal file
117
src/Elfisa.UI/Helpers/WindowChromeHelper.cs
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
83
src/Elfisa.UI/Theming/DarkProductivityPalette.cs
Normal file
83
src/Elfisa.UI/Theming/DarkProductivityPalette.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace Elfisa.UI.Theming
|
||||
{
|
||||
/// <summary>
|
||||
/// Вариант H — Dark Productivity (ui-ux-pro-max: indigo accents, dark surfaces).
|
||||
/// Макет: elfisa-design/desktop/variant-h-dark-productivity.html
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<ThemeVariant> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -8,7 +8,8 @@ namespace Elfisa.UI.Theming
|
||||
LightOffice = 3,
|
||||
DarkRider = 4,
|
||||
DarkFluent = 5,
|
||||
FluentWin11 = 6
|
||||
FluentWin11 = 6,
|
||||
DarkProductivity = 7
|
||||
}
|
||||
|
||||
public enum ThemeMode
|
||||
|
||||
Loading…
Reference in New Issue
Block a user