using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.ComponentModel; using WeifenLuo.WinFormsUI.Docking; namespace DockSample.Customization { internal class VS2003DockPaneStrip : DockPaneStripBase { private class TabVS2003 : Tab { internal TabVS2003(IDockContent content) : base(content) { } private int m_tabX; protected internal int TabX { get { return m_tabX; } set { m_tabX = value; } } private int m_tabWidth; protected internal int TabWidth { get { return m_tabWidth; } set { m_tabWidth = value; } } private int m_maxWidth; protected internal int MaxWidth { get { return m_maxWidth; } set { m_maxWidth = value; } } private bool m_flag; protected internal bool Flag { get { return m_flag; } set { m_flag = value; } } } protected override DockPaneStripBase.Tab CreateTab(IDockContent content) { return new TabVS2003(content); } private class DocumentButton : Label { public DocumentButton(Image image) { Image = image; } } #region consts private const int _ToolWindowStripGapLeft = 4; private const int _ToolWindowStripGapRight = 3; private const int _ToolWindowImageHeight = 16; private const int _ToolWindowImageWidth = 16; private const int _ToolWindowImageGapTop = 3; private const int _ToolWindowImageGapBottom = 1; private const int _ToolWindowImageGapLeft = 3; private const int _ToolWindowImageGapRight = 2; private const int _ToolWindowTextGapRight = 1; private const int _ToolWindowTabSeperatorGapTop = 3; private const int _ToolWindowTabSeperatorGapBottom = 3; private const int _DocumentTabMaxWidth = 200; private const int _DocumentButtonGapTop = 5; private const int _DocumentButtonGapBottom = 5; private const int _DocumentButtonGapBetween = 0; private const int _DocumentButtonGapRight = 3; private const int _DocumentTabGapTop = 3; private const int _DocumentTabGapLeft = 3; private const int _DocumentTabGapRight = 3; private const int _DocumentIconGapLeft = 6; private const int _DocumentIconHeight = 16; private const int _DocumentIconWidth = 16; #endregion private InertButton m_buttonClose, m_buttonScrollLeft, m_buttonScrollRight; private IContainer m_components; private ToolTip m_toolTip; /// protected IContainer Components { get { return m_components; } } private int m_offsetX = 0; private int OffsetX { get { return m_offsetX; } set { m_offsetX = value; #if DEBUG if (m_offsetX > 0) throw new InvalidOperationException(); #endif } } #region Customizable Properties /// protected virtual int ToolWindowStripGapLeft { get { return _ToolWindowStripGapLeft; } } /// protected virtual int ToolWindowStripGapRight { get { return _ToolWindowStripGapRight; } } /// protected virtual int ToolWindowImageHeight { get { return _ToolWindowImageHeight; } } /// protected virtual int ToolWindowImageWidth { get { return _ToolWindowImageWidth; } } /// protected virtual int ToolWindowImageGapTop { get { return _ToolWindowImageGapTop; } } /// protected virtual int ToolWindowImageGapBottom { get { return _ToolWindowImageGapBottom; } } /// protected virtual int ToolWindowImageGapLeft { get { return _ToolWindowImageGapLeft; } } /// protected virtual int ToolWindowImageGapRight { get { return _ToolWindowImageGapRight; } } /// protected virtual int ToolWindowTextGapRight { get { return _ToolWindowTextGapRight; } } /// protected virtual int ToolWindowTabSeperatorGapTop { get { return _ToolWindowTabSeperatorGapTop; } } /// protected virtual int ToolWindowTabSeperatorGapBottom { get { return _ToolWindowTabSeperatorGapBottom; } } private static Image _imageCloseEnabled = null; /// protected virtual Image ImageCloseEnabled { get { if (_imageCloseEnabled == null) _imageCloseEnabled = Resources.DockPaneStrip_CloseEnabled; return _imageCloseEnabled; } } private static Image _imageCloseDisabled = null; /// protected virtual Image ImageCloseDisabled { get { if (_imageCloseDisabled == null) _imageCloseDisabled = Resources.DockPaneStrip_CloseDisabled; return _imageCloseDisabled; } } private static Image _imageScrollLeftEnabled = null; /// protected virtual Image ImageScrollLeftEnabled { get { if (_imageScrollLeftEnabled == null) _imageScrollLeftEnabled = Resources.DockPaneStrip_ScrollLeftEnabled; return _imageScrollLeftEnabled; } } private static Image _imageScrollLeftDisabled = null; /// protected virtual Image ImageScrollLeftDisabled { get { if (_imageScrollLeftDisabled == null) _imageScrollLeftDisabled = Resources.DockPaneStrip_ScrollLeftDisabled; return _imageScrollLeftDisabled; } } private static Image _imageScrollRightEnabled = null; /// protected virtual Image ImageScrollRightEnabled { get { if (_imageScrollRightEnabled == null) _imageScrollRightEnabled = Resources.DockPaneStrip_ScrollRightEnabled; return _imageScrollRightEnabled; } } private static Image _imageScrollRightDisabled = null; /// protected virtual Image ImageScrollRightDisabled { get { if (_imageScrollRightDisabled == null) _imageScrollRightDisabled = Resources.DockPaneStrip_ScrollRightDisabled; return _imageScrollRightDisabled; } } private static string _toolTipClose = null; /// protected virtual string ToolTipClose { get { if (_toolTipClose == null) _toolTipClose = Strings.DockPaneStrip_ToolTipClose; return _toolTipClose; } } private static string _toolTipScrollLeft = null; /// protected virtual string ToolTipScrollLeft { get { if (_toolTipScrollLeft == null) _toolTipScrollLeft = Strings.DockPaneStrip_ToolTipScrollLeft; return _toolTipScrollLeft; } } private static string _toolTipScrollRight = null; /// protected virtual string ToolTipScrollRight { get { if (_toolTipScrollRight == null) _toolTipScrollRight = Strings.DockPaneStrip_ToolTipScrollRight; return _toolTipScrollRight; } } private static TextFormatFlags _toolWindowTextFormat = TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter; /// protected virtual TextFormatFlags ToolWindowTextFormat { get { return _toolWindowTextFormat; } } private static TextFormatFlags _documentTextFormat = TextFormatFlags.PathEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter; /// public static TextFormatFlags DocumentTextFormat { get { return _documentTextFormat; } } /// protected virtual int DocumentTabMaxWidth { get { return _DocumentTabMaxWidth; } } /// protected virtual int DocumentButtonGapTop { get { return _DocumentButtonGapTop; } } /// protected virtual int DocumentButtonGapBottom { get { return _DocumentButtonGapBottom; } } /// protected virtual int DocumentButtonGapBetween { get { return _DocumentButtonGapBetween; } } /// protected virtual int DocumentButtonGapRight { get { return _DocumentButtonGapRight; } } /// protected virtual int DocumentTabGapTop { get { return _DocumentTabGapTop; } } /// protected virtual int DocumentTabGapLeft { get { return _DocumentTabGapLeft; } } /// protected virtual int DocumentTabGapRight { get { return _DocumentTabGapRight; } } /// protected virtual int DocumentIconGapLeft { get { return _DocumentIconGapLeft; } } /// protected virtual int DocumentIconWidth { get { return _DocumentIconWidth; } } /// protected virtual int DocumentIconHeight { get { return _DocumentIconHeight; } } /// protected virtual Pen OutlineInnerPen { get { return SystemPens.ControlText; } } /// protected virtual Pen OutlineOuterPen { get { return SystemPens.ActiveCaptionText; } } /// protected virtual Brush ActiveBackBrush { get { return SystemBrushes.Control; } } /// protected virtual Color ActiveTextColor { get { return SystemColors.ControlText; } } /// protected virtual Pen TabSeperatorPen { get { return SystemPens.GrayText; } } /// protected virtual Color InactiveTextColor { get { return SystemColors.ControlDarkDark; } } #endregion public VS2003DockPaneStrip(DockPane pane) : base(pane) { SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SuspendLayout(); Font = SystemInformation.MenuFont; BackColor = Color.WhiteSmoke; m_components = new Container(); m_toolTip = new ToolTip(Components); m_buttonClose = new InertButton(ImageCloseEnabled, ImageCloseDisabled); m_buttonScrollLeft = new InertButton(ImageScrollLeftEnabled, ImageScrollLeftDisabled); m_buttonScrollRight = new InertButton(ImageScrollRightEnabled, ImageScrollRightDisabled); m_buttonClose.ToolTipText = ToolTipClose; m_buttonClose.Anchor = AnchorStyles.Top | AnchorStyles.Right; m_buttonClose.Click += new EventHandler(Close_Click); m_buttonScrollLeft.Enabled = false; m_buttonScrollLeft.RepeatClick = true; m_buttonScrollLeft.ToolTipText = ToolTipScrollLeft; m_buttonScrollLeft.Anchor = AnchorStyles.Top | AnchorStyles.Right; m_buttonScrollLeft.Click += new EventHandler(ScrollLeft_Click); m_buttonScrollRight.Enabled = false; m_buttonScrollRight.RepeatClick = true; m_buttonScrollRight.ToolTipText = ToolTipScrollRight; m_buttonScrollRight.Anchor = AnchorStyles.Top | AnchorStyles.Right; m_buttonScrollRight.Click += new EventHandler(ScrollRight_Click); Controls.AddRange(new Control[] { m_buttonClose, m_buttonScrollLeft, m_buttonScrollRight }); ResumeLayout(); } protected override void Dispose(bool disposing) { if (disposing) { Components.Dispose(); } base.Dispose (disposing); } protected override int MeasureHeight() { if (Appearance == DockPane.AppearanceStyle.ToolWindow) return MeasureHeight_ToolWindow(); else return MeasureHeight_Document(); } private int MeasureHeight_ToolWindow() { if (DockPane.IsAutoHide || Tabs.Count <= 1) return 0; int height = Math.Max(Font.Height, ToolWindowImageHeight) + ToolWindowImageGapTop + ToolWindowImageGapBottom; return height; } private int MeasureHeight_Document() { int height = Math.Max(Font.Height + DocumentTabGapTop, ImageCloseEnabled.Height + DocumentButtonGapTop + DocumentButtonGapBottom); return height; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); CalculateTabs(); DrawTabStrip(e.Graphics); } protected override void OnRefreshChanges() { CalculateTabs(); SetInertButtons(); Invalidate(); } protected override GraphicsPath GetOutline(int index) { Point[] pts = new Point[8]; if (Appearance == DockPane.AppearanceStyle.Document) { Rectangle rectTab = GetTabRectangle(index); rectTab.Intersect(TabsRectangle); int y = DockPane.PointToClient(PointToScreen(new Point(0, rectTab.Bottom))).Y; Rectangle rectPaneClient = DockPane.ClientRectangle; pts[0] = DockPane.PointToScreen(new Point(rectPaneClient.Left, y)); pts[1] = PointToScreen(new Point(rectTab.Left, rectTab.Bottom)); pts[2] = PointToScreen(new Point(rectTab.Left, rectTab.Top)); pts[3] = PointToScreen(new Point(rectTab.Right, rectTab.Top)); pts[4] = PointToScreen(new Point(rectTab.Right, rectTab.Bottom)); pts[5] = DockPane.PointToScreen(new Point(rectPaneClient.Right, y)); pts[6] = DockPane.PointToScreen(new Point(rectPaneClient.Right, rectPaneClient.Bottom)); pts[7] = DockPane.PointToScreen(new Point(rectPaneClient.Left, rectPaneClient.Bottom)); } else { Rectangle rectTab = GetTabRectangle(index); rectTab.Intersect(TabsRectangle); int y = DockPane.PointToClient(PointToScreen(new Point(0, rectTab.Top))).Y; Rectangle rectPaneClient = DockPane.ClientRectangle; pts[0] = DockPane.PointToScreen(new Point(rectPaneClient.Left, rectPaneClient.Top)); pts[1] = DockPane.PointToScreen(new Point(rectPaneClient.Right, rectPaneClient.Top)); pts[2] = DockPane.PointToScreen(new Point(rectPaneClient.Right, y)); pts[3] = PointToScreen(new Point(rectTab.Right, rectTab.Top)); pts[4] = PointToScreen(new Point(rectTab.Right, rectTab.Bottom)); pts[5] = PointToScreen(new Point(rectTab.Left, rectTab.Bottom)); pts[6] = PointToScreen(new Point(rectTab.Left, rectTab.Top)); pts[7] = DockPane.PointToScreen(new Point(rectPaneClient.Left, y)); } GraphicsPath path = new GraphicsPath(); path.AddLines(pts); return path; } private void CalculateTabs() { if (Appearance == DockPane.AppearanceStyle.ToolWindow) CalculateTabs_ToolWindow(); else CalculateTabs_Document(); } private void CalculateTabs_ToolWindow() { if (Tabs.Count <= 1 || DockPane.IsAutoHide) return; Rectangle rectTabStrip = ClientRectangle; // Calculate tab widths int countTabs = Tabs.Count; foreach (TabVS2003 tab in Tabs) { tab.MaxWidth = GetTabOriginalWidth(Tabs.IndexOf(tab)); tab.Flag = false; } // Set tab whose max width less than average width bool anyWidthWithinAverage = true; int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight; int totalAllocatedWidth = 0; int averageWidth = totalWidth / countTabs; int remainedTabs = countTabs; for (anyWidthWithinAverage=true; anyWidthWithinAverage && remainedTabs>0;) { anyWidthWithinAverage = false; foreach (TabVS2003 tab in Tabs) { if (tab.Flag) continue; if (tab.MaxWidth <= averageWidth) { tab.Flag = true; tab.TabWidth = tab.MaxWidth; totalAllocatedWidth += tab.TabWidth; anyWidthWithinAverage = true; remainedTabs--; } } if (remainedTabs != 0) averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs; } // If any tab width not set yet, set it to the average width if (remainedTabs > 0) { int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs); foreach (TabVS2003 tab in Tabs) { if (tab.Flag) continue; tab.Flag = true; if (roundUpWidth > 0) { tab.TabWidth = averageWidth + 1; roundUpWidth --; } else tab.TabWidth = averageWidth; } } // Set the X position of the tabs int x = rectTabStrip.X + ToolWindowStripGapLeft; foreach (TabVS2003 tab in Tabs) { tab.TabX = x; x += tab.TabWidth; } } private void CalculateTabs_Document() { Rectangle rectTabStrip = TabsRectangle; int totalWidth = 0; foreach (TabVS2003 tab in Tabs) { tab.TabWidth = Math.Min(GetTabOriginalWidth(Tabs.IndexOf(tab)), DocumentTabMaxWidth); totalWidth += tab.TabWidth; } if (totalWidth + OffsetX < rectTabStrip.Width && OffsetX < 0) OffsetX = Math.Min(0, rectTabStrip.Width - totalWidth); int x = rectTabStrip.X + OffsetX; foreach (TabVS2003 tab in Tabs) { tab.TabX = x; x += tab.TabWidth; } } protected override void EnsureTabVisible(IDockContent content) { if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content)) return; Rectangle rectTabStrip = TabsRectangle; Rectangle rectTab = GetTabRectangle(Tabs.IndexOf(content)); if (rectTab.Right > rectTabStrip.Right) { OffsetX -= rectTab.Right - rectTabStrip.Right; rectTab.X -= rectTab.Right - rectTabStrip.Right; } if (rectTab.Left < rectTabStrip.Left) OffsetX += rectTabStrip.Left - rectTab.Left; OnRefreshChanges(); } private int GetTabOriginalWidth(int index) { if (Appearance == DockPane.AppearanceStyle.ToolWindow) return GetTabOriginalWidth_ToolWindow(index); else return GetTabOriginalWidth_Document(index); } private int GetTabOriginalWidth_ToolWindow(int index) { IDockContent content = Tabs[index].Content; using (Graphics g = CreateGraphics()) { Size sizeString = TextRenderer.MeasureText(g, content.DockHandler.TabText, Font); return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft + ToolWindowImageGapRight + ToolWindowTextGapRight; } } private int GetTabOriginalWidth_Document(int index) { IDockContent content = Tabs[index].Content; int height = GetTabRectangle_Document(index).Height; using (Graphics g = CreateGraphics()) { Size sizeText; if (content == DockPane.ActiveContent && DockPane.IsActiveDocumentPane) { using (Font boldFont = new Font(this.Font, FontStyle.Bold)) { sizeText = TextRenderer.MeasureText(g, content.DockHandler.TabText, boldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); } } else sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, Font, new Size(DocumentTabMaxWidth, height), DocumentTextFormat); if (DockPane.DockPanel.ShowDocumentIcon) return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft; else return sizeText.Width; } } private void DrawTabStrip(Graphics g) { OnBeginDrawTabStrip(); if (Appearance == DockPane.AppearanceStyle.Document) DrawTabStrip_Document(g); else DrawTabStrip_ToolWindow(g); OnEndDrawTabStrip(); } private void DrawTabStrip_Document(Graphics g) { int count = Tabs.Count; if (count == 0) return; Rectangle rectTabStrip = ClientRectangle; g.DrawLine(OutlineOuterPen, rectTabStrip.Left, rectTabStrip.Bottom - 1, rectTabStrip.Right, rectTabStrip.Bottom - 1); // Draw the tabs Rectangle rectTabOnly = TabsRectangle; Rectangle rectTab = Rectangle.Empty; g.SetClip(rectTabOnly); for (int i=0; i rectTabOnly.Right; // show/hide close button if (Appearance == DockPane.AppearanceStyle.ToolWindow) m_buttonClose.Visible = false; else { bool showCloseButton = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton; if (m_buttonClose.Visible != showCloseButton) { m_buttonClose.Visible = showCloseButton; PerformLayout(); } } } /// protected override void OnLayout(LayoutEventArgs levent) { Rectangle rectTabStrip = ClientRectangle; // Set position and size of the buttons int buttonWidth = ImageCloseEnabled.Width; int buttonHeight = ImageCloseEnabled.Height; int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom; if (buttonHeight < height) { buttonWidth = buttonWidth * (height / buttonHeight); buttonHeight = height; } Size buttonSize = new Size(buttonWidth, buttonHeight); m_buttonClose.Size = m_buttonScrollLeft.Size = m_buttonScrollRight.Size = buttonSize; int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft - DocumentButtonGapRight - buttonWidth; int y = rectTabStrip.Y + DocumentButtonGapTop; m_buttonClose.Location = new Point(x, y); Point point = m_buttonClose.Location; bool showCloseButton = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton; if (showCloseButton) point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0); m_buttonScrollRight.Location = point; point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0); m_buttonScrollLeft.Location = point; OnRefreshChanges(); base.OnLayout (levent); } private void Close_Click(object sender, EventArgs e) { DockPane.CloseActiveContent(); } /// protected override int HitTest(Point ptMouse) { Rectangle rectTabStrip = TabsRectangle; for (int i=0; i protected override void OnMouseMove(MouseEventArgs e) { int index = HitTest(PointToClient(Control.MousePosition)); string toolTip = string.Empty; base.OnMouseMove(e); if (index != -1) { Rectangle rectTab = GetTabRectangle(index); if (Tabs[index].Content.DockHandler.ToolTipText != null) toolTip = Tabs[index].Content.DockHandler.ToolTipText; else if (rectTab.Width < GetTabOriginalWidth(index)) toolTip = Tabs[index].Content.DockHandler.TabText; } if (m_toolTip.GetToolTip(this) != toolTip) { m_toolTip.Active = false; m_toolTip.SetToolTip(this, toolTip); m_toolTip.Active = true; } } /// protected virtual void OnBeginDrawTabStrip() { } /// protected virtual void OnEndDrawTabStrip() { } /// protected virtual void OnBeginDrawTab(Tab tab) { } /// protected virtual void OnEndDrawTab(Tab tab) { } } }