diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..beb1ecd
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,26 @@
+# Copilot instructions — Электронная Фармация
+
+## Stack
+
+- WinForms (.NET Framework 4.7.2), **not** WinUI 3
+- UI library: `src/Elfisa.UI` (custom Modern* controls + theming)
+- Apply **Fluent Design principles** from `winui-design` via theme tokens, not XAML
+
+## Design rules (from winui-design, adapted)
+
+1. Use `ThemeManager.Colors` / `UiThemeHelper` — never hard-code colors in forms.
+2. Typography: Segoe UI 12–14; icons: Segoe Fluent Icons via `FluentFonts`.
+3. Spacing: 8px grid (8, 16, 24, 32).
+4. App shape: developer tool — top nav + document tabs + content cards/grids.
+5. Feedback: `ToastNotification` / `UiDialogs`, not blocking `MessageBox` for routine messages.
+6. Data grids: styled `ModernDataGridView`; no WPF DataGrid patterns.
+
+## When changing UI
+
+- Prefer editing `Elfisa.UI` theme/palette over per-form colors.
+- Test light theme (`FluentWin11`) after visual changes.
+- Keep business logic in `ElectronicPharmacy`; keep visuals in `Elfisa.UI`.
+
+## WinUI plugin
+
+See `docs/WINUI-PLUGIN-SETUP.md` for `winui@awesome-copilot` install and CLI usage.
diff --git a/docs/WINUI-PLUGIN-SETUP.md b/docs/WINUI-PLUGIN-SETUP.md
new file mode 100644
index 0000000..fcbcd02
--- /dev/null
+++ b/docs/WINUI-PLUGIN-SETUP.md
@@ -0,0 +1,57 @@
+# WinUI agent plugin (Microsoft) — setup for this repo
+
+The [WinUI agent plugin](https://learn.microsoft.com/en-us/windows/apps/develop/ai-assisted/winui-agent-plugin) targets **GitHub Copilot CLI** and **Claude Code**. It does **not** plug into Cursor chat directly.
+
+This WinForms project applies **Fluent Design tokens** from the plugin's `winui-design` skill in `Elfisa.UI` (`FluentWin11` theme).
+
+## Prerequisites
+
+```powershell
+winget install Microsoft.winappcli --source winget
+winget install GitHub.cli
+```
+
+GitHub Copilot subscription required for Copilot CLI.
+
+## Install Copilot CLI + WinUI plugin
+
+```powershell
+gh auth login
+gh extension install github/gh-copilot
+gh copilot plugin install winui@awesome-copilot
+gh copilot plugin list
+```
+
+## Use with Copilot CLI
+
+```powershell
+gh copilot -p "@winui-dev Review the WinForms shell in src/ElectronicPharmacy for Fluent alignment"
+```
+
+Interactive session:
+
+```powershell
+copilot
+# then: @winui-dev Suggest toolbar layout improvements for FOrders
+```
+
+## WinForms adaptation (this repo)
+
+| WinUI guidance | WinForms implementation |
+|----------------|-------------------------|
+| Semantic brushes, no hard-coded `#RRGGBB` in UI code | `ThemeColors` + `FluentWin11Palette` |
+| Segoe UI typography | `Segoe UI` 12–14 in palette fonts |
+| 8px spacing grid | Toolbar layout in `FOrders.ApplyToolbarLayout` |
+| Developer-tool silhouette | `ModernAppHeader` + `ModernDocumentTabStrip` |
+| WinUI `AccentButton` / `Button` | `ModernButton` + `ModernButtonStyles.ApplyAuto` |
+| Focus ring | keyboard focus outline in `ModernButton` |
+| Disabled opacity | muted fill/text when `Enabled = false` |
+
+Default theme: `ThemeVariant.FluentWin11` in `Program.cs`.
+
+## Claude Code (optional)
+
+```powershell
+claude plugin marketplace add microsoft/win-dev-skills
+claude plugin install winui@win-dev-skills
+```
diff --git a/src/ElectronicPharmacy/Classes/UiThemeHelper.cs b/src/ElectronicPharmacy/Classes/UiThemeHelper.cs
index b46f464..82b6b4b 100644
--- a/src/ElectronicPharmacy/Classes/UiThemeHelper.cs
+++ b/src/ElectronicPharmacy/Classes/UiThemeHelper.cs
@@ -30,6 +30,7 @@ namespace Электронная_Фармация.Classes
if (!modernButton.HeaderNavMode && !modernButton.TopNavMode && !modernButton.SidebarMode)
{
modernButton.AllowTextEllipsis = false;
+ ModernButtonStyles.ApplyAuto(modernButton);
}
}
else if (control is ModernTextBox modernTextBox)
@@ -44,10 +45,6 @@ namespace Электронная_Фармация.Classes
{
modernSearch.ApplyTheme(theme);
}
- else if (control is ModernComboBox modernCombo)
- {
- modernCombo.ApplyTheme(theme);
- }
else if (control is DataGridView grid)
{
grid.EnableHeadersVisualStyles = false;
diff --git a/src/ElectronicPharmacy/Form1.UiShell.cs b/src/ElectronicPharmacy/Form1.UiShell.cs
index 3b3005a..39e80b4 100644
--- a/src/ElectronicPharmacy/Form1.UiShell.cs
+++ b/src/ElectronicPharmacy/Form1.UiShell.cs
@@ -8,6 +8,7 @@ using Elfisa.UI.Loading;
using Elfisa.UI.Notifications;
using Elfisa.UI.Theming;
using Электронная_Фармация.Classes;
+using Электронная_Фармация.Properties;
using Электронная_Фармация.Forms;
using Электронная_Фармация.HelpForms;
using Электронная_Фармация.UserControls;
@@ -23,11 +24,13 @@ namespace Электронная_Фармация
private ModernAppHeader _appHeader;
private ModernDocumentTabStrip _documentTabStrip;
private Panel _documentHost;
+ private Panel _statusFooter;
+ private Label _lblCurrentUser;
private ContextMenuStrip _directoryMenu;
partial void InitializeModernShell()
{
- Font = new Font("Segoe UI", 13f);
+ Font = new Font("Segoe UI", 12f);
AutoScaleMode = AutoScaleMode.Dpi;
KeyPreview = true;
MinimumSize = new Size(900, 620);
@@ -54,8 +57,36 @@ namespace Электронная_Фармация
_documentTabStrip = new ModernDocumentTabStrip { Name = "documentTabStrip", Dock = DockStyle.Top };
_documentHost = new Panel { Name = "documentHost", Dock = DockStyle.Fill, Tag = "chrome-child" };
+ _statusFooter = new Panel
+ {
+ Name = "statusFooter",
+ Dock = DockStyle.Bottom,
+ Height = 30,
+ Tag = "status-footer",
+ Padding = new Padding(12, 0, 16, 0)
+ };
+ _statusFooter.Paint += (_, e) =>
+ {
+ var border = ThemeManager.Colors.Border;
+ using (var pen = new Pen(border))
+ {
+ e.Graphics.DrawLine(pen, 0, 0, _statusFooter.Width, 0);
+ }
+ };
+
+ _lblCurrentUser = new Label
+ {
+ Name = "lblCurrentUser",
+ Dock = DockStyle.Fill,
+ TextAlign = ContentAlignment.MiddleRight,
+ AutoEllipsis = true,
+ Tag = "muted"
+ };
+ _statusFooter.Controls.Add(_lblCurrentUser);
+
Controls.Add(_loadingOverlay);
Controls.Add(_documentHost);
+ Controls.Add(_statusFooter);
Controls.Add(_documentTabStrip);
Controls.Add(_appHeader);
@@ -88,6 +119,31 @@ namespace Электронная_Фармация
ThemeManager.CurrentVariant = ThemeVariant.PharmaTrust;
_themeService.Initialize(this);
UiThemeHelper.ApplyToControlTree(this);
+ RefreshCurrentUserStatus();
+ }
+
+ private void RefreshCurrentUserStatus()
+ {
+ if (_lblCurrentUser == null)
+ {
+ return;
+ }
+
+ var login = Settings.Default.stringLogin?.Trim();
+ var hasToken = !string.IsNullOrWhiteSpace(Settings.Default.stringToken);
+
+ if (!string.IsNullOrWhiteSpace(login) && hasToken)
+ {
+ _lblCurrentUser.Text = $"Пользователь: {login}";
+ }
+ else if (!string.IsNullOrWhiteSpace(login))
+ {
+ _lblCurrentUser.Text = $"Пользователь: {login} (не авторизован)";
+ }
+ else
+ {
+ _lblCurrentUser.Text = "Пользователь не авторизован";
+ }
}
private void OnAppHeaderItemSelected(object sender, string key)
diff --git a/src/ElectronicPharmacy/Form1.cs b/src/ElectronicPharmacy/Form1.cs
index af98918..93323d3 100644
--- a/src/ElectronicPharmacy/Form1.cs
+++ b/src/ElectronicPharmacy/Form1.cs
@@ -573,7 +573,10 @@ namespace Электронная_Фармация
{
var hF_Registration = new HF_Registration();
UiThemeHelper.ApplyToControlTree(hF_Registration);
- hF_Registration.ShowDialog();
+ if (hF_Registration.ShowDialog() == DialogResult.OK)
+ {
+ RefreshCurrentUserStatus();
+ }
}
private async void tsBtnSentData_Click(object sender, EventArgs e)
diff --git a/src/ElectronicPharmacy/HelpForms/HFConsignees.Designer.cs b/src/ElectronicPharmacy/HelpForms/HFConsignees.Designer.cs
index 71d4faf..3594399 100644
--- a/src/ElectronicPharmacy/HelpForms/HFConsignees.Designer.cs
+++ b/src/ElectronicPharmacy/HelpForms/HFConsignees.Designer.cs
@@ -30,8 +30,8 @@
{
this.dgvConsignees = new Elfisa.UI.Controls.ModernDataGridView();
this.label1 = new System.Windows.Forms.Label();
- this.btnConfirmConsignee = new System.Windows.Forms.Button();
- this.btnCloseThis = new System.Windows.Forms.Button();
+ this.btnConfirmConsignee = new Elfisa.UI.Controls.ModernButton();
+ this.btnCloseThis = new Elfisa.UI.Controls.ModernButton();
((System.ComponentModel.ISupportInitialize)(this.dgvConsignees)).BeginInit();
this.SuspendLayout();
//
@@ -113,7 +113,7 @@
private Elfisa.UI.Controls.ModernDataGridView dgvConsignees;
private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Button btnConfirmConsignee;
- private System.Windows.Forms.Button btnCloseThis;
+ private Elfisa.UI.Controls.ModernButton btnConfirmConsignee;
+ private Elfisa.UI.Controls.ModernButton btnCloseThis;
}
}
\ No newline at end of file
diff --git a/src/ElectronicPharmacy/HelpForms/HF_Comment.Designer.cs b/src/ElectronicPharmacy/HelpForms/HF_Comment.Designer.cs
index 299b95a..3d354cd 100644
--- a/src/ElectronicPharmacy/HelpForms/HF_Comment.Designer.cs
+++ b/src/ElectronicPharmacy/HelpForms/HF_Comment.Designer.cs
@@ -59,34 +59,22 @@
//
// btnCancel
//
- this.btnCancel.BackColor = System.Drawing.Color.Firebrick;
- this.btnCancel.FlatAppearance.BorderSize = 0;
- this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnCancel.Font = new System.Drawing.Font("Segoe UI Semibold", 10.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnCancel.ForeColor = System.Drawing.Color.White;
this.btnCancel.Location = new System.Drawing.Point(335, 224);
this.btnCancel.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(100, 41);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Отмена";
- this.btnCancel.UseVisualStyleBackColor = false;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnAddComment
//
- this.btnAddComment.BackColor = System.Drawing.SystemColors.HotTrack;
- this.btnAddComment.FlatAppearance.BorderSize = 0;
- this.btnAddComment.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnAddComment.Font = new System.Drawing.Font("Segoe UI Semibold", 10.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnAddComment.ForeColor = System.Drawing.Color.White;
this.btnAddComment.Location = new System.Drawing.Point(472, 224);
this.btnAddComment.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btnAddComment.Name = "btnAddComment";
this.btnAddComment.Size = new System.Drawing.Size(100, 41);
this.btnAddComment.TabIndex = 3;
this.btnAddComment.Text = "ОК";
- this.btnAddComment.UseVisualStyleBackColor = false;
this.btnAddComment.Click += new System.EventHandler(this.btnAddComment_Click);
//
// HF_Comment
diff --git a/src/ElectronicPharmacy/HelpForms/HF_Registration.Designer.cs b/src/ElectronicPharmacy/HelpForms/HF_Registration.Designer.cs
index 09e7947..dedb66b 100644
--- a/src/ElectronicPharmacy/HelpForms/HF_Registration.Designer.cs
+++ b/src/ElectronicPharmacy/HelpForms/HF_Registration.Designer.cs
@@ -83,32 +83,20 @@
//
// btnConfirmRegistration
//
- this.btnConfirmRegistration.BackColor = System.Drawing.SystemColors.HotTrack;
- this.btnConfirmRegistration.FlatAppearance.BorderSize = 0;
- this.btnConfirmRegistration.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnConfirmRegistration.Font = new System.Drawing.Font("Segoe UI Semibold", 10.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnConfirmRegistration.ForeColor = System.Drawing.Color.White;
this.btnConfirmRegistration.Location = new System.Drawing.Point(188, 401);
this.btnConfirmRegistration.Name = "btnConfirmRegistration";
this.btnConfirmRegistration.Size = new System.Drawing.Size(215, 43);
this.btnConfirmRegistration.TabIndex = 5;
this.btnConfirmRegistration.Text = "Зарегистрировать";
- this.btnConfirmRegistration.UseVisualStyleBackColor = false;
this.btnConfirmRegistration.Click += new System.EventHandler(this.btnConfirmRegistration_Click);
//
// btnCloseThis
//
- this.btnCloseThis.BackColor = System.Drawing.Color.Firebrick;
- this.btnCloseThis.FlatAppearance.BorderSize = 0;
- this.btnCloseThis.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnCloseThis.Font = new System.Drawing.Font("Segoe UI Semibold", 10.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnCloseThis.ForeColor = System.Drawing.Color.White;
this.btnCloseThis.Location = new System.Drawing.Point(28, 401);
this.btnCloseThis.Name = "btnCloseThis";
this.btnCloseThis.Size = new System.Drawing.Size(125, 43);
this.btnCloseThis.TabIndex = 6;
this.btnCloseThis.Text = "Отмена";
- this.btnCloseThis.UseVisualStyleBackColor = false;
this.btnCloseThis.Click += new System.EventHandler(this.btnCloseThis_Click);
//
// checkTokenGained
diff --git a/src/ElectronicPharmacy/Program.cs b/src/ElectronicPharmacy/Program.cs
index a8be127..b7d1b4c 100644
--- a/src/ElectronicPharmacy/Program.cs
+++ b/src/ElectronicPharmacy/Program.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Windows.Forms;
using Elfisa.UI.Theming;
@@ -11,7 +11,7 @@ namespace Электронная_Фармация
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- ThemeManager.CurrentVariant = ThemeVariant.PharmaTrust;
+ ThemeManager.CurrentVariant = ThemeVariant.FluentWin11;
Application.Run(new ElectroPharmacy());
}
}
diff --git a/src/ElectronicPharmacy/UserControls/FOrders.Designer.cs b/src/ElectronicPharmacy/UserControls/FOrders.Designer.cs
index 2fcdc47..4fa6a2e 100644
--- a/src/ElectronicPharmacy/UserControls/FOrders.Designer.cs
+++ b/src/ElectronicPharmacy/UserControls/FOrders.Designer.cs
@@ -32,9 +32,10 @@
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FOrders));
this.panelToolbar = new System.Windows.Forms.Panel();
+ this.panelToolbar = new System.Windows.Forms.Panel();
this.txtGoodFromOrders = new Elfisa.UI.Controls.ModernTextBox();
this.btnClearSuppliers = new Elfisa.UI.Controls.ModernButton();
- this.comboSuppliers = new System.Windows.Forms.ComboBox();
+ this.comboSuppliers = new Elfisa.UI.Controls.ModernComboBox();
this.panelOrderItems = new System.Windows.Forms.Panel();
this.dataGridView1 = new Elfisa.UI.Controls.ModernDataGridView();
this.dgvOrderItems = new Elfisa.UI.Controls.ModernDataGridView();
@@ -98,12 +99,12 @@
//
// comboSuppliers
//
- this.comboSuppliers.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+ this.comboSuppliers.Font = new System.Drawing.Font("Segoe UI", 11.25F);
this.comboSuppliers.FormattingEnabled = true;
this.comboSuppliers.Location = new System.Drawing.Point(874, 31);
this.comboSuppliers.Margin = new System.Windows.Forms.Padding(4);
this.comboSuppliers.Name = "comboSuppliers";
- this.comboSuppliers.Size = new System.Drawing.Size(160, 29);
+ this.comboSuppliers.Size = new System.Drawing.Size(170, 33);
this.comboSuppliers.TabIndex = 21;
this.comboSuppliers.Text = "Поставщик";
this.comboSuppliers.Visible = false;
@@ -182,6 +183,7 @@
this.panelOrdersHeader.Location = new System.Drawing.Point(0, 0);
this.panelOrdersHeader.Margin = new System.Windows.Forms.Padding(2);
this.panelOrdersHeader.Name = "panelOrdersHeader";
+ this.panelOrdersHeader.Padding = new System.Windows.Forms.Padding(8, 14, 8, 6);
this.panelOrdersHeader.Size = new System.Drawing.Size(1178, 200);
this.panelOrdersHeader.TabIndex = 0;
//
@@ -260,7 +262,7 @@
// panel1
//
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.panel1.Location = new System.Drawing.Point(0, 96);
+ this.panel1.Location = new System.Drawing.Point(0, 114);
this.panel1.Margin = new System.Windows.Forms.Padding(2);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1201, 354);
@@ -285,8 +287,8 @@
this.panelToolbar.Dock = System.Windows.Forms.DockStyle.Top;
this.panelToolbar.Location = new System.Drawing.Point(0, 0);
this.panelToolbar.Name = "panelToolbar";
- this.panelToolbar.Padding = new System.Windows.Forms.Padding(10, 8, 10, 8);
- this.panelToolbar.Size = new System.Drawing.Size(1201, 96);
+ this.panelToolbar.Padding = new System.Windows.Forms.Padding(12, 10, 12, 14);
+ this.panelToolbar.Size = new System.Drawing.Size(1201, 114);
this.panelToolbar.TabIndex = 31;
//
// label2
@@ -340,33 +342,21 @@
// btnClearGoodSearch
//
this.btnClearGoodSearch.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
- this.btnClearGoodSearch.BackColor = System.Drawing.Color.Firebrick;
- this.btnClearGoodSearch.FlatAppearance.BorderSize = 0;
- this.btnClearGoodSearch.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnClearGoodSearch.Font = new System.Drawing.Font("Segoe UI Semibold", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnClearGoodSearch.Image = ((System.Drawing.Image)(resources.GetObject("btnClearGoodSearch.Image")));
this.btnClearGoodSearch.Location = new System.Drawing.Point(252, 48);
this.btnClearGoodSearch.Margin = new System.Windows.Forms.Padding(4);
this.btnClearGoodSearch.Name = "btnClearGoodSearch";
- this.btnClearGoodSearch.Size = new System.Drawing.Size(36, 32);
+ this.btnClearGoodSearch.Size = new System.Drawing.Size(34, 32);
this.btnClearGoodSearch.TabIndex = 26;
- this.btnClearGoodSearch.UseVisualStyleBackColor = false;
this.btnClearGoodSearch.Click += new System.EventHandler(this.btnClearGoodSearch_Click);
//
// btnClearOrderNumberFilter
//
this.btnClearOrderNumberFilter.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
- this.btnClearOrderNumberFilter.BackColor = System.Drawing.Color.Firebrick;
- this.btnClearOrderNumberFilter.FlatAppearance.BorderSize = 0;
- this.btnClearOrderNumberFilter.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnClearOrderNumberFilter.Font = new System.Drawing.Font("Segoe UI Semibold", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnClearOrderNumberFilter.Image = ((System.Drawing.Image)(resources.GetObject("btnClearOrderNumberFilter.Image")));
this.btnClearOrderNumberFilter.Location = new System.Drawing.Point(540, 48);
this.btnClearOrderNumberFilter.Margin = new System.Windows.Forms.Padding(4);
this.btnClearOrderNumberFilter.Name = "btnClearOrderNumberFilter";
- this.btnClearOrderNumberFilter.Size = new System.Drawing.Size(36, 32);
+ this.btnClearOrderNumberFilter.Size = new System.Drawing.Size(34, 32);
this.btnClearOrderNumberFilter.TabIndex = 28;
- this.btnClearOrderNumberFilter.UseVisualStyleBackColor = false;
this.btnClearOrderNumberFilter.Click += new System.EventHandler(this.btnClearOrderNumberFilter_Click);
//
// txtOrderNumberFilter
@@ -384,42 +374,24 @@
//
// btnAddComment
//
- this.btnAddComment.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
- this.btnAddComment.BackColor = System.Drawing.SystemColors.HotTrack;
- this.btnAddComment.FlatAppearance.BorderSize = 0;
- this.btnAddComment.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnAddComment.Font = new System.Drawing.Font("Segoe UI Semibold", 10.2F, System.Drawing.FontStyle.Bold);
- this.btnAddComment.ForeColor = System.Drawing.Color.White;
- this.btnAddComment.Image = ((System.Drawing.Image)(resources.GetObject("btnAddComment.Image")));
- this.btnAddComment.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.btnAddComment.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnAddComment.Location = new System.Drawing.Point(584, 46);
this.btnAddComment.Margin = new System.Windows.Forms.Padding(4);
this.btnAddComment.Name = "btnAddComment";
- this.btnAddComment.Size = new System.Drawing.Size(240, 36);
+ this.btnAddComment.Size = new System.Drawing.Size(200, 34);
this.btnAddComment.TabIndex = 29;
this.btnAddComment.Text = "КОММЕНТАРИЙ";
- this.btnAddComment.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.btnAddComment.UseVisualStyleBackColor = false;
this.btnAddComment.Click += new System.EventHandler(this.btnAddComment_Click);
//
// btnDeleteOrder
//
- this.btnDeleteOrder.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
- this.btnDeleteOrder.BackColor = System.Drawing.Color.Firebrick;
- this.btnDeleteOrder.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
- this.btnDeleteOrder.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnDeleteOrder.Font = new System.Drawing.Font("Segoe UI Semibold", 10.2F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
- this.btnDeleteOrder.ForeColor = System.Drawing.Color.White;
- this.btnDeleteOrder.Image = ((System.Drawing.Image)(resources.GetObject("btnDeleteOrder.Image")));
- this.btnDeleteOrder.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.btnDeleteOrder.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnDeleteOrder.Location = new System.Drawing.Point(390, 6);
this.btnDeleteOrder.Margin = new System.Windows.Forms.Padding(4);
this.btnDeleteOrder.Name = "btnDeleteOrder";
- this.btnDeleteOrder.Size = new System.Drawing.Size(160, 36);
+ this.btnDeleteOrder.Size = new System.Drawing.Size(130, 34);
this.btnDeleteOrder.TabIndex = 30;
this.btnDeleteOrder.Text = "УДАЛИТЬ";
- this.btnDeleteOrder.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.btnDeleteOrder.UseVisualStyleBackColor = false;
this.btnDeleteOrder.Click += new System.EventHandler(this.btnDeleteOrder_Click);
//
// FOrders
@@ -454,7 +426,7 @@
#endregion
private Elfisa.UI.Controls.ModernButton btnClearSuppliers;
- private System.Windows.Forms.ComboBox comboSuppliers;
+ private Elfisa.UI.Controls.ModernComboBox comboSuppliers;
private System.Windows.Forms.Panel panelOrderItems;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Panel panelOrdersHeader;
diff --git a/src/ElectronicPharmacy/UserControls/FOrders.cs b/src/ElectronicPharmacy/UserControls/FOrders.cs
index add1943..73cc359 100644
--- a/src/ElectronicPharmacy/UserControls/FOrders.cs
+++ b/src/ElectronicPharmacy/UserControls/FOrders.cs
@@ -31,6 +31,8 @@ namespace Электронная_Фармация.UserControls
{
UiThemeHelper.ApplyToControlTree(this);
Tag = "chrome-child";
+ panelToolbar.Tag = "toolbar";
+ panelOrdersHeader.Padding = new Padding(8, 14, 8, 6);
dtpDateFrom.Value = DateTime.Now.AddDays(-3);
dtpDateTo.Value = DateTime.Now;
@@ -45,16 +47,15 @@ namespace Электронная_Фармация.UserControls
panelToolbar.Resize += (_, __) => ApplyToolbarLayout();
}
- private ComboBox _comboOrderStatus;
- private ComboBox _comboConsignees;
+ private ModernComboBox _comboOrderStatus;
+ private ModernComboBox _comboConsignees;
private ModernButton _btnSendOrder;
private void InitOrderToolbar()
{
- _comboOrderStatus = new ComboBox
+ _comboOrderStatus = new ModernComboBox
{
- DropDownStyle = ComboBoxStyle.DropDownList,
- Font = new Font("Segoe UI", 9.75f),
+ Font = new Font("Segoe UI", 11.25f),
Name = "comboOrderStatus"
};
_comboOrderStatus.Items.AddRange(new object[] { "Все статусы", "НОВЫЙ", "ОТПРАВЛЕН" });
@@ -62,10 +63,9 @@ namespace Электронная_Фармация.UserControls
_comboOrderStatus.SelectionChangeCommitted += (_, __) => ApplyOrderFilters();
panelToolbar.Controls.Add(_comboOrderStatus);
- _comboConsignees = new ComboBox
+ _comboConsignees = new ModernComboBox
{
- DropDownStyle = ComboBoxStyle.DropDownList,
- Font = new Font("Segoe UI", 9.75f),
+ Font = new Font("Segoe UI", 11.25f),
Name = "comboConsigneesFilter"
};
_comboConsignees.SelectionChangeCommitted += (_, __) => ApplyOrderFilters();
@@ -74,25 +74,28 @@ namespace Электронная_Фармация.UserControls
_btnSendOrder = new ModernButton
{
Text = "ОТПРАВИТЬ",
- Font = new Font("Segoe UI Semibold", 10f, FontStyle.Bold),
- BackColor = Color.FromArgb(0, 120, 212),
- ForeColor = Color.White,
- FlatStyle = FlatStyle.Flat,
Name = "btnSendOrder"
};
- _btnSendOrder.FlatAppearance.BorderSize = 0;
_btnSendOrder.Click += async (_, __) => await SendSelectedOrderAsync();
panelToolbar.Controls.Add(_btnSendOrder);
+
+ UiThemeHelper.ApplyToControlTree(_comboOrderStatus);
+ UiThemeHelper.ApplyToControlTree(_comboConsignees);
+ UiThemeHelper.ApplyToControlTree(_btnSendOrder);
}
private void ApplyToolbarLayout()
{
- const int pad = 10;
+ const int pad = 12;
const int gap = 8;
- const int row1Y = 8;
- const int row2Y = 50;
+ const int row1Y = 10;
const int controlHeight = 32;
+ const int filterHeight = 33;
const int buttonHeight = 34;
+ const int rowGap = 14;
+ const int row2Y = row1Y + buttonHeight + rowGap;
+ const int commentWidth = 200;
+ const int filterY = row1Y + (buttonHeight - filterHeight) / 2;
int x = pad;
@@ -112,13 +115,13 @@ namespace Электронная_Фармация.UserControls
_btnSendOrder.SetBounds(right - 150, row1Y, 150, buttonHeight);
right = _btnSendOrder.Left - gap;
- _comboConsignees.SetBounds(right - 190, row1Y, 190, controlHeight);
+ _comboConsignees.SetBounds(right - 190, filterY, 190, filterHeight);
right = _comboConsignees.Left - gap;
- comboSuppliers.SetBounds(right - 170, row1Y, 170, controlHeight);
+ comboSuppliers.SetBounds(right - 170, filterY, 170, filterHeight);
right = comboSuppliers.Left - gap;
- _comboOrderStatus.SetBounds(right - 150, row1Y, 150, controlHeight);
+ _comboOrderStatus.SetBounds(right - 150, filterY, 150, filterHeight);
x = pad;
txtGoodFromOrders.SetBounds(x, row2Y, 220, controlHeight);
@@ -130,10 +133,12 @@ namespace Электронная_Фармация.UserControls
btnClearOrderNumberFilter.SetBounds(x, row2Y, 34, controlHeight);
x = btnClearOrderNumberFilter.Right + gap;
- int commentWidth = Math.Max(180, panelToolbar.ClientSize.Width - x - pad);
btnAddComment.SetBounds(x, row2Y, commentWidth, buttonHeight);
btnClearSuppliers.Visible = false;
+
+ panelToolbar.Height = row2Y + buttonHeight + pad + 8;
+ panelToolbar.Padding = new Padding(pad, 10, pad, 14);
}
private void ApplyOrderFilters()
@@ -166,6 +171,14 @@ namespace Электронная_Фармация.UserControls
parts.Add($"ConsigneeName = '{consignee}'");
}
+ if (_comboConsignees != null &&
+ _comboConsignees.SelectedIndex > 0 &&
+ !string.IsNullOrWhiteSpace(_comboConsignees.Text))
+ {
+ var consignee = _comboConsignees.Text.Replace("'", "''");
+ parts.Add($"ConsigneeName = '{consignee}'");
+ }
+
var addon = parts.Count == 0 ? string.Empty : " and " + string.Join(" and ", parts);
LoadOrders(
dtpDateFrom.Value.ToString("dd.MM.yyyy"),
@@ -241,6 +254,10 @@ and OrderDate <= '{dateTo}'
{
tableOrders.Columns[9].ColumnName = "Грузополучатель";
}
+ if (tableOrders.Columns.Count > 9)
+ {
+ tableOrders.Columns[9].ColumnName = "Грузополучатель";
+ }
//DGVOrders.DataSource = tableOrders;
diff --git a/src/ElectronicPharmacy/UserControls/UCOrderItems.Designer.cs b/src/ElectronicPharmacy/UserControls/UCOrderItems.Designer.cs
index 66740fc..80cfc67 100644
--- a/src/ElectronicPharmacy/UserControls/UCOrderItems.Designer.cs
+++ b/src/ElectronicPharmacy/UserControls/UCOrderItems.Designer.cs
@@ -83,38 +83,26 @@
//
// btnEraseOrder
//
- this.btnEraseOrder.BackColor = System.Drawing.Color.Firebrick;
this.btnEraseOrder.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnEraseOrder.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold);
- this.btnEraseOrder.ForeColor = System.Drawing.Color.White;
- this.btnEraseOrder.Image = ((System.Drawing.Image)(resources.GetObject("btnEraseOrder.Image")));
- this.btnEraseOrder.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnEraseOrder.Location = new System.Drawing.Point(272, 36);
this.btnEraseOrder.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.btnEraseOrder.Name = "btnEraseOrder";
this.btnEraseOrder.Size = new System.Drawing.Size(260, 38);
this.btnEraseOrder.TabIndex = 13;
this.btnEraseOrder.Text = "Очистить корзину";
- this.btnEraseOrder.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.btnEraseOrder.UseVisualStyleBackColor = false;
this.btnEraseOrder.Click += new System.EventHandler(this.btnEraseOrder_Click);
//
// btnSendOrder
//
- this.btnSendOrder.BackColor = System.Drawing.SystemColors.HotTrack;
this.btnSendOrder.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSendOrder.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold);
- this.btnSendOrder.ForeColor = System.Drawing.Color.White;
- this.btnSendOrder.Image = ((System.Drawing.Image)(resources.GetObject("btnSendOrder.Image")));
- this.btnSendOrder.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnSendOrder.Location = new System.Drawing.Point(4, 36);
this.btnSendOrder.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.btnSendOrder.Name = "btnSendOrder";
this.btnSendOrder.Size = new System.Drawing.Size(260, 38);
this.btnSendOrder.TabIndex = 12;
this.btnSendOrder.Text = "Сохранить заказ";
- this.btnSendOrder.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.btnSendOrder.UseVisualStyleBackColor = false;
this.btnSendOrder.Click += new System.EventHandler(this.btnSendOrder_Click);
//
// button1
diff --git a/src/ElectronicPharmacy/UserControls/UCPriceList.Designer.cs b/src/ElectronicPharmacy/UserControls/UCPriceList.Designer.cs
index 6ce1b52..50322c0 100644
--- a/src/ElectronicPharmacy/UserControls/UCPriceList.Designer.cs
+++ b/src/ElectronicPharmacy/UserControls/UCPriceList.Designer.cs
@@ -164,19 +164,13 @@
//
// btnDeleteGood
//
- this.btnDeleteGood.BackColor = System.Drawing.Color.Firebrick;
- this.btnDeleteGood.FlatAppearance.BorderSize = 0;
this.btnDeleteGood.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDeleteGood.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold);
- this.btnDeleteGood.ForeColor = System.Drawing.Color.White;
- this.btnDeleteGood.Image = ((System.Drawing.Image)(resources.GetObject("btnDeleteGood.Image")));
- this.btnDeleteGood.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnDeleteGood.Location = new System.Drawing.Point(8, 62);
this.btnDeleteGood.Name = "btnDeleteGood";
this.btnDeleteGood.Size = new System.Drawing.Size(360, 34);
this.btnDeleteGood.TabIndex = 13;
this.btnDeleteGood.Text = "Удалить товар (BACKSPACE)";
- this.btnDeleteGood.UseVisualStyleBackColor = false;
this.btnDeleteGood.Click += new System.EventHandler(this.btnDeleteGood_Click);
//
// checkUsePercentageAsDefault
@@ -372,16 +366,12 @@
// btnClearSearchInPriceList
//
this.btnClearSearchInPriceList.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
- this.btnClearSearchInPriceList.BackColor = System.Drawing.Color.Firebrick;
- this.btnClearSearchInPriceList.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnClearSearchInPriceList.BackgroundImage")));
- this.btnClearSearchInPriceList.FlatAppearance.BorderSize = 0;
- this.btnClearSearchInPriceList.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClearSearchInPriceList.Font = new System.Drawing.Font("Segoe UI", 9.75F);
this.btnClearSearchInPriceList.Location = new System.Drawing.Point(393, 7);
this.btnClearSearchInPriceList.Name = "btnClearSearchInPriceList";
this.btnClearSearchInPriceList.Size = new System.Drawing.Size(32, 30);
this.btnClearSearchInPriceList.TabIndex = 9;
- this.btnClearSearchInPriceList.UseVisualStyleBackColor = false;
+ this.btnClearSearchInPriceList.Text = "×";
this.btnClearSearchInPriceList.Click += new System.EventHandler(this.btnClearSearchInPriceList_Click);
//
// btnImport
@@ -443,15 +433,11 @@
// btnClearSupplierFilter
//
this.btnClearSupplierFilter.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
- this.btnClearSupplierFilter.BackColor = System.Drawing.Color.Firebrick;
- this.btnClearSupplierFilter.FlatAppearance.BorderSize = 0;
- this.btnClearSupplierFilter.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnClearSupplierFilter.Font = new System.Drawing.Font("Segoe UI", 9.75F);
this.btnClearSupplierFilter.Location = new System.Drawing.Point(818, 7);
this.btnClearSupplierFilter.Name = "btnClearSupplierFilter";
this.btnClearSupplierFilter.Size = new System.Drawing.Size(32, 30);
this.btnClearSupplierFilter.TabIndex = 15;
- this.btnClearSupplierFilter.UseVisualStyleBackColor = false;
this.btnClearSupplierFilter.Text = "×";
this.btnClearSupplierFilter.Click += new System.EventHandler(this.btnClearSupplierFilter_Click);
//
diff --git a/src/Elfisa.UI/Controls/ModernButton.cs b/src/Elfisa.UI/Controls/ModernButton.cs
index c6bacb3..2e0213b 100644
--- a/src/Elfisa.UI/Controls/ModernButton.cs
+++ b/src/Elfisa.UI/Controls/ModernButton.cs
@@ -21,6 +21,7 @@ namespace Elfisa.UI.Controls
private string _navIconGlyph;
private string _iconGlyph;
private bool _compactIconMode;
+ private bool _focused;
private bool _allowTextEllipsis = true;
private readonly AnimationTimer _animTimer;
@@ -30,7 +31,6 @@ namespace Elfisa.UI.Controls
set
{
_compactIconMode = value;
- UpdateRoundedRegion();
Invalidate();
}
}
@@ -106,15 +106,13 @@ namespace Elfisa.UI.Controls
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer |
- ControlStyles.ResizeRedraw |
- ControlStyles.SupportsTransparentBackColor, true);
+ ControlStyles.ResizeRedraw, true);
FlatStyle = FlatStyle.Flat;
FlatAppearance.BorderSize = 0;
- UseVisualStyleBackColor = false;
- BackColor = Color.Transparent;
Cursor = Cursors.Hand;
- Font = new Font("Segoe UI Semibold", 13f);
- Height = 36;
+ Font = new Font("Segoe UI Semibold", 12f);
+ Height = ModernButtonStyles.DefaultHeight;
+ MinimumSize = new Size(64, ModernButtonStyles.DefaultHeight);
Padding = new Padding(14, 6, 14, 6);
TabStop = true;
_animTimer = new AnimationTimer(v => { _hoverAnim = v; Invalidate(); });
@@ -125,7 +123,7 @@ namespace Elfisa.UI.Controls
_theme = theme;
if (_headerNavMode)
{
- Font = new Font("Segoe UI", 12f, FontStyle.Bold);
+ Font = new Font("Segoe UI", 11f, FontStyle.Bold);
}
else if (_compactIconMode)
{
@@ -135,32 +133,9 @@ namespace Elfisa.UI.Controls
{
Font = theme.FontSemibold14;
}
- UpdateRoundedRegion();
Invalidate();
}
- protected override void OnResize(EventArgs e)
- {
- base.OnResize(e);
- UpdateRoundedRegion();
- }
-
- private void UpdateRoundedRegion()
- {
- Region?.Dispose();
- Region = null;
-
- if (_headerNavMode || _topNavMode || _sidebarMode || _compactIconMode || Width <= 0 || Height <= 0)
- {
- return;
- }
-
- var theme = _theme ?? ThemeManager.Colors;
- var path = GraphicsExtensions.CreateRoundedRectangle(new Rectangle(0, 0, Width, Height), theme.CornerRadiusSmall);
- Region = new Region(path);
- path.Dispose();
- }
-
protected override void OnMouseEnter(EventArgs e)
{
_hover = true;
@@ -201,13 +176,25 @@ namespace Elfisa.UI.Controls
base.OnEnabledChanged(e);
}
+ protected override void OnGotFocus(EventArgs e)
+ {
+ _focused = true;
+ Invalidate();
+ base.OnGotFocus(e);
+ }
+
+ protected override void OnLostFocus(EventArgs e)
+ {
+ _focused = false;
+ Invalidate();
+ base.OnLostFocus(e);
+ }
+
protected override void Dispose(bool disposing)
{
if (disposing)
{
_animTimer.Dispose();
- Region?.Dispose();
- Region = null;
}
base.Dispose(disposing);
}
@@ -217,10 +204,11 @@ namespace Elfisa.UI.Controls
var theme = _theme ?? ThemeManager.Colors;
var g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ g.CompositingQuality = CompositingQuality.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
- var inset = _pressed && !_headerNavMode ? 1 : 0;
- var bounds = new Rectangle(inset, inset, Width - (inset * 2), Height - (inset * 2));
+ var bounds = new Rectangle(0, 0, Width - 1, Height - 1);
var radius = theme.CornerRadiusSmall;
var baseColor = ResolveBaseColor(theme);
var fill = baseColor;
@@ -260,9 +248,25 @@ namespace Elfisa.UI.Controls
fill = theme.SidebarItemHover;
}
}
+ else if (_buttonStyle == ModernButtonStyle.Subtle)
+ {
+ fill = Color.Transparent;
+ if (!Enabled)
+ {
+ fill = Color.Transparent;
+ }
+ else if (_pressed)
+ {
+ fill = GraphicsExtensions.Blend(theme.GridRowHover, theme.BorderSubtle, 0.35f);
+ }
+ else if (_hover)
+ {
+ fill = GraphicsExtensions.Blend(theme.GridRowHover, Color.Transparent, 1f - (_hoverAnim * 0.65f));
+ }
+ }
else if (!Enabled)
{
- fill = GraphicsExtensions.Blend(baseColor, theme.BorderSubtle, 0.45f);
+ fill = ApplyDisabledFill(theme, baseColor);
}
else if (_pressed)
{
@@ -278,39 +282,11 @@ namespace Elfisa.UI.Controls
if (!_topNavMode)
{
- if (!_sidebarMode && !_headerNavMode && Enabled && IsSolidActionStyle(_buttonStyle) && !_pressed)
+ if (fill.A > 0)
{
- var shadowAlpha = (int)(14 + (_hoverAnim * 10));
- var shadowRect = new Rectangle(bounds.X, bounds.Y + 1, bounds.Width, bounds.Height - 1);
- using (var shadowBrush = new SolidBrush(Color.FromArgb(shadowAlpha, 0, 0, 0)))
- using (var clipPath = GraphicsExtensions.CreateRoundedRectangle(bounds, radius))
+ using (var brush = new SolidBrush(fill))
{
- var state = g.Save();
- g.SetClip(clipPath);
- GraphicsExtensions.FillRoundedRectangle(g, shadowBrush, shadowRect, radius);
- g.Restore(state);
- }
- }
-
- using (var brush = new SolidBrush(fill))
- {
- GraphicsExtensions.FillRoundedRectangle(g, brush, bounds, radius);
- }
-
- if (!_sidebarMode && !_headerNavMode && Enabled && IsSolidActionStyle(_buttonStyle))
- {
- var glossRect = new Rectangle(bounds.X + 1, bounds.Y + 1, bounds.Width - 2, Math.Max(4, bounds.Height / 2));
- using (var glossBrush = new LinearGradientBrush(
- glossRect,
- Color.FromArgb(_pressed ? 0 : 42, 255, 255, 255),
- Color.FromArgb(0, 255, 255, 255),
- LinearGradientMode.Vertical))
- using (var clipPath = GraphicsExtensions.CreateRoundedRectangle(bounds, radius))
- {
- var state = g.Save();
- g.SetClip(clipPath);
- g.FillRectangle(glossBrush, glossRect);
- g.Restore(state);
+ GraphicsExtensions.FillRoundedRectangle(g, brush, bounds, radius);
}
}
}
@@ -332,14 +308,39 @@ namespace Elfisa.UI.Controls
}
}
}
- else if ((_buttonStyle == ModernButtonStyle.Secondary || _buttonStyle == ModernButtonStyle.DangerSoft) && !_sidebarMode)
+ else if ((_buttonStyle == ModernButtonStyle.Secondary
+ || _buttonStyle == ModernButtonStyle.DangerSoft
+ || _buttonStyle == ModernButtonStyle.Subtle) && !_sidebarMode)
{
- var borderColor = _buttonStyle == ModernButtonStyle.DangerSoft
- ? GraphicsExtensions.Blend(theme.Danger, Color.White, 0.65f)
- : theme.Border;
- using (var pen = new Pen(borderColor, 1f))
+ if (_buttonStyle == ModernButtonStyle.Subtle && !_hover && !_pressed && !_focused)
{
- GraphicsExtensions.DrawRoundedRectangle(g, pen, bounds, radius);
+ // WinUI SubtleButton — no border at rest.
+ }
+ else
+ {
+ var borderColor = _buttonStyle == ModernButtonStyle.DangerSoft
+ ? GraphicsExtensions.Blend(theme.Danger, Color.White, 0.55f)
+ : _buttonStyle == ModernButtonStyle.Subtle
+ ? theme.Border
+ : theme.InputBorder;
+ if (_hover && Enabled)
+ {
+ borderColor = theme.InputBorderFocus;
+ }
+
+ using (var pen = new Pen(borderColor, 1f))
+ {
+ GraphicsExtensions.DrawRoundedRectangle(g, pen, bounds, radius);
+ }
+ }
+ }
+
+ if (_focused && Enabled && ShowFocusCues && !_headerNavMode && !_topNavMode && !_sidebarMode)
+ {
+ var focusBounds = Rectangle.Inflate(bounds, -2, -2);
+ using (var pen = new Pen(theme.InputBorderFocus, 2f))
+ {
+ GraphicsExtensions.DrawRoundedRectangle(g, pen, focusBounds, Math.Max(2, radius - 1));
}
}
@@ -349,6 +350,8 @@ namespace Elfisa.UI.Controls
? (_isActiveItem ? theme.SidebarItemActiveText : theme.SidebarItem)
: _buttonStyle == ModernButtonStyle.DangerSoft
? theme.Danger
+ : _buttonStyle == ModernButtonStyle.Subtle
+ ? theme.TextPrimary
: _buttonStyle == ModernButtonStyle.Secondary
? theme.TextPrimary
: theme.TextOnAccent;
@@ -360,7 +363,7 @@ namespace Elfisa.UI.Controls
if (!Enabled)
{
- textColor = theme.TextMuted;
+ textColor = GraphicsExtensions.Blend(textColor, theme.TextMuted, 0.55f);
}
DrawActionButtonContent(g, bounds, textColor);
@@ -404,7 +407,7 @@ namespace Elfisa.UI.Controls
? bounds.X + horizontalPad
: bounds.X + horizontalPad + Math.Max(0, (innerWidth - contentWidth) / 2);
- using (var iconFont = new Font("Segoe MDL2 Assets", 13f))
+ using (var iconFont = FluentFonts.CreateIconFont(13f))
{
var iconRect = new Rectangle(startX, bounds.Y, iconWidth, bounds.Height);
TextRenderer.DrawText(
@@ -448,44 +451,49 @@ namespace Elfisa.UI.Controls
private void DrawHeaderNavContent(Graphics g, Rectangle bounds, ThemeColors theme)
{
- var iconFont = new Font("Segoe MDL2 Assets", 18f);
- var textColor = Color.White;
- var iconRect = new Rectangle(bounds.X, bounds.Y + 8, bounds.Width, 28);
- var textRect = new Rectangle(bounds.X, bounds.Y + 34, bounds.Width, bounds.Height - 34);
-
- if (!string.IsNullOrEmpty(_navIconGlyph))
+ using (var iconFont = FluentFonts.CreateIconFont(18f))
{
+ var textColor = Color.White;
+ var iconRect = new Rectangle(bounds.X, bounds.Y + 8, bounds.Width, 28);
+ var textRect = new Rectangle(bounds.X, bounds.Y + 34, bounds.Width, bounds.Height - 34);
+
+ if (!string.IsNullOrEmpty(_navIconGlyph))
+ {
+ TextRenderer.DrawText(
+ g,
+ _navIconGlyph,
+ iconFont,
+ iconRect,
+ textColor,
+ TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine);
+ }
+
TextRenderer.DrawText(
g,
- _navIconGlyph,
- iconFont,
- iconRect,
+ Text,
+ Font,
+ textRect,
textColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine);
}
-
- TextRenderer.DrawText(
- g,
- Text,
- Font,
- textRect,
- textColor,
- TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine);
}
- private static bool IsSolidActionStyle(ModernButtonStyle style)
+ private static Color ApplyDisabledFill(ThemeColors theme, Color baseColor)
{
- return style == ModernButtonStyle.Primary
- || style == ModernButtonStyle.Success
- || style == ModernButtonStyle.Danger
- || style == ModernButtonStyle.Warning;
+ if (baseColor == theme.Surface || baseColor == theme.DangerSoft)
+ {
+ return GraphicsExtensions.Blend(baseColor, theme.BorderSubtle, 0.35f);
+ }
+
+ return GraphicsExtensions.Blend(baseColor, theme.BorderSubtle, 0.55f);
}
private Color ResolveBaseColor(ThemeColors theme)
{
switch (_buttonStyle)
{
- case ModernButtonStyle.Secondary: return theme.AccentSecondary;
+ case ModernButtonStyle.Secondary: return theme.Surface;
+ case ModernButtonStyle.Subtle: return Color.Transparent;
case ModernButtonStyle.Success: return theme.Success;
case ModernButtonStyle.Warning: return theme.Warning;
case ModernButtonStyle.Danger: return theme.Danger;
@@ -497,6 +505,8 @@ namespace Elfisa.UI.Controls
private static Color ResolveHoverColor(ThemeColors theme, Color baseColor)
{
if (baseColor == theme.AccentPrimary) return theme.AccentPrimaryHover;
+ if (baseColor == theme.Surface) return theme.GridRowHover;
+ if (baseColor == theme.DangerSoft) return GraphicsExtensions.Blend(theme.DangerSoft, theme.Danger, 0.08f);
if (baseColor == theme.Success) return GraphicsExtensions.Blend(theme.Success, Color.White, 0.12f);
if (baseColor == theme.Warning) return GraphicsExtensions.Blend(theme.Warning, Color.White, 0.12f);
if (baseColor == theme.Danger) return GraphicsExtensions.Blend(theme.Danger, Color.White, 0.12f);
diff --git a/src/Elfisa.UI/Controls/ModernButtonStyle.cs b/src/Elfisa.UI/Controls/ModernButtonStyle.cs
index 5ab3408..f7d1254 100644
--- a/src/Elfisa.UI/Controls/ModernButtonStyle.cs
+++ b/src/Elfisa.UI/Controls/ModernButtonStyle.cs
@@ -7,6 +7,7 @@ namespace Elfisa.UI.Controls
Success,
Warning,
Danger,
- DangerSoft
+ DangerSoft,
+ Subtle
}
}
diff --git a/src/Elfisa.UI/Controls/ModernButtonStyles.cs b/src/Elfisa.UI/Controls/ModernButtonStyles.cs
new file mode 100644
index 0000000..df7cf1b
--- /dev/null
+++ b/src/Elfisa.UI/Controls/ModernButtonStyles.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using Elfisa.UI.Theming;
+
+namespace Elfisa.UI.Controls
+{
+ ///
+ /// WinUI 3–style presets for in WinForms.
+ ///
+ public static class ModernButtonStyles
+ {
+ public const int DefaultHeight = 32;
+
+ public static void ApplyAuto(ModernButton button)
+ {
+ if (button == null || button.HeaderNavMode || button.TopNavMode || button.SidebarMode)
+ {
+ return;
+ }
+
+ var text = (button.Text ?? string.Empty).Trim();
+ if (IsClearButton(button, text))
+ {
+ ApplyClear(button);
+ return;
+ }
+
+ if (IsDangerAction(text))
+ {
+ ApplyAction(button, ModernButtonStyle.Danger, ResolveIcon(text, "\uE74D"));
+ return;
+ }
+
+ if (IsPrimaryAction(text))
+ {
+ ApplyAction(button, ModernButtonStyle.Primary, ResolveIcon(text, "\uE725"));
+ return;
+ }
+
+ ApplyAction(button, ModernButtonStyle.Secondary, ResolveIcon(text, null));
+ }
+
+ public static void ApplyAction(ModernButton button, ModernButtonStyle style, string iconGlyph = null)
+ {
+ if (button == null)
+ {
+ return;
+ }
+
+ button.ButtonStyle = style;
+ button.CompactIconMode = false;
+ button.Image = null;
+ button.BackgroundImage = null;
+ button.UseVisualStyleBackColor = false;
+ button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
+ button.MinimumSize = new Size(64, DefaultHeight);
+ if (button.Height < DefaultHeight)
+ {
+ button.Height = DefaultHeight;
+ }
+
+ button.Padding = new Padding(14, 6, 14, 6);
+ button.Font = (ThemeManager.Colors?.FontSemibold14) ?? new Font("Segoe UI Semibold", 12f);
+ button.IconGlyph = iconGlyph;
+ }
+
+ public static void ApplyClear(ModernButton button)
+ {
+ if (button == null)
+ {
+ return;
+ }
+
+ button.ButtonStyle = ModernButtonStyle.DangerSoft;
+ button.CompactIconMode = true;
+ button.Image = null;
+ button.BackgroundImage = null;
+ button.UseVisualStyleBackColor = false;
+ button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
+ button.Text = "×";
+ button.Font = new Font("Segoe UI", 13f, FontStyle.Bold);
+ button.MinimumSize = new Size(32, DefaultHeight);
+ button.Size = new Size(Math.Max(button.Width, 32), DefaultHeight);
+ button.IconGlyph = null;
+ }
+
+ private static bool IsClearButton(ModernButton button, string text)
+ {
+ return text == "×"
+ || text.Equals("X", StringComparison.OrdinalIgnoreCase)
+ || (button.Width <= 40 && button.Height <= 36 && text.Length <= 2);
+ }
+
+ private static bool IsDangerAction(string text)
+ {
+ var lower = text.ToLowerInvariant();
+ return lower.Contains("удал")
+ || lower.Contains("отмен")
+ || lower.Contains("очист")
+ || lower.Contains("delete")
+ || lower.Contains("cancel")
+ || lower.Contains("erase");
+ }
+
+ private static bool IsPrimaryAction(string text)
+ {
+ var lower = text.ToLowerInvariant();
+ return lower.Contains("отправ")
+ || lower.Contains("сохран")
+ || lower.Contains("зарег")
+ || lower.Contains("выполн")
+ || lower.Contains("коммент")
+ || lower.Contains("подтвер")
+ || lower.Contains("send")
+ || lower.Contains("save")
+ || lower == "ок";
+ }
+
+ private static string ResolveIcon(string text, string fallback)
+ {
+ var lower = text.ToLowerInvariant();
+ if (lower.Contains("отправ") || lower.Contains("send"))
+ {
+ return "\uE725";
+ }
+
+ if (lower.Contains("удал") || lower.Contains("delete"))
+ {
+ return "\uE74D";
+ }
+
+ if (lower.Contains("коммент"))
+ {
+ return "\uE8BD";
+ }
+
+ if (lower.Contains("сохран") || lower.Contains("save"))
+ {
+ return "\uE74E";
+ }
+
+ if (lower.Contains("отмен") || lower.Contains("cancel") || lower.Contains("закры"))
+ {
+ return "\uE711";
+ }
+
+ if (lower.Contains("очист") || lower.Contains("clear"))
+ {
+ return "\uE894";
+ }
+
+ if (lower.Contains("печат") || lower.Contains("print"))
+ {
+ return "\uE749";
+ }
+
+ if (lower.Contains("импорт") || lower.Contains("import"))
+ {
+ return "\uE896";
+ }
+
+ if (lower.Contains("подроб") || lower.Contains("info"))
+ {
+ return "\uE946";
+ }
+
+ if (lower.Contains("зарег") || lower.Contains("подтвер") || lower == "ок")
+ {
+ return "\uE73E";
+ }
+
+ return fallback;
+ }
+ }
+}
diff --git a/src/Elfisa.UI/Helpers/FluentFonts.cs b/src/Elfisa.UI/Helpers/FluentFonts.cs
new file mode 100644
index 0000000..145c448
--- /dev/null
+++ b/src/Elfisa.UI/Helpers/FluentFonts.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Drawing;
+
+namespace Elfisa.UI.Helpers
+{
+ ///
+ /// Segoe Fluent Icons with MDL2 fallback (WinUI design guidance).
+ ///
+ public static class FluentFonts
+ {
+ private static readonly Lazy IconFamily = new Lazy(ResolveIconFamily);
+
+ public static Font CreateIconFont(float size, FontStyle style = FontStyle.Regular)
+ {
+ return new Font(IconFamily.Value, size, style, GraphicsUnit.Point);
+ }
+
+ private static FontFamily ResolveIconFamily()
+ {
+ if (FontFamilyExists("Segoe Fluent Icons"))
+ {
+ return new FontFamily("Segoe Fluent Icons");
+ }
+
+ return new FontFamily("Segoe MDL2 Assets");
+ }
+
+ private static bool FontFamilyExists(string familyName)
+ {
+ using (var font = new Font(familyName, 10f))
+ {
+ return string.Equals(font.FontFamily.Name, familyName, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+ }
+}
diff --git a/src/Elfisa.UI/Theming/FluentWin11Palette.cs b/src/Elfisa.UI/Theming/FluentWin11Palette.cs
new file mode 100644
index 0000000..63d451c
--- /dev/null
+++ b/src/Elfisa.UI/Theming/FluentWin11Palette.cs
@@ -0,0 +1,99 @@
+using System.Drawing;
+
+namespace Elfisa.UI.Theming
+{
+ ///
+ /// WinUI 3 / Fluent Design light tokens adapted for WinForms
+ /// (see microsoft/win-dev-skills winui-design skill).
+ ///
+ public sealed class FluentWin11Palette : IThemePalette
+ {
+ public ThemeVariant Variant => ThemeVariant.FluentWin11;
+
+ public ThemeColors Colors { get; } = new ThemeColors
+ {
+ Name = "Fluent Win11",
+ Mode = ThemeMode.Light,
+
+ // SolidBackgroundFillColorBase / Secondary
+ BackgroundPrimary = Color.FromArgb(243, 243, 243),
+ BackgroundSecondary = Color.FromArgb(249, 249, 249),
+ Surface = Color.White,
+ SurfaceElevated = Color.White,
+
+ // ControlStrokeColorDefault / Divider
+ Border = Color.FromArgb(229, 229, 229),
+ BorderSubtle = Color.FromArgb(240, 240, 240),
+
+ // TextFillColorPrimary / Secondary / Tertiary
+ TextPrimary = Color.FromArgb(26, 26, 26),
+ TextSecondary = Color.FromArgb(97, 97, 97),
+ TextMuted = Color.FromArgb(138, 138, 138),
+ TextOnAccent = Color.White,
+
+ // AccentFillColorDefault (pharmacy green on Fluent chrome)
+ AccentPrimary = Color.FromArgb(15, 108, 189),
+ AccentPrimaryHover = Color.FromArgb(14, 94, 163),
+ AccentPrimaryPressed = Color.FromArgb(12, 80, 140),
+ AccentPrimarySoft = Color.FromArgb(235, 243, 252),
+ AccentPrimaryBorder = Color.FromArgb(199, 224, 244),
+ AccentSecondary = Color.FromArgb(16, 124, 16),
+
+ Success = Color.FromArgb(16, 124, 16),
+ SuccessSoft = Color.FromArgb(223, 246, 221),
+ Warning = Color.FromArgb(157, 93, 0),
+ WarningSoft = Color.FromArgb(255, 244, 206),
+ Danger = Color.FromArgb(196, 43, 28),
+ DangerSoft = Color.FromArgb(253, 231, 233),
+ Info = Color.FromArgb(15, 108, 189),
+ InfoSoft = Color.FromArgb(235, 243, 252),
+
+ // Commanding layer — light Mica-style header (not heavy gradient)
+ TitleBarTop = Color.FromArgb(249, 249, 249),
+ TitleBarBottom = Color.FromArgb(237, 237, 237),
+ NavBackground = Color.FromArgb(249, 249, 249),
+ CartHeaderBackground = Color.FromArgb(243, 243, 243),
+ ToolbarBackground = Color.FromArgb(249, 249, 249),
+ SectionHeaderBackground = Color.FromArgb(243, 243, 243),
+
+ SidebarBackground = Color.FromArgb(249, 249, 249),
+ SidebarItem = Color.FromArgb(97, 97, 97),
+ SidebarItemHover = Color.FromArgb(243, 243, 243),
+ SidebarItemActive = Color.FromArgb(235, 243, 252),
+ SidebarItemActiveText = Color.FromArgb(15, 108, 189),
+
+ GridHeaderBackground = Color.FromArgb(243, 243, 243),
+ GridHeaderForeground = Color.FromArgb(26, 26, 26),
+ GridRowBackground = Color.White,
+ GridRowAlternate = Color.FromArgb(249, 249, 249),
+ GridRowHover = Color.FromArgb(243, 243, 243),
+ GridRowSelected = Color.FromArgb(15, 108, 189),
+ GridRowSelectedText = Color.White,
+ GridBorder = Color.FromArgb(229, 229, 229),
+
+ InputBackground = Color.White,
+ InputBorder = Color.FromArgb(229, 229, 229),
+ InputBorderFocus = Color.FromArgb(15, 108, 189),
+
+ OverlayScrim = Color.FromArgb(120, 0, 0, 0),
+ Shadow = Color.FromArgb(24, 0, 0, 0),
+ ScrollbarThumb = Color.FromArgb(200, 200, 200),
+ ScrollbarTrack = Color.FromArgb(243, 243, 243),
+
+ CornerRadiusSmall = 4,
+ CornerRadiusMedium = 8,
+ GridRowHeight = 36,
+ GridHeaderHeight = 40
+ };
+
+ public FluentWin11Palette()
+ {
+ Colors.FontRegular12 = new Font("Segoe UI", 12f);
+ Colors.FontRegular13 = new Font("Segoe UI", 12f);
+ 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 Semibold", 18f);
+ }
+ }
+}
diff --git a/src/Elfisa.UI/Theming/ThemeManager.cs b/src/Elfisa.UI/Theming/ThemeManager.cs
index 5f64372..5d6e702 100644
--- a/src/Elfisa.UI/Theming/ThemeManager.cs
+++ b/src/Elfisa.UI/Theming/ThemeManager.cs
@@ -12,10 +12,11 @@ namespace Elfisa.UI.Theming
{ ThemeVariant.ClinicalPro, new ClinicalProPalette() },
{ ThemeVariant.LightOffice, new LightOfficePalette() },
{ ThemeVariant.DarkRider, new DarkRiderPalette() },
- { ThemeVariant.DarkFluent, new DarkFluentPalette() }
+ { ThemeVariant.DarkFluent, new DarkFluentPalette() },
+ { ThemeVariant.FluentWin11, new FluentWin11Palette() }
};
- private static ThemeVariant _currentVariant = ThemeVariant.PharmaTrust;
+ private static ThemeVariant _currentVariant = ThemeVariant.FluentWin11;
public static event EventHandler ThemeChanged;
@@ -39,7 +40,7 @@ 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 };
+ new[] { ThemeVariant.PharmaTrust, ThemeVariant.Apotheca, ThemeVariant.ClinicalPro, ThemeVariant.LightOffice, ThemeVariant.DarkRider, ThemeVariant.DarkFluent, ThemeVariant.FluentWin11 };
public static string GetVariantDisplayName(ThemeVariant variant)
{
diff --git a/src/Elfisa.UI/Theming/ThemeRenderer.cs b/src/Elfisa.UI/Theming/ThemeRenderer.cs
index bc59063..ff02593 100644
--- a/src/Elfisa.UI/Theming/ThemeRenderer.cs
+++ b/src/Elfisa.UI/Theming/ThemeRenderer.cs
@@ -1,6 +1,5 @@
using System.Windows.Forms;
using Elfisa.UI.Controls;
-using Elfisa.UI.Loading;
namespace Elfisa.UI.Theming
{
@@ -26,6 +25,10 @@ namespace Elfisa.UI.Theming
else if (control is ModernButton button)
{
button.ApplyTheme(colors);
+ if (!button.HeaderNavMode && !button.TopNavMode && !button.SidebarMode)
+ {
+ ModernButtonStyles.ApplyAuto(button);
+ }
}
else if (control is ModernDataGridView grid)
{
@@ -87,14 +90,14 @@ namespace Elfisa.UI.Theming
{
uploadPanel.ApplyTheme(colors);
}
- else if (control is LoadingOverlay loadingOverlay)
- {
- loadingOverlay.ApplyTheme(colors);
- }
else if (control.Tag as string == "toolbar")
{
control.BackColor = colors.ToolbarBackground;
}
+ else if (control.Tag as string == "status-footer")
+ {
+ control.BackColor = colors.Surface;
+ }
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")
diff --git a/src/Elfisa.UI/Theming/ThemeVariant.cs b/src/Elfisa.UI/Theming/ThemeVariant.cs
index 644cbed..01ce683 100644
--- a/src/Elfisa.UI/Theming/ThemeVariant.cs
+++ b/src/Elfisa.UI/Theming/ThemeVariant.cs
@@ -7,7 +7,8 @@ namespace Elfisa.UI.Theming
ClinicalPro = 2,
LightOffice = 3,
DarkRider = 4,
- DarkFluent = 5
+ DarkFluent = 5,
+ FluentWin11 = 6
}
public enum ThemeMode