Polish cart tabs and dialog chrome for light/dark themes.
Add ModernTabControl/SplitContainer for cart UI without system borders, fix button corner artifacts and dialog text contrast, and use TitleBarTop green for auth header in light mode. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7ed8822bd4
commit
5cc202dea7
@ -91,6 +91,14 @@ namespace Электронная_Фармация.Classes
|
|||||||
label.ForeColor = theme.TextPrimary;
|
label.ForeColor = theme.TextPrimary;
|
||||||
label.Font = theme.FontRegular13;
|
label.Font = theme.FontRegular13;
|
||||||
}
|
}
|
||||||
|
else if (control is ModernTabControl modernTabControl)
|
||||||
|
{
|
||||||
|
modernTabControl.ApplyTheme(theme);
|
||||||
|
}
|
||||||
|
else if (control is ModernSplitContainer modernSplitContainer)
|
||||||
|
{
|
||||||
|
modernSplitContainer.ApplyTheme(theme);
|
||||||
|
}
|
||||||
else if (control is TabControl tabControl)
|
else if (control is TabControl tabControl)
|
||||||
{
|
{
|
||||||
tabControl.BackColor = theme.BackgroundSecondary;
|
tabControl.BackColor = theme.BackgroundSecondary;
|
||||||
@ -101,7 +109,13 @@ namespace Электронная_Фармация.Classes
|
|||||||
toolStrip.BackColor = theme.TitleBarBottom;
|
toolStrip.BackColor = theme.TitleBarBottom;
|
||||||
toolStrip.ForeColor = Color.White;
|
toolStrip.ForeColor = Color.White;
|
||||||
}
|
}
|
||||||
else if (control is Panel || control is UserControl || control is TableLayoutPanel || control is SplitContainer)
|
else if (control is SplitContainer splitContainer)
|
||||||
|
{
|
||||||
|
splitContainer.BackColor = theme.Mode == ThemeMode.Dark ? theme.BorderSubtle : theme.Border;
|
||||||
|
splitContainer.Panel1.BackColor = theme.BackgroundPrimary;
|
||||||
|
splitContainer.Panel2.BackColor = theme.BackgroundPrimary;
|
||||||
|
}
|
||||||
|
else if (control is Panel || control is UserControl || control is TableLayoutPanel)
|
||||||
{
|
{
|
||||||
if (control.Tag as string == "keep-bg")
|
if (control.Tag as string == "keep-bg")
|
||||||
{
|
{
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using System.Data.SQLite;
|
|||||||
using Электронная_Фармация.UserControls;
|
using Электронная_Фармация.UserControls;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using Электронная_Фармация.Classes;
|
using Электронная_Фармация.Classes;
|
||||||
|
using Elfisa.UI.Theming;
|
||||||
|
|
||||||
namespace Электронная_Фармация.UserControls
|
namespace Электронная_Фармация.UserControls
|
||||||
{
|
{
|
||||||
@ -223,6 +224,7 @@ and ConsigneesName = '{consigneeName}'
|
|||||||
UiThemeHelper.ApplyToControlTree(this);
|
UiThemeHelper.ApplyToControlTree(this);
|
||||||
_consigneeName = ParentForm?.ConsigneeName ?? string.Empty;
|
_consigneeName = ParentForm?.ConsigneeName ?? string.Empty;
|
||||||
loadDataAboutOrderV2(_supplierName);
|
loadDataAboutOrderV2(_supplierName);
|
||||||
|
dgvOrder.ApplyTheme(ThemeManager.Colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnEraseOrder_Click(object sender, EventArgs e)
|
private void btnEraseOrder_Click(object sender, EventArgs e)
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UCPriceList));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UCPriceList));
|
||||||
this.PContentPriceList = new System.Windows.Forms.Panel();
|
this.PContentPriceList = new System.Windows.Forms.Panel();
|
||||||
this.SplitPriceList = new System.Windows.Forms.SplitContainer();
|
this.SplitPriceList = new Elfisa.UI.Controls.ModernSplitContainer();
|
||||||
this.TLPPriceList = new System.Windows.Forms.TableLayoutPanel();
|
this.TLPPriceList = new System.Windows.Forms.TableLayoutPanel();
|
||||||
this.dgvPriceList = new Elfisa.UI.Controls.ModernDataGridView();
|
this.dgvPriceList = new Elfisa.UI.Controls.ModernDataGridView();
|
||||||
this.panel1 = new System.Windows.Forms.Panel();
|
this.panel1 = new System.Windows.Forms.Panel();
|
||||||
@ -45,7 +45,7 @@
|
|||||||
this.label3 = new System.Windows.Forms.Label();
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
this.POrderInfo = new System.Windows.Forms.Panel();
|
this.POrderInfo = new System.Windows.Forms.Panel();
|
||||||
this.dgvOrder = new Elfisa.UI.Controls.ModernDataGridView();
|
this.dgvOrder = new Elfisa.UI.Controls.ModernDataGridView();
|
||||||
this.tabOrderItems = new System.Windows.Forms.TabControl();
|
this.tabOrderItems = new Elfisa.UI.Controls.ModernTabControl();
|
||||||
this.lblSumOfOrder = new System.Windows.Forms.Label();
|
this.lblSumOfOrder = new System.Windows.Forms.Label();
|
||||||
this.btnEraseOrder = new Elfisa.UI.Controls.ModernButton();
|
this.btnEraseOrder = new Elfisa.UI.Controls.ModernButton();
|
||||||
this.btnSendOrder = new Elfisa.UI.Controls.ModernButton();
|
this.btnSendOrder = new Elfisa.UI.Controls.ModernButton();
|
||||||
@ -100,6 +100,7 @@
|
|||||||
this.SplitPriceList.Panel2.Controls.Add(this.POrderInfo);
|
this.SplitPriceList.Panel2.Controls.Add(this.POrderInfo);
|
||||||
this.SplitPriceList.Size = new System.Drawing.Size(1053, 532);
|
this.SplitPriceList.Size = new System.Drawing.Size(1053, 532);
|
||||||
this.SplitPriceList.SplitterDistance = 290;
|
this.SplitPriceList.SplitterDistance = 290;
|
||||||
|
this.SplitPriceList.SplitterWidth = 2;
|
||||||
this.SplitPriceList.TabIndex = 0;
|
this.SplitPriceList.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// TLPPriceList
|
// TLPPriceList
|
||||||
@ -288,12 +289,13 @@
|
|||||||
this.tabOrderItems.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
this.tabOrderItems.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
| System.Windows.Forms.AnchorStyles.Left)
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.tabOrderItems.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.tabOrderItems.Font = new System.Drawing.Font("Segoe UI", 11.25F);
|
this.tabOrderItems.Font = new System.Drawing.Font("Segoe UI", 11.25F);
|
||||||
this.tabOrderItems.Location = new System.Drawing.Point(2, 24);
|
this.tabOrderItems.Location = new System.Drawing.Point(0, 0);
|
||||||
this.tabOrderItems.Margin = new System.Windows.Forms.Padding(2);
|
this.tabOrderItems.Margin = new System.Windows.Forms.Padding(2);
|
||||||
this.tabOrderItems.Name = "tabOrderItems";
|
this.tabOrderItems.Name = "tabOrderItems";
|
||||||
this.tabOrderItems.SelectedIndex = 0;
|
this.tabOrderItems.SelectedIndex = 0;
|
||||||
this.tabOrderItems.Size = new System.Drawing.Size(1048, 215);
|
this.tabOrderItems.Size = new System.Drawing.Size(1048, 238);
|
||||||
this.tabOrderItems.TabIndex = 11;
|
this.tabOrderItems.TabIndex = 11;
|
||||||
//
|
//
|
||||||
// lblSumOfOrder
|
// lblSumOfOrder
|
||||||
@ -485,7 +487,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private System.Windows.Forms.Panel PContentPriceList;
|
private System.Windows.Forms.Panel PContentPriceList;
|
||||||
private System.Windows.Forms.SplitContainer SplitPriceList;
|
private Elfisa.UI.Controls.ModernSplitContainer SplitPriceList;
|
||||||
private System.Windows.Forms.Panel POrderInfo;
|
private System.Windows.Forms.Panel POrderInfo;
|
||||||
private Elfisa.UI.Controls.ModernTextBox txtSearchGoodNameInPriceList;
|
private Elfisa.UI.Controls.ModernTextBox txtSearchGoodNameInPriceList;
|
||||||
private System.Windows.Forms.Label label2;
|
private System.Windows.Forms.Label label2;
|
||||||
@ -499,7 +501,7 @@
|
|||||||
private System.Windows.Forms.NumericUpDown numericPercent;
|
private System.Windows.Forms.NumericUpDown numericPercent;
|
||||||
private System.Windows.Forms.TableLayoutPanel TLPPriceList;
|
private System.Windows.Forms.TableLayoutPanel TLPPriceList;
|
||||||
private Elfisa.UI.Controls.ModernTextBox txtConsignee;
|
private Elfisa.UI.Controls.ModernTextBox txtConsignee;
|
||||||
private System.Windows.Forms.TabControl tabOrderItems;
|
private Elfisa.UI.Controls.ModernTabControl tabOrderItems;
|
||||||
public Elfisa.UI.Controls.ModernDataGridView dgvPriceList;
|
public Elfisa.UI.Controls.ModernDataGridView dgvPriceList;
|
||||||
private Elfisa.UI.Controls.ModernDataGridView dgvOrder;
|
private Elfisa.UI.Controls.ModernDataGridView dgvOrder;
|
||||||
private System.Windows.Forms.Label lblSumOfOrder;
|
private System.Windows.Forms.Label lblSumOfOrder;
|
||||||
|
|||||||
@ -326,18 +326,18 @@ namespace Электронная_Фармация.UserControls
|
|||||||
}
|
}
|
||||||
|
|
||||||
TabPage pageSupplier = new TabPage($"{tabName}");
|
TabPage pageSupplier = new TabPage($"{tabName}");
|
||||||
|
if (SupplierName == string.Empty)
|
||||||
|
{
|
||||||
|
pageSupplier.Tag = "cart";
|
||||||
|
}
|
||||||
|
|
||||||
UCOrderItems UCOrderItemsBySuppliers = new UCOrderItems(SupplierName);
|
UCOrderItems UCOrderItemsBySuppliers = new UCOrderItems(SupplierName);
|
||||||
UCOrderItemsBySuppliers.ParentForm = this;
|
UCOrderItemsBySuppliers.ParentForm = this;
|
||||||
|
UCOrderItemsBySuppliers.Dock = DockStyle.Fill;
|
||||||
pageSupplier.SuspendLayout();
|
|
||||||
pageSupplier.ResumeLayout();
|
|
||||||
tabOrderItems.TabPages.Add(pageSupplier);
|
|
||||||
|
|
||||||
|
|
||||||
pageSupplier.Controls.Add(UCOrderItemsBySuppliers);
|
pageSupplier.Controls.Add(UCOrderItemsBySuppliers);
|
||||||
|
|
||||||
UCOrderItemsBySuppliers.Dock = DockStyle.Fill;
|
tabOrderItems.TabPages.Add(pageSupplier);
|
||||||
|
|
||||||
tabOrderItems.SelectTab(pageSupplier);
|
tabOrderItems.SelectTab(pageSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -83,6 +83,7 @@ namespace Elfisa.UI.Controls
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_buttonStyle = value;
|
_buttonStyle = value;
|
||||||
|
ApplyRoundedRegion();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +115,56 @@ namespace Elfisa.UI.Controls
|
|||||||
return theme.BackgroundSecondary;
|
return theme.BackgroundSecondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parent?.BackColor ?? theme.ToolbarBackground;
|
var current = Parent;
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
if (current.Tag as string == "keep-bg")
|
||||||
|
{
|
||||||
|
current = current.Parent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var backColor = current.BackColor;
|
||||||
|
if (backColor.A > 0 && backColor != Color.Transparent)
|
||||||
|
{
|
||||||
|
return backColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme.Surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetCornerRadius()
|
||||||
|
{
|
||||||
|
if (_headerNavMode || _topNavMode || _sidebarMode)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SkillGradientButtonPaint.UsesGradient(_buttonStyle, _compactIconMode))
|
||||||
|
{
|
||||||
|
return SkillGradientButtonPaint.GetCornerRadius(_buttonStyle, _compactIconMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyRoundedRegion()
|
||||||
|
{
|
||||||
|
var radius = GetCornerRadius();
|
||||||
|
if (radius <= 0 || Width <= 0 || Height <= 0)
|
||||||
|
{
|
||||||
|
Region = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = new Rectangle(0, 0, Width, Height);
|
||||||
|
using (var path = GraphicsExtensions.CreateRoundedRectangle(bounds, radius))
|
||||||
|
{
|
||||||
|
Region = new Region(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModernButton()
|
public ModernButton()
|
||||||
@ -157,6 +207,7 @@ namespace Elfisa.UI.Controls
|
|||||||
BackColor = ResolveChromeBackground();
|
BackColor = ResolveChromeBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ApplyRoundedRegion();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +251,25 @@ namespace Elfisa.UI.Controls
|
|||||||
base.OnEnabledChanged(e);
|
base.OnEnabledChanged(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnHandleCreated(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnHandleCreated(e);
|
||||||
|
ApplyRoundedRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResize(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnResize(e);
|
||||||
|
ApplyRoundedRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParentChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnParentChanged(e);
|
||||||
|
ApplyRoundedRegion();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnGotFocus(EventArgs e)
|
protected override void OnGotFocus(EventArgs e)
|
||||||
{
|
{
|
||||||
_focused = true;
|
_focused = true;
|
||||||
@ -235,6 +305,14 @@ namespace Elfisa.UI.Controls
|
|||||||
var bounds = new Rectangle(0, 0, Width, Height);
|
var bounds = new Rectangle(0, 0, Width, Height);
|
||||||
var usesGradient = SkillGradientButtonPaint.UsesGradient(_buttonStyle, _compactIconMode);
|
var usesGradient = SkillGradientButtonPaint.UsesGradient(_buttonStyle, _compactIconMode);
|
||||||
|
|
||||||
|
if (!_headerNavMode && !_topNavMode && !_sidebarMode)
|
||||||
|
{
|
||||||
|
using (var bgBrush = new SolidBrush(ResolveChromeBackground()))
|
||||||
|
{
|
||||||
|
g.FillRectangle(bgBrush, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_headerNavMode)
|
if (_headerNavMode)
|
||||||
{
|
{
|
||||||
var headerBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
var headerBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||||
@ -262,11 +340,6 @@ namespace Elfisa.UI.Controls
|
|||||||
|
|
||||||
if (usesGradient && !_topNavMode && !_sidebarMode)
|
if (usesGradient && !_topNavMode && !_sidebarMode)
|
||||||
{
|
{
|
||||||
using (var bgBrush = new SolidBrush(ResolveChromeBackground()))
|
|
||||||
{
|
|
||||||
g.FillRectangle(bgBrush, bounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkillGradientButtonPaint.Paint(
|
SkillGradientButtonPaint.Paint(
|
||||||
g,
|
g,
|
||||||
bounds,
|
bounds,
|
||||||
@ -288,7 +361,7 @@ namespace Elfisa.UI.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
var flatBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
var flatBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||||
var radius = _compactIconMode ? 6 : 6;
|
var radius = GetCornerRadius();
|
||||||
var baseColor = ResolveBaseColor(theme);
|
var baseColor = ResolveBaseColor(theme);
|
||||||
var fill = baseColor;
|
var fill = baseColor;
|
||||||
|
|
||||||
|
|||||||
@ -23,17 +23,34 @@ namespace Elfisa.UI.Controls
|
|||||||
AllowUserToResizeColumns = true;
|
AllowUserToResizeColumns = true;
|
||||||
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
|
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
|
||||||
ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
|
ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
|
||||||
ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
|
ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None;
|
||||||
DoubleBuffered = true;
|
DoubleBuffered = true;
|
||||||
|
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
|
||||||
CellFormatting += OnGridCellFormatting;
|
CellFormatting += OnGridCellFormatting;
|
||||||
ApplyTheme(ThemeManager.Colors);
|
ApplyTheme(ThemeManager.Colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyBorderStyles(ThemeColors theme)
|
||||||
|
{
|
||||||
|
GridColor = theme.GridBorder;
|
||||||
|
|
||||||
|
AdvancedCellBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
|
||||||
|
AdvancedCellBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Single;
|
||||||
|
|
||||||
|
AdvancedColumnHeadersBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
|
||||||
|
AdvancedColumnHeadersBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.Single;
|
||||||
|
|
||||||
|
if (Rows.Count > 0)
|
||||||
|
{
|
||||||
|
AdvancedRowHeadersBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ApplyTheme(ThemeColors theme)
|
public void ApplyTheme(ThemeColors theme)
|
||||||
{
|
{
|
||||||
_theme = theme;
|
_theme = theme;
|
||||||
BackgroundColor = theme.GridRowBackground;
|
BackgroundColor = theme.GridRowBackground;
|
||||||
GridColor = theme.GridBorder;
|
ApplyBorderStyles(theme);
|
||||||
ColumnHeadersHeight = theme.GridHeaderHeight;
|
ColumnHeadersHeight = theme.GridHeaderHeight;
|
||||||
RowTemplate.Height = theme.GridRowHeight;
|
RowTemplate.Height = theme.GridRowHeight;
|
||||||
Font = theme.FontRegular13;
|
Font = theme.FontRegular13;
|
||||||
@ -69,6 +86,24 @@ namespace Elfisa.UI.Controls
|
|||||||
Invalidate(true);
|
Invalidate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPaint(e);
|
||||||
|
|
||||||
|
var theme = _theme ?? ThemeManager.Colors;
|
||||||
|
using (var pen = new Pen(theme.GridBorder))
|
||||||
|
{
|
||||||
|
var rect = new Rectangle(0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
|
||||||
|
e.Graphics.DrawRectangle(pen, rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnRowsAdded(DataGridViewRowsAddedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnRowsAdded(e);
|
||||||
|
ApplyBorderStyles(_theme ?? ThemeManager.Colors);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGridCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
|
private void OnGridCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.RowIndex < 0 || e.ColumnIndex < 0)
|
if (e.RowIndex < 0 || e.ColumnIndex < 0)
|
||||||
|
|||||||
24
src/Elfisa.UI/Controls/ModernSplitContainer.cs
Normal file
24
src/Elfisa.UI/Controls/ModernSplitContainer.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Elfisa.UI.Theming;
|
||||||
|
|
||||||
|
namespace Elfisa.UI.Controls
|
||||||
|
{
|
||||||
|
public class ModernSplitContainer : SplitContainer
|
||||||
|
{
|
||||||
|
public ModernSplitContainer()
|
||||||
|
{
|
||||||
|
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
|
||||||
|
BorderStyle = BorderStyle.None;
|
||||||
|
SplitterWidth = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTheme(ThemeColors theme)
|
||||||
|
{
|
||||||
|
BackColor = theme.Mode == ThemeMode.Dark ? theme.Border : theme.Border;
|
||||||
|
Panel1.BackColor = theme.BackgroundPrimary;
|
||||||
|
Panel2.BackColor = theme.BackgroundPrimary;
|
||||||
|
Invalidate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
389
src/Elfisa.UI/Controls/ModernTabControl.cs
Normal file
389
src/Elfisa.UI/Controls/ModernTabControl.cs
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Elfisa.UI.Helpers;
|
||||||
|
using Elfisa.UI.Theming;
|
||||||
|
|
||||||
|
namespace Elfisa.UI.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Вкладки в стиле документных. Контент показывается в Panel — без системной рамки TabControl.
|
||||||
|
/// </summary>
|
||||||
|
public class ModernTabControl : UserControl
|
||||||
|
{
|
||||||
|
private const int StripHeight = 40;
|
||||||
|
private const int TabTop = 6;
|
||||||
|
private const int TabHeight = 28;
|
||||||
|
private const int MinTabWidth = 120;
|
||||||
|
private const int TabGap = 8;
|
||||||
|
private const int ContentOverlap = 2;
|
||||||
|
private const int FramePadding = 1;
|
||||||
|
|
||||||
|
private readonly TabControl _inner;
|
||||||
|
private readonly Panel _contentFrame;
|
||||||
|
private readonly Panel _contentHost;
|
||||||
|
private readonly Panel _strip;
|
||||||
|
private readonly List<Rectangle> _tabHitAreas = new List<Rectangle>();
|
||||||
|
private ThemeColors _theme;
|
||||||
|
private int _hoverIndex = -1;
|
||||||
|
private TabPage _displayedPage;
|
||||||
|
private bool _isReparenting;
|
||||||
|
|
||||||
|
public TabControl.TabPageCollection TabPages => _inner.TabPages;
|
||||||
|
|
||||||
|
public int SelectedIndex
|
||||||
|
{
|
||||||
|
get => _inner.SelectedIndex;
|
||||||
|
set => _inner.SelectedIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TabCount => _inner.TabCount;
|
||||||
|
|
||||||
|
public ModernTabControl()
|
||||||
|
{
|
||||||
|
SetStyle(ControlStyles.AllPaintingInWmPaint |
|
||||||
|
ControlStyles.OptimizedDoubleBuffer |
|
||||||
|
ControlStyles.ResizeRedraw, true);
|
||||||
|
|
||||||
|
_inner = new TabControl
|
||||||
|
{
|
||||||
|
Visible = false,
|
||||||
|
Size = new Size(0, 0),
|
||||||
|
TabStop = false,
|
||||||
|
Tag = "keep-bg"
|
||||||
|
};
|
||||||
|
_inner.SelectedIndexChanged += (_, __) =>
|
||||||
|
{
|
||||||
|
DisplaySelectedTab();
|
||||||
|
_strip.Invalidate();
|
||||||
|
};
|
||||||
|
_inner.ControlAdded += OnInnerControlAdded;
|
||||||
|
_inner.ControlRemoved += OnInnerControlRemoved;
|
||||||
|
|
||||||
|
_contentHost = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Tag = "keep-bg"
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentFrame = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Padding = new Padding(FramePadding),
|
||||||
|
Tag = "keep-bg"
|
||||||
|
};
|
||||||
|
_contentFrame.Controls.Add(_contentHost);
|
||||||
|
|
||||||
|
_strip = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = StripHeight,
|
||||||
|
Tag = "keep-bg"
|
||||||
|
};
|
||||||
|
_strip.Paint += OnStripPaint;
|
||||||
|
_strip.MouseMove += OnStripMouseMove;
|
||||||
|
_strip.MouseLeave += OnStripMouseLeave;
|
||||||
|
_strip.MouseClick += OnStripMouseClick;
|
||||||
|
|
||||||
|
Controls.Add(_inner);
|
||||||
|
Controls.Add(_contentFrame);
|
||||||
|
Controls.Add(_strip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectTab(TabPage page)
|
||||||
|
{
|
||||||
|
var index = _inner.TabPages.IndexOf(page);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inner.SelectedIndex == index)
|
||||||
|
{
|
||||||
|
DisplaySelectedTab();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_inner.SelectedIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTheme(ThemeColors theme)
|
||||||
|
{
|
||||||
|
_theme = theme;
|
||||||
|
BackColor = theme.BackgroundSecondary;
|
||||||
|
_strip.BackColor = theme.BackgroundSecondary;
|
||||||
|
_contentFrame.BackColor = theme.Border;
|
||||||
|
_contentHost.BackColor = theme.BackgroundPrimary;
|
||||||
|
SyncTabPageTheme();
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInnerControlAdded(object sender, ControlEventArgs e)
|
||||||
|
{
|
||||||
|
SyncTabPageTheme();
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInnerControlRemoved(object sender, ControlEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Control is TabPage page && page == _displayedPage)
|
||||||
|
{
|
||||||
|
_displayedPage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inner.TabCount == 0)
|
||||||
|
{
|
||||||
|
_displayedPage = null;
|
||||||
|
_contentHost.Controls.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisplaySelectedTab()
|
||||||
|
{
|
||||||
|
if (_isReparenting)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isReparenting = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReturnControlsToTabPage(_displayedPage);
|
||||||
|
|
||||||
|
if (_inner.SelectedIndex < 0 || _inner.SelectedIndex >= _inner.TabCount)
|
||||||
|
{
|
||||||
|
_displayedPage = null;
|
||||||
|
_contentHost.Controls.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_displayedPage = _inner.TabPages[_inner.SelectedIndex];
|
||||||
|
MoveControlsToHost(_displayedPage);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isReparenting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReturnControlsToTabPage(TabPage page)
|
||||||
|
{
|
||||||
|
if (page == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var controls = new Control[_contentHost.Controls.Count];
|
||||||
|
_contentHost.Controls.CopyTo(controls, 0);
|
||||||
|
_contentHost.Controls.Clear();
|
||||||
|
|
||||||
|
foreach (var control in controls)
|
||||||
|
{
|
||||||
|
control.Dock = DockStyle.Fill;
|
||||||
|
page.Controls.Add(control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveControlsToHost(TabPage page)
|
||||||
|
{
|
||||||
|
_contentHost.Controls.Clear();
|
||||||
|
|
||||||
|
var controls = new Control[page.Controls.Count];
|
||||||
|
page.Controls.CopyTo(controls, 0);
|
||||||
|
page.Controls.Clear();
|
||||||
|
|
||||||
|
foreach (var control in controls)
|
||||||
|
{
|
||||||
|
control.Dock = DockStyle.Fill;
|
||||||
|
_contentHost.Controls.Add(control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStripPaint(object sender, PaintEventArgs e)
|
||||||
|
{
|
||||||
|
var theme = _theme ?? ThemeManager.Colors;
|
||||||
|
var g = e.Graphics;
|
||||||
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||||
|
|
||||||
|
using (var bgBrush = new SolidBrush(theme.BackgroundSecondary))
|
||||||
|
{
|
||||||
|
g.FillRectangle(bgBrush, _strip.ClientRectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
_tabHitAreas.Clear();
|
||||||
|
if (_inner.TabCount == 0)
|
||||||
|
{
|
||||||
|
DrawStripSeparator(g, theme, null, _strip.Width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = 10;
|
||||||
|
Rectangle? activeRect = null;
|
||||||
|
using (var textFont = theme.FontSemibold14 ?? new Font("Segoe UI", 10f, FontStyle.Bold))
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _inner.TabCount; i++)
|
||||||
|
{
|
||||||
|
var page = _inner.TabPages[i];
|
||||||
|
var textSize = TextRenderer.MeasureText(page.Text, textFont);
|
||||||
|
var tabWidth = Math.Max(MinTabWidth, textSize.Width + 28);
|
||||||
|
var tabRect = new Rectangle(x, TabTop, tabWidth, TabHeight);
|
||||||
|
_tabHitAreas.Add(tabRect);
|
||||||
|
|
||||||
|
var isActive = _inner.SelectedIndex == i;
|
||||||
|
var isHover = _hoverIndex == i;
|
||||||
|
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
activeRect = new Rectangle(x, TabTop, tabWidth, StripHeight - TabTop + ContentOverlap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var backColor = theme.Surface;
|
||||||
|
if (isHover)
|
||||||
|
{
|
||||||
|
backColor = GraphicsExtensions.Blend(backColor, theme.AccentPrimarySoft, 0.35f);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var brush = new SolidBrush(backColor))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.FillRoundedRectangle(g, brush, tabRect, theme.CornerRadiusSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var pen = new Pen(theme.BorderSubtle))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.DrawRoundedRectangle(g, pen, tabRect, theme.CornerRadiusSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRenderer.DrawText(
|
||||||
|
g,
|
||||||
|
page.Text,
|
||||||
|
textFont,
|
||||||
|
tabRect,
|
||||||
|
theme.TextSecondary,
|
||||||
|
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.EndEllipsis);
|
||||||
|
}
|
||||||
|
|
||||||
|
x += tabWidth + TabGap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeRect.HasValue)
|
||||||
|
{
|
||||||
|
var rect = activeRect.Value;
|
||||||
|
using (var brush = new SolidBrush(theme.BackgroundPrimary))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.FillTopRoundedRectangle(g, brush, rect, theme.CornerRadiusSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
var outlineColor = theme.Mode == ThemeMode.Dark ? theme.BorderSubtle : theme.AccentPrimaryBorder;
|
||||||
|
using (var pen = new Pen(outlineColor, 1f))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.DrawAttachedTabOutline(g, pen, rect, theme.CornerRadiusSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var seam = new SolidBrush(theme.BackgroundPrimary))
|
||||||
|
{
|
||||||
|
g.FillRectangle(seam, rect.Left, StripHeight - ContentOverlap - 1, rect.Width, ContentOverlap + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var textFont = theme.FontSemibold14 ?? new Font("Segoe UI", 10f, FontStyle.Bold))
|
||||||
|
{
|
||||||
|
var textRect = new Rectangle(rect.X, TabTop, rect.Width, TabHeight);
|
||||||
|
TextRenderer.DrawText(
|
||||||
|
g,
|
||||||
|
_inner.TabPages[_inner.SelectedIndex].Text,
|
||||||
|
textFont,
|
||||||
|
textRect,
|
||||||
|
theme.TextPrimary,
|
||||||
|
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.EndEllipsis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawStripSeparator(g, theme, activeRect, _strip.Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawStripSeparator(Graphics g, ThemeColors theme, Rectangle? activeRect, int width)
|
||||||
|
{
|
||||||
|
var y = StripHeight - 1;
|
||||||
|
using (var separator = new Pen(theme.Border))
|
||||||
|
{
|
||||||
|
if (activeRect.HasValue)
|
||||||
|
{
|
||||||
|
var rect = activeRect.Value;
|
||||||
|
if (rect.Left > 0)
|
||||||
|
{
|
||||||
|
g.DrawLine(separator, 0, y, rect.Left, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rect.Right < width)
|
||||||
|
{
|
||||||
|
g.DrawLine(separator, rect.Right, y, width, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g.DrawLine(separator, 0, y, width, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStripMouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
var hoverIndex = HitTestTab(e.Location);
|
||||||
|
if (hoverIndex != _hoverIndex)
|
||||||
|
{
|
||||||
|
_hoverIndex = hoverIndex;
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_strip.Cursor = hoverIndex >= 0 ? Cursors.Hand : Cursors.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStripMouseLeave(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_hoverIndex = -1;
|
||||||
|
_strip.Cursor = Cursors.Default;
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStripMouseClick(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
var index = HitTestTab(e.Location);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
SelectedIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int HitTestTab(Point location)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _tabHitAreas.Count; i++)
|
||||||
|
{
|
||||||
|
if (_tabHitAreas[i].Contains(location))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncTabPageTheme()
|
||||||
|
{
|
||||||
|
var theme = _theme ?? ThemeManager.Colors;
|
||||||
|
foreach (TabPage page in _inner.TabPages)
|
||||||
|
{
|
||||||
|
page.BackColor = theme.BackgroundPrimary;
|
||||||
|
page.ForeColor = theme.TextPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
_strip.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,21 +19,21 @@ namespace Elfisa.UI.Dialogs
|
|||||||
ShowInTaskbar = false;
|
ShowInTaskbar = false;
|
||||||
Size = new Size(440, 220);
|
Size = new Size(440, 220);
|
||||||
Padding = new Padding(20);
|
Padding = new Padding(20);
|
||||||
BackColor = ThemeManager.Colors.Surface;
|
|
||||||
|
|
||||||
var titleLabel = new Label
|
var titleLabel = new Label
|
||||||
{
|
{
|
||||||
Text = title,
|
Text = title,
|
||||||
Dock = DockStyle.Top,
|
Dock = DockStyle.Top,
|
||||||
Height = 34,
|
Height = 34,
|
||||||
Font = ThemeManager.Colors.FontSemibold16
|
Font = ThemeManager.Colors.FontSemibold16,
|
||||||
|
BackColor = Color.Transparent
|
||||||
};
|
};
|
||||||
var messageLabel = new Label
|
var messageLabel = new Label
|
||||||
{
|
{
|
||||||
Text = message,
|
Text = message,
|
||||||
Dock = DockStyle.Fill,
|
Dock = DockStyle.Fill,
|
||||||
Font = ThemeManager.Colors.FontRegular14,
|
Font = ThemeManager.Colors.FontRegular14,
|
||||||
Tag = "muted"
|
BackColor = Color.Transparent
|
||||||
};
|
};
|
||||||
|
|
||||||
var buttonPanel = new FlowLayoutPanel
|
var buttonPanel = new FlowLayoutPanel
|
||||||
@ -63,11 +63,41 @@ namespace Elfisa.UI.Dialogs
|
|||||||
Controls.Add(messageLabel);
|
Controls.Add(messageLabel);
|
||||||
Controls.Add(buttonPanel);
|
Controls.Add(buttonPanel);
|
||||||
Controls.Add(titleLabel);
|
Controls.Add(titleLabel);
|
||||||
|
|
||||||
|
ApplyTheme(ThemeManager.Colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyTheme(ThemeColors theme)
|
||||||
|
{
|
||||||
|
BackColor = theme.Surface;
|
||||||
|
ForeColor = theme.TextPrimary;
|
||||||
|
|
||||||
|
foreach (Control control in Controls)
|
||||||
|
{
|
||||||
|
if (control is Label label)
|
||||||
|
{
|
||||||
|
label.ForeColor = theme.TextPrimary;
|
||||||
|
label.BackColor = Color.Transparent;
|
||||||
|
}
|
||||||
|
else if (control is FlowLayoutPanel panel)
|
||||||
|
{
|
||||||
|
panel.BackColor = theme.Surface;
|
||||||
|
panel.ForeColor = theme.TextPrimary;
|
||||||
|
foreach (Control child in panel.Controls)
|
||||||
|
{
|
||||||
|
if (child is ModernButton button)
|
||||||
|
{
|
||||||
|
button.ApplyTheme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddButton(FlowLayoutPanel panel, string text, ModernButtonStyle style, DialogResult result)
|
private void AddButton(FlowLayoutPanel panel, string text, ModernButtonStyle style, DialogResult result)
|
||||||
{
|
{
|
||||||
var button = new ModernButton { Text = text, Width = 100, ButtonStyle = style };
|
var button = new ModernButton { Text = text, Width = 100, ButtonStyle = style };
|
||||||
|
button.ApplyTheme(ThemeManager.Colors);
|
||||||
button.Click += (_, __) =>
|
button.Click += (_, __) =>
|
||||||
{
|
{
|
||||||
DialogResult = result;
|
DialogResult = result;
|
||||||
|
|||||||
@ -29,6 +29,72 @@ namespace Elfisa.UI.Helpers
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GraphicsPath CreateTopRoundedRectangle(Rectangle bounds, int radius)
|
||||||
|
{
|
||||||
|
var path = new GraphicsPath();
|
||||||
|
if (radius <= 0 || bounds.Width <= 0 || bounds.Height <= 0)
|
||||||
|
{
|
||||||
|
path.AddRectangle(bounds);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var diameter = radius * 2;
|
||||||
|
var arc = new Rectangle(bounds.X, bounds.Y, diameter, diameter);
|
||||||
|
path.AddArc(arc, 180, 90);
|
||||||
|
arc.X = bounds.Right - diameter;
|
||||||
|
path.AddArc(arc, 270, 90);
|
||||||
|
path.AddLine(bounds.Right, bounds.Y + radius, bounds.Right, bounds.Bottom);
|
||||||
|
path.AddLine(bounds.Right, bounds.Bottom, bounds.Left, bounds.Bottom);
|
||||||
|
path.AddLine(bounds.Left, bounds.Bottom, bounds.Left, bounds.Y + radius);
|
||||||
|
path.CloseFigure();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FillTopRoundedRectangle(Graphics graphics, Brush brush, Rectangle bounds, int radius)
|
||||||
|
{
|
||||||
|
using (var path = CreateTopRoundedRectangle(bounds, radius))
|
||||||
|
{
|
||||||
|
graphics.FillPath(brush, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawTopRoundedRectangle(Graphics graphics, Pen pen, Rectangle bounds, int radius)
|
||||||
|
{
|
||||||
|
using (var path = CreateTopRoundedRectangle(bounds, radius))
|
||||||
|
{
|
||||||
|
graphics.DrawPath(pen, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawAttachedTabOutline(Graphics graphics, Pen pen, Rectangle bounds, int radius)
|
||||||
|
{
|
||||||
|
if (bounds.Width <= 0 || bounds.Height <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius <= 0)
|
||||||
|
{
|
||||||
|
graphics.DrawLine(pen, bounds.Left, bounds.Top, bounds.Right, bounds.Top);
|
||||||
|
graphics.DrawLine(pen, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
|
||||||
|
graphics.DrawLine(pen, bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var path = new GraphicsPath())
|
||||||
|
{
|
||||||
|
var diameter = radius * 2;
|
||||||
|
var arc = new Rectangle(bounds.X, bounds.Y, diameter, diameter);
|
||||||
|
path.AddArc(arc, 180, 90);
|
||||||
|
arc.X = bounds.Right - diameter;
|
||||||
|
path.AddArc(arc, 270, 90);
|
||||||
|
path.AddLine(bounds.Right, bounds.Y + radius, bounds.Right, bounds.Bottom);
|
||||||
|
graphics.DrawPath(pen, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics.DrawLine(pen, bounds.Left, bounds.Y + radius, bounds.Left, bounds.Bottom);
|
||||||
|
}
|
||||||
|
|
||||||
public static void FillRoundedRectangle(Graphics graphics, Brush brush, Rectangle bounds, int radius)
|
public static void FillRoundedRectangle(Graphics graphics, Brush brush, Rectangle bounds, int radius)
|
||||||
{
|
{
|
||||||
using (var path = CreateRoundedRectangle(bounds, radius))
|
using (var path = CreateRoundedRectangle(bounds, radius))
|
||||||
|
|||||||
@ -80,41 +80,31 @@ namespace Elfisa.UI.Helpers
|
|||||||
clientRect.Width - 1,
|
clientRect.Width - 1,
|
||||||
clientRect.Height - 1);
|
clientRect.Height - 1);
|
||||||
|
|
||||||
g.SetClip(clientRect);
|
using (var clipPath = GraphicsExtensions.CreateRoundedRectangle(buttonRect, radius))
|
||||||
|
|
||||||
if (!enabled)
|
|
||||||
{
|
{
|
||||||
using (var brush = new SolidBrush(Color.FromArgb(220, 230, 235)))
|
g.SetClip(clipPath);
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
{
|
{
|
||||||
GraphicsExtensions.FillRoundedRectangle(g, brush, buttonRect, radius);
|
using (var brush = new SolidBrush(Color.FromArgb(220, 230, 235)))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.FillRoundedRectangle(g, brush, buttonRect, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.ResetClip();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
GetGradient(style, hover, pressed, out var top, out var bottom);
|
||||||
}
|
|
||||||
|
|
||||||
// Лёгкая тень — один слой, без чёрной полосы снизу
|
using (var path = GraphicsExtensions.CreateRoundedRectangle(buttonRect, radius))
|
||||||
var shadowRect = new Rectangle(buttonRect.X, buttonRect.Y + 1, buttonRect.Width, buttonRect.Height);
|
using (var brush = new LinearGradientBrush(buttonRect, top, bottom, LinearGradientMode.Vertical))
|
||||||
using (var shadowPath = GraphicsExtensions.CreateRoundedRectangle(shadowRect, radius))
|
|
||||||
using (var shadowBrush = new SolidBrush(Color.FromArgb(28, 0, 0, 0)))
|
|
||||||
{
|
|
||||||
g.FillPath(shadowBrush, shadowPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var faceRect = new Rectangle(buttonRect.X, buttonRect.Y, buttonRect.Width, buttonRect.Height - 1);
|
|
||||||
GetGradient(style, hover, pressed, out var top, out var bottom);
|
|
||||||
|
|
||||||
using (var path = GraphicsExtensions.CreateRoundedRectangle(faceRect, radius))
|
|
||||||
using (var brush = new LinearGradientBrush(faceRect, top, bottom, LinearGradientMode.Vertical))
|
|
||||||
{
|
|
||||||
g.FillPath(brush, path);
|
|
||||||
|
|
||||||
using (var highlightPen = new Pen(Color.FromArgb(36, Color.White), 1f))
|
|
||||||
{
|
{
|
||||||
g.DrawArc(highlightPen, faceRect.X, faceRect.Y, radius * 2, radius * 2, 180, 90);
|
g.FillPath(brush, path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
g.ResetClip();
|
g.ResetClip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Rectangle GetContentRect(Rectangle clientRect, ModernButtonStyle style, bool compactIconMode, bool enabled)
|
public static Rectangle GetContentRect(Rectangle clientRect, ModernButtonStyle style, bool compactIconMode, bool enabled)
|
||||||
|
|||||||
@ -46,8 +46,8 @@ namespace Elfisa.UI.Helpers
|
|||||||
TrySetInt(form.Handle, DwmwaUseImmersiveDarkMode, useDarkMode);
|
TrySetInt(form.Handle, DwmwaUseImmersiveDarkMode, useDarkMode);
|
||||||
TrySetInt(form.Handle, DwmwaUseImmersiveDarkModeLegacy, useDarkMode);
|
TrySetInt(form.Handle, DwmwaUseImmersiveDarkModeLegacy, useDarkMode);
|
||||||
|
|
||||||
var caption = isDark ? theme.TitleBarTop : Color.White;
|
var caption = theme.TitleBarTop;
|
||||||
var text = isDark ? Color.White : Color.Black;
|
var text = IsLightCaption(caption) ? Color.Black : Color.White;
|
||||||
|
|
||||||
TrySetUInt(form.Handle, DwmwaCaptionColor, ColorToDwm(caption));
|
TrySetUInt(form.Handle, DwmwaCaptionColor, ColorToDwm(caption));
|
||||||
TrySetUInt(form.Handle, DwmwaTextColor, ColorToDwm(text));
|
TrySetUInt(form.Handle, DwmwaTextColor, ColorToDwm(text));
|
||||||
@ -62,18 +62,23 @@ namespace Elfisa.UI.Helpers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var isDark = theme.Mode == ThemeMode.Dark;
|
|
||||||
if (headerPanel != null)
|
if (headerPanel != null)
|
||||||
{
|
{
|
||||||
headerPanel.BackColor = isDark ? theme.TitleBarTop : Color.White;
|
headerPanel.BackColor = theme.TitleBarTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerLabel != null)
|
if (headerLabel != null)
|
||||||
{
|
{
|
||||||
headerLabel.ForeColor = isDark ? Color.White : Color.Black;
|
headerLabel.ForeColor = IsLightCaption(theme.TitleBarTop) ? Color.Black : Color.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsLightCaption(Color color)
|
||||||
|
{
|
||||||
|
var luminance = (0.299 * color.R) + (0.587 * color.G) + (0.114 * color.B);
|
||||||
|
return luminance > 180;
|
||||||
|
}
|
||||||
|
|
||||||
public static void ApplyDialogChrome(Form form, Panel headerPanel = null, Label headerLabel = null)
|
public static void ApplyDialogChrome(Form form, Panel headerPanel = null, Label headerLabel = null)
|
||||||
{
|
{
|
||||||
if (form == null)
|
if (form == null)
|
||||||
|
|||||||
@ -97,6 +97,14 @@ namespace Elfisa.UI.Theming
|
|||||||
{
|
{
|
||||||
sectionHeader.ApplyTheme(colors, sectionHeader.Tag as string == "cart");
|
sectionHeader.ApplyTheme(colors, sectionHeader.Tag as string == "cart");
|
||||||
}
|
}
|
||||||
|
else if (control is ModernTabControl modernTabControl)
|
||||||
|
{
|
||||||
|
modernTabControl.ApplyTheme(colors);
|
||||||
|
}
|
||||||
|
else if (control is ModernSplitContainer modernSplitContainer)
|
||||||
|
{
|
||||||
|
modernSplitContainer.ApplyTheme(colors);
|
||||||
|
}
|
||||||
else if (control is ModernUploadZone uploadZone)
|
else if (control is ModernUploadZone uploadZone)
|
||||||
{
|
{
|
||||||
uploadZone.ApplyTheme(colors);
|
uploadZone.ApplyTheme(colors);
|
||||||
@ -140,7 +148,9 @@ namespace Elfisa.UI.Theming
|
|||||||
}
|
}
|
||||||
else if (control is SplitContainer splitContainer)
|
else if (control is SplitContainer splitContainer)
|
||||||
{
|
{
|
||||||
splitContainer.BackColor = colors.BackgroundSecondary;
|
splitContainer.BackColor = colors.Mode == ThemeMode.Dark ? colors.BorderSubtle : colors.Border;
|
||||||
|
splitContainer.Panel1.BackColor = colors.BackgroundPrimary;
|
||||||
|
splitContainer.Panel2.BackColor = colors.BackgroundPrimary;
|
||||||
}
|
}
|
||||||
else if (control.Tag as string == "toolbar")
|
else if (control.Tag as string == "toolbar")
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user