520 lines
20 KiB
C#
520 lines
20 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Text;
|
|
using System.Windows.Forms;
|
|
|
|
namespace DevComponents.DotNetBar
|
|
{
|
|
/// <summary>
|
|
/// Represents base class for tab display.
|
|
/// </summary>
|
|
internal class TabStripBaseDisplay
|
|
{
|
|
#region Private Variables
|
|
private bool m_AntiAlias=true;
|
|
private bool m_HorizontalText=false;
|
|
private bool m_CloseButtonOnTabs = false;
|
|
private Size m_TabCloseButtonSize = new Size(11, 11);
|
|
private int m_TabCloseButtonSpacing = 3;
|
|
#endregion
|
|
|
|
public TabStripBaseDisplay()
|
|
{
|
|
}
|
|
|
|
#region Methods
|
|
/// <summary>
|
|
/// Main method for painting.
|
|
/// </summary>
|
|
/// <param name="g">Reference to graphics object</param>
|
|
/// <param name="tabStrip">TabStrip to paint</param>
|
|
public virtual void Paint(Graphics g, TabStrip tabStrip)
|
|
{
|
|
if(this.AntiAlias)
|
|
{
|
|
g.SmoothingMode=SmoothingMode.AntiAlias;
|
|
g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
|
|
}
|
|
}
|
|
|
|
protected virtual void PaintTab(Graphics g, TabItem tab, bool first, bool last)
|
|
{
|
|
if(!tab.Visible)
|
|
return;
|
|
|
|
if (tab.Parent!=null && tab.Parent.HasPreRenderTabItem)
|
|
{
|
|
RenderTabItemEventArgs re = new RenderTabItemEventArgs(tab, g);
|
|
tab.Parent.InvokePreRenderTabItem(re);
|
|
if (re.Cancel) return;
|
|
}
|
|
|
|
using (GraphicsPath path = GetTabItemPath(tab, first, last))
|
|
{
|
|
TabColors colors = tab.Parent.GetTabColors(tab);
|
|
|
|
DrawTabItemBackground(tab, path, colors, g);
|
|
|
|
DrawTabText(tab, colors, g);
|
|
}
|
|
|
|
if (tab.Parent != null && tab.Parent.HasPostRenderTabItem)
|
|
{
|
|
RenderTabItemEventArgs re = new RenderTabItemEventArgs(tab, g);
|
|
tab.Parent.InvokePostRenderTabItem(re);
|
|
}
|
|
}
|
|
|
|
protected virtual Region GetTabsRegion(TabsCollection tabs, TabItem lastTab)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual void DrawTabItemBackground(TabItem tab, GraphicsPath path, TabColors colors, Graphics g)
|
|
{
|
|
RectangleF rf=path.GetBounds();
|
|
Rectangle tabRect=new Rectangle((int)rf.X, (int)rf.Y, (int)rf.Width, (int)rf.Height);
|
|
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.Default;
|
|
|
|
eBackgroundColorBlendType blendType = colors.BackgroundColorBlend.GetBlendType();
|
|
int ga = colors.BackColorGradientAngle;
|
|
if (tab.TabAlignment == eTabStripAlignment.Left || tab.TabAlignment == eTabStripAlignment.Right)
|
|
ga -= 90;
|
|
|
|
if (blendType != eBackgroundColorBlendType.Invalid)
|
|
{
|
|
if (blendType == eBackgroundColorBlendType.Relative)
|
|
{
|
|
if (!colors.BackColor.IsEmpty || !colors.BackColor2.IsEmpty)
|
|
{
|
|
try
|
|
{
|
|
Rectangle rb = Rectangle.Ceiling(rf);
|
|
rb.Inflate(1, 1);
|
|
using (LinearGradientBrush brush = DisplayHelp.CreateLinearGradientBrush(rb, colors.BackColor, colors.BackColor2, ga))
|
|
{
|
|
brush.InterpolationColors = colors.BackgroundColorBlend.GetColorBlend();
|
|
g.FillPath(brush, path);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
blendType = eBackgroundColorBlendType.Invalid;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Rectangle bounds = Rectangle.Ceiling(rf);
|
|
BackgroundColorBlendCollection bc = colors.BackgroundColorBlend;
|
|
Region oldClip = g.Clip;
|
|
g.SetClip(path, CombineMode.Intersect);
|
|
for (int i = 0; i < bc.Count; i += 2)
|
|
{
|
|
BackgroundColorBlend b1 = bc[i];
|
|
BackgroundColorBlend b2 = null;
|
|
if (i < bc.Count)
|
|
b2 = bc[i + 1];
|
|
if (b1 != null && b2 != null)
|
|
{
|
|
Rectangle rb = new Rectangle(bounds.X, bounds.Y + (int)b1.Position, bounds.Width,
|
|
(b2.Position == 1f ? bounds.Height : (int)b2.Position) - (int)b1.Position);
|
|
using (LinearGradientBrush brush = DisplayHelp.CreateLinearGradientBrush(rb, b1.Color, b2.Color, ga))
|
|
g.FillRectangle(brush, rb);
|
|
}
|
|
}
|
|
g.Clip = oldClip;
|
|
}
|
|
}
|
|
|
|
if (blendType == eBackgroundColorBlendType.Invalid)
|
|
{
|
|
if (colors.BackColor2.IsEmpty)
|
|
{
|
|
if (!colors.BackColor.IsEmpty)
|
|
{
|
|
using (SolidBrush brush = new SolidBrush(colors.BackColor))
|
|
g.FillPath(brush, path);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (SolidBrush brush = new SolidBrush(Color.White))
|
|
g.FillPath(brush, path);
|
|
using (LinearGradientBrush brush = CreateTabGradientBrush(tabRect, colors.BackColor, colors.BackColor2, ga))
|
|
g.FillPath(brush, path);
|
|
}
|
|
}
|
|
|
|
g.SmoothingMode = sm;
|
|
|
|
DrawTabBorder(tab, path, colors, g);
|
|
}
|
|
|
|
protected virtual void DrawTabBorder(TabItem tab, GraphicsPath path, TabColors colors, Graphics g)
|
|
{
|
|
if (!colors.BorderColor.IsEmpty)
|
|
{
|
|
using (Pen pen = new Pen(colors.BorderColor, 1))
|
|
g.DrawPath(pen, path);
|
|
}
|
|
}
|
|
|
|
protected virtual LinearGradientBrush CreateTabGradientBrush(Rectangle r,Color color1,Color color2,int gradientAngle)
|
|
{
|
|
if(r.Width<=0)
|
|
r.Width=1;
|
|
if(r.Height<=0)
|
|
r.Height=1;
|
|
LinearGradientBrush brush=new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(r.X,r.Y-1,r.Width,r.Height+1),color1,color2,gradientAngle);
|
|
return brush;
|
|
}
|
|
|
|
private Rectangle DrawCloseButton(Graphics g, bool vertical, bool mouseOver, bool isSelected, ref Rectangle tabRect, TabStrip tabStrip)
|
|
{
|
|
return DrawCloseButton(g, vertical, mouseOver, isSelected, ref tabRect, tabStrip, true);
|
|
}
|
|
private Rectangle DrawCloseButton(Graphics g, bool vertical, bool mouseOver, bool isSelected, ref Rectangle tabRect, TabStrip tabStrip, bool performPaint)
|
|
{
|
|
Size closeSize = Dpi.Size(m_TabCloseButtonSize);
|
|
int spacing = m_TabCloseButtonSpacing;
|
|
bool closeOnLeftSide = (tabStrip.CloseButtonPosition == eTabCloseButtonPosition.Left);
|
|
|
|
Rectangle close = Rectangle.Empty; //new Rectangle(tabRect.X + spacing, tabRect.Y + (tabRect.Height - closeSize.Height) / 2, closeSize.Width, closeSize.Height);
|
|
|
|
if (closeOnLeftSide)
|
|
{
|
|
if (vertical)
|
|
close = new Rectangle(tabRect.X + (tabRect.Width - closeSize.Width) / 2, tabRect.Y + spacing, closeSize.Width, closeSize.Height);
|
|
else
|
|
close = new Rectangle(tabRect.X + spacing, tabRect.Y + (tabRect.Height - closeSize.Height) / 2, closeSize.Width, closeSize.Height);
|
|
}
|
|
else
|
|
{
|
|
if (vertical)
|
|
close = new Rectangle(tabRect.X + (tabRect.Width - closeSize.Width) / 2, tabRect.Bottom - spacing - closeSize.Height, closeSize.Width, closeSize.Height);
|
|
else
|
|
close = new Rectangle(tabRect.Right - spacing - closeSize.Width, tabRect.Y + (tabRect.Height - closeSize.Height) / 2, closeSize.Width, closeSize.Height);
|
|
}
|
|
AdjustCloseButtonRectangle(ref close, closeOnLeftSide, vertical);
|
|
if (performPaint)
|
|
TabStripBaseDisplay.PaintTabItemCloseButton(g, close, mouseOver, isSelected, tabStrip);
|
|
if (vertical)
|
|
{
|
|
if (closeOnLeftSide)
|
|
tabRect.Y += close.Height + spacing * 2;
|
|
tabRect.Height -= close.Height + spacing * 2;
|
|
}
|
|
else
|
|
{
|
|
if (closeOnLeftSide)
|
|
tabRect.X += close.Width + spacing * 2;
|
|
tabRect.Width -= close.Width + spacing * 2;
|
|
}
|
|
|
|
return close;
|
|
}
|
|
|
|
protected virtual void AdjustCloseButtonRectangle(ref Rectangle close, bool closeOnLeftSide, bool vertical) { }
|
|
|
|
protected virtual void DrawTabText(TabItem tab, TabColors colors, Graphics g)
|
|
{
|
|
int MIN_TEXT_WIDTH = 4;
|
|
eTextFormat strFormat = eTextFormat.Default | eTextFormat.SingleLine | eTextFormat.EndEllipsis | eTextFormat.HorizontalCenter | eTextFormat.VerticalCenter;
|
|
eTabStripAlignment align = tab.Parent.TabAlignment;
|
|
Rectangle rText = tab.DisplayRectangle;
|
|
bool isVertical = ((align == eTabStripAlignment.Left || align == eTabStripAlignment.Right) && !m_HorizontalText);
|
|
|
|
if (m_CloseButtonOnTabs && tab.CloseButtonVisible)
|
|
{
|
|
if (isVertical)
|
|
{
|
|
rText.Y++;
|
|
rText.Height--;
|
|
}
|
|
else
|
|
{
|
|
rText.X += 2;
|
|
rText.Width -= 2;
|
|
}
|
|
bool renderCloseButton = tab.IsSelected || tab.IsMouseOver || tab.Parent.CloseButtonOnTabsAlwaysDisplayed;
|
|
tab.CloseButtonBounds = DrawCloseButton(g, isVertical, tab.CloseButtonMouseOver, tab.IsSelected, ref rText, tab.Parent, renderCloseButton);
|
|
}
|
|
|
|
// Draw image
|
|
CompositeImage image = GetTabImage(tab);
|
|
if (image != null && image.Width + 4 <= rText.Width)
|
|
{
|
|
if (align == eTabStripAlignment.Top || align == eTabStripAlignment.Bottom || m_HorizontalText)
|
|
{
|
|
image.DrawImage(g, new Rectangle(rText.X + 3, rText.Y + (rText.Height - image.Height) / 2, image.Width, image.Height));
|
|
int offset = image.Width + 2;
|
|
rText.X += offset;
|
|
rText.Width -= offset;
|
|
}
|
|
else
|
|
{
|
|
image.DrawImage(g, new Rectangle(rText.X + (rText.Width - image.Width) / 2, rText.Y + 3, image.Width, image.Height));
|
|
int offset = image.Height + 2;
|
|
rText.Y += offset;
|
|
rText.Height -= offset;
|
|
}
|
|
}
|
|
if (image != null) image.Dispose();
|
|
|
|
// Draw text
|
|
bool isSelected = tab == tab.Parent.SelectedTab;
|
|
if (!tab.Parent.DisplaySelectedTextOnly || isSelected)
|
|
{
|
|
if (!tab.Parent.AntiAlias)
|
|
g.TextRenderingHint = TextRenderingHint.SystemDefault;
|
|
|
|
Font font = tab.Parent.Font;
|
|
if (isSelected && tab.Parent.SelectedTabFont != null)
|
|
font = tab.Parent.SelectedTabFont;
|
|
AdjustTextRectangle(ref rText, align);
|
|
if (isVertical)
|
|
{
|
|
g.RotateTransform(90);
|
|
rText = new Rectangle(rText.Top, -rText.Right, rText.Height, rText.Width);
|
|
}
|
|
|
|
if (rText.Width > MIN_TEXT_WIDTH)
|
|
{
|
|
if ((align == eTabStripAlignment.Left || align == eTabStripAlignment.Right) && !m_HorizontalText)
|
|
TextDrawing.DrawStringLegacy(g, tab.Text, font, colors.TextColor, rText, strFormat);
|
|
else
|
|
TextDrawing.DrawString(g, tab.Text, font, colors.TextColor, rText, strFormat);
|
|
}
|
|
//using (Pen pen = new Pen(Color.Red))
|
|
// g.DrawRectangle(pen, rText);
|
|
if (isVertical)
|
|
g.ResetTransform();
|
|
if (!tab.Parent.AntiAlias)
|
|
g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
|
|
|
|
if (tab.Parent.ShowFocusRectangle && tab.Parent.Focused && isSelected)
|
|
ControlPaint.DrawFocusRectangle(g, GetFocusRectangle(tab.DisplayRectangle));
|
|
}
|
|
}
|
|
|
|
protected virtual void AdjustTextRectangle(ref Rectangle rText, eTabStripAlignment tabAlignment) {}
|
|
|
|
protected virtual CompositeImage GetTabImage(TabItem tab)
|
|
{
|
|
Image image=tab.GetImage();
|
|
if(image!=null)
|
|
return new CompositeImage(image,false);
|
|
Icon icon=tab.Icon;
|
|
if(icon!=null)
|
|
return new CompositeImage(icon,false,tab.IconSize);
|
|
|
|
return null;
|
|
}
|
|
|
|
protected virtual Rectangle GetFocusRectangle(Rectangle rText)
|
|
{
|
|
rText.Inflate(-1,-1);
|
|
return rText;
|
|
}
|
|
|
|
protected virtual TabItem GetLastVisibleTab(TabsCollection tabs)
|
|
{
|
|
int c=tabs.Count-1;
|
|
for(int i=c;i>=0;i--)
|
|
{
|
|
if(tabs[i].Visible)
|
|
return tabs[i];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected virtual void DrawBackground(TabStrip tabStrip, Rectangle tabStripRect, Graphics g, TabColorScheme colors, Region tabsRegion, eTabStripAlignment tabAlignment, Rectangle selectedTabRect)
|
|
{
|
|
if(colors.TabBackground2.IsEmpty)
|
|
{
|
|
if (!colors.TabBackground.IsEmpty)
|
|
{
|
|
using (SolidBrush brush = new SolidBrush(colors.TabBackground))
|
|
g.FillRegion(brush, tabsRegion);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using(LinearGradientBrush brush=BarFunctions.CreateLinearGradientBrush(tabsRegion.GetBounds(g),colors.TabBackground,colors.TabBackground2,colors.TabBackgroundGradientAngle))
|
|
g.FillRegion(brush, tabsRegion);
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region Tab Path Functions
|
|
protected virtual GraphicsPath GetTabItemPath(TabItem tab, bool bFirst, bool bLast)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected virtual ArcData GetCornerArc(Rectangle bounds, int cornerDiameter, eCornerArc corner)
|
|
{
|
|
ArcData a;
|
|
int diameter=cornerDiameter*2;
|
|
switch(corner)
|
|
{
|
|
case eCornerArc.TopLeft:
|
|
a=new ArcData(bounds.X,bounds.Y,diameter,diameter,180,90);
|
|
break;
|
|
case eCornerArc.TopRight:
|
|
a=new ArcData(bounds.Right-diameter,bounds.Y,diameter,diameter,270,90);
|
|
break;
|
|
case eCornerArc.BottomLeft:
|
|
a=new ArcData(bounds.X,bounds.Bottom-diameter,diameter,diameter,90,90);
|
|
break;
|
|
default: // eCornerArc.BottomRight:
|
|
a=new ArcData(bounds.Right-diameter,bounds.Bottom-diameter,diameter,diameter,0,90);
|
|
break;
|
|
}
|
|
return a;
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>
|
|
/// Gets or sets whether anti-alias is used for painting the tabs. Default value is true.
|
|
/// </summary>
|
|
public virtual bool AntiAlias
|
|
{
|
|
get {return m_AntiAlias;}
|
|
set {m_AntiAlias=value;}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether text is drawn horizontaly regardless of tab orientation.
|
|
/// </summary>
|
|
public bool HorizontalText
|
|
{
|
|
get {return m_HorizontalText;}
|
|
set {m_HorizontalText=value;}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether close button is painted on each tab.
|
|
/// </summary>
|
|
public bool CloseButtonOnTabs
|
|
{
|
|
get { return m_CloseButtonOnTabs; }
|
|
set { m_CloseButtonOnTabs = value; }
|
|
}
|
|
|
|
public int TabCloseButtonSpacing
|
|
{
|
|
get { return m_TabCloseButtonSpacing; }
|
|
set { m_TabCloseButtonSpacing=value; }
|
|
}
|
|
#endregion
|
|
|
|
#region Static Methods
|
|
public static void PaintTabItemCloseButton(Graphics g, Rectangle r, bool mouseOver, bool isSelected, TabStrip tabStrip)
|
|
{
|
|
if (tabStrip.TabCloseButtonNormal != null)
|
|
{
|
|
Image image = tabStrip.TabCloseButtonNormal;
|
|
if (mouseOver && tabStrip.TabCloseButtonHot != null)
|
|
image = tabStrip.TabCloseButtonHot;
|
|
g.DrawImageUnscaled(image, r);
|
|
return;
|
|
}
|
|
|
|
Color fillColor = tabStrip.ColorScheme.TabItemBorder;
|
|
Color lineColor = tabStrip.ColorScheme.TabItemBorderLight;
|
|
if (!fillColor.IsEmpty && Math.Abs(fillColor.GetBrightness() - lineColor.GetBrightness()) <= .38)
|
|
{
|
|
lineColor = BarFunctions.Ligten(lineColor, 60);
|
|
fillColor = BarFunctions.Darken(fillColor, 40);
|
|
}
|
|
|
|
if (fillColor.IsEmpty)
|
|
{
|
|
if(tabStrip.Style == eTabStripStyle.Office2003)
|
|
{
|
|
fillColor = tabStrip.ColorScheme.TabPanelBackground;
|
|
lineColor = tabStrip.ColorScheme.TabItemText;
|
|
}
|
|
else if (!tabStrip.ColorScheme.TabItemSelectedBorder.IsEmpty)
|
|
{
|
|
fillColor = tabStrip.ColorScheme.TabItemSelectedBorder;
|
|
if (!tabStrip.ColorScheme.TabItemSelectedBorderLight.IsEmpty)
|
|
lineColor = tabStrip.ColorScheme.TabItemSelectedBorderLight;
|
|
else if (isSelected && fillColor == tabStrip.ColorScheme.TabItemSelectedBackground && !tabStrip.ColorScheme.TabItemSelectedText.IsEmpty)
|
|
lineColor = tabStrip.ColorScheme.TabItemSelectedText;
|
|
else if (tabStrip.Style == eTabStripStyle.Metro)
|
|
lineColor = tabStrip.ColorScheme.TabBackground;
|
|
}
|
|
else
|
|
{
|
|
fillColor = SystemColors.ControlDark;
|
|
lineColor = SystemColors.ControlLightLight;
|
|
}
|
|
}
|
|
|
|
if(lineColor.IsEmpty)
|
|
lineColor = SystemColors.ControlLightLight;
|
|
|
|
//if (!fillColor.IsEmpty && Math.Abs(fillColor.GetBrightness() - lineColor.GetBrightness()) <= .38)
|
|
//{
|
|
// if (lineColor.GetBrightness() < .5)
|
|
// {
|
|
// fillColor = lineColor;
|
|
// lineColor = SystemColors.ControlLightLight;
|
|
// }
|
|
// else
|
|
// fillColor = (lineColor.GetBrightness() < .5 ? SystemColors.ControlLightLight : SystemColors.ControlDarkDark);
|
|
//}
|
|
|
|
fillColor = Color.FromArgb(mouseOver ? 255 : 200, fillColor);
|
|
|
|
if ((tabStrip.Style == eTabStripStyle.Metro || tabStrip.Style == eTabStripStyle.Office2003) && !mouseOver)
|
|
{
|
|
if (StyleManager.Style == eStyle.Metro || StyleManager.Style == eStyle.OfficeMobile2014 || StyleManager.Style == eStyle.Office2016)
|
|
lineColor = fillColor;
|
|
fillColor = Color.Empty;
|
|
}
|
|
|
|
if (!fillColor.IsEmpty)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
using (Pen pen = new Pen(Color.White, Dpi.Width1))
|
|
g.DrawEllipse(pen, r);
|
|
using (Pen pen = new Pen(fillColor, Dpi.Width1))
|
|
{
|
|
g.DrawEllipse(pen, r);
|
|
}
|
|
using (SolidBrush brush = new SolidBrush(Color.White))
|
|
g.FillEllipse(brush, r);
|
|
using (SolidBrush brush = new SolidBrush(fillColor))
|
|
{
|
|
g.FillEllipse(brush, r);
|
|
}
|
|
g.SmoothingMode = sm;
|
|
}
|
|
|
|
using (Pen pen = new Pen(lineColor, Dpi.Width1))
|
|
{
|
|
Rectangle close = r;
|
|
close.Inflate(-Dpi.Width3, -Dpi.Height3);
|
|
close.Width--;
|
|
g.DrawLine(pen, close.X, close.Y, close.Right, close.Bottom);
|
|
g.DrawLine(pen, close.X, close.Bottom, close.Right, close.Y);
|
|
close.Offset(1, 0);
|
|
g.DrawLine(pen, close.X, close.Y, close.Right, close.Bottom);
|
|
g.DrawLine(pen, close.X, close.Bottom, close.Right, close.Y);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|