Files

370 lines
14 KiB
C#
Raw Permalink Normal View History

2026-08-27 10:57:58 -06:00
using Pulsar.Server.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
// thanks to Mavamaarten~ for coding this
namespace Pulsar.Server.Controls
{
public class TabPageEventArgs : EventArgs
{
public TabPage TabPage { get; }
public TabPageEventArgs(TabPage tabPage)
{
TabPage = tabPage;
}
}
internal class DotNetBarTabControl : TabControl
{
private bool _darkMode = Settings.DarkMode;
private Dictionary<int, Rectangle> _closeButtonRects = new Dictionary<int, Rectangle>();
private bool _showCloseButtons = true;
public event EventHandler<TabPageEventArgs> TabClosed;
/// <summary>
/// Gets or sets whether close buttons are shown on tabs.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool ShowCloseButtons
{
get { return _showCloseButtons; }
set
{
if (_showCloseButtons != value)
{
_showCloseButtons = value;
Invalidate();
}
}
}
public DotNetBarTabControl()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true);
SizeMode = TabSizeMode.Fixed;
SelectedIndex = 0;
ShowCloseButtons = false;
MouseClick += DotNetBarTabControl_MouseClick;
}
private void DotNetBarTabControl_MouseClick(object sender, MouseEventArgs e)
{
if (!_showCloseButtons)
return;
foreach (var kvp in _closeButtonRects)
{
if (kvp.Value.Contains(e.Location))
{
int tabIndex = kvp.Key;
if (tabIndex >= 0 && tabIndex < TabCount)
{
TabPage tabPage = TabPages[tabIndex];
TabPages.Remove(tabPage);
TabClosed?.Invoke(this, new TabPageEventArgs(tabPage));
Invalidate();
}
break;
}
}
}
private void DrawTabText(Graphics g, Rectangle rect, string text, Font baseFont, Brush textBrush, bool isSelected)
{
int maxTextWidth = rect.Width - 20;
if (_showCloseButtons)
maxTextWidth -= 20;
SizeF textSize = g.MeasureString(text, baseFont);
Font fontToUse = baseFont;
float scaleFactor = 1.0f;
if (textSize.Width > maxTextWidth)
{
scaleFactor = maxTextWidth / textSize.Width;
float newSize = Math.Max(baseFont.Size * scaleFactor, 7.0f);
fontToUse = new Font(baseFont.FontFamily, newSize, isSelected ? FontStyle.Bold : FontStyle.Regular);
}
else if (isSelected && baseFont.Style != FontStyle.Bold)
{
fontToUse = new Font(baseFont.FontFamily, baseFont.Size, FontStyle.Bold);
}
g.DrawString(text, fontToUse, textBrush, rect, new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisCharacter
});
if (fontToUse != baseFont)
{
fontToUse.Dispose();
}
}
private void DrawCloseButton(Graphics g, Rectangle tabRect, int tabIndex, bool isSelected)
{
if (!_showCloseButtons)
return;
int buttonSize = 16;
int buttonX = tabRect.Right - buttonSize - 5;
int buttonY = tabRect.Top + (tabRect.Height - buttonSize) / 2;
Rectangle closeRect = new Rectangle(buttonX, buttonY, buttonSize, buttonSize);
_closeButtonRects[tabIndex] = closeRect;
Color bgColor = _darkMode
? (isSelected ? Color.FromArgb(90, 90, 90) : Color.FromArgb(60, 60, 60))
: (isSelected ? Color.FromArgb(240, 240, 250) : Color.FromArgb(220, 220, 240));
using (SolidBrush bgBrush = new SolidBrush(bgColor))
{
g.FillEllipse(bgBrush, closeRect);
}
Color xColor = _darkMode
? Color.FromArgb(200, 200, 200)
: Color.FromArgb(100, 100, 100);
using (Pen xPen = new Pen(xColor, 1.5f))
{
g.DrawLine(xPen,
closeRect.Left + 4, closeRect.Top + 4,
closeRect.Right - 4, closeRect.Bottom - 4);
g.DrawLine(xPen,
closeRect.Left + 4, closeRect.Bottom - 4,
closeRect.Right - 4, closeRect.Top + 4);
}
}
protected override void OnPaint(PaintEventArgs e)
{
_closeButtonRects.Clear();
Bitmap b = new Bitmap(Width, Height);
Graphics g = Graphics.FromImage(b);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
if (_darkMode)
{
DrawDarkMode(g);
}
else
{
DrawLightMode(g);
}
e.Graphics.DrawImage(b, new Point(0, 0));
g.Dispose();
b.Dispose();
}
private void DrawDarkMode(Graphics g)
{
if (!DesignMode && TabCount > 0 && SelectedIndex >= 0)
SelectedTab.BackColor = Color.FromArgb(43, 43, 43);
g.Clear(Color.FromArgb(43, 43, 43));
g.FillRectangle(new SolidBrush(Color.FromArgb(43, 43, 43)),
new Rectangle(0, 0, ItemSize.Height + 4, Height));
g.DrawLine(new Pen(Color.FromArgb(80, 80, 80)), new Point(ItemSize.Height + 3, 0),
new Point(ItemSize.Height + 3, 999));
g.DrawLine(new Pen(Color.FromArgb(80, 80, 80)), new Point(0, Size.Height - 1),
new Point(Width + 3, Size.Height - 1));
for (int i = 0; i <= TabCount - 1; i++)
{
if (i == SelectedIndex)
{
Rectangle x2 = new Rectangle(new Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2),
new Size(GetTabRect(i).Width + 3, GetTabRect(i).Height - 1));
g.FillRectangle(new SolidBrush(Color.FromArgb(70, 70, 70)), x2);
g.DrawRectangle(new Pen(Color.FromArgb(43, 43, 43)), x2);
g.SmoothingMode = SmoothingMode.HighQuality;
if (ImageList != null)
{
try
{
g.DrawImage(ImageList.Images[TabPages[i].ImageIndex],
new Point(x2.Location.X + 8, x2.Location.Y + 6));
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.White, true);
}
catch (Exception)
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.White, true);
}
}
else
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.White, true);
}
DrawCloseButton(g, x2, i, true);
}
else
{
Rectangle x2 = new Rectangle(new Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2),
new Size(GetTabRect(i).Width + 3, GetTabRect(i).Height - 1));
g.FillRectangle(new SolidBrush(Color.FromArgb(43, 43, 43)), x2);
g.DrawLine(new Pen(Color.FromArgb(80, 80, 80)), new Point(x2.Right, x2.Top),
new Point(x2.Right, x2.Bottom));
if (ImageList != null)
{
try
{
g.DrawImage(ImageList.Images[TabPages[i].ImageIndex],
new Point(x2.Location.X + 8, x2.Location.Y + 6));
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.LightGray, false);
}
catch (Exception)
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.LightGray, false);
}
}
else
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.LightGray, false);
}
DrawCloseButton(g, x2, i, false);
}
}
}
private void DrawLightMode(Graphics g)
{
if (!DesignMode && TabCount > 0 && SelectedIndex >= 0)
SelectedTab.BackColor = SystemColors.Control;
g.Clear(SystemColors.Control);
g.FillRectangle(new SolidBrush(Color.FromArgb(246, 248, 252)),
new Rectangle(0, 0, ItemSize.Height + 4, Height));
g.DrawLine(new Pen(Color.FromArgb(170, 187, 204)), new Point(ItemSize.Height + 3, 0),
new Point(ItemSize.Height + 3, 999));
g.DrawLine(new Pen(Color.FromArgb(170, 187, 204)), new Point(0, Size.Height - 1),
new Point(Width + 3, Size.Height - 1));
for (int i = 0; i <= TabCount - 1; i++)
{
if (i == SelectedIndex)
{
Rectangle x2 = new Rectangle(new Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2),
new Size(GetTabRect(i).Width + 3, GetTabRect(i).Height - 1));
ColorBlend myBlend = new ColorBlend();
myBlend.Colors = new Color[] { Color.FromArgb(232, 232, 240), Color.FromArgb(232, 232, 240), Color.FromArgb(232, 232, 240) };
myBlend.Positions = new float[] { 0f, 0.5f, 1f };
LinearGradientBrush lgBrush = new LinearGradientBrush(x2, Color.Black, Color.Black, 90f);
lgBrush.InterpolationColors = myBlend;
g.FillRectangle(lgBrush, x2);
g.DrawRectangle(new Pen(Color.FromArgb(170, 187, 204)), x2);
g.SmoothingMode = SmoothingMode.HighQuality;
Point[] p =
{
new Point(ItemSize.Height - 3, GetTabRect(i).Location.Y + 20),
new Point(ItemSize.Height + 4, GetTabRect(i).Location.Y + 14),
new Point(ItemSize.Height + 4, GetTabRect(i).Location.Y + 27)
};
g.FillPolygon(SystemBrushes.Control, p);
g.DrawPolygon(new Pen(Color.FromArgb(170, 187, 204)), p);
if (ImageList != null)
{
try
{
g.DrawImage(ImageList.Images[TabPages[i].ImageIndex],
new Point(x2.Location.X + 8, x2.Location.Y + 6));
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.Black, true);
}
catch (Exception)
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.Black, true);
}
}
else
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.Black, true);
}
g.DrawLine(new Pen(Color.FromArgb(200, 200, 250)), new Point(x2.Location.X - 1, x2.Location.Y - 1),
new Point(x2.Location.X, x2.Location.Y));
g.DrawLine(new Pen(Color.FromArgb(200, 200, 250)), new Point(x2.Location.X - 1, x2.Bottom - 1),
new Point(x2.Location.X, x2.Bottom));
DrawCloseButton(g, x2, i, true);
}
else
{
Rectangle x2 = new Rectangle(new Point(GetTabRect(i).Location.X - 2, GetTabRect(i).Location.Y - 2),
new Size(GetTabRect(i).Width + 3, GetTabRect(i).Height - 1));
g.FillRectangle(new SolidBrush(Color.FromArgb(246, 248, 252)), x2);
g.DrawLine(new Pen(Color.FromArgb(170, 187, 204)), new Point(x2.Right, x2.Top),
new Point(x2.Right, x2.Bottom));
if (ImageList != null)
{
try
{
g.DrawImage(ImageList.Images[TabPages[i].ImageIndex],
new Point(x2.Location.X + 8, x2.Location.Y + 6));
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.DimGray, false);
}
catch (Exception)
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.DimGray, false);
}
}
else
{
DrawTabText(g, x2, TabPages[i].Text, Font, Brushes.DimGray, false);
}
DrawCloseButton(g, x2, i, false);
}
}
}
}
}