UltimateZoneBuilder/Source/Core/Controls/VisualStudioTabControl.cs

337 lines
12 KiB
C#
Raw Normal View History

#region ======================== Namespaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
#endregion
// Based on http://www.codeproject.com/Articles/1106140/VisualStudio-Like-TabControl
namespace CodeImp.DoomBuilder.Controls
{
public class VSTabControl : TabControl
{
#region ======================== Events
public event EventHandler<TabControlEventArgs> OnCloseTabClicked;
#endregion
#region ======================== Properties
public bool ShowClosingButton { get; set; }
[Category("Colors"), Browsable(true), Description("The color of the selected page")]
public Color ActiveColor { get { return activeColor; } set { activeColor = value; } }
[Category("Colors"), Browsable(true), Description("The color of the highlighted page")]
public Color HighlightColor { get { return highlightColor; } set { highlightColor = value; } }
[Category("Colors"), Browsable(true), Description("The color of the background of the tab")]
public Color BackTabColor { get { return backTabColor; } set { backTabColor = value; } }
[Category("Colors"), Browsable(true), Description("The color of the border of the control")]
public Color BorderColor { get { return borderColor; } set { borderColor = value; } }
[Category("Colors"), Browsable(true), Description("The color of the title of the page")]
public Color TextColor { get { return textColor; } set { textColor = value; } }
[Category("Colors"), Browsable(true), Description("The color of the title of the page")]
public Color SelectedTextColor { get { return selectedTextColor; } set { selectedTextColor = value; } }
#endregion
#region ======================== Variables
private readonly StringFormat centersringformat = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center };
private TabPage predraggedTab;
private Color textColor = SystemColors.WindowText;
private Color selectedTextColor = SystemColors.HighlightText;
private Color activeColor = SystemColors.HotTrack;
private Color highlightColor = SystemColors.Highlight;
private Color backTabColor = SystemColors.Control;
private Color borderColor = SystemColors.Control;
private int closebuttonmouseoverindex = -1; //mxd
#endregion
#region ======================== Constructor
public VSTabControl()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw
| ControlStyles.OptimizedDoubleBuffer,
true);
DoubleBuffered = true;
SizeMode = TabSizeMode.Normal;
ItemSize = new Size(240, 16);
AllowDrop = true;
}
#endregion
#region ======================== Event overrides
protected override void CreateHandle()
{
base.CreateHandle();
Alignment = TabAlignment.Top;
}
protected override void OnDragOver(DragEventArgs drgevent)
{
//mxd. Collect used tab page types...
var tabpagetypes = new HashSet<Type>();
foreach(var page in TabPages) tabpagetypes.Add(page.GetType());
//mxd. Identify dragged tab type...
TabPage draggedTab = null;
foreach(var T in tabpagetypes)
{
draggedTab = (TabPage)drgevent.Data.GetData(T);
if(draggedTab != null) break;
}
var pointedTab = GetPointedTab();
if(ReferenceEquals(draggedTab, predraggedTab) && pointedTab != null)
{
drgevent.Effect = DragDropEffects.Move;
if(!ReferenceEquals(pointedTab, draggedTab)) ReplaceTabPages(draggedTab, pointedTab);
}
base.OnDragOver(drgevent);
}
protected override void OnMouseDown(MouseEventArgs e)
{
predraggedTab = GetPointedTab();
//mxd. MEMO: OnMouseUp is not fired when clicking on inactive tab...
if(ShowClosingButton)
{
for(var i = 0; i < TabCount; i++)
{
Rectangle r = GetCloseButtonRect(GetTabRect(i));
if(r.Contains(e.Location))
{
// Raise event...
if(OnCloseTabClicked != null)
{
TabControlEventArgs te = new TabControlEventArgs(TabPages[i], i, TabControlAction.Selected);
OnCloseTabClicked(this, te);
closebuttonmouseoverindex = -1;
}
break;
}
}
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if(e.Button == MouseButtons.Left && predraggedTab != null)
{
DoDragDrop(predraggedTab, DragDropEffects.Move);
}
//mxd. Closing button highlight needs updating?
else if(ShowClosingButton)
{
int index = GetPointedTabIndex();
if(index != -1)
{
Rectangle cr = GetCloseButtonRect(GetTabRect(index));
bool inside = cr.Contains(PointToClient(Cursor.Position));
if(inside && closebuttonmouseoverindex == -1)
{
closebuttonmouseoverindex = index;
Refresh();
}
else if(!inside && closebuttonmouseoverindex != -1)
{
closebuttonmouseoverindex = -1;
Refresh();
}
}
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
predraggedTab = null;
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.Clear(backTabColor);
//mxd
int highlightedtabindex = GetPointedTabIndex();
for(var i = 0; i < TabCount; i++)
{
var tabrect = GetTabRect(i); //mxd
var Header = new Rectangle(
new Point(tabrect.Location.X + 2, tabrect.Location.Y),
new Size(tabrect.Width, tabrect.Height));
var HeaderSize = new Rectangle(Header.Location, new Size(Header.Width, Header.Height));
var TextSize = new Rectangle(HeaderSize.Location.X, HeaderSize.Location.Y, HeaderSize.Width, HeaderSize.Height - 2);
//mxd
if(TabPages[i].ImageIndex != -1)
{
int offset = ImageList.Images[TabPages[i].ImageIndex].Width + 2;
HeaderSize.X += offset;
HeaderSize.Width -= offset;
TextSize.X += offset + 2;
TextSize.Width -= offset + 2;
}
if(i == SelectedIndex || i == highlightedtabindex)
{
// Draws the back of the color when it is selected
var tabbgrect = new Rectangle(tabrect.X, tabrect.Y - 2, tabrect.Width, tabrect.Height + 2);
using(var bgbrush = new SolidBrush(i == SelectedIndex ? activeColor : highlightColor))
g.FillRectangle(bgbrush, tabbgrect);
// Draws the title of the page
using(var textbrush = new SolidBrush(selectedTextColor))
{
g.DrawString(TabPages[i].Text, Font, textbrush, TextSize, centersringformat);
// Draws the closing button
if(ShowClosingButton)
{
//mxd. Draw bg rect?
var bgrect = GetCloseButtonRect(tabrect);
if(closebuttonmouseoverindex == i)
{
using(var bgbrush = new SolidBrush(Color.FromArgb(96, selectedTextColor)))
g.FillRectangle(bgbrush, bgrect);
}
//mxd. Draw X
using(var closepen = new Pen(selectedTextColor, 1f))
{
const int offset = 4;
int tlx = bgrect.X + offset;
int tly = bgrect.Y + offset;
int brx = bgrect.X + bgrect.Width - offset;
int bry = bgrect.Y + bgrect.Height - offset;
g.DrawLine(closepen, tlx, tly, brx, bry);
g.DrawLine(closepen, tlx, bry, brx, tly);
}
}
}
}
else
{
// Simply draw the header when it is not selected
using(var textbrush = new SolidBrush(textColor))
{
g.DrawString(TabPages[i].Text, Font, textbrush, TextSize, centersringformat);
}
}
//mxd. Draw icon?
if(TabPages[i].ImageIndex != -1)
{
g.DrawImage(ImageList.Images[TabPages[i].ImageIndex], Header.X + 2, 3);
}
}
// Draw the background of the tab control
using(var backtabbrush = new SolidBrush(backTabColor))
g.FillRectangle(backtabbrush, new Rectangle(0, ItemSize.Height, Width, Height - ItemSize.Height));
// Draw the border of the TabControl
using(var borderpen = new Pen(borderColor, 2))
g.DrawRectangle(borderpen, new Rectangle(0, ItemSize.Height, Width, Height - ItemSize.Height));
// Draw the horizontal line
using(var linepen = new Pen(activeColor, 2))
g.DrawLine(linepen, new Point(0, ItemSize.Height - 1), new Point(Width, ItemSize.Height - 1));
}
#endregion
#region ======================== Methods
//mxd
private static Rectangle GetCloseButtonRect(Rectangle tabrect)
{
int height = tabrect.Height - 6;
return new Rectangle(tabrect.Right - height - 3, 3, height, height);
}
private TabPage GetPointedTab()
{
for(var i = 0; i < TabPages.Count; i++)
{
if(GetTabRect(i).Contains(PointToClient(Cursor.Position)))
{
return TabPages[i];
}
}
return null;
}
//mxd
private int GetPointedTabIndex()
{
for(var i = 0; i < TabPages.Count; i++)
{
if(GetTabRect(i).Contains(PointToClient(Cursor.Position)))
{
return i;
}
}
return -1;
}
private void ReplaceTabPages(TabPage Source, TabPage Destination)
{
var SourceIndex = TabPages.IndexOf(Source);
var DestinationIndex = TabPages.IndexOf(Destination);
TabPages[DestinationIndex] = Source;
TabPages[SourceIndex] = Destination;
if(SelectedIndex == SourceIndex)
{
SelectedIndex = DestinationIndex;
}
else if(SelectedIndex == DestinationIndex)
{
SelectedIndex = SourceIndex;
}
Refresh();
}
#endregion
}
}