Apply skill gradient Primary/Danger buttons to Elfisa.UI and add button demos.
Integrate winforms-modern-buttons gradient paint for primary actions and clear (×) controls, align PharmaTrust startup theme, and add Material/gradient/button skill demo projects for comparison. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
14c4b08ad6
commit
1ccb2b33cf
74
Elfisa.sln
74
Elfisa.sln
@ -1,23 +1,95 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elfisa.UI", "src\Elfisa.UI\Elfisa.UI.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elfisa.UI", "src\Elfisa.UI\Elfisa.UI.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectronicPharmacy", "src\ElectronicPharmacy\ElectronicPharmacy.csproj", "{145D8060-4187-4871-B4FB-8DF795727B66}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectronicPharmacy", "src\ElectronicPharmacy\ElectronicPharmacy.csproj", "{145D8060-4187-4871-B4FB-8DF795727B66}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elfisa.MaterialDemo", "src\Elfisa.MaterialDemo\Elfisa.MaterialDemo.csproj", "{7974F646-2F23-46E3-A614-A3D0C5D8C844}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elfisa.ButtonSkillDemo", "src\Elfisa.ButtonSkillDemo\Elfisa.ButtonSkillDemo.csproj", "{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elfisa.GradientButtonDemo", "src\Elfisa.GradientButtonDemo\Elfisa.GradientButtonDemo.csproj", "{19457083-89B8-4C5B-BCA1-BFB66C273502}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|Any CPU.Build.0 = Release|Any CPU
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{145D8060-4187-4871-B4FB-8DF795727B66}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{7974F646-2F23-46E3-A614-A3D0C5D8C844} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||||
|
{1A28299F-5E9B-4E2E-AEC1-EB35FB911F85} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||||
|
{19457083-89B8-4C5B-BCA1-BFB66C273502} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Elfisa.UI.Theming;
|
using Elfisa.UI.Theming;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ namespace Электронная_Фармация
|
|||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
ThemeManager.CurrentVariant = ThemeVariant.FluentWin11;
|
ThemeManager.CurrentVariant = ThemeVariant.PharmaTrust;
|
||||||
Application.Run(new ElectroPharmacy());
|
Application.Run(new ElectroPharmacy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ namespace Электронная_Фармация.UserControls
|
|||||||
const int row1Y = 10;
|
const int row1Y = 10;
|
||||||
const int controlHeight = 32;
|
const int controlHeight = 32;
|
||||||
const int filterHeight = 33;
|
const int filterHeight = 33;
|
||||||
const int buttonHeight = 34;
|
const int buttonHeight = 37;
|
||||||
const int rowGap = 14;
|
const int rowGap = 14;
|
||||||
const int row2Y = row1Y + buttonHeight + rowGap;
|
const int row2Y = row1Y + buttonHeight + rowGap;
|
||||||
const int commentWidth = 200;
|
const int commentWidth = 200;
|
||||||
@ -109,10 +109,10 @@ namespace Электронная_Фармация.UserControls
|
|||||||
|
|
||||||
int right = panelToolbar.ClientSize.Width - pad;
|
int right = panelToolbar.ClientSize.Width - pad;
|
||||||
|
|
||||||
btnDeleteOrder.SetBounds(right - 130, row1Y, 130, buttonHeight);
|
btnDeleteOrder.SetBounds(right - 148, row1Y, 148, buttonHeight);
|
||||||
right = btnDeleteOrder.Left - gap;
|
right = btnDeleteOrder.Left - gap;
|
||||||
|
|
||||||
_btnSendOrder.SetBounds(right - 150, row1Y, 150, buttonHeight);
|
_btnSendOrder.SetBounds(right - 168, row1Y, 168, buttonHeight);
|
||||||
right = _btnSendOrder.Left - gap;
|
right = _btnSendOrder.Left - gap;
|
||||||
|
|
||||||
_comboConsignees.SetBounds(right - 190, filterY, 190, filterHeight);
|
_comboConsignees.SetBounds(right - 190, filterY, 190, filterHeight);
|
||||||
@ -126,14 +126,15 @@ namespace Электронная_Фармация.UserControls
|
|||||||
x = pad;
|
x = pad;
|
||||||
txtGoodFromOrders.SetBounds(x, row2Y, 220, controlHeight);
|
txtGoodFromOrders.SetBounds(x, row2Y, 220, controlHeight);
|
||||||
x = txtGoodFromOrders.Right + gap;
|
x = txtGoodFromOrders.Right + gap;
|
||||||
btnClearGoodSearch.SetBounds(x, row2Y, 34, controlHeight);
|
btnClearGoodSearch.SetBounds(x, row2Y, 32, controlHeight + 3);
|
||||||
x = btnClearGoodSearch.Right + gap;
|
x = btnClearGoodSearch.Right + gap;
|
||||||
txtOrderNumberFilter.SetBounds(x, row2Y, 220, controlHeight);
|
txtOrderNumberFilter.SetBounds(x, row2Y, 220, controlHeight);
|
||||||
x = txtOrderNumberFilter.Right + gap;
|
x = txtOrderNumberFilter.Right + gap;
|
||||||
btnClearOrderNumberFilter.SetBounds(x, row2Y, 34, controlHeight);
|
btnClearOrderNumberFilter.SetBounds(x, row2Y, 32, controlHeight + 3);
|
||||||
x = btnClearOrderNumberFilter.Right + gap;
|
x = btnClearOrderNumberFilter.Right + gap;
|
||||||
|
|
||||||
btnAddComment.SetBounds(x, row2Y, commentWidth, buttonHeight);
|
btnAddComment.SetBounds(x, row2Y, commentWidth, buttonHeight);
|
||||||
|
ModernButtonStyles.FitToText(btnAddComment, buttonHeight);
|
||||||
|
|
||||||
btnClearSuppliers.Visible = false;
|
btnClearSuppliers.Visible = false;
|
||||||
|
|
||||||
|
|||||||
@ -52,9 +52,9 @@ namespace Электронная_Фармация.UserControls
|
|||||||
Tag = "chrome-child";
|
Tag = "chrome-child";
|
||||||
|
|
||||||
btnDeleteGood.Height = 34;
|
btnDeleteGood.Height = 34;
|
||||||
btnClearSearchInPriceList.Height = 32;
|
btnClearSearchInPriceList.Height = 35;
|
||||||
txtSearchGoodNameInPriceList.Height = 32;
|
txtSearchGoodNameInPriceList.Height = 32;
|
||||||
btnClearSupplierFilter.Height = 32;
|
btnClearSupplierFilter.Height = 35;
|
||||||
|
|
||||||
panel1.SizeChanged += (_, __) => LayoutMarkupRow();
|
panel1.SizeChanged += (_, __) => LayoutMarkupRow();
|
||||||
LayoutMarkupRow();
|
LayoutMarkupRow();
|
||||||
|
|||||||
223
src/Elfisa.ButtonSkillDemo/ButtonSkillDemoForm.cs
Normal file
223
src/Elfisa.ButtonSkillDemo/ButtonSkillDemoForm.cs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Elfisa.ButtonSkillDemo;
|
||||||
|
|
||||||
|
internal sealed class ButtonSkillDemoForm : Form
|
||||||
|
{
|
||||||
|
public ButtonSkillDemoForm()
|
||||||
|
{
|
||||||
|
Text = "Skill ModernButton — демо стилей";
|
||||||
|
Size = new Size(920, 620);
|
||||||
|
MinimumSize = new Size(820, 520);
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
BackColor = Color.FromArgb(18, 18, 22);
|
||||||
|
Font = new Font("Segoe UI", 10f);
|
||||||
|
|
||||||
|
var header = new Label
|
||||||
|
{
|
||||||
|
Text = "Custom Modern Button (skill) — варианты стилей",
|
||||||
|
ForeColor = Color.White,
|
||||||
|
AutoSize = false,
|
||||||
|
Height = 48,
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Padding = new Padding(24, 14, 24, 0),
|
||||||
|
Font = new Font("Segoe UI Semibold", 14f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
|
||||||
|
var scroll = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
AutoScroll = true,
|
||||||
|
Padding = new Padding(24)
|
||||||
|
};
|
||||||
|
|
||||||
|
var layout = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
ColumnCount = 2,
|
||||||
|
Padding = new Padding(0, 8, 0, 24)
|
||||||
|
};
|
||||||
|
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 220));
|
||||||
|
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||||
|
|
||||||
|
AddSection(layout, "Default (тёмная)", CreateDefaultButton());
|
||||||
|
AddSection(layout, "Светлая тема", CreateLightButton());
|
||||||
|
AddSection(layout, "Неоновый стиль", CreateNeonButton());
|
||||||
|
AddSection(layout, "Glass (полупрозрачный)", CreateGlassButton());
|
||||||
|
AddSection(layout, "Pharma Trust — синяя", CreatePharmaPrimaryButton());
|
||||||
|
AddSection(layout, "Pharma Trust — красный ×", CreatePharmaClearButton());
|
||||||
|
AddSection(layout, "Большая CTA", CreateLargeCtaButton());
|
||||||
|
|
||||||
|
var note = new Label
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
MaximumSize = new Size(820, 0),
|
||||||
|
ForeColor = Color.FromArgb(180, 180, 190),
|
||||||
|
Text =
|
||||||
|
"Это отдельный класс SkillModernButton для демо. Основное приложение использует Elfisa.UI.Controls.ModernButton + ThemeManager.\n" +
|
||||||
|
"Наведите курсор и нажмите кнопки — видны hover и pressed.",
|
||||||
|
Margin = new Padding(0, 8, 0, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.Controls.Add(note, 0, layout.RowCount);
|
||||||
|
layout.SetColumnSpan(note, 2);
|
||||||
|
|
||||||
|
scroll.Controls.Add(layout);
|
||||||
|
Controls.Add(scroll);
|
||||||
|
Controls.Add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddSection(TableLayoutPanel layout, string title, Control content)
|
||||||
|
{
|
||||||
|
var row = layout.RowCount;
|
||||||
|
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
|
||||||
|
var label = new Label
|
||||||
|
{
|
||||||
|
Text = title,
|
||||||
|
ForeColor = Color.FromArgb(200, 200, 210),
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(0, 16, 12, 8),
|
||||||
|
Font = new Font("Segoe UI Semibold", 10.5f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
|
||||||
|
content.Margin = new Padding(0, 12, 0, 8);
|
||||||
|
layout.Controls.Add(label, 0, row);
|
||||||
|
layout.Controls.Add(content, 1, row);
|
||||||
|
layout.RowCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FlowLayoutPanel Row(params Control[] buttons)
|
||||||
|
{
|
||||||
|
var panel = new FlowLayoutPanel
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
WrapContents = true,
|
||||||
|
FlowDirection = FlowDirection.LeftToRight
|
||||||
|
};
|
||||||
|
foreach (var btn in buttons)
|
||||||
|
{
|
||||||
|
panel.Controls.Add(btn);
|
||||||
|
}
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreateDefaultButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Красивая кнопка",
|
||||||
|
Size = new Size(200, 48),
|
||||||
|
Margin = new Padding(0, 0, 12, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreateLightButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Светлая кнопка",
|
||||||
|
Size = new Size(200, 48),
|
||||||
|
BackColor = Color.White,
|
||||||
|
ForeColor = Color.FromArgb(30, 30, 30),
|
||||||
|
BorderColor = Color.FromArgb(0, 122, 204),
|
||||||
|
HoverColor = Color.FromArgb(245, 249, 255),
|
||||||
|
PressedColor = Color.FromArgb(230, 240, 250),
|
||||||
|
BorderRadius = 12
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreateNeonButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Неон",
|
||||||
|
Size = new Size(180, 48),
|
||||||
|
BackColor = Color.FromArgb(20, 24, 28),
|
||||||
|
ForeColor = Color.FromArgb(220, 255, 250),
|
||||||
|
BorderRadius = 8,
|
||||||
|
BorderColor = Color.FromArgb(0, 255, 200),
|
||||||
|
HoverColor = Color.FromArgb(50, 255, 220),
|
||||||
|
PressedColor = Color.FromArgb(0, 180, 140),
|
||||||
|
BorderSize = 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreateGlassButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Glass",
|
||||||
|
Size = new Size(180, 48),
|
||||||
|
BackColor = Color.FromArgb(80, 80, 80),
|
||||||
|
ForeColor = Color.White,
|
||||||
|
BorderColor = Color.FromArgb(160, 160, 170),
|
||||||
|
HoverColor = Color.FromArgb(110, 110, 120),
|
||||||
|
PressedColor = Color.FromArgb(60, 60, 68),
|
||||||
|
BorderRadius = 16,
|
||||||
|
BorderSize = 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreatePharmaPrimaryButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Сохранить заказ",
|
||||||
|
Size = new Size(200, 40),
|
||||||
|
BackColor = Color.FromArgb(3, 105, 161),
|
||||||
|
ForeColor = Color.White,
|
||||||
|
BorderColor = Color.FromArgb(3, 105, 161),
|
||||||
|
HoverColor = Color.FromArgb(7, 89, 133),
|
||||||
|
PressedColor = Color.FromArgb(12, 74, 110),
|
||||||
|
BorderRadius = 6,
|
||||||
|
BorderSize = 0,
|
||||||
|
Font = new Font("Segoe UI Semibold", 10f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkillModernButton CreatePharmaClearButton()
|
||||||
|
{
|
||||||
|
return new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "×",
|
||||||
|
Size = new Size(32, 32),
|
||||||
|
BackColor = Color.FromArgb(220, 38, 38),
|
||||||
|
ForeColor = Color.White,
|
||||||
|
BorderColor = Color.FromArgb(220, 38, 38),
|
||||||
|
HoverColor = Color.FromArgb(239, 68, 68),
|
||||||
|
PressedColor = Color.FromArgb(185, 28, 28),
|
||||||
|
BorderRadius = 6,
|
||||||
|
BorderSize = 0,
|
||||||
|
Font = new Font("Segoe UI Semibold", 13f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Control CreateLargeCtaButton()
|
||||||
|
{
|
||||||
|
return Row(
|
||||||
|
new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Загрузить на сервер",
|
||||||
|
Size = new Size(220, 52),
|
||||||
|
BorderRadius = 20,
|
||||||
|
BorderColor = Color.FromArgb(64, 158, 255),
|
||||||
|
BackColor = Color.FromArgb(30, 30, 30),
|
||||||
|
HoverColor = Color.FromArgb(0, 140, 230),
|
||||||
|
PressedColor = Color.FromArgb(0, 100, 180)
|
||||||
|
},
|
||||||
|
new SkillModernButton
|
||||||
|
{
|
||||||
|
Text = "Отмена",
|
||||||
|
Size = new Size(140, 52),
|
||||||
|
BackColor = Color.White,
|
||||||
|
ForeColor = Color.FromArgb(30, 30, 30),
|
||||||
|
BorderColor = Color.FromArgb(200, 200, 210),
|
||||||
|
HoverColor = Color.FromArgb(245, 245, 248),
|
||||||
|
PressedColor = Color.FromArgb(230, 230, 235),
|
||||||
|
BorderRadius = 20
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Elfisa.ButtonSkillDemo/Elfisa.ButtonSkillDemo.csproj
Normal file
11
src/Elfisa.ButtonSkillDemo/Elfisa.ButtonSkillDemo.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
11
src/Elfisa.ButtonSkillDemo/Program.cs
Normal file
11
src/Elfisa.ButtonSkillDemo/Program.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Elfisa.ButtonSkillDemo;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
ApplicationConfiguration.Initialize();
|
||||||
|
Application.Run(new ButtonSkillDemoForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/Elfisa.ButtonSkillDemo/README.md
Normal file
24
src/Elfisa.ButtonSkillDemo/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Button Skill Demo
|
||||||
|
|
||||||
|
Демо кнопок из skill **Custom Modern Button** (`SkillModernButton`).
|
||||||
|
|
||||||
|
Не путать с `Elfisa.UI.Controls.ModernButton` — это другой класс для основного приложения.
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet run --project src/Elfisa.ButtonSkillDemo/Elfisa.ButtonSkillDemo.csproj -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Exe: `src/Elfisa.ButtonSkillDemo/bin/Release/net8.0-windows/Elfisa.ButtonSkillDemo.exe`
|
||||||
|
|
||||||
|
## Стили в демо
|
||||||
|
|
||||||
|
| Секция | Настройки |
|
||||||
|
|--------|-----------|
|
||||||
|
| Default | тёмный фон, синяя рамка, radius 12 |
|
||||||
|
| Светлая | белый фон, тёмный текст |
|
||||||
|
| Неон | cyan border + hover |
|
||||||
|
| Glass | серый полупрозрачный вид |
|
||||||
|
| Pharma Trust | синяя / красная × как в ЭльФиСА |
|
||||||
|
| CTA | большие кнопки radius 20 |
|
||||||
132
src/Elfisa.ButtonSkillDemo/SkillModernButton.cs
Normal file
132
src/Elfisa.ButtonSkillDemo/SkillModernButton.cs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Elfisa.ButtonSkillDemo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Кнопка из skill «Custom Modern Button» (отдельно от Elfisa.UI.ModernButton).
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SkillModernButton : Button
|
||||||
|
{
|
||||||
|
public Color BorderColor { get; set; } = Color.FromArgb(0, 122, 204);
|
||||||
|
public Color HoverColor { get; set; } = Color.FromArgb(0, 140, 230);
|
||||||
|
public Color PressedColor { get; set; } = Color.FromArgb(0, 100, 180);
|
||||||
|
public int BorderRadius { get; set; } = 12;
|
||||||
|
public int BorderSize { get; set; } = 2;
|
||||||
|
|
||||||
|
private bool _isHover;
|
||||||
|
private bool _isPressed;
|
||||||
|
|
||||||
|
public SkillModernButton()
|
||||||
|
{
|
||||||
|
FlatStyle = FlatStyle.Flat;
|
||||||
|
FlatAppearance.BorderSize = 0;
|
||||||
|
BackColor = Color.FromArgb(30, 30, 30);
|
||||||
|
ForeColor = Color.White;
|
||||||
|
Font = new Font("Segoe UI", 10.5f, FontStyle.Bold);
|
||||||
|
Cursor = Cursors.Hand;
|
||||||
|
Size = new Size(160, 45);
|
||||||
|
|
||||||
|
SetStyle(ControlStyles.AllPaintingInWmPaint |
|
||||||
|
ControlStyles.UserPaint |
|
||||||
|
ControlStyles.OptimizedDoubleBuffer |
|
||||||
|
ControlStyles.ResizeRedraw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
|
{
|
||||||
|
var g = e.Graphics;
|
||||||
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||||
|
|
||||||
|
var rect = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||||
|
|
||||||
|
var currentColor = BackColor;
|
||||||
|
if (_isPressed)
|
||||||
|
{
|
||||||
|
currentColor = PressedColor;
|
||||||
|
}
|
||||||
|
else if (_isHover)
|
||||||
|
{
|
||||||
|
currentColor = HoverColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var path = GetRoundedPath(rect, BorderRadius))
|
||||||
|
{
|
||||||
|
using (var brush = new SolidBrush(currentColor))
|
||||||
|
{
|
||||||
|
g.FillPath(brush, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BorderSize > 0)
|
||||||
|
{
|
||||||
|
using (var pen = new Pen(BorderColor, BorderSize))
|
||||||
|
{
|
||||||
|
g.DrawPath(pen, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine;
|
||||||
|
TextRenderer.DrawText(g, Text, Font, rect, ForeColor, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GraphicsPath GetRoundedPath(Rectangle rect, int radius)
|
||||||
|
{
|
||||||
|
var path = new GraphicsPath();
|
||||||
|
var r = Math.Max(0, Math.Min(radius, Math.Min(rect.Width, rect.Height) / 2));
|
||||||
|
if (r == 0)
|
||||||
|
{
|
||||||
|
path.AddRectangle(rect);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var diameter = r * 2;
|
||||||
|
path.StartFigure();
|
||||||
|
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
|
||||||
|
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
|
||||||
|
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
|
||||||
|
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
|
||||||
|
path.CloseFigure();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseEnter(EventArgs e)
|
||||||
|
{
|
||||||
|
_isHover = true;
|
||||||
|
Invalidate();
|
||||||
|
base.OnMouseEnter(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e)
|
||||||
|
{
|
||||||
|
_isHover = false;
|
||||||
|
_isPressed = false;
|
||||||
|
Invalidate();
|
||||||
|
base.OnMouseLeave(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Button == MouseButtons.Left)
|
||||||
|
{
|
||||||
|
_isPressed = true;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
base.OnMouseDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseEventArgs e)
|
||||||
|
{
|
||||||
|
_isPressed = false;
|
||||||
|
Invalidate();
|
||||||
|
base.OnMouseUp(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<RootNamespace>Elfisa.GradientButtonDemo</RootNamespace>
|
||||||
|
<AssemblyName>Elfisa.GradientButtonDemo</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
205
src/Elfisa.GradientButtonDemo/GradientButtonDemoForm.cs
Normal file
205
src/Elfisa.GradientButtonDemo/GradientButtonDemoForm.cs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using ModernControls;
|
||||||
|
|
||||||
|
namespace Elfisa.GradientButtonDemo
|
||||||
|
{
|
||||||
|
internal sealed class GradientButtonDemoForm : Form
|
||||||
|
{
|
||||||
|
public GradientButtonDemoForm()
|
||||||
|
{
|
||||||
|
Text = "winforms-modern-buttons skill — демо";
|
||||||
|
Size = new Size(980, 700);
|
||||||
|
MinimumSize = new Size(860, 600);
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
BackColor = Color.FromArgb(245, 247, 250);
|
||||||
|
Font = new Font("Segoe UI", 10f);
|
||||||
|
|
||||||
|
var header = new Label
|
||||||
|
{
|
||||||
|
Text = "ModernGradientButton — градиент + тень + скругление (.NET Framework 4.7.2)",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 52,
|
||||||
|
Padding = new Padding(24, 16, 24, 0),
|
||||||
|
Font = new Font("Segoe UI Semibold", 13f, FontStyle.Bold),
|
||||||
|
ForeColor = Color.FromArgb(30, 41, 59)
|
||||||
|
};
|
||||||
|
|
||||||
|
var scroll = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
AutoScroll = true,
|
||||||
|
Padding = new Padding(24, 8, 24, 24)
|
||||||
|
};
|
||||||
|
|
||||||
|
var layout = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
ColumnCount = 2,
|
||||||
|
Width = 900
|
||||||
|
};
|
||||||
|
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 240));
|
||||||
|
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||||
|
|
||||||
|
AddRow(layout, "Primary (skill)", PresetButton(ModernGradientButton.Preset.Primary, "Сохранить"));
|
||||||
|
AddRow(layout, "Success", PresetButton(ModernGradientButton.Preset.Success, "Подтвердить"));
|
||||||
|
AddRow(layout, "Danger", PresetButton(ModernGradientButton.Preset.Danger, "Удалить"));
|
||||||
|
AddRow(layout, "Neutral", PresetButton(ModernGradientButton.Preset.Neutral, "Отмена"));
|
||||||
|
|
||||||
|
AddRow(layout, "Кастом (оранжевый)", CustomOrangeButton());
|
||||||
|
AddRow(layout, "Pharma Trust — синяя", PharmaPrimaryButton());
|
||||||
|
AddRow(layout, "Крестик × у поиска", ClearSearchButton());
|
||||||
|
AddRow(layout, "Toolbar (мелкая)", ToolbarRow());
|
||||||
|
|
||||||
|
var note = new Label
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
MaximumSize = new Size(860, 0),
|
||||||
|
Margin = new Padding(0, 20, 0, 0),
|
||||||
|
ForeColor = Color.FromArgb(100, 116, 139),
|
||||||
|
Text =
|
||||||
|
"Skill: winforms-modern-buttons · Класс ModernControls.ModernGradientButton\n" +
|
||||||
|
"Наведите и нажмите — видны hover/pressed. Тень: ShadowDepth, градиент: GradientTop/Bottom.\n" +
|
||||||
|
"Основное приложение ЭльФиСА пока на Elfisa.UI.ModernButton — это отдельное демо для сравнения."
|
||||||
|
};
|
||||||
|
layout.Controls.Add(note, 0, layout.RowCount);
|
||||||
|
layout.SetColumnSpan(note, 2);
|
||||||
|
|
||||||
|
scroll.Controls.Add(layout);
|
||||||
|
Controls.Add(scroll);
|
||||||
|
Controls.Add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddRow(TableLayoutPanel layout, string title, Control content)
|
||||||
|
{
|
||||||
|
var row = layout.RowCount;
|
||||||
|
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
|
||||||
|
layout.Controls.Add(new Label
|
||||||
|
{
|
||||||
|
Text = title,
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(0, 18, 12, 8),
|
||||||
|
Font = new Font("Segoe UI Semibold", 10f, FontStyle.Bold),
|
||||||
|
ForeColor = Color.FromArgb(51, 65, 85)
|
||||||
|
}, 0, row);
|
||||||
|
|
||||||
|
content.Margin = new Padding(0, 14, 0, 4);
|
||||||
|
layout.Controls.Add(content, 1, row);
|
||||||
|
layout.RowCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModernGradientButton PresetButton(ModernGradientButton.Preset preset, string text)
|
||||||
|
{
|
||||||
|
var btn = new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = text,
|
||||||
|
Size = new Size(160, 48),
|
||||||
|
Margin = new Padding(0, 0, 12, 8)
|
||||||
|
};
|
||||||
|
btn.ApplyPreset(preset);
|
||||||
|
btn.Click += (_, __) => MessageBox.Show(text + " — клик!", "Демо", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModernGradientButton CustomOrangeButton()
|
||||||
|
{
|
||||||
|
return new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = "Свой стиль",
|
||||||
|
Size = new Size(180, 50),
|
||||||
|
CornerRadius = 20,
|
||||||
|
ShadowDepth = 6,
|
||||||
|
GradientTop = Color.FromArgb(255, 179, 71),
|
||||||
|
GradientBottom = Color.FromArgb(230, 126, 34),
|
||||||
|
HoverGradientTop = Color.FromArgb(255, 195, 110),
|
||||||
|
HoverGradientBottom = Color.FromArgb(245, 145, 50),
|
||||||
|
PressedGradientTop = Color.FromArgb(220, 120, 30),
|
||||||
|
PressedGradientBottom = Color.FromArgb(190, 100, 20)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModernGradientButton PharmaPrimaryButton()
|
||||||
|
{
|
||||||
|
var btn = new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = "Сохранить заказ",
|
||||||
|
Size = new Size(190, 44),
|
||||||
|
CornerRadius = 6,
|
||||||
|
ShadowDepth = 4,
|
||||||
|
GradientTop = Color.FromArgb(14, 116, 181),
|
||||||
|
GradientBottom = Color.FromArgb(3, 105, 161),
|
||||||
|
HoverGradientTop = Color.FromArgb(37, 130, 195),
|
||||||
|
HoverGradientBottom = Color.FromArgb(7, 89, 133),
|
||||||
|
PressedGradientTop = Color.FromArgb(12, 74, 110),
|
||||||
|
PressedGradientBottom = Color.FromArgb(8, 60, 90)
|
||||||
|
};
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Control ClearSearchRow()
|
||||||
|
{
|
||||||
|
var panel = new FlowLayoutPanel { AutoSize = true, WrapContents = false };
|
||||||
|
|
||||||
|
var search = new TextBox
|
||||||
|
{
|
||||||
|
Text = "прокладки",
|
||||||
|
Width = 280,
|
||||||
|
Height = 32,
|
||||||
|
Font = new Font("Segoe UI", 10f),
|
||||||
|
Margin = new Padding(0, 8, 8, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
var clear = new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = "×",
|
||||||
|
Size = new Size(36, 36),
|
||||||
|
CornerRadius = 6,
|
||||||
|
ShadowDepth = 3,
|
||||||
|
Font = new Font("Segoe UI Semibold", 13f, FontStyle.Bold),
|
||||||
|
Margin = new Padding(0, 6, 0, 0)
|
||||||
|
};
|
||||||
|
clear.ApplyPreset(ModernGradientButton.Preset.Danger);
|
||||||
|
clear.Click += (_, __) => search.Clear();
|
||||||
|
|
||||||
|
panel.Controls.Add(search);
|
||||||
|
panel.Controls.Add(clear);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Control ClearSearchButton()
|
||||||
|
{
|
||||||
|
return ClearSearchRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Control ToolbarRow()
|
||||||
|
{
|
||||||
|
var panel = new FlowLayoutPanel { AutoSize = true };
|
||||||
|
|
||||||
|
var small = new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = "×",
|
||||||
|
Size = new Size(32, 32),
|
||||||
|
CornerRadius = 5,
|
||||||
|
ShadowDepth = 2,
|
||||||
|
Font = new Font("Segoe UI", 11f, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
small.ApplyPreset(ModernGradientButton.Preset.Danger);
|
||||||
|
|
||||||
|
var neutral = new ModernGradientButton
|
||||||
|
{
|
||||||
|
Text = "Фильтр",
|
||||||
|
Size = new Size(100, 34),
|
||||||
|
CornerRadius = 8,
|
||||||
|
ShadowDepth = 3
|
||||||
|
};
|
||||||
|
neutral.ApplyPreset(ModernGradientButton.Preset.Neutral);
|
||||||
|
|
||||||
|
panel.Controls.Add(small);
|
||||||
|
panel.Controls.Add(neutral);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
220
src/Elfisa.GradientButtonDemo/ModernGradientButton.cs
Normal file
220
src/Elfisa.GradientButtonDemo/ModernGradientButton.cs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ModernControls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Из skill winforms-modern-buttons: градиент, тень, скругление, hover/pressed.
|
||||||
|
/// </summary>
|
||||||
|
public class ModernGradientButton : Button
|
||||||
|
{
|
||||||
|
public enum ButtonState { Normal, Hover, Pressed }
|
||||||
|
|
||||||
|
private ButtonState _state = ButtonState.Normal;
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color GradientTop { get; set; } = Color.FromArgb(66, 133, 244);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color GradientBottom { get; set; } = Color.FromArgb(30, 87, 194);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color HoverGradientTop { get; set; } = Color.FromArgb(90, 150, 255);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color HoverGradientBottom { get; set; } = Color.FromArgb(45, 105, 220);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color PressedGradientTop { get; set; } = Color.FromArgb(25, 70, 160);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color PressedGradientBottom { get; set; } = Color.FromArgb(15, 55, 130);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public int CornerRadius { get; set; } = 12;
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public int ShadowDepth { get; set; } = 5;
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public Color ShadowColor { get; set; } = Color.FromArgb(60, 0, 0, 0);
|
||||||
|
|
||||||
|
[Category("Appearance")]
|
||||||
|
public bool AnimateHover { get; set; } = true;
|
||||||
|
|
||||||
|
public ModernGradientButton()
|
||||||
|
{
|
||||||
|
SetStyle(ControlStyles.AllPaintingInWmPaint
|
||||||
|
| ControlStyles.UserPaint
|
||||||
|
| ControlStyles.ResizeRedraw
|
||||||
|
| ControlStyles.SupportsTransparentBackColor
|
||||||
|
| ControlStyles.OptimizedDoubleBuffer, true);
|
||||||
|
|
||||||
|
FlatStyle = FlatStyle.Flat;
|
||||||
|
FlatAppearance.BorderSize = 0;
|
||||||
|
BackColor = Color.Transparent;
|
||||||
|
ForeColor = Color.White;
|
||||||
|
Font = new Font("Segoe UI", 9.5f, FontStyle.Regular);
|
||||||
|
Cursor = Cursors.Hand;
|
||||||
|
Size = new Size(140, 42);
|
||||||
|
Padding = new Padding(0, 0, 0, ShadowDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseEnter(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseEnter(e);
|
||||||
|
_state = ButtonState.Hover;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseLeave(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnMouseLeave(e);
|
||||||
|
_state = ButtonState.Normal;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseEventArgs mevent)
|
||||||
|
{
|
||||||
|
base.OnMouseDown(mevent);
|
||||||
|
_state = ButtonState.Pressed;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseEventArgs mevent)
|
||||||
|
{
|
||||||
|
base.OnMouseUp(mevent);
|
||||||
|
_state = ClientRectangle.Contains(mevent.Location) ? ButtonState.Hover : ButtonState.Normal;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GraphicsPath RoundedRect(Rectangle bounds, int radius)
|
||||||
|
{
|
||||||
|
var d = radius * 2;
|
||||||
|
var path = new GraphicsPath();
|
||||||
|
|
||||||
|
if (radius <= 0)
|
||||||
|
{
|
||||||
|
path.AddRectangle(bounds);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.StartFigure();
|
||||||
|
path.AddArc(bounds.X, bounds.Y, d, d, 180, 90);
|
||||||
|
path.AddArc(bounds.Right - d, bounds.Y, d, d, 270, 90);
|
||||||
|
path.AddArc(bounds.Right - d, bounds.Bottom - d, d, d, 0, 90);
|
||||||
|
path.AddArc(bounds.X, bounds.Bottom - d, d, d, 90, 90);
|
||||||
|
path.CloseFigure();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs pevent)
|
||||||
|
{
|
||||||
|
var g = pevent.Graphics;
|
||||||
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||||
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||||
|
|
||||||
|
var buttonRect = new Rectangle(0, 0, Width - 1, Height - 1 - ShadowDepth);
|
||||||
|
|
||||||
|
for (var i = ShadowDepth; i > 0; i--)
|
||||||
|
{
|
||||||
|
var alpha = ShadowColor.A * i / (ShadowDepth * 3);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(alpha, ShadowColor)))
|
||||||
|
using (var shadowPath = RoundedRect(
|
||||||
|
new Rectangle(i, buttonRect.Y + i + 1, buttonRect.Width - i, buttonRect.Height - 1),
|
||||||
|
CornerRadius))
|
||||||
|
{
|
||||||
|
g.FillPath(shadowBrush, shadowPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color top;
|
||||||
|
Color bottom;
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case ButtonState.Hover:
|
||||||
|
top = HoverGradientTop;
|
||||||
|
bottom = HoverGradientBottom;
|
||||||
|
break;
|
||||||
|
case ButtonState.Pressed:
|
||||||
|
top = PressedGradientTop;
|
||||||
|
bottom = PressedGradientBottom;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
top = GradientTop;
|
||||||
|
bottom = GradientBottom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var path = RoundedRect(buttonRect, CornerRadius))
|
||||||
|
using (var brush = new LinearGradientBrush(buttonRect, top, bottom, LinearGradientMode.Vertical))
|
||||||
|
{
|
||||||
|
g.FillPath(brush, path);
|
||||||
|
|
||||||
|
using (var highlightPen = new Pen(Color.FromArgb(40, Color.White), 1))
|
||||||
|
{
|
||||||
|
g.DrawArc(highlightPen, buttonRect.X, buttonRect.Y, CornerRadius * 2, CornerRadius * 2, 180, 90);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRenderer.DrawText(
|
||||||
|
g,
|
||||||
|
Text,
|
||||||
|
Font,
|
||||||
|
buttonRect,
|
||||||
|
ForeColor,
|
||||||
|
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyPreset(Preset preset)
|
||||||
|
{
|
||||||
|
switch (preset)
|
||||||
|
{
|
||||||
|
case Preset.Primary:
|
||||||
|
GradientTop = Color.FromArgb(66, 133, 244);
|
||||||
|
GradientBottom = Color.FromArgb(30, 87, 194);
|
||||||
|
HoverGradientTop = Color.FromArgb(90, 150, 255);
|
||||||
|
HoverGradientBottom = Color.FromArgb(45, 105, 220);
|
||||||
|
PressedGradientTop = Color.FromArgb(25, 70, 160);
|
||||||
|
PressedGradientBottom = Color.FromArgb(15, 55, 130);
|
||||||
|
break;
|
||||||
|
case Preset.Success:
|
||||||
|
GradientTop = Color.FromArgb(67, 189, 118);
|
||||||
|
GradientBottom = Color.FromArgb(30, 140, 80);
|
||||||
|
HoverGradientTop = Color.FromArgb(90, 205, 135);
|
||||||
|
HoverGradientBottom = Color.FromArgb(40, 160, 95);
|
||||||
|
PressedGradientTop = Color.FromArgb(20, 120, 65);
|
||||||
|
PressedGradientBottom = Color.FromArgb(10, 95, 50);
|
||||||
|
break;
|
||||||
|
case Preset.Danger:
|
||||||
|
GradientTop = Color.FromArgb(235, 87, 87);
|
||||||
|
GradientBottom = Color.FromArgb(200, 40, 40);
|
||||||
|
HoverGradientTop = Color.FromArgb(245, 110, 110);
|
||||||
|
HoverGradientBottom = Color.FromArgb(215, 55, 55);
|
||||||
|
PressedGradientTop = Color.FromArgb(175, 30, 30);
|
||||||
|
PressedGradientBottom = Color.FromArgb(140, 20, 20);
|
||||||
|
break;
|
||||||
|
case Preset.Neutral:
|
||||||
|
GradientTop = Color.FromArgb(120, 130, 140);
|
||||||
|
GradientBottom = Color.FromArgb(80, 90, 100);
|
||||||
|
HoverGradientTop = Color.FromArgb(140, 150, 160);
|
||||||
|
HoverGradientBottom = Color.FromArgb(95, 105, 115);
|
||||||
|
PressedGradientTop = Color.FromArgb(65, 75, 85);
|
||||||
|
PressedGradientBottom = Color.FromArgb(50, 60, 70);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Preset { Primary, Success, Danger, Neutral }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Elfisa.GradientButtonDemo/Program.cs
Normal file
16
src/Elfisa.GradientButtonDemo/Program.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Elfisa.GradientButtonDemo
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new GradientButtonDemoForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Elfisa.GradientButtonDemo/README.md
Normal file
20
src/Elfisa.GradientButtonDemo/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Gradient Button Demo (skill)
|
||||||
|
|
||||||
|
Демо по skill **winforms-modern-buttons** — класс `ModernControls.ModernGradientButton`.
|
||||||
|
|
||||||
|
- .NET Framework **4.7.2** (как в skill и в ЭльФиСА)
|
||||||
|
- Градиент, тень, скругление, 4 пресета
|
||||||
|
|
||||||
|
## Запуск
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet run --project src/Elfisa.GradientButtonDemo/Elfisa.GradientButtonDemo.csproj -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Exe: `src/Elfisa.GradientButtonDemo/bin/Release/Elfisa.GradientButtonDemo.exe`
|
||||||
|
|
||||||
|
## Файлы skill
|
||||||
|
|
||||||
|
Исходник skill распакован из `winforms-modern-buttons.skill`:
|
||||||
|
- `ModernGradientButton.cs` — копия из `assets/`
|
||||||
|
- Skill также можно установить в `~/.cursor/skills/winforms-modern-buttons/`
|
||||||
15
src/Elfisa.MaterialDemo/Elfisa.MaterialDemo.csproj
Normal file
15
src/Elfisa.MaterialDemo/Elfisa.MaterialDemo.csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MaterialSkin.2" Version="2.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
286
src/Elfisa.MaterialDemo/PharmacyMaterialForm.cs
Normal file
286
src/Elfisa.MaterialDemo/PharmacyMaterialForm.cs
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
using MaterialSkin;
|
||||||
|
using MaterialSkin.Controls;
|
||||||
|
|
||||||
|
namespace Elfisa.MaterialDemo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Demo: как может выглядеть «Электронная Фармация» на MaterialSkin.2 (отдельно от Elfisa.UI).
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class PharmacyMaterialForm : MaterialForm
|
||||||
|
{
|
||||||
|
private readonly MaterialTabControl _tabs;
|
||||||
|
private readonly Panel _contentHost;
|
||||||
|
private readonly MaterialLabel _statusLabel;
|
||||||
|
|
||||||
|
public PharmacyMaterialForm()
|
||||||
|
{
|
||||||
|
Text = "ЭльФиСА — MaterialSkin demo";
|
||||||
|
MinimumSize = new Size(960, 640);
|
||||||
|
Size = new Size(1100, 720);
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
|
||||||
|
MaterialSkinManager.Instance.AddFormToManage(this);
|
||||||
|
|
||||||
|
var header = new MaterialLabel
|
||||||
|
{
|
||||||
|
Text = "MaterialSkin.2 — демо для сравнения с Elfisa.UI",
|
||||||
|
FontType = MaterialSkinManager.fontType.H6,
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 48,
|
||||||
|
Padding = new Padding(24, 12, 24, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
_tabs = new MaterialTabControl
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 48,
|
||||||
|
Depth = 0
|
||||||
|
};
|
||||||
|
_tabs.TabPages.Add(new TabPage("Прайс-лист") { Tag = "price" });
|
||||||
|
_tabs.TabPages.Add(new TabPage("Заказы") { Tag = "orders" });
|
||||||
|
_tabs.TabPages.Add(new TabPage("Загрузить") { Tag = "upload" });
|
||||||
|
_tabs.SelectedIndexChanged += (_, __) => ShowTab(_tabs.SelectedTab?.Tag as string ?? "price");
|
||||||
|
|
||||||
|
_contentHost = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Padding = new Padding(24)
|
||||||
|
};
|
||||||
|
|
||||||
|
_statusLabel = new MaterialLabel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Bottom,
|
||||||
|
Height = 36,
|
||||||
|
Text = "Пользователь: demo@apteka (MaterialSkin dark / teal)",
|
||||||
|
FontType = MaterialSkinManager.fontType.Caption,
|
||||||
|
Padding = new Padding(24, 8, 24, 8)
|
||||||
|
};
|
||||||
|
|
||||||
|
Controls.Add(_contentHost);
|
||||||
|
Controls.Add(_statusLabel);
|
||||||
|
Controls.Add(_tabs);
|
||||||
|
Controls.Add(header);
|
||||||
|
|
||||||
|
ShowTab("price");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowTab(string key)
|
||||||
|
{
|
||||||
|
_contentHost.Controls.Clear();
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case "orders":
|
||||||
|
_contentHost.Controls.Add(BuildOrdersView());
|
||||||
|
break;
|
||||||
|
case "upload":
|
||||||
|
_contentHost.Controls.Add(BuildUploadView());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_contentHost.Controls.Add(BuildPriceView());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Control BuildPriceView()
|
||||||
|
{
|
||||||
|
var root = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
ColumnCount = 1,
|
||||||
|
RowCount = 3
|
||||||
|
};
|
||||||
|
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
|
||||||
|
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 120f));
|
||||||
|
|
||||||
|
var toolbar = new FlowLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
AutoSize = true,
|
||||||
|
WrapContents = false,
|
||||||
|
Padding = new Padding(0, 0, 0, 16)
|
||||||
|
};
|
||||||
|
|
||||||
|
var search = new MaterialTextBox
|
||||||
|
{
|
||||||
|
Hint = "Поиск по наименованию…",
|
||||||
|
Width = 320,
|
||||||
|
Margin = new Padding(0, 8, 12, 0)
|
||||||
|
};
|
||||||
|
var clearBtn = new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "×",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Outlined,
|
||||||
|
Size = new Size(48, 36),
|
||||||
|
Margin = new Padding(0, 8, 12, 0)
|
||||||
|
};
|
||||||
|
var supplier = new MaterialComboBox
|
||||||
|
{
|
||||||
|
Hint = "Поставщик",
|
||||||
|
Width = 200,
|
||||||
|
Margin = new Padding(0, 8, 0, 0)
|
||||||
|
};
|
||||||
|
supplier.Items.AddRange(new object[] { "Катрен", "Протек", "Все поставщики" });
|
||||||
|
supplier.SelectedIndex = 0;
|
||||||
|
|
||||||
|
toolbar.Controls.Add(search);
|
||||||
|
toolbar.Controls.Add(clearBtn);
|
||||||
|
toolbar.Controls.Add(supplier);
|
||||||
|
|
||||||
|
var grid = new MaterialListView
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
FullRowSelect = true,
|
||||||
|
View = View.Details,
|
||||||
|
BorderStyle = BorderStyle.None
|
||||||
|
};
|
||||||
|
grid.Columns.Add("Наименование", 420);
|
||||||
|
grid.Columns.Add("Производитель", 220);
|
||||||
|
grid.Columns.Add("Цена", 90);
|
||||||
|
grid.Columns.Add("Остаток", 90);
|
||||||
|
grid.Items.Add(new ListViewItem(new[] { "Нурофен 200 мг №10", "Reckitt", "189,00", "42" }));
|
||||||
|
grid.Items.Add(new ListViewItem(new[] { "Амоксициллин 500 мг №20", "Sandoz", "124,50", "18" }));
|
||||||
|
grid.Items.Add(new ListViewItem(new[] { "Омез 20 мг №30", "Dr. Reddy's", "312,00", "7" }));
|
||||||
|
|
||||||
|
var cartCard = new MaterialCard
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Padding = new Padding(16)
|
||||||
|
};
|
||||||
|
var cartLayout = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
ColumnCount = 4
|
||||||
|
};
|
||||||
|
cartLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40f));
|
||||||
|
cartLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20f));
|
||||||
|
cartLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20f));
|
||||||
|
cartLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20f));
|
||||||
|
|
||||||
|
cartLayout.Controls.Add(new MaterialLabel
|
||||||
|
{
|
||||||
|
Text = "Корзина: 2 позиции · 313,50 ₽",
|
||||||
|
FontType = MaterialSkinManager.fontType.Subtitle1,
|
||||||
|
Dock = DockStyle.Fill
|
||||||
|
}, 0, 0);
|
||||||
|
|
||||||
|
cartLayout.Controls.Add(new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "Сохранить заказ",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Contained,
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
HighEmphasis = true
|
||||||
|
}, 1, 0);
|
||||||
|
|
||||||
|
cartLayout.Controls.Add(new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "Очистить",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Outlined,
|
||||||
|
Dock = DockStyle.Fill
|
||||||
|
}, 2, 0);
|
||||||
|
|
||||||
|
cartLayout.Controls.Add(new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "Отправить",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Contained,
|
||||||
|
Dock = DockStyle.Fill
|
||||||
|
}, 3, 0);
|
||||||
|
|
||||||
|
cartCard.Controls.Add(cartLayout);
|
||||||
|
|
||||||
|
root.Controls.Add(toolbar, 0, 0);
|
||||||
|
root.Controls.Add(grid, 0, 1);
|
||||||
|
root.Controls.Add(cartCard, 0, 2);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Control BuildOrdersView()
|
||||||
|
{
|
||||||
|
var card = new MaterialCard
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Padding = new Padding(24)
|
||||||
|
};
|
||||||
|
|
||||||
|
var title = new MaterialLabel
|
||||||
|
{
|
||||||
|
Text = "Журнал заказов",
|
||||||
|
FontType = MaterialSkinManager.fontType.H5,
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 40
|
||||||
|
};
|
||||||
|
|
||||||
|
var grid = new MaterialListView
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
View = View.Details,
|
||||||
|
FullRowSelect = true
|
||||||
|
};
|
||||||
|
grid.Columns.Add("№", 80);
|
||||||
|
grid.Columns.Add("Дата", 120);
|
||||||
|
grid.Columns.Add("Поставщик", 180);
|
||||||
|
grid.Columns.Add("Статус", 140);
|
||||||
|
grid.Columns.Add("Сумма", 100);
|
||||||
|
grid.Items.Add(new ListViewItem(new[] { "1042", "14.07.2026", "Катрен", "Отправлен", "4 820,00" }));
|
||||||
|
grid.Items.Add(new ListViewItem(new[] { "1041", "13.07.2026", "Протек", "Черновик", "1 240,00" }));
|
||||||
|
|
||||||
|
card.Controls.Add(grid);
|
||||||
|
card.Controls.Add(title);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Control BuildUploadView()
|
||||||
|
{
|
||||||
|
var card = new MaterialCard
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Padding = new Padding(32)
|
||||||
|
};
|
||||||
|
|
||||||
|
var stack = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
ColumnCount = 1,
|
||||||
|
RowCount = 4
|
||||||
|
};
|
||||||
|
stack.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
stack.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
stack.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
stack.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
|
||||||
|
|
||||||
|
stack.Controls.Add(new MaterialLabel
|
||||||
|
{
|
||||||
|
Text = "Загрузка данных с сервера",
|
||||||
|
FontType = MaterialSkinManager.fontType.H5,
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(0, 0, 0, 8)
|
||||||
|
}, 0, 0);
|
||||||
|
|
||||||
|
stack.Controls.Add(new MaterialLabel
|
||||||
|
{
|
||||||
|
Text = "MaterialSkin даёт готовые карточки, ripple-кнопки и тёмную тему из коробки.",
|
||||||
|
FontType = MaterialSkinManager.fontType.Body1,
|
||||||
|
AutoSize = true,
|
||||||
|
Margin = new Padding(0, 0, 0, 24)
|
||||||
|
}, 0, 1);
|
||||||
|
|
||||||
|
var buttons = new FlowLayoutPanel { AutoSize = true, WrapContents = false };
|
||||||
|
buttons.Controls.Add(new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "Загрузить прайс",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Contained,
|
||||||
|
HighEmphasis = true,
|
||||||
|
Margin = new Padding(0, 0, 12, 0)
|
||||||
|
});
|
||||||
|
buttons.Controls.Add(new MaterialButton
|
||||||
|
{
|
||||||
|
Text = "Отправить заказы",
|
||||||
|
Type = MaterialButton.MaterialButtonType.Outlined
|
||||||
|
});
|
||||||
|
stack.Controls.Add(buttons, 0, 2);
|
||||||
|
|
||||||
|
card.Controls.Add(stack);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/Elfisa.MaterialDemo/Program.cs
Normal file
24
src/Elfisa.MaterialDemo/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using MaterialSkin;
|
||||||
|
using MaterialSkin.Controls;
|
||||||
|
|
||||||
|
namespace Elfisa.MaterialDemo;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
ApplicationConfiguration.Initialize();
|
||||||
|
|
||||||
|
var skin = MaterialSkinManager.Instance;
|
||||||
|
skin.Theme = MaterialSkinManager.Themes.DARK;
|
||||||
|
skin.ColorScheme = new ColorScheme(
|
||||||
|
Primary.Teal800,
|
||||||
|
Primary.Teal900,
|
||||||
|
Primary.Teal200,
|
||||||
|
Accent.LightBlue200,
|
||||||
|
TextShade.WHITE);
|
||||||
|
|
||||||
|
Application.Run(new PharmacyMaterialForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/Elfisa.MaterialDemo/README.md
Normal file
19
src/Elfisa.MaterialDemo/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# MaterialSkin demo
|
||||||
|
|
||||||
|
Отдельное приложение для сравнения **MaterialSkin.2** с текущей библиотекой **Elfisa.UI**.
|
||||||
|
|
||||||
|
Запуск:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet run --project src/Elfisa.MaterialDemo/Elfisa.MaterialDemo.csproj -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Или exe:
|
||||||
|
|
||||||
|
`src/Elfisa.MaterialDemo/bin/Release/net8.0-windows/Elfisa.MaterialDemo.exe`
|
||||||
|
|
||||||
|
## Зачем отдельно
|
||||||
|
|
||||||
|
Основной клиент (`ElectronicPharmacy`) уже построен на `Elfisa.UI` (owner-draw, PharmaTrust, кастомные контролы). Подмешивать MaterialSkin в ту же форму — конфликт двух систем тем и двойная перерисовка.
|
||||||
|
|
||||||
|
Это демо показывает, как выглядел бы тот же сценарий (прайс / заказы / загрузка) на готовой библиотеке Google Material.
|
||||||
@ -110,10 +110,10 @@ namespace Elfisa.UI.Controls
|
|||||||
FlatStyle = FlatStyle.Flat;
|
FlatStyle = FlatStyle.Flat;
|
||||||
FlatAppearance.BorderSize = 0;
|
FlatAppearance.BorderSize = 0;
|
||||||
Cursor = Cursors.Hand;
|
Cursor = Cursors.Hand;
|
||||||
Font = new Font("Segoe UI Semibold", 12f);
|
Font = new Font("Segoe UI Semibold", 10f, FontStyle.Bold);
|
||||||
Height = ModernButtonStyles.DefaultHeight;
|
Height = ModernButtonStyles.DefaultHeight;
|
||||||
MinimumSize = new Size(64, ModernButtonStyles.DefaultHeight);
|
MinimumSize = new Size(72, ModernButtonStyles.DefaultHeight);
|
||||||
Padding = new Padding(14, 6, 14, 6);
|
Padding = new Padding(16, 6, 16, 6);
|
||||||
TabStop = true;
|
TabStop = true;
|
||||||
_animTimer = new AnimationTimer(v => { _hoverAnim = v; Invalidate(); });
|
_animTimer = new AnimationTimer(v => { _hoverAnim = v; Invalidate(); });
|
||||||
}
|
}
|
||||||
@ -127,11 +127,13 @@ namespace Elfisa.UI.Controls
|
|||||||
}
|
}
|
||||||
else if (_compactIconMode)
|
else if (_compactIconMode)
|
||||||
{
|
{
|
||||||
Font = new Font("Segoe UI", 16f, FontStyle.Bold);
|
Font = new Font("Segoe UI Semibold", 13f, FontStyle.Bold);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Font = theme.FontSemibold14;
|
Font = theme.FontSemibold14 != null
|
||||||
|
? new Font(theme.FontSemibold14.FontFamily, 10f, FontStyle.Bold)
|
||||||
|
: new Font("Segoe UI Semibold", 10f, FontStyle.Bold);
|
||||||
}
|
}
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
@ -208,34 +210,61 @@ namespace Elfisa.UI.Controls
|
|||||||
g.CompositingQuality = CompositingQuality.HighQuality;
|
g.CompositingQuality = CompositingQuality.HighQuality;
|
||||||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||||||
|
|
||||||
var bounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
var bounds = new Rectangle(0, 0, Width, Height);
|
||||||
var radius = theme.CornerRadiusSmall;
|
var usesGradient = SkillGradientButtonPaint.UsesGradient(_buttonStyle, _compactIconMode);
|
||||||
var baseColor = ResolveBaseColor(theme);
|
|
||||||
var fill = baseColor;
|
|
||||||
|
|
||||||
if (_headerNavMode)
|
if (_headerNavMode)
|
||||||
{
|
{
|
||||||
|
var headerBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||||
|
var headerRadius = theme.CornerRadiusSmall;
|
||||||
var activeBoost = _isActiveItem ? 0.22f : 0.06f;
|
var activeBoost = _isActiveItem ? 0.22f : 0.06f;
|
||||||
var hoverBoost = _hoverAnim * 0.14f;
|
var hoverBoost = _hoverAnim * 0.14f;
|
||||||
var alpha = (int)(255 * (activeBoost + hoverBoost));
|
var alpha = (int)(255 * (activeBoost + hoverBoost));
|
||||||
fill = Color.FromArgb(alpha, 255, 255, 255);
|
var headerFill = Color.FromArgb(alpha, 255, 255, 255);
|
||||||
using (var brush = new SolidBrush(fill))
|
using (var brush = new SolidBrush(headerFill))
|
||||||
{
|
{
|
||||||
GraphicsExtensions.FillRoundedRectangle(g, brush, bounds, radius);
|
GraphicsExtensions.FillRoundedRectangle(g, brush, headerBounds, headerRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isActiveItem)
|
if (_isActiveItem)
|
||||||
{
|
{
|
||||||
using (var pen = new Pen(Color.FromArgb(180, 255, 255, 255), 1f))
|
using (var pen = new Pen(Color.FromArgb(180, 255, 255, 255), 1f))
|
||||||
{
|
{
|
||||||
GraphicsExtensions.DrawRoundedRectangle(g, pen, bounds, radius);
|
GraphicsExtensions.DrawRoundedRectangle(g, pen, headerBounds, headerRadius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawHeaderNavContent(g, bounds, theme);
|
DrawHeaderNavContent(g, headerBounds, theme);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usesGradient && !_topNavMode && !_sidebarMode)
|
||||||
|
{
|
||||||
|
SkillGradientButtonPaint.Paint(
|
||||||
|
g,
|
||||||
|
bounds,
|
||||||
|
_buttonStyle,
|
||||||
|
_compactIconMode,
|
||||||
|
_hover && Enabled,
|
||||||
|
_pressed && Enabled,
|
||||||
|
Enabled);
|
||||||
|
|
||||||
|
var contentRect = SkillGradientButtonPaint.GetContentRect(
|
||||||
|
bounds,
|
||||||
|
_buttonStyle,
|
||||||
|
_compactIconMode,
|
||||||
|
Enabled);
|
||||||
|
|
||||||
|
var gradientTextColor = Enabled ? theme.TextOnAccent : theme.TextMuted;
|
||||||
|
DrawActionButtonContent(g, contentRect, gradientTextColor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flatBounds = new Rectangle(0, 0, Width - 1, Height - 1);
|
||||||
|
var radius = _compactIconMode ? 6 : 6;
|
||||||
|
var baseColor = ResolveBaseColor(theme);
|
||||||
|
var fill = baseColor;
|
||||||
|
|
||||||
if (_topNavMode)
|
if (_topNavMode)
|
||||||
{
|
{
|
||||||
fill = Color.Transparent;
|
fill = Color.Transparent;
|
||||||
@ -277,17 +306,14 @@ namespace Elfisa.UI.Controls
|
|||||||
fill = GraphicsExtensions.Blend(
|
fill = GraphicsExtensions.Blend(
|
||||||
ResolveHoverColor(theme, baseColor),
|
ResolveHoverColor(theme, baseColor),
|
||||||
baseColor,
|
baseColor,
|
||||||
1f - (_hoverAnim * 0.35f));
|
1f - (_hoverAnim * 0.45f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_topNavMode)
|
if (!_topNavMode && fill.A > 0)
|
||||||
{
|
{
|
||||||
if (fill.A > 0)
|
using (var brush = new SolidBrush(fill))
|
||||||
{
|
{
|
||||||
using (var brush = new SolidBrush(fill))
|
GraphicsExtensions.FillRoundedRectangle(g, brush, flatBounds, radius);
|
||||||
{
|
|
||||||
GraphicsExtensions.FillRoundedRectangle(g, brush, bounds, radius);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +336,7 @@ namespace Elfisa.UI.Controls
|
|||||||
}
|
}
|
||||||
else if ((_buttonStyle == ModernButtonStyle.Secondary
|
else if ((_buttonStyle == ModernButtonStyle.Secondary
|
||||||
|| _buttonStyle == ModernButtonStyle.DangerSoft
|
|| _buttonStyle == ModernButtonStyle.DangerSoft
|
||||||
|| _buttonStyle == ModernButtonStyle.Subtle) && !_sidebarMode)
|
|| _buttonStyle == ModernButtonStyle.Subtle) && !_sidebarMode && !_compactIconMode)
|
||||||
{
|
{
|
||||||
if (_buttonStyle == ModernButtonStyle.Subtle && !_hover && !_pressed && !_focused)
|
if (_buttonStyle == ModernButtonStyle.Subtle && !_hover && !_pressed && !_focused)
|
||||||
{
|
{
|
||||||
@ -330,14 +356,14 @@ namespace Elfisa.UI.Controls
|
|||||||
|
|
||||||
using (var pen = new Pen(borderColor, 1f))
|
using (var pen = new Pen(borderColor, 1f))
|
||||||
{
|
{
|
||||||
GraphicsExtensions.DrawRoundedRectangle(g, pen, bounds, radius);
|
GraphicsExtensions.DrawRoundedRectangle(g, pen, flatBounds, radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_focused && Enabled && ShowFocusCues && !_headerNavMode && !_topNavMode && !_sidebarMode)
|
if (_focused && Enabled && ShowFocusCues && !_headerNavMode && !_topNavMode && !_sidebarMode)
|
||||||
{
|
{
|
||||||
var focusBounds = Rectangle.Inflate(bounds, -2, -2);
|
var focusBounds = Rectangle.Inflate(flatBounds, -2, -2);
|
||||||
using (var pen = new Pen(theme.InputBorderFocus, 2f))
|
using (var pen = new Pen(theme.InputBorderFocus, 2f))
|
||||||
{
|
{
|
||||||
GraphicsExtensions.DrawRoundedRectangle(g, pen, focusBounds, Math.Max(2, radius - 1));
|
GraphicsExtensions.DrawRoundedRectangle(g, pen, focusBounds, Math.Max(2, radius - 1));
|
||||||
@ -366,7 +392,7 @@ namespace Elfisa.UI.Controls
|
|||||||
textColor = GraphicsExtensions.Blend(textColor, theme.TextMuted, 0.55f);
|
textColor = GraphicsExtensions.Blend(textColor, theme.TextMuted, 0.55f);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawActionButtonContent(g, bounds, textColor);
|
DrawActionButtonContent(g, flatBounds, textColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawActionButtonContent(Graphics g, Rectangle bounds, Color textColor)
|
private void DrawActionButtonContent(Graphics g, Rectangle bounds, Color textColor)
|
||||||
@ -507,9 +533,9 @@ namespace Elfisa.UI.Controls
|
|||||||
if (baseColor == theme.AccentPrimary) return theme.AccentPrimaryHover;
|
if (baseColor == theme.AccentPrimary) return theme.AccentPrimaryHover;
|
||||||
if (baseColor == theme.Surface) return theme.GridRowHover;
|
if (baseColor == theme.Surface) return theme.GridRowHover;
|
||||||
if (baseColor == theme.DangerSoft) return GraphicsExtensions.Blend(theme.DangerSoft, theme.Danger, 0.08f);
|
if (baseColor == theme.DangerSoft) return GraphicsExtensions.Blend(theme.DangerSoft, theme.Danger, 0.08f);
|
||||||
|
if (baseColor == theme.Danger) return GraphicsExtensions.Blend(theme.Danger, Color.White, 0.08f);
|
||||||
if (baseColor == theme.Success) return GraphicsExtensions.Blend(theme.Success, Color.White, 0.12f);
|
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.Warning) return GraphicsExtensions.Blend(theme.Warning, Color.White, 0.12f);
|
||||||
if (baseColor == theme.Danger) return GraphicsExtensions.Blend(theme.Danger, Color.White, 0.12f);
|
|
||||||
return GraphicsExtensions.Blend(baseColor, Color.White, 0.08f);
|
return GraphicsExtensions.Blend(baseColor, Color.White, 0.08f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,13 @@ using Elfisa.UI.Theming;
|
|||||||
namespace Elfisa.UI.Controls
|
namespace Elfisa.UI.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WinUI 3–style presets for <see cref="ModernButton"/> in WinForms.
|
/// Стили кнопок по макету Pharma Trust (variant-e-pharma-trust.html).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ModernButtonStyles
|
public static class ModernButtonStyles
|
||||||
{
|
{
|
||||||
public const int DefaultHeight = 32;
|
public const int DefaultHeight = 34;
|
||||||
|
public const int ClearSize = 32;
|
||||||
|
private static readonly Font ActionFont = new Font("Segoe UI Semibold", 10f, FontStyle.Bold);
|
||||||
|
|
||||||
public static void ApplyAuto(ModernButton button)
|
public static void ApplyAuto(ModernButton button)
|
||||||
{
|
{
|
||||||
@ -28,20 +30,20 @@ namespace Elfisa.UI.Controls
|
|||||||
|
|
||||||
if (IsDangerAction(text))
|
if (IsDangerAction(text))
|
||||||
{
|
{
|
||||||
ApplyAction(button, ModernButtonStyle.Danger, ResolveIcon(text, "\uE74D"));
|
ApplyAction(button, ModernButtonStyle.Danger);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPrimaryAction(text))
|
if (IsPrimaryAction(text))
|
||||||
{
|
{
|
||||||
ApplyAction(button, ModernButtonStyle.Primary, ResolveIcon(text, "\uE725"));
|
ApplyAction(button, ModernButtonStyle.Primary);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyAction(button, ModernButtonStyle.Secondary, ResolveIcon(text, null));
|
ApplyAction(button, ModernButtonStyle.Secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ApplyAction(ModernButton button, ModernButtonStyle style, string iconGlyph = null)
|
public static void ApplyAction(ModernButton button, ModernButtonStyle style)
|
||||||
{
|
{
|
||||||
if (button == null)
|
if (button == null)
|
||||||
{
|
{
|
||||||
@ -54,15 +56,16 @@ namespace Elfisa.UI.Controls
|
|||||||
button.BackgroundImage = null;
|
button.BackgroundImage = null;
|
||||||
button.UseVisualStyleBackColor = false;
|
button.UseVisualStyleBackColor = false;
|
||||||
button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
button.MinimumSize = new Size(64, DefaultHeight);
|
button.IconGlyph = null;
|
||||||
if (button.Height < DefaultHeight)
|
button.AllowTextEllipsis = false;
|
||||||
{
|
button.Font = ActionFont;
|
||||||
button.Height = DefaultHeight;
|
button.Padding = new Padding(16, 6, 16, 6);
|
||||||
}
|
var height = style == ModernButtonStyle.Primary || style == ModernButtonStyle.Danger
|
||||||
|
? DefaultHeight + 3
|
||||||
|
: DefaultHeight;
|
||||||
|
button.Height = Math.Max(button.Height, height);
|
||||||
|
|
||||||
button.Padding = new Padding(14, 6, 14, 6);
|
FitToText(button, height);
|
||||||
button.Font = (ThemeManager.Colors?.FontSemibold14) ?? new Font("Segoe UI Semibold", 12f);
|
|
||||||
button.IconGlyph = iconGlyph;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ApplyClear(ModernButton button)
|
public static void ApplyClear(ModernButton button)
|
||||||
@ -72,24 +75,58 @@ namespace Elfisa.UI.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.ButtonStyle = ModernButtonStyle.DangerSoft;
|
button.ButtonStyle = ModernButtonStyle.Danger;
|
||||||
button.CompactIconMode = true;
|
button.CompactIconMode = true;
|
||||||
button.Image = null;
|
button.Image = null;
|
||||||
button.BackgroundImage = null;
|
button.BackgroundImage = null;
|
||||||
button.UseVisualStyleBackColor = false;
|
button.UseVisualStyleBackColor = false;
|
||||||
button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
button.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
button.Text = "×";
|
button.Text = "×";
|
||||||
button.Font = new Font("Segoe UI", 13f, FontStyle.Bold);
|
button.Font = new Font("Segoe UI Semibold", 13f, FontStyle.Bold);
|
||||||
button.MinimumSize = new Size(32, DefaultHeight);
|
|
||||||
button.Size = new Size(Math.Max(button.Width, 32), DefaultHeight);
|
|
||||||
button.IconGlyph = null;
|
button.IconGlyph = null;
|
||||||
|
button.AllowTextEllipsis = false;
|
||||||
|
button.MinimumSize = new Size(ClearSize, ClearSize + 3);
|
||||||
|
button.Size = new Size(ClearSize, ClearSize + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FitToText(ModernButton button, int height = DefaultHeight)
|
||||||
|
{
|
||||||
|
if (button == null || button.CompactIconMode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = button.Text ?? string.Empty;
|
||||||
|
if (text.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var textWidth = TextRenderer.MeasureText(
|
||||||
|
text,
|
||||||
|
button.Font ?? ActionFont,
|
||||||
|
Size.Empty,
|
||||||
|
TextFormatFlags.SingleLine).Width;
|
||||||
|
|
||||||
|
var width = textWidth + button.Padding.Horizontal + 8;
|
||||||
|
width = Math.Max(width, 72);
|
||||||
|
button.MinimumSize = new Size(width, height);
|
||||||
|
if (button.Width < width)
|
||||||
|
{
|
||||||
|
button.Width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.Height < height)
|
||||||
|
{
|
||||||
|
button.Height = height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsClearButton(ModernButton button, string text)
|
private static bool IsClearButton(ModernButton button, string text)
|
||||||
{
|
{
|
||||||
return text == "×"
|
return text == "×"
|
||||||
|| text.Equals("X", StringComparison.OrdinalIgnoreCase)
|
|| text.Equals("X", StringComparison.OrdinalIgnoreCase)
|
||||||
|| (button.Width <= 40 && button.Height <= 36 && text.Length <= 2);
|
|| (button.Width <= 40 && button.Height <= 40 && text.Length <= 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsDangerAction(string text)
|
private static bool IsDangerAction(string text)
|
||||||
@ -116,61 +153,5 @@ namespace Elfisa.UI.Controls
|
|||||||
|| lower.Contains("save")
|
|| lower.Contains("save")
|
||||||
|| lower == "ок";
|
|| 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
159
src/Elfisa.UI/Helpers/SkillGradientButtonPaint.cs
Normal file
159
src/Elfisa.UI/Helpers/SkillGradientButtonPaint.cs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using Elfisa.UI.Controls;
|
||||||
|
|
||||||
|
namespace Elfisa.UI.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Градиент и тень из skill winforms-modern-buttons для ModernButton.
|
||||||
|
/// </summary>
|
||||||
|
internal static class SkillGradientButtonPaint
|
||||||
|
{
|
||||||
|
private static readonly Color ShadowBase = Color.FromArgb(60, 0, 0, 0);
|
||||||
|
|
||||||
|
public static bool UsesGradient(ModernButtonStyle style, bool compactIconMode)
|
||||||
|
{
|
||||||
|
return style == ModernButtonStyle.Primary
|
||||||
|
|| style == ModernButtonStyle.Danger
|
||||||
|
|| (compactIconMode && style == ModernButtonStyle.Danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetCornerRadius(ModernButtonStyle style, bool compactIconMode)
|
||||||
|
{
|
||||||
|
if (compactIconMode)
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return style == ModernButtonStyle.Primary ? 12 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetShadowDepth(ModernButtonStyle style, bool compactIconMode, bool enabled)
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compactIconMode)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return style == ModernButtonStyle.Primary ? 5 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetGradient(
|
||||||
|
ModernButtonStyle style,
|
||||||
|
bool hover,
|
||||||
|
bool pressed,
|
||||||
|
out Color top,
|
||||||
|
out Color bottom)
|
||||||
|
{
|
||||||
|
if (style == ModernButtonStyle.Danger)
|
||||||
|
{
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(175, 30, 30);
|
||||||
|
bottom = Color.FromArgb(140, 20, 20);
|
||||||
|
}
|
||||||
|
else if (hover)
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(245, 110, 110);
|
||||||
|
bottom = Color.FromArgb(215, 55, 55);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(235, 87, 87);
|
||||||
|
bottom = Color.FromArgb(200, 40, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primary preset from skill
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(25, 70, 160);
|
||||||
|
bottom = Color.FromArgb(15, 55, 130);
|
||||||
|
}
|
||||||
|
else if (hover)
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(90, 150, 255);
|
||||||
|
bottom = Color.FromArgb(45, 105, 220);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top = Color.FromArgb(66, 133, 244);
|
||||||
|
bottom = Color.FromArgb(30, 87, 194);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Paint(
|
||||||
|
Graphics g,
|
||||||
|
Rectangle clientRect,
|
||||||
|
ModernButtonStyle style,
|
||||||
|
bool compactIconMode,
|
||||||
|
bool hover,
|
||||||
|
bool pressed,
|
||||||
|
bool enabled)
|
||||||
|
{
|
||||||
|
var shadowDepth = GetShadowDepth(style, compactIconMode, enabled);
|
||||||
|
var radius = GetCornerRadius(style, compactIconMode);
|
||||||
|
var buttonRect = new Rectangle(
|
||||||
|
clientRect.X,
|
||||||
|
clientRect.Y,
|
||||||
|
clientRect.Width - 1,
|
||||||
|
clientRect.Height - 1 - shadowDepth);
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
using (var brush = new SolidBrush(Color.FromArgb(220, 230, 235)))
|
||||||
|
{
|
||||||
|
GraphicsExtensions.FillRoundedRectangle(g, brush, buttonRect, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = shadowDepth; i > 0; i--)
|
||||||
|
{
|
||||||
|
var alpha = ShadowBase.A * i / (shadowDepth * 3);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(alpha, ShadowBase)))
|
||||||
|
using (var shadowPath = GraphicsExtensions.CreateRoundedRectangle(
|
||||||
|
new Rectangle(
|
||||||
|
clientRect.X + i,
|
||||||
|
buttonRect.Y + i + 1,
|
||||||
|
buttonRect.Width - i,
|
||||||
|
buttonRect.Height - 1),
|
||||||
|
radius))
|
||||||
|
{
|
||||||
|
g.FillPath(shadowBrush, shadowPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetGradient(style, hover, pressed, out var top, out var bottom);
|
||||||
|
|
||||||
|
using (var path = GraphicsExtensions.CreateRoundedRectangle(buttonRect, radius))
|
||||||
|
using (var brush = new LinearGradientBrush(buttonRect, top, bottom, LinearGradientMode.Vertical))
|
||||||
|
{
|
||||||
|
g.FillPath(brush, path);
|
||||||
|
|
||||||
|
using (var highlightPen = new Pen(Color.FromArgb(40, Color.White), 1f))
|
||||||
|
{
|
||||||
|
g.DrawArc(highlightPen, buttonRect.X, buttonRect.Y, radius * 2, radius * 2, 180, 90);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rectangle GetContentRect(Rectangle clientRect, ModernButtonStyle style, bool compactIconMode, bool enabled)
|
||||||
|
{
|
||||||
|
var shadowDepth = GetShadowDepth(style, compactIconMode, enabled);
|
||||||
|
return new Rectangle(
|
||||||
|
clientRect.X,
|
||||||
|
clientRect.Y,
|
||||||
|
clientRect.Width - 1,
|
||||||
|
clientRect.Height - 1 - shadowDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user