575 lines
31 KiB
C#
575 lines
31 KiB
C#
using CustomMessageBox;
|
||
using DAL;
|
||
using DALL;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Drawing;
|
||
using System.Drawing.Drawing2D;
|
||
using System.Windows.Forms;
|
||
|
||
namespace UI
|
||
{
|
||
public class SidebarControl : UserControl
|
||
{
|
||
// ── Conexão ───────────────────────────────────────────────────────────
|
||
string _cx = DadosDaConexao.ObterConexao();
|
||
|
||
// ── Cores do Tema LevelOS ─────────────────────────────────────────────
|
||
private static readonly Color NavyDark = Color.FromArgb(15, 30, 60);
|
||
private static readonly Color NavyMid = Color.FromArgb(26, 45, 80);
|
||
private static readonly Color AccentBlue = Color.FromArgb(37, 99, 235);
|
||
private static readonly Color TextLight = Color.FromArgb(255, 255, 255);
|
||
private static readonly Color TextMuted = Color.FromArgb(148, 163, 184);
|
||
private static readonly Color Divider = Color.FromArgb(40, 255, 255, 255);
|
||
|
||
// ── Estado e Escalonamento (DPI) ──────────────────────────────────────
|
||
private float _scale = 1.0f;
|
||
private int _activeIndex = 0;
|
||
private int _hoverIndex = -1;
|
||
|
||
private int ScaledWidth => (int)(220 * _scale);
|
||
private int ScaledLogoH => (int)(55 * _scale);
|
||
private int ScaledSectionH => (int)(32 * _scale);
|
||
private int ScaledItemH => (int)(40 * _scale);
|
||
private int ScaledItemPadX => (int)(12 * _scale);
|
||
private int ScaledFooterH => (int)(50 * _scale);
|
||
private int ScaledIconSize => (int)(16 * _scale);
|
||
|
||
// ── Submenus ──────────────────────────────────────────────────────────
|
||
private ContextMenuStrip _subMenuBanco = null!;
|
||
private ContextMenuStrip _subMenuConfiguracao = null!;
|
||
private ContextMenuStrip _subMenuAjuda = null!;
|
||
private ContextMenuStrip _subMenuOrdemServico = null!;
|
||
private ContextMenuStrip _subMenuFinanceiro = null!;
|
||
private ContextMenuStrip _subMenuCadastro = null!;
|
||
private ContextMenuStrip _subMenuAgenda = null!;
|
||
|
||
public string UserName = "Levelcode";
|
||
public string UserFunction = "Administrador";
|
||
public event EventHandler<int>? NavItemClicked;
|
||
|
||
private readonly List<NavItem> _items = new()
|
||
{
|
||
new NavItem("Dashboard", SvgIcon.Grid, "Principal", null),
|
||
new NavItem("Cadastro", SvgIcon.UserPlus, null, "3"),
|
||
new NavItem("Ordens de Serviço", SvgIcon.FileText, null, "12"),
|
||
new NavItem("Agenda", SvgIcon.Calendar, null, null),
|
||
new NavItem("Produtos", SvgIcon.Package, "Gestão", null),
|
||
new NavItem("Estoque", SvgIcon.Inventory, null, null),
|
||
new NavItem("Financeiro", SvgIcon.DollarSign, null, null),
|
||
new NavItem("Banco de Dados", SvgIcon.Database, "Sistema", null),
|
||
new NavItem("Configurações", SvgIcon.Settings, null, null),
|
||
new NavItem("Suporte Técnico", SvgIcon.Support, "Ajuda", null),
|
||
};
|
||
|
||
// ── Backup ────────────────────────────────────────────────────────────
|
||
public void backupFull(string conexao)
|
||
{
|
||
var svc = new DALLBackupService(conexao);
|
||
var r = svc.ExecutarBackupFull();
|
||
if (r.Sucesso)
|
||
NT_MessageBox.Show($"✅ Backup FULL concluído em {r.Duracao.TotalSeconds:F1}s",
|
||
"Backup do banco de dados", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
else
|
||
NT_MessageBox.Show($"❌ Erro no Backup FULL: {r.Erro}",
|
||
"Erro ao tentar executar backup do sistema.", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
|
||
public void backupDifrencial(string conexao)
|
||
{
|
||
var svc = new DALLBackupService(conexao);
|
||
var r = svc.ExecutarBackupDiferencial();
|
||
if (r.Sucesso)
|
||
NT_MessageBox.Show($"✅ Backup DIFERENCIAL concluído em {r.Duracao.TotalSeconds:F1}s",
|
||
"Backup diferencial concluido", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
else
|
||
NT_MessageBox.Show($"❌ Erro no Backup DIFERENCIAL: {r.Erro}",
|
||
"Erro ao tentar executar backup diferencial no sistema", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
|
||
// ── Construtor ────────────────────────────────────────────────────────
|
||
public SidebarControl()
|
||
{
|
||
BackColor = NavyDark;
|
||
DoubleBuffered = true;
|
||
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
||
}
|
||
|
||
protected override void OnHandleCreated(EventArgs e)
|
||
{
|
||
base.OnHandleCreated(e);
|
||
using (Graphics g = this.CreateGraphics()) { _scale = g.DpiX / 96f; }
|
||
this.Width = ScaledWidth;
|
||
SetupSubMenus();
|
||
}
|
||
|
||
// ── Setup de Submenus ─────────────────────────────────────────────────
|
||
private void SetupSubMenus()
|
||
{
|
||
// ── CADASTRO ──────────────────────────────────────────────────────
|
||
_subMenuCadastro = CreateStyledMenu();
|
||
_subMenuCadastro.Items.Add(CreateItem("👤 Clientes", (s, e) => NavItemClicked?.Invoke(this, 99)));
|
||
_subMenuCadastro.Items.Add(CreateItem("💻 Equipamentos", (s, e) => NavItemClicked?.Invoke(this, 100)));
|
||
_subMenuCadastro.Items.Add(CreateItem("📜 Contratos", (s, e) => NavItemClicked?.Invoke(this, 101)));
|
||
_subMenuCadastro.Items.Add(CreateItem("🏭 Fornecedores", (s, e) => NavItemClicked?.Invoke(this, 102)));
|
||
|
||
// ── Funcionários com submenu aninhado ─────────────────────────────
|
||
var menuFuncionarios = CreateParentItem("👔 Funcionários");
|
||
menuFuncionarios.DropDownItems.Add(CreateItem("➕ Novo funcionário", (s, e) => NavItemClicked?.Invoke(this, 103)));
|
||
menuFuncionarios.DropDownItems.Add(CreateItem("🔍 Consultar funcionários", (s, e) => NavItemClicked?.Invoke(this, 108)));
|
||
_subMenuCadastro.Items.Add(menuFuncionarios);
|
||
// ──────────────────────────────────────────────────────────────────
|
||
|
||
_subMenuCadastro.Items.Add(CreateItem("🚚 Transportadoras", (s, e) => NavItemClicked?.Invoke(this, 104)));
|
||
_subMenuCadastro.Items.Add(CreateItem("🛠️ Serviços", (s, e) => NavItemClicked?.Invoke(this, 105)));
|
||
_subMenuCadastro.Items.Add(CreateItem("🏢 Empresa", (s, e) => NavItemClicked?.Invoke(this, 106)));
|
||
_subMenuCadastro.Items.Add(CreateItem("🔑 Usuários do Sistema", (s, e) => NavItemClicked?.Invoke(this, 107)));
|
||
|
||
// ── BANCO DE DADOS ────────────────────────────────────────────────
|
||
_subMenuBanco = CreateStyledMenu();
|
||
_subMenuBanco.Items.Add(CreateItem("⚙️ Configuração Database", (s, e) => showForms<Form>()));
|
||
_subMenuBanco.Items.Add(CreateItem("💾 Backup de Dados (FULL)", (s, e) => backupFull(_cx)));
|
||
_subMenuBanco.Items.Add(CreateItem("⚡ Backup de Dados (DIFF)", (s, e) => backupDifrencial(_cx)));
|
||
_subMenuBanco.Items.Add(CreateItem("🔄 Restaurar Banco"));
|
||
|
||
// ── CONFIGURAÇÕES ─────────────────────────────────────────────────
|
||
_subMenuConfiguracao = CreateStyledMenu();
|
||
_subMenuConfiguracao.Items.Add(CreateItem("🖼️ Personalização de OS", (s, e) => NavItemClicked?.Invoke(this, 200)));
|
||
_subMenuConfiguracao.Items.Add(CreateItem("🖥️ Personalização de Sistema", (s, e) => NavItemClicked?.Invoke(this, 201)));
|
||
_subMenuConfiguracao.Items.Add(CreateItem(" Configuração Empresa", (s, e) => NavItemClicked?.Invoke(this, 202)));
|
||
_subMenuConfiguracao.Items.Add(new ToolStripSeparator());
|
||
_subMenuConfiguracao.Items.Add(CreateItem("📂 FTP-Cliente", (s, e) => NavItemClicked?.Invoke(this, 203)));
|
||
_subMenuConfiguracao.Items.Add(CreateItem("💬 Telegram-Cliente", (s, e) => NavItemClicked?.Invoke(this, 204)));
|
||
_subMenuConfiguracao.Items.Add(CreateItem("📩 SMTP-Cliente", (s, e) => NavItemClicked?.Invoke(this, 205)));
|
||
_subMenuConfiguracao.Items.Add(new ToolStripSeparator());
|
||
_subMenuConfiguracao.Items.Add(CreateItem("⏰ Backups Automáticos", (s, e) => NavItemClicked?.Invoke(this, 206)));
|
||
_subMenuConfiguracao.Items.Add(CreateItem("☁️ Backup em Nuvem", (s, e) => NavItemClicked?.Invoke(this, 207)));
|
||
// ── AJUDA ─────────────────────────────────────────────────────────
|
||
_subMenuAjuda = CreateStyledMenu();
|
||
_subMenuAjuda.Items.Add(CreateItem("💬 Atendimento Online"));
|
||
_subMenuAjuda.Items.Add(CreateItem("📖 Manual do Sistema"));
|
||
|
||
// ── ORDENS DE SERVIÇO ─────────────────────────────────────────────
|
||
_subMenuOrdemServico = CreateStyledMenu();
|
||
_subMenuOrdemServico.Items.Add(CreateItem("✚ Abrir nova O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("✎ Alterar O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("🔒 Encerrar O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("🔍 Localizar O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("📋 Orçamento de O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("📜 Histórico de O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("📊 Relatório de O.S"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("🖨 Imprimir"));
|
||
var item = CreateItem("⚠️ Chamado Técnico"); item.Click += (s, e) => NavItemClicked?.Invoke(this, 309);
|
||
_subMenuOrdemServico.Items.Add(item);
|
||
_subMenuOrdemServico.Items.Add(CreateItem("🌐 OS WEB"));
|
||
_subMenuOrdemServico.Items.Add(CreateItem("🔓 Reabrir OS"));
|
||
|
||
// ── FINANCEIRO ────────────────────────────────────────────────────
|
||
_subMenuFinanceiro = CreateStyledMenu();
|
||
_subMenuFinanceiro.Items.Add(CreateItem("💳 Contas", (s, e) => NavItemClicked?.Invoke(this, 400)));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("📈 Contas a receber", (s, e) => NavItemClicked?.Invoke(this, 401)));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("📉 Contas a pagar", (s, e) => NavItemClicked?.Invoke(this, 402)));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("📉 Boletos/Duplicatas", (s, e) => NavItemClicked?.Invoke(this, 500)));
|
||
_subMenuFinanceiro.Items.Add(new ToolStripSeparator());
|
||
_subMenuFinanceiro.Items.Add(CreateItem("🛒 Compras"));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("💰 Vendas"));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("🧾 Notas Fiscais"));
|
||
_subMenuFinanceiro.Items.Add(new ToolStripSeparator());
|
||
_subMenuFinanceiro.Items.Add(CreateItem("📂 Arquivo Contador"));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("🏦 Dados Bancários"));
|
||
_subMenuFinanceiro.Items.Add(CreateItem("🕒 Histórico Financeiro"));
|
||
|
||
// ── AGENDA ────────────────────────────────────────────────────────
|
||
_subMenuAgenda = CreateStyledMenu();
|
||
_subMenuAgenda.Items.Add(CreateItem("➕ Novo compromisso", (s, e) => NavItemClicked?.Invoke(this, 300)));
|
||
_subMenuAgenda.Items.Add(CreateItem("🔍 Consultar compromissos", (s, e) => NavItemClicked?.Invoke(this, 301)));
|
||
_subMenuAgenda.Items.Add(CreateItem("✏️ Alterar compromisso"));
|
||
_subMenuAgenda.Items.Add(CreateItem("🖨️ Imprimir"));
|
||
}
|
||
|
||
// ── Helpers de criação de itens ───────────────────────────────────────
|
||
|
||
/// <summary>Cria um ToolStripMenuItem simples com estilo aplicado.</summary>
|
||
private ToolStripMenuItem CreateItem(string text, EventHandler? onClick = null)
|
||
{
|
||
var item = new ToolStripMenuItem(text)
|
||
{
|
||
BackColor = NavyMid,
|
||
ForeColor = TextLight,
|
||
Font = new Font("Segoe UI", 10f * _scale)
|
||
};
|
||
if (onClick != null) item.Click += onClick;
|
||
return item;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Cria um ToolStripMenuItem pai (com submenu aninhado).
|
||
/// O estilo é aplicado aqui e também propagado para os filhos
|
||
/// via evento DropDownOpening.
|
||
/// </summary>
|
||
private ToolStripMenuItem CreateParentItem(string text)
|
||
{
|
||
var item = new ToolStripMenuItem(text)
|
||
{
|
||
BackColor = NavyMid,
|
||
ForeColor = TextLight,
|
||
Font = new Font("Segoe UI", 10f * _scale)
|
||
};
|
||
|
||
// Garante estilo no dropdown aninhado quando abrir
|
||
item.DropDown.BackColor = NavyMid;
|
||
item.DropDown.ForeColor = TextLight;
|
||
item.DropDown.Renderer = new DarkMenuRenderer();
|
||
(item.DropDown as ToolStripDropDownMenu)!.ShowImageMargin = false;
|
||
RemoverImageMargin(item.DropDown);
|
||
|
||
return item;
|
||
}
|
||
|
||
// ── Factories de menu e form ──────────────────────────────────────────
|
||
/// <summary>
|
||
/// Remove fisicamente a reserva de espaco da margem de icones via reflection.
|
||
/// ShowImageMargin = false esconde visualmente mas o .NET ainda reserva o espaco
|
||
/// internamente — esse metodo zera o campo privado que controla a largura real.
|
||
/// </summary>
|
||
private static void RemoverImageMargin(ToolStrip menu)
|
||
{
|
||
try
|
||
{
|
||
var field = typeof(ToolStripDropDownMenu)
|
||
.GetField("imageMarginWidth",
|
||
System.Reflection.BindingFlags.NonPublic |
|
||
System.Reflection.BindingFlags.Instance);
|
||
field?.SetValue(menu, 0);
|
||
}
|
||
catch { /* silencia */ }
|
||
}
|
||
|
||
private ContextMenuStrip CreateStyledMenu()
|
||
{
|
||
var menu = new ContextMenuStrip
|
||
{
|
||
BackColor = NavyMid,
|
||
ForeColor = TextLight,
|
||
ShowImageMargin = false,
|
||
Font = new Font("Segoe UI", 10f * _scale),
|
||
Renderer = new DarkMenuRenderer()
|
||
};
|
||
RemoverImageMargin(menu);
|
||
return menu;
|
||
}
|
||
|
||
private void showForms<T>() where T : Form, new()
|
||
{
|
||
using var form = new T();
|
||
form.StartPosition = FormStartPosition.CenterScreen;
|
||
form.ShowDialog();
|
||
}
|
||
|
||
// ── Agenda Form ───────────────────────────────────────────────────────
|
||
public class AgendaForm : Form
|
||
{
|
||
public AgendaForm()
|
||
{
|
||
Text = "Agenda de Compromissos";
|
||
Size = new Size(1150, 780);
|
||
StartPosition = FormStartPosition.CenterScreen;
|
||
BackColor = Color.White;
|
||
Controls.Add(new AgendaCadastroPanel());
|
||
}
|
||
}
|
||
|
||
// ── Paint ─────────────────────────────────────────────────────────────
|
||
protected override void OnPaint(PaintEventArgs e)
|
||
{
|
||
var g = e.Graphics;
|
||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
||
|
||
DrawLogo(g);
|
||
DrawNavItems(g, ScaledLogoH + (int)(8 * _scale));
|
||
DrawFooter(g);
|
||
}
|
||
|
||
private void DrawNavItems(Graphics g, int startY)
|
||
{
|
||
int y = startY;
|
||
using var fSection = new Font("Segoe UI", 8f * _scale, FontStyle.Bold);
|
||
using var fItem = new Font("Segoe UI", 10f * _scale);
|
||
using var fItemSel = new Font("Segoe UI Semibold", 10f * _scale);
|
||
|
||
for (int i = 0; i < _items.Count; i++)
|
||
{
|
||
var item = _items[i];
|
||
|
||
if (item.Section != null)
|
||
{
|
||
y += (int)(10 * _scale);
|
||
g.DrawString(item.Section.ToUpper(), fSection,
|
||
new SolidBrush(Color.FromArgb(120, TextMuted)),
|
||
ScaledItemPadX + (int)(8 * _scale), y);
|
||
y += ScaledSectionH;
|
||
}
|
||
|
||
bool isActive = (i == _activeIndex);
|
||
bool isHover = (i == _hoverIndex && !isActive);
|
||
var itemRect = new Rectangle(ScaledItemPadX, y, Width - ScaledItemPadX * 2, ScaledItemH);
|
||
|
||
if (isActive) FillRoundRect(g, new SolidBrush(AccentBlue), itemRect, (int)(6 * _scale));
|
||
else if (isHover) FillRoundRect(g, new SolidBrush(Color.FromArgb(20, 255, 255, 255)), itemRect, (int)(6 * _scale));
|
||
|
||
var color = isActive ? TextLight : Color.FromArgb(200, TextLight);
|
||
DrawIcon(g, item.Icon,
|
||
ScaledItemPadX + (int)(10 * _scale),
|
||
y + (ScaledItemH - ScaledIconSize) / 2,
|
||
ScaledIconSize, color);
|
||
g.DrawString(item.Label, isActive ? fItemSel : fItem,
|
||
new SolidBrush(color),
|
||
ScaledItemPadX + (int)(36 * _scale),
|
||
y + (ScaledItemH - (int)(16 * _scale)) / 2);
|
||
|
||
if (HasSubMenu(item.Label))
|
||
g.DrawString("›", fItem,
|
||
new SolidBrush(Color.FromArgb(100, TextLight)),
|
||
Width - (int)(30 * _scale),
|
||
y + (ScaledItemH - (int)(18 * _scale)) / 2);
|
||
|
||
y += ScaledItemH + (int)(2 * _scale);
|
||
}
|
||
}
|
||
|
||
private bool HasSubMenu(string label) =>
|
||
label == "Cadastro" ||
|
||
label == "Banco de Dados" ||
|
||
label == "Financeiro" ||
|
||
label == "Ordens de Serviço" ||
|
||
label == "Configurações" ||
|
||
label == "Suporte Técnico" ||
|
||
label == "Agenda";
|
||
|
||
protected override void OnMouseClick(MouseEventArgs e)
|
||
{
|
||
int hit = HitTest(e.Y);
|
||
if (hit < 0) return;
|
||
|
||
_activeIndex = hit;
|
||
Invalidate();
|
||
|
||
string label = _items[hit].Label;
|
||
Point menuPos = new Point(Width + 2, e.Y - (int)(15 * _scale));
|
||
|
||
switch (label)
|
||
{
|
||
case "Cadastro": _subMenuCadastro.Show(this, menuPos); break;
|
||
case "Banco de Dados": _subMenuBanco.Show(this, menuPos); break;
|
||
case "Financeiro": _subMenuFinanceiro.Show(this, menuPos); break;
|
||
case "Agenda": _subMenuAgenda.Show(this, menuPos); break;
|
||
case "Ordens de Serviço": _subMenuOrdemServico.Show(this, menuPos); break;
|
||
case "Configurações": _subMenuConfiguracao.Show(this, menuPos); break;
|
||
case "Suporte Técnico": _subMenuAjuda.Show(this, menuPos); break;
|
||
default: NavItemClicked?.Invoke(this, hit); break;
|
||
}
|
||
}
|
||
|
||
private int HitTest(int mouseY)
|
||
{
|
||
int y = ScaledLogoH + (int)(8 * _scale);
|
||
for (int i = 0; i < _items.Count; i++)
|
||
{
|
||
if (_items[i].Section != null) y += (int)(10 * _scale) + ScaledSectionH;
|
||
if (mouseY >= y && mouseY < y + ScaledItemH) return i;
|
||
y += ScaledItemH + (int)(2 * _scale);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
protected override void OnMouseMove(MouseEventArgs e)
|
||
{
|
||
int hit = HitTest(e.Y);
|
||
if (hit != _hoverIndex) { _hoverIndex = hit; Invalidate(); }
|
||
}
|
||
|
||
protected override void OnMouseLeave(EventArgs e) { _hoverIndex = -1; Invalidate(); }
|
||
|
||
// ── Logo e Footer ─────────────────────────────────────────────────────
|
||
private void DrawLogo(Graphics g)
|
||
{
|
||
var iconRect = new Rectangle((int)(16 * _scale), (int)(18 * _scale), (int)(34 * _scale), (int)(34 * _scale));
|
||
FillRoundRect(g, new SolidBrush(AccentBlue), iconRect, (int)(8 * _scale));
|
||
using var fIcon = new Font("Segoe UI", 14f * _scale, FontStyle.Bold);
|
||
DrawCenteredString(g, "S", fIcon, TextLight, iconRect);
|
||
g.DrawString("LevelOS", new Font("Segoe UI Semibold", 13f * _scale), new SolidBrush(TextLight), 58 * _scale, 20 * _scale);
|
||
g.DrawString("SISTEMA ERP", new Font("Segoe UI", 8f * _scale), new SolidBrush(TextMuted), 59 * _scale, 38 * _scale);
|
||
g.DrawLine(new Pen(Divider), 0, ScaledLogoH, Width, ScaledLogoH);
|
||
}
|
||
|
||
private void DrawFooter(Graphics g)
|
||
{
|
||
int fy = Height - ScaledFooterH;
|
||
g.DrawLine(new Pen(Divider), 0, fy, Width, fy);
|
||
var avRect = new Rectangle((int)(16 * _scale), fy + (int)(14 * _scale), (int)(32 * _scale), (int)(32 * _scale));
|
||
g.FillEllipse(new SolidBrush(AccentBlue), avRect);
|
||
DrawCenteredString(g, "AD", new Font("Segoe UI Semibold", 10f * _scale), TextLight, avRect);
|
||
g.DrawString(UserName, new Font("Segoe UI Semibold", 11f * _scale), new SolidBrush(TextLight), 56 * _scale, fy + (14 * _scale));
|
||
g.DrawString(UserFunction, new Font("Segoe UI", 9f * _scale), new SolidBrush(TextMuted), 57 * _scale, fy + (30 * _scale));
|
||
}
|
||
|
||
// ── Motor de Ícones (GDI+) ────────────────────────────────────────────
|
||
private void DrawIcon(Graphics g, SvgIcon icon, int x, int y, int size, Color color)
|
||
{
|
||
using var p = new Pen(color, 1.6f * _scale) { StartCap = LineCap.Round, EndCap = LineCap.Round, LineJoin = LineJoin.Round };
|
||
float s = size / 24f;
|
||
g.TranslateTransform(x, y);
|
||
g.ScaleTransform(s, s);
|
||
|
||
switch (icon)
|
||
{
|
||
case SvgIcon.Grid:
|
||
g.DrawRectangle(p, 3, 3, 7, 7); g.DrawRectangle(p, 14, 3, 7, 7);
|
||
g.DrawRectangle(p, 3, 14, 7, 7); g.DrawRectangle(p, 14, 14, 7, 7); break;
|
||
case SvgIcon.Users:
|
||
g.DrawEllipse(p, 5, 3, 8, 8); g.DrawArc(p, 2, 13, 14, 8, 180, 180);
|
||
g.DrawArc(p, 15, 8, 6, 6, 270, 180); break;
|
||
case SvgIcon.FileText:
|
||
g.DrawLines(p, new PointF[] { new(6, 2), new(6, 22), new(18, 22), new(18, 8), new(14, 2), new(6, 2) });
|
||
g.DrawLine(p, 14, 2, 14, 8); g.DrawLine(p, 14, 8, 18, 8); break;
|
||
case SvgIcon.Package:
|
||
g.DrawLines(p, new PointF[] { new(12, 2), new(2, 7), new(12, 12), new(22, 7), new(12, 2) });
|
||
g.DrawLine(p, 2, 7, 2, 17); g.DrawLine(p, 22, 7, 22, 17); g.DrawLine(p, 12, 12, 12, 22); break;
|
||
case SvgIcon.DollarSign:
|
||
g.DrawLine(p, 12, 2, 12, 22); g.DrawArc(p, 7, 5, 10, 7, 110, 250); g.DrawArc(p, 7, 12, 10, 7, 270, 250); break;
|
||
case SvgIcon.Database:
|
||
g.DrawEllipse(p, 4, 3, 16, 6); g.DrawLine(p, 4, 6, 4, 18);
|
||
g.DrawLine(p, 20, 6, 20, 18); g.DrawArc(p, 4, 15, 16, 6, 0, 180); break;
|
||
case SvgIcon.Calendar:
|
||
g.DrawRectangle(p, 3, 4, 18, 17); g.DrawLine(p, 3, 9, 21, 9);
|
||
g.DrawLine(p, 8, 2, 8, 6); g.DrawLine(p, 16, 2, 16, 6); break;
|
||
case SvgIcon.Truck:
|
||
g.DrawRectangle(p, 1, 5, 13, 11);
|
||
g.DrawLines(p, new PointF[] { new(14, 16), new(14, 8), new(19, 8), new(23, 12), new(23, 16) });
|
||
g.DrawEllipse(p, 3, 15, 4, 4); g.DrawEllipse(p, 17, 15, 4, 4); break;
|
||
case SvgIcon.Factory:
|
||
g.DrawRectangle(p, 2, 10, 20, 11);
|
||
g.DrawLines(p, new PointF[] { new(2, 10), new(2, 5), new(8, 10), new(8, 5), new(14, 10) }); break;
|
||
case SvgIcon.Briefcase:
|
||
g.DrawRectangle(p, 3, 7, 18, 13); g.DrawArc(p, 9, 3, 6, 8, 180, 180); break;
|
||
case SvgIcon.Support:
|
||
g.DrawArc(p, 4, 4, 16, 16, 180, 180);
|
||
g.DrawRectangle(p, 3, 13, 3, 5); g.DrawRectangle(p, 18, 13, 3, 5); break;
|
||
case SvgIcon.Inventory:
|
||
g.DrawRectangle(p, 3, 3, 18, 8); g.DrawRectangle(p, 3, 13, 18, 8); break;
|
||
case SvgIcon.Settings:
|
||
g.DrawEllipse(p, 9, 9, 6, 6);
|
||
for (int a = 0; a < 360; a += 45)
|
||
{
|
||
float r = a * (float)Math.PI / 180f;
|
||
g.DrawLine(p, 12 + (float)Math.Cos(r) * 8, 12 + (float)Math.Sin(r) * 8,
|
||
12 + (float)Math.Cos(r) * 11, 12 + (float)Math.Sin(r) * 11);
|
||
}
|
||
break;
|
||
case SvgIcon.User:
|
||
g.DrawEllipse(p, 8, 2, 8, 8); g.DrawArc(p, 3, 14, 18, 8, 180, 180); break;
|
||
case SvgIcon.UserCheck:
|
||
g.DrawEllipse(p, 8, 3, 8, 8); g.DrawArc(p, 3, 14, 18, 8, 180, 180);
|
||
g.DrawRectangle(p, 10, 15, 4, 3); break;
|
||
case SvgIcon.UserPlus:
|
||
g.DrawEllipse(p, 4, 4, 8, 8);
|
||
g.DrawArc(p, 1, 14, 14, 8, 180, 180);
|
||
g.DrawLine(p, 19, 7, 19, 15);
|
||
g.DrawLine(p, 15, 11, 23, 11); break;
|
||
}
|
||
|
||
g.ResetTransform();
|
||
}
|
||
|
||
// ── Helpers visuais ───────────────────────────────────────────────────
|
||
private static void FillRoundRect(Graphics g, Brush b, Rectangle r, int rad)
|
||
{
|
||
using var path = RoundRectPath(r, rad);
|
||
g.FillPath(b, path);
|
||
}
|
||
|
||
private static GraphicsPath RoundRectPath(Rectangle r, int rad)
|
||
{
|
||
var path = new GraphicsPath();
|
||
int d = Math.Max(rad * 2, 1);
|
||
path.AddArc(r.X, r.Y, d, d, 180, 90);
|
||
path.AddArc(r.Right - d, r.Y, d, d, 270, 90);
|
||
path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90);
|
||
path.AddArc(r.X, r.Bottom - d, d, d, 90, 90);
|
||
path.CloseFigure();
|
||
return path;
|
||
}
|
||
|
||
private static void DrawCenteredString(Graphics g, string t, Font f, Color c, Rectangle r)
|
||
{
|
||
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||
g.DrawString(t, f, new SolidBrush(c), r, sf);
|
||
}
|
||
|
||
// ── Classes internas ──────────────────────────────────────────────────
|
||
private class NavItem
|
||
{
|
||
public string Label { get; }
|
||
public SvgIcon Icon { get; }
|
||
public string? Section { get; }
|
||
public string? Badge { get; }
|
||
public NavItem(string l, SvgIcon i, string? s, string? b) { Label = l; Icon = i; Section = s; Badge = b; }
|
||
}
|
||
|
||
private class SubMenuColorTable : ProfessionalColorTable
|
||
{
|
||
public override Color ToolStripDropDownBackground => NavyMid;
|
||
public override Color MenuItemSelected => AccentBlue;
|
||
public override Color MenuItemBorder => Color.Transparent;
|
||
public override Color MenuItemSelectedGradientBegin => AccentBlue;
|
||
public override Color MenuItemSelectedGradientEnd => AccentBlue;
|
||
public override Color ImageMarginGradientBegin => NavyMid;
|
||
public override Color ImageMarginGradientMiddle => NavyMid;
|
||
public override Color ImageMarginGradientEnd => NavyMid;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Renderer que elimina a faixa branca da margem de ícones
|
||
/// sobrescrevendo o desenho do ImageMargin para pintar com NavyMid.
|
||
/// </summary>
|
||
private class DarkMenuRenderer : ToolStripProfessionalRenderer
|
||
{
|
||
public DarkMenuRenderer() : base(new SubMenuColorTable()) { }
|
||
|
||
protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
|
||
{
|
||
using var brush = new SolidBrush(NavyMid);
|
||
e.Graphics.FillRectangle(brush, e.AffectedBounds);
|
||
}
|
||
|
||
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
||
{
|
||
if (!e.Item.Selected)
|
||
{
|
||
using var brush = new SolidBrush(NavyMid);
|
||
e.Graphics.FillRectangle(brush, new Rectangle(Point.Empty, e.Item.Size));
|
||
}
|
||
else
|
||
{
|
||
using var brush = new SolidBrush(AccentBlue);
|
||
e.Graphics.FillRectangle(brush, new Rectangle(Point.Empty, e.Item.Size));
|
||
}
|
||
}
|
||
|
||
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
|
||
{
|
||
using var brush = new SolidBrush(NavyMid);
|
||
e.Graphics.FillRectangle(brush, e.AffectedBounds);
|
||
}
|
||
}
|
||
}
|
||
|
||
public enum SvgIcon
|
||
{
|
||
Grid, Users, FileText, Package, DollarSign, User, Settings,
|
||
Database, Truck, Factory, UserCheck, Briefcase, Support,
|
||
Inventory, Wallet, ShoppingCart, ShoppingBag, Calendar, UserPlus
|
||
}
|
||
}
|