RaUI/Source/ryControls/Gdu.WinFormUI/Forms/MdiBarController.cs
如果当时 34a3ef3ed9 ### 2021-02-22更新
------
#### ryControls    V2.1.2102.2201
*.[新增]新加入Gdu.WinformUI控件。
2021-02-22 21:42:59 +08:00

1368 lines
44 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 本代码受中华人民共和国著作权法保护,作者仅授权下载代码之人在学习和交流范围内
* 自由使用与修改代码;欲将代码用于商业用途的,请与作者联系。
* 使用本代码请保留此处信息。作者联系方式ping3108@163.com, 欢迎进行技术交流
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using MGdu.WinFormUI.MyGraphics;
//忽略没有注释警告
#pragma warning disable 1591
namespace MGdu.WinFormUI
{
/// <summary>
/// 该类处理mdi-bar的绘制及鼠标事件管理
/// </summary>
internal class MdiBarController
{
#region private var
GMForm _owner;
public List<MdiGMTabItem> _listTabItems { get; private set; }
// 有时候可能有很多tab,不能全部显示,那么就用两个变量来标识
// 是第几个到第几个tab被显示出来了。
int _beginShowIndex;
int _endShowIndex;
int _activeTabIndex;
// 有多少tab被隐藏了
int _hiddenTabsCount;
Point _lastMouseUpLocation;
WLButton _newTabBtn;
WLButton _listAllBtn;
EventHandler _newTabBtnClick;
EventHandler _tabCloseBtnClick;
ContextMenuStrip _menuPopup;
private Rectangle _hitTestBounds;
#endregion
#region event & event handler
public event EventHandler NewTabButtonClick
{
add { _newTabBtnClick = value; }
remove { _newTabBtnClick = null; }
}
public event EventHandler TabCloseButtonClick
{
add { _tabCloseBtnClick = value; }
remove { _tabCloseBtnClick = null; }
}
private void OnNewTabBtnClick(object sender, EventArgs e)
{
_newTabBtnClick?.Invoke(this, EventArgs.Empty);
}
private void OnTabCloseBtnClick(object sender, EventArgs e)
{
if (sender is Form f)
{
_tabCloseBtnClick?.Invoke(f, EventArgs.Empty);
}
}
private void OnListAllBtnClick(object sender, EventArgs e)
{
if (_listTabItems.Count < 1)
return;
foreach (MdiGMTabItem tab in _listTabItems)
{
if (tab.IsFormActive)
{
tab.MenuItemPop.Checked = true;
tab.MenuItemPop.Image = null;
}
else
{
tab.MenuItemPop.Checked = false;
tab.MenuItemPop.Image = tab.Form.Icon.ToBitmap();
}
tab.MenuItemPop.Text = tab.Form.Text;
if (!tab.IsHidden)
tab.MenuItemPop.Font = new Font(tab.MenuItemPop.Font, FontStyle.Bold);
else
tab.MenuItemPop.Font = new Font(tab.MenuItemPop.Font, FontStyle.Regular);
}
_menuPopup.Show(_owner, ListAllBtnBounds.Left, ListAllBtnBounds.Bottom);
}
private void OnActivateChild(Form child)
{
if (child != _owner.ActiveMdiChild)
{
if (_owner.XTheme.Mdi_UseMsgToActivateChild)
_owner.ActivateMdiChildForm(child);
else
child.Activate();
}
}
private void OnPopMenuItemClick(object sender, EventArgs e)
{
if (sender is ToolStripMenuItem ctl)
{
if (ctl.Tag is Form f)
{
OnActivateChild(f);
}
}
}
#endregion
#region Constructor & initial
public MdiBarController(GMForm owner)
{
_owner = owner;
_listTabItems = new List<MdiGMTabItem>();
_newTabBtn = new WLButton(owner);
_listAllBtn = new WLButton(owner);
// ini _newtabbtn
_newTabBtn.ColorTable = NewTabBtnColor;
_newTabBtn.Click += new EventHandler(OnNewTabBtnClick);
_newTabBtn.ForePathGetter = new ButtonForePathGetter(
MGdu.WinFormUI.MyGraphics.GraphicsPathHelper.CreatePlusFlag);
_listAllBtn.ColorTable = ListAllBtnColor;
_listAllBtn.Click +=new EventHandler(OnListAllBtnClick);
_listAllBtn.ForePathGetter = new ButtonForePathGetter(
MGdu.WinFormUI.MyGraphics.GraphicsPathHelper.CreateDownTriangleFlag);
_listAllBtn.ForePathSize = new Size(10, 9);
_listAllBtn.ForeFont = new Font("微软雅黑", 8);
_menuPopup = new ContextMenuStrip();
}
#endregion
#region editable properties from thmem info
/// <summary>
/// use left,top,right to location the bar in owner form,
/// the margin is from Form.ClientRectangle
/// </summary>
public Padding Margin
{
get { return _owner.XTheme.Mdi_BarMargin; }
}
/// <summary>
/// 整个标签栏高度,包含标签栏底部区域、标签、标签顶部空隙
/// </summary>
public int BarHeight
{
get { return BarBottomRegionHeight + Math.Max(TabHeight, TabHeightActive) + TabTopSpace; }
}
/// <summary>
/// 标签栏底部区域的高度
/// </summary>
public int BarBottomRegionHeight
{
get { return _owner.XTheme.Mdi_BarBottomRegionHeight; }
}
/// <summary>
/// 是否显示标签栏边框
/// </summary>
public bool DrawBarBorder
{
get { return _owner.XTheme.Mdi_DrawBarBorder; }
}
/// <summary>
/// 是否显示标签栏背景
/// </summary>
public bool DrawBarBackgound
{
get { return _owner.XTheme.Mdi_DrawBarBackground; }
}
/// <summary>
///标签栏左内边距
/// </summary>
public int BarLeftPadding
{
get { return _owner.XTheme.Mdi_BarLeftPadding; }
}
/// <summary>
/// 标签栏右内边距
/// </summary>
public int BarRightPadding
{
get { return _owner.XTheme.Mdi_BarRightPadding; }
}
/// <summary>
/// 标签高度
/// </summary>
public int TabHeight
{
get { return _owner.XTheme.Mdi_TabHeight; }
}
/// <summary>
/// 激活的标签高度
/// </summary>
public int TabHeightActive
{
get { return _owner.XTheme.Mdi_TabHeightActive; }
}
/// <summary>
/// tab顶部与bar顶部的空间,这个值用来计算 BarHeight
/// </summary>
public int TabTopSpace
{
get { return _owner.XTheme.Mdi_TabTopSpace; }
}
/// <summary>
/// 每个标签的左右边界可以不是垂直的,而是都有一个斜度
/// </summary>
public int TabSlopeWidth
{
get { return _owner.XTheme.Mdi_TabSlopeWidth; }
}
/// <summary>
/// tab与tab之间的距离用负值可以使tab有重叠的效果
/// </summary>
public int TabAndTabSpace
{
get { return _owner.XTheme.Mdi_TabAndTabSpace; }
}
/// <summary>
/// 标签是否显示图标
/// </summary>
public bool ShowTabIcon
{
get { return _owner.XTheme.Mdi_ShowTabIcon; }
}
/// <summary>
/// 是否显示标签关闭按钮
/// </summary>
public bool ShowTabCloseIcon
{
get { return _owner.XTheme.Mdi_ShowTabCloseIcon; }
}
/// <summary>
/// 标签图标大小
/// </summary>
public Size IconSize
{
get { return ShowTabIcon ? new Size(16, 16) : Size.Empty; }
}
/// <summary>
/// 标签图标距离左边的距离
/// </summary>
public int IconLeftSpace
{
get { return TabSlopeWidth + (ShowTabIcon ? 2 : 0); }
}
/// <summary>
/// 标签文字距离左边的距离
/// </summary>
public int TextLeftSpace
{
get { return 2; }
}
/// <summary>
/// 标签关闭按钮的大小
/// </summary>
public Size TabCloseBtnSize
{
get { return new Size(16, 16); }
}
/// <summary>
/// 标签关闭按钮距离右边的距离
/// </summary>
public int TabCloseBtnRightSpace
{
get { return TabSlopeWidth + 2; }
}
/// <summary>
/// 是否显示新建标签按钮
/// </summary>
public bool ShowNewTabBtn
{
get { return _owner.XTheme.Mdi_ShowNewTabBtn; }
}
/// <summary>
/// 新建标签按钮的大小
/// </summary>
public Size NewTabBtnSize
{
get { return _owner.XTheme.Mdi_NewTabBtnSize; }
}
public Rectangle NewTabBtnBounds
{
get;
set;
}
/// <summary>
/// 新建标签距离左边的距离
/// </summary>
public int NewTabBtnLeftSpace
{
get { return _owner.XTheme.Mdi_NewTabBtnLeftSpace; }
}
/// <summary>
/// 按钮与Bar底部的距离
/// </summary>
public int NewTabBtnBottomSpace
{
get { return _owner.XTheme.Mdi_NewTabBtnBottomSpace; }
}
public Rectangle ListAllBtnBounds { get; set; }
public Size ListAllBtnSize
{
get { return _owner.XTheme.Mdi_ListAllBtnSize; }
}
public int ListAllBtnLeftSpace
{
get { return _owner.XTheme.Mdi_ListAllBtnLeftSpace; }
}
public int ListAllBtnBottomSpace
{
get { return _owner.XTheme.Mdi_ListAllBtnBottomSpace; }
}
public BarButtonAlignmentType ListAllBtnAlign
{
get { return _owner.XTheme.Mdi_ListAllBtnAlign; }
}
public bool AlwaysShowListAllBtn
{ get { return _owner.XTheme.Mdi_AlwaysShowListAllBtn; } }
/// <summary>
/// 一个tab允许的最小宽度
/// </summary>
public int TabMinWidth
{
get
{
return Math.Max(TabSlopeWidth * 2 + IconLeftSpace + IconSize.Width
+ TabCloseBtnRightSpace + TabCloseBtnSize.Width + 36,
_owner.XTheme.Mdi_TabMinWidth);
}
}
/// <summary>
/// 一个tab允许的最大显示宽度
/// </summary>
public int TabMaxWidth
{
get { return _owner.XTheme.Mdi_TabMaxWidth; }
}
/// <summary>
/// 标签正常宽度
/// </summary>
public int TabNormalWidth
{
get { return _owner.XTheme.Mdi_TabNormalWidth; }
}
#region bar & tab color
public Color BarBorderColor
{
get { return _owner.XTheme.Mdi_BarBorderColor; }
}
public Color BarBackColor
{
get { return _owner.XTheme.Mdi_BarBackColor; }
}
public Color TabOutterBorderColor
{
get { return _owner.XTheme.Mdi_TabOutterBorderColor; }
}
public Color TabInnerBorderColor
{
get { return _owner.XTheme.Mdi_TabInnerBorderColor; }
}
public bool TabShowBorder
{
get { return _owner.XTheme.Mdi_TabShowBorder; }
}
public Color TabActiveBackColorTop
{
get { return _owner.XTheme.Mdi_TabActiveBackColorTop; }
}
public Color TabActiveBackColorBottom
{
get { return _owner.XTheme.Mdi_TabActiveBackColorBottom; }
}
public Color TabDeactiveBackColorTop
{
get { return _owner.XTheme.Mdi_TabDeactiveBackColorTop; }
}
public Color TabDeactiveBackColorBottom
{
get { return _owner.XTheme.Mdi_TabDeactiveBackColorBottom; }
}
public Color BarBottomRegionBackColor
{
get { return _owner.XTheme.Mdi_BarBottomRegionBackColor; }
}
public Color TabActiveForeColor
{
get { return _owner.XTheme.Mdi_TabActiveForeColor; }
}
public Color TabDeactiveForeColor
{
get { return _owner.XTheme.Mdi_TabDeactiveForeColor; }
}
#endregion
#region tab btn color
public ButtonColorTable NewTabBtnColor
{
get { return _owner.XTheme.Mdi_NewTabBtnColor; }
}
public ButtonColorTable ListAllBtnColor
{
get { return _owner.XTheme.Mdi_ListAllBtnColor; }
}
public ButtonColorTable TabCloseBtnColor
{
get { return ButtonColorTable.GetDefaultCloseBtnColor(); }
}
#endregion
#endregion
#region Calculated Properties
public int BarWidth
{
get { return _owner.ClientSize.Width - Margin.Left - Margin.Right; }
}
public Rectangle Bounds
{
get
{
return new Rectangle(
_owner.ClientRectangle.Left + Margin.Left,
_owner.ClientRectangle.Top + Margin.Top,
BarWidth,
BarHeight);
}
}
public Rectangle BarBottomRegionBounds
{
get
{
return new Rectangle(
Bounds.Left,
Bounds.Top + (Bounds.Height - BarBottomRegionHeight),
BarWidth,
BarBottomRegionHeight);
}
}
public Rectangle HitTestBounds
{
get { return _hitTestBounds; }
}
#endregion
#region private method
private MdiGMTabItem CreateNewTab(Form f)
{
MdiGMTabItem tab = new MdiGMTabItem(this);
tab.Form = f;
tab.CloseBtn = new WLButton(_owner)
{
ColorTable = TabCloseBtnColor,
BorderType = ButtonBorderType.Ellipse,
DrawForePathTwice = true,
//tab.CloseBtn.DrawLightGlass = true;
ClickSendBackOject = f,
ForePathGetter = new
ButtonForePathGetter(MGdu.WinFormUI.MyGraphics.GraphicsPathHelper.CreateSingleLineCloseFlag)
};
tab.CloseBtn.Click += new EventHandler(OnTabCloseBtnClick);
// menu item
tab.MenuItemPop = new ToolStripMenuItem();
tab.MenuItemPop.Tag = f;
tab.MenuItemPop.Click += new EventHandler(OnPopMenuItemClick);
_menuPopup.Items.Add(tab.MenuItemPop);
return tab;
}
/// <summary>
/// 同步_listTabItems与mdi主窗体实际存在的子form
/// </summary>
private void CheckTabItemsWithOwnerMdiForm()
{
List<Form> listCurrent = _owner.GetCurrentMdiChildren();
List<Form> newForm = new List<Form>();
foreach (MdiGMTabItem tab in _listTabItems)
tab.IsStillValid = false;
foreach (Form f in listCurrent)
{
MdiGMTabItem tab;
if (IsTabItemsContaining(f, out tab))
tab.IsStillValid = true;
else
newForm.Add(f);
}
// remove the closed form tab
for (int i = _listTabItems.Count - 1; i >= 0; i--)
if (!_listTabItems[i].IsStillValid)
{
_menuPopup.Items.Remove(_listTabItems[i].MenuItemPop);
_listTabItems[i].MenuItemPop.Dispose();
_listTabItems.RemoveAt(i);
}
// create tabs for newly added forms
foreach (Form f in newForm)
{
_listTabItems.Add(CreateNewTab(f));
}
// find the active tab
int j = 0;
foreach (MdiGMTabItem tab in _listTabItems)
{
if (tab.Form == _owner.ActiveMdiChild)
{
_activeTabIndex = j;
tab.IsFormActive = true;
}
else
tab.IsFormActive = false;
j++;
}
}
private bool IsTabItemsContaining(Form f, out MdiGMTabItem theTab)
{
theTab = null;
foreach (MdiGMTabItem tab in _listTabItems)
{
if (f == tab.Form)
{
theTab = tab;
return true;
}
}
return false;
}
/// <summary>
/// 为每个tab分配空间如果tab数目太多则有些会被隐藏
/// </summary>
private void CalculateSpaceForEachTab()
{
int beginOld = _beginShowIndex;
int endOld = _endShowIndex;
_beginShowIndex = 0;
_endShowIndex = _listTabItems.Count - 1;
_hiddenTabsCount = 0;
int availableWidth = BarWidth - BarLeftPadding - BarRightPadding;
if (ShowNewTabBtn)
availableWidth -= (NewTabBtnSize.Width + NewTabBtnLeftSpace);
if (AlwaysShowListAllBtn)
availableWidth -= (ListAllBtnSize.Width + ListAllBtnLeftSpace * 2);
//int tabCount = _listTabItems.Count;
int widthAll = 0;
int tabShorterThanNormalCount = 0;
int tabLongerThanMinWidthCount = 0;
int index = 0;
foreach (MdiGMTabItem tab in _listTabItems)
{
tab.FinalWidth = tab.GetFullShowTabWidth();
widthAll += (tab.FinalWidth + (index > 0 ? TabAndTabSpace : 0));
if (tab.FinalWidth < TabNormalWidth)
tabShorterThanNormalCount++;
if (tab.FinalWidth > TabMinWidth && index != _activeTabIndex)
tabLongerThanMinWidthCount++;
index++;
}
if (widthAll <= availableWidth)
{
#region 1.
int extraWidth = availableWidth - widthAll;
//把剩余的空间分配给那些还没有达到normal宽度的tab
index=0;
while (extraWidth > 0 && tabShorterThanNormalCount > 0)
{
if (_listTabItems[index].FinalWidth < TabNormalWidth)
{
if (extraWidth > 2)
{
_listTabItems[index].FinalWidth += 2;
extraWidth -= 2;
}
else
{
_listTabItems[index].FinalWidth += extraWidth;
extraWidth = 0;
}
if (_listTabItems[index].FinalWidth >= TabNormalWidth)
tabShorterThanNormalCount--;
}
index++;
if (index >= _listTabItems.Count)
index = 0;
}
return;
#endregion
}
// 空间有限不能以全文本方式显示所有tab则统一缩小非active的tab
int neededWidth = widthAll - availableWidth;
#region active tab,tabminwidth
// 统一缩小非active-tab看是否能在所有tab达到min宽度前腾出空间
index = 0;
while (neededWidth > 0 && tabLongerThanMinWidthCount > 0)
{
if (_listTabItems[index].FinalWidth > TabMinWidth && index != _activeTabIndex)
{
int diff = _listTabItems[index].FinalWidth - TabMinWidth;
if (diff > 2)
{
_listTabItems[index].FinalWidth -= 2;
neededWidth -= 2;
}
else
{
_listTabItems[index].FinalWidth = TabMinWidth;
neededWidth -= diff;
}
if (_listTabItems[index].FinalWidth <= TabMinWidth)
tabLongerThanMinWidthCount--;
}
index++;
if (index >= _listTabItems.Count)
index = 0;
}
#endregion
if (neededWidth <= 0)
{
// 2. 缩小非actvie-tab后可以全部显示
return;
}
if ((_listTabItems[_activeTabIndex].FinalWidth > TabNormalWidth))
{
// 若active-tab的宽度大于normal则逐渐减小到normal
int width = _listTabItems[_activeTabIndex].FinalWidth;
while (width > TabNormalWidth && neededWidth > 0)
{
width--;
neededWidth--;
}
_listTabItems[_activeTabIndex].FinalWidth = width;
if (neededWidth <= 0)
{
// 3. 缩小active-tab达到normal宽度后可以显示全部标签
return;
}
}
#region 4. tab
if (!AlwaysShowListAllBtn)
{
availableWidth -= (ListAllBtnSize.Width + ListAllBtnLeftSpace * 2);
neededWidth += (ListAllBtnSize.Width + ListAllBtnLeftSpace * 2);
}
if (availableWidth < _listTabItems[_activeTabIndex].FinalWidth)
{
_listTabItems[_activeTabIndex].FinalWidth = availableWidth;
if (availableWidth < (TabCloseBtnSize.Width + TabSlopeWidth * 2))
_listTabItems[_activeTabIndex].FinalWidth = TabCloseBtnSize.Width + TabSlopeWidth * 2;
}
_hiddenTabsCount = neededWidth / (TabMinWidth + TabAndTabSpace);
if ((neededWidth % (TabMinWidth + TabAndTabSpace)) != 0)
_hiddenTabsCount++;
if (_hiddenTabsCount >= _listTabItems.Count)
_hiddenTabsCount = _listTabItems.Count - 1;
//先看一下之前所隐藏的tab数是否与将要隐藏的tab数一致如果一致
//且不影响active的显示则不需要改变之前所隐藏的tab
//若不行,则简单点,先隐藏右边,不够的再隐藏左边
#region tabs被隐藏
int showTabCount = endOld - beginOld + 1;
if ((_listTabItems.Count - _hiddenTabsCount) == showTabCount)
{
if (endOld > _listTabItems.Count - 1)
{
endOld = _listTabItems.Count - 1;
beginOld = endOld - showTabCount + 1;
}
if (beginOld <= _activeTabIndex && endOld >= _activeTabIndex)
{
_beginShowIndex = beginOld;
_endShowIndex = endOld;
}
else
{
//平移一下使_actvieTabIndex包含其中
if (_activeTabIndex < beginOld)
{
_beginShowIndex = _activeTabIndex;
_endShowIndex = _activeTabIndex + showTabCount - 1;
}
else
{
_endShowIndex = _activeTabIndex;
_beginShowIndex = _activeTabIndex - showTabCount + 1;
}
}
}
else
{
//先隐藏右边,不够的再隐藏左边
int tabCntAfterActive = _listTabItems.Count - (_activeTabIndex + 1);
if (tabCntAfterActive >= _hiddenTabsCount)
{
_beginShowIndex = 0;
_endShowIndex = _listTabItems.Count - 1 - _hiddenTabsCount;
}
else
{
_beginShowIndex = _hiddenTabsCount - tabCntAfterActive;
_endShowIndex = _activeTabIndex;
}
}
#endregion
// 再次把多出的空间重新分配给能显示的tab
int remainWidth = _hiddenTabsCount * (TabMinWidth + TabAndTabSpace) - neededWidth;
if (remainWidth > (_endShowIndex - _beginShowIndex + 1) * 3)
{
int average = remainWidth / (_endShowIndex - _beginShowIndex + 1);
for (int i = _beginShowIndex; i <= _endShowIndex; i++)
_listTabItems[i].FinalWidth += average;
}
#endregion
}
private void SetTabsVisibility()
{
for (int i = 0; i < _listTabItems.Count; i++)
{
if (i >= _beginShowIndex && i <= _endShowIndex)
_listTabItems[i].IsHidden = false;
else
_listTabItems[i].IsHidden = true;
}
}
private void SetTabsAndBarButtonBounds()
{
if (ListAllBtnAlign == BarButtonAlignmentType.Left)
{
SetListAllBtnBounds();
SetEachTabBounds();
SetNewTabBtnBounds();
}
else
{
SetEachTabBounds();
SetNewTabBtnBounds();
SetListAllBtnBounds();
}
SetHitTestBounds();
}
private void SetHitTestBounds()
{
int right = Bounds.Right - BarRightPadding;
if(ListAllBtnAlign != BarButtonAlignmentType.Left &&
(AlwaysShowListAllBtn || _hiddenTabsCount>0))
{
right = ListAllBtnBounds.Right;
}
else if (ShowNewTabBtn)
{
right = NewTabBtnBounds.Right;
}
else if (_listTabItems.Count > 0 && _endShowIndex < _listTabItems.Count)
{
right = _listTabItems[_endShowIndex].Bounds.Right;
}
int left = Bounds.Left + BarLeftPadding;
int width = right - left;
_hitTestBounds = new Rectangle(left, Bounds.Top, width, Bounds.Height);
}
private void SetEachTabBounds()
{
int x = Bounds.X + BarLeftPadding;
if (ListAllBtnAlign == BarButtonAlignmentType.Left)
{
if (AlwaysShowListAllBtn || _hiddenTabsCount > 0)
{
x = ListAllBtnBounds.Right + ListAllBtnLeftSpace;
}
}
if (_listTabItems.Count > 0)
{
for (int i = _beginShowIndex; i <= _endShowIndex; i++)
{
int height = _listTabItems[i].IsFormActive ? TabHeightActive : TabHeight;
int y = Bounds.Bottom - BarBottomRegionHeight - height;
int w = _listTabItems[i].FinalWidth;
_listTabItems[i].Bounds = new Rectangle(x, y, w, height);
x += (w + TabAndTabSpace);
}
}
}
private void SetNewTabBtnBounds()
{
int tabsCount = _listTabItems.Count;
int x;
if (tabsCount > 0 && _endShowIndex < tabsCount)
{
x = _listTabItems[_endShowIndex].Bounds.Right + NewTabBtnLeftSpace;
if (x > (Bounds.Right - BarRightPadding - NewTabBtnSize.Width))
x = Bounds.Right - BarRightPadding - NewTabBtnSize.Width;
if (x < Bounds.Left + BarLeftPadding)
x = Bounds.Left + BarLeftPadding;
}
else
{
x = Bounds.Left + BarLeftPadding;
if (ListAllBtnAlign == BarButtonAlignmentType.Left)
x = ListAllBtnBounds.Right + ListAllBtnLeftSpace;
}
int y = Bounds.Bottom - NewTabBtnBottomSpace - NewTabBtnSize.Height;
var size = ShowNewTabBtn ? NewTabBtnSize : Size.Empty;
if (size.Width > Bounds.Width)
size.Width = Bounds.Width;
NewTabBtnBounds = new Rectangle(new Point(x, y), size);
}
private void SetListAllBtnBounds()
{
int x;
if (ListAllBtnAlign == BarButtonAlignmentType.Left)
{
x = Bounds.X + BarLeftPadding;
}
else
{
x = NewTabBtnBounds.Right;
if (ShowNewTabBtn || _listTabItems.Count > 0)
x += ListAllBtnLeftSpace;
if (x > (Bounds.Right - BarRightPadding - ListAllBtnSize.Width))
x = Bounds.Right - BarRightPadding - ListAllBtnSize.Width;
}
int y = Bounds.Bottom - ListAllBtnBottomSpace - ListAllBtnSize.Height;
var size = ((_hiddenTabsCount>0 || AlwaysShowListAllBtn) ? ListAllBtnSize : Size.Empty);
if (size.Width > Bounds.Width)
size.Width = Bounds.Width;
ListAllBtnBounds = new Rectangle(new Point(x, y), size);
}
private void RenderEachBarItem(Graphics g)
{
Region oldClip = g.Clip;
Region newClip = new Region(Bounds);
g.Clip = newClip;
SmoothingMode oldMode = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
DrawBarBorderAndBackground(g);
DrawEachTabItem(g);
DrawOtherBarButtons(g);
DrawBarBottomRegion(g);
g.SmoothingMode = oldMode;
g.Clip = oldClip;
newClip.Dispose();
}
private void DrawBarBorderAndBackground(Graphics g)
{
Rectangle rect = Bounds;
if (DrawBarBackgound)
{
using (SolidBrush sb = new SolidBrush(BarBackColor))
{
g.FillRectangle(sb, rect);
}
}
if (DrawBarBorder)
{
rect.Width--;
rect.Height--;
using (Pen p = new Pen(BarBorderColor))
{
g.DrawRectangle(p, rect);
}
}
}
private void DrawBarBottomRegion(Graphics g)
{
// bottom region
using (SolidBrush sb = new SolidBrush(BarBottomRegionBackColor))
{
using (NewSmoothModeGraphics newGP = new NewSmoothModeGraphics(g, SmoothingMode.HighSpeed))
{
g.FillRectangle(sb, BarBottomRegionBounds);
}
}
}
private void DrawOtherBarButtons(Graphics g)
{
// new-tab-btn
if (ShowNewTabBtn)
{
_newTabBtn.Bounds = NewTabBtnBounds;
_newTabBtn.DrawButton(g);
}
// list-all-btn
if (_hiddenTabsCount > 0 || AlwaysShowListAllBtn)
{
_listAllBtn.Bounds = ListAllBtnBounds;
if (_hiddenTabsCount == 0)
_listAllBtn.Text = string.Empty;
else
_listAllBtn.Text = _hiddenTabsCount.ToString();
_listAllBtn.DrawButton(g);
}
}
private void DrawEachTabItem(Graphics g)
{
foreach (MdiGMTabItem tab in _listTabItems)
{
if (!tab.IsHidden && !tab.IsFormActive)
RenderTabItem(g, tab);
}
// active-tab last
if (_listTabItems.Count > 0)
RenderTabItem(g, _listTabItems[_activeTabIndex]);
}
private void RenderTabItem(Graphics g, MdiGMTabItem tab)
{
Rectangle rect = tab.Bounds;
Region oldRegion = g.Clip;
Region newRegion = new Region(rect);
g.Clip = newRegion;
// fill backgroung
Color backTop,backBottom;
if (tab.IsFormActive)
{
backTop = TabActiveBackColorTop;
backBottom = TabActiveBackColorBottom;
}
else
{
backTop = TabDeactiveBackColorTop;
backBottom = TabDeactiveBackColorBottom;
}
// background
using (LinearGradientBrush lb = new LinearGradientBrush(
rect, backTop, backBottom, LinearGradientMode.Vertical))
{
using (GraphicsPath path = PathGetter.GetTabBorderPath(rect, TabSlopeWidth))
{
g.FillPath(lb, path);
}
}
// icon
if (ShowTabIcon && tab.Form.Icon != null)
{
if (tab.IconRect.Right < tab.Bounds.Right)
g.DrawIcon(tab.Form.Icon, tab.IconRect);
}
if (tab.IsFormActive)
{
// text
TextRenderer.DrawText(g, tab.Form.Text, tab.Form.Font, tab.TextRect,TabActiveForeColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
}
else
{
TextRenderer.DrawText(g, tab.Form.Text, tab.Form.Font, tab.TextRect, TabDeactiveForeColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
}
// outter border
rect.Width--;
rect.Height--;
if (TabShowBorder)
{
using (Pen p = new Pen(TabOutterBorderColor))
{
if (tab.IsFormActive)
{
Rectangle rectTab = tab.Bounds;
Rectangle rectBottom = BarBottomRegionBounds;
Point p1 = new Point(rectBottom.X, rectBottom.Y - 1);
Point p2 = new Point(rectTab.X, rectTab.Bottom - 1);
Point p3 = new Point(rectTab.X + TabSlopeWidth, rectTab.Y);
Point p4 = new Point(rectTab.Right - 1 - TabSlopeWidth, rectTab.Y);
Point p5 = new Point(rectTab.Right - 1, rectTab.Bottom - 1);
Point p6 = new Point(rectBottom.Right - 1, rectBottom.Y - 1);
g.Clip = oldRegion;
//g.DrawLines(p, new Point[] { p1, p2, p3, p4, p5, p6 });
g.Clip = newRegion;
}
else
{
using (GraphicsPath path = PathGetter.GetTabBorderPath(rect, TabSlopeWidth))
{
//g.DrawPath(p, path);
}
}
}
}
// inner border
rect.Inflate(-1, -1);
rect.Height++; // 为了使bar-bottom-region 与 active-tab 的连线能覆盖非 active-tab 的底部的线
if (TabShowBorder)
{
using (Pen p = new Pen(TabInnerBorderColor))
{
using (GraphicsPath path = PathGetter.GetTabBorderPath(rect, TabSlopeWidth))
{
g.DrawPath(p, path);
}
}
}
// do not let the active-tab to have bottom-line
if (tab.IsFormActive)
{
Rectangle rtmp = tab.Bounds;
Point p1 = new Point(rtmp.Left + 1, rtmp.Bottom - 1);
Point p2 = new Point(rtmp.Right - 2, rtmp.Bottom - 1);
using (Pen pen = new Pen(backBottom))
{
g.DrawLine(pen, p1, p2);
}
}
if (ShowTabCloseIcon)
{
//close btn
tab.CloseBtn.Bounds = tab.CloseBtnRect;
tab.CloseBtn.DrawButton(g);
}
g.Clip = oldRegion;
newRegion.Dispose();
}
#region mouse operation
private void MouseOperationDown(Point location)
{
foreach (MdiGMTabItem tab in _listTabItems)
{
if (!tab.IsHidden)
{
if (tab.Bounds.Contains(location) && !tab.CloseBtnRect.Contains(location))
{
tab.Capture = true;
break;
}
}
}
}
private void MouseOperationUp(Point location)
{
foreach (MdiGMTabItem tab in _listTabItems)
{
if (!tab.IsHidden)
{
if (tab.Capture && tab.Bounds.Contains(location))
{
tab.Capture = false;
OnActivateChild(tab.Form);
//break;
}
}
tab.Capture = false;
}
}
#endregion
#endregion
#region public method
/// <summary>
/// 重绘整个标签栏
/// </summary>
/// <param name="g"></param>
public void RenderTheBar(Graphics g)
{
// 先把已关闭的form对应的tab删除对新加的form则为其创建相应tab
CheckTabItemsWithOwnerMdiForm();
if (_listTabItems.Count > 0)
{
// 按照指定方式为每个tab分配空间
CalculateSpaceForEachTab();
SetTabsVisibility();
}
SetTabsAndBarButtonBounds();
RenderEachBarItem(g);
if (ShowNewTabBtn)
{
if (_lastMouseUpLocation != Point.Empty)
{
//gdu debug: currently we need this to set the btn back to normal
if (!NewTabBtnBounds.Contains(_lastMouseUpLocation)
&& _newTabBtn.State == GMButtonState.Hover)
_newTabBtn.MouseOperation(_lastMouseUpLocation, MouseOperationType.Move);
}
}
}
/// <summary>
/// 处理鼠标事件。该方法会触发一些click事件重刷一些按钮等
/// </summary>
/// <param name="location"></param>
/// <param name="type"></param>
public void MouseOperation(Point location, MouseOperationType type)
{
//if (type == MouseOperationType.Up)
_lastMouseUpLocation = location;
//else
// _lastMouseUpLocation = Point.Empty;
if (ShowNewTabBtn)
_newTabBtn.MouseOperation(location, type);
if (_hiddenTabsCount > 0 || AlwaysShowListAllBtn)
_listAllBtn.MouseOperation(location, type);
foreach (MdiGMTabItem tab in _listTabItems)
{
if (!tab.IsHidden)
{
if (ShowTabCloseIcon)
{ tab.CloseBtn.MouseOperation(location, type); }
}
}
switch (type)
{
case MouseOperationType.Down:
MouseOperationDown(location);
break;
case MouseOperationType.Up:
MouseOperationUp(location);
break;
}
}
#endregion
}
/// <summary>
/// 该类表示一个单独的标签项
/// </summary>
internal class MdiGMTabItem
{
#region
#endregion
// mdi bar which this tab item is belong to
MdiBarController _barContainer;
public MdiGMTabItem(MdiBarController barContainer)
{
_barContainer = barContainer;
IsStillValid = true;
}
/// <summary>
/// 该标签所对应的窗体
/// </summary>
public Form Form { get; set; }
public bool IsFormActive { get; set; }
/// <summary>
/// 最终分配到的整个tab的宽度
/// </summary>
public int FinalWidth { get; set; }
/// <summary>
/// 表示所对应的form是否仍未被关闭
/// </summary>
public bool IsStillValid { get; set; }
public Rectangle Bounds { get; set; }
public WLButton CloseBtn { get; set; }
public bool Capture { get; set; }
/// <summary>
/// 是否因空间不足而被隐藏
/// </summary>
public bool IsHidden { get; set; }
public ToolStripMenuItem MenuItemPop { get; set; }
public Rectangle IconRect
{
get
{
return new Rectangle(
Bounds.Left + _barContainer.IconLeftSpace,
Bounds.Top + (Bounds.Height - _barContainer.IconSize.Height) / 2,
_barContainer.IconSize.Width,
_barContainer.IconSize.Height);
}
}
public Rectangle TextRect
{
get
{
int x = IconRect.Right + _barContainer.TextLeftSpace;
int w = CloseBtnRect.Left - x;
if (w < 0)
w = 0;
return new Rectangle(x, Bounds.Top, w, Bounds.Height);
}
}
public Rectangle CloseBtnRect
{
get
{
return new Rectangle(
Bounds.Right - _barContainer.TabCloseBtnRightSpace - _barContainer.TabCloseBtnSize.Width,
Bounds.Top + (Bounds.Height - _barContainer.TabCloseBtnSize.Height) / 2,
_barContainer.TabCloseBtnSize.Width,
_barContainer.TabCloseBtnSize.Height);
}
}
/// <summary>
/// 返回全部显示该标签文本所需的长度
/// </summary>
/// <returns></returns>
private int GetFullTextLength()
{
if (string.IsNullOrEmpty(Form.Text))
return 0;
return TextRenderer.MeasureText(Form.Text, Form.Font).Width;
}
/// <summary>
/// 返回显示全部文本时该tab所需的宽度,该宽度不超过bar-container
/// 规定的tabmaxwidth
/// </summary>
/// <returns></returns>
public int GetFullShowTabWidth()
{
int w = _barContainer.TabSlopeWidth * 2 + _barContainer.IconSize.Width
+ _barContainer.IconLeftSpace + _barContainer.TabCloseBtnSize.Width
+ _barContainer.TabCloseBtnRightSpace + GetFullTextLength();
if (w > _barContainer.TabMaxWidth)
w = _barContainer.TabMaxWidth;
return w;
}
}
public enum BarButtonAlignmentType
{
/// <summary>
/// 居左
/// </summary>
Left,
/// <summary>
/// 显示在最后一个标签后面
/// </summary>
AfterLastTab,
}
internal static class PathGetter
{
public static GraphicsPath GetTabBorderPath(Rectangle rect, int slopeWidth)
{
GraphicsPath path = new GraphicsPath();
Point p1 = new Point(rect.X + slopeWidth, rect.Y);
Point p2 = new Point(rect.Right - slopeWidth, rect.Y);
Point p3 = new Point(rect.Right, rect.Bottom);
Point p4 = new Point(rect.X, rect.Bottom);
path.AddLine(p1, p2);
path.AddLine(p3, p4);
path.CloseFigure();
return path;
}
}
}