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? NavItemClicked; private readonly List _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
())); _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))); // Adicionando ao sub-menu de configurações _subMenuConfiguracao.Items.Add(CreateItem(">_ SSH-Cliente", (s, e) => NavItemClicked?.Invoke(this, 206))); _subMenuConfiguracao.Items.Add(new ToolStripSeparator()); _subMenuConfiguracao.Items.Add(CreateItem("⏰ Backups Automáticos", (s, e) => NavItemClicked?.Invoke(this, 207))); _subMenuConfiguracao.Items.Add(CreateItem("☁️ Backup em Nuvem", (s, e) => NavItemClicked?.Invoke(this, 208))); // ── 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",(s, e) => NavItemClicked?.Invoke(this, 299))); _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", (s, e) => NavItemClicked?.Invoke(this, 304))); _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 ─────────────────────────────────────── /// Cria um ToolStripMenuItem simples com estilo aplicado. 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; } /// /// Cria um ToolStripMenuItem pai (com submenu aninhado). /// O estilo é aplicado aqui e também propagado para os filhos /// via evento DropDownOpening. /// 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 ────────────────────────────────────────── /// /// 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. /// 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() 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; } /// /// Renderer que elimina a faixa branca da margem de ícones /// sobrescrevendo o desenho do ImageMargin para pintar com NavyMid. /// 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 } }