This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
gwen-dotnet/Gwen/Control/TabControl.cs

251 lines
7.4 KiB
C#
Raw Normal View History

using System;
//using System.Drawing;
using Gwen.ControlInternal;
namespace Gwen.Control
{
/// <summary>
/// Control with multiple tabs that can be reordered and dragged.
/// </summary>
public class TabControl : Base
{
private readonly TabStrip m_TabStrip;
private readonly ScrollBarButton[] m_Scroll;
private TabButton m_CurrentButton;
private int m_ScrollOffset;
/// <summary>
/// Invoked when a tab has been added.
/// </summary>
public event GwenEventHandler TabAdded;
/// <summary>
/// Invoked when a tab has been removed.
/// </summary>
public event GwenEventHandler TabRemoved;
/// <summary>
/// Determines if tabs can be reordered by dragging.
/// </summary>
public bool AllowReorder { get { return m_TabStrip.AllowReorder; } set { m_TabStrip.AllowReorder = value; } }
/// <summary>
/// Currently active tab button.
/// </summary>
public TabButton CurrentButton { get { return m_CurrentButton; } }
/// <summary>
/// Current tab strip position.
/// </summary>
public Pos TabStripPosition { get { return m_TabStrip.StripPosition; }set { m_TabStrip.StripPosition = value; } }
/// <summary>
/// Tab strip.
/// </summary>
public TabStrip TabStrip { get { return m_TabStrip; } }
/// <summary>
/// Initializes a new instance of the <see cref="TabControl"/> class.
/// </summary>
/// <param name="parent">Parent control.</param>
public TabControl(Base parent)
: base(parent)
{
m_Scroll = new ScrollBarButton[2];
m_ScrollOffset = 0;
m_TabStrip = new TabStrip(this);
m_TabStrip.StripPosition = Pos.Top;
// Make this some special control?
m_Scroll[0] = new ScrollBarButton(this);
m_Scroll[0].SetDirectionLeft();
m_Scroll[0].Clicked += ScrollPressedLeft;
m_Scroll[0].SetSize(14, 16);
m_Scroll[1] = new ScrollBarButton(this);
m_Scroll[1].SetDirectionRight();
m_Scroll[1].Clicked += ScrollPressedRight;
m_Scroll[1].SetSize(14, 16);
m_InnerPanel = new TabControlInner(this);
m_InnerPanel.Dock = Pos.Fill;
m_InnerPanel.SendToBack();
IsTabable = false;
}
/// <summary>
/// Adds a new page/tab.
/// </summary>
/// <param name="label">Tab label.</param>
/// <param name="page">Page contents.</param>
/// <returns>Newly created control.</returns>
public TabButton AddPage(String label, Base page = null)
{
if (null == page)
{
page = new Base(this);
}
else
{
page.Parent = this;
}
TabButton button = new TabButton(m_TabStrip);
button.SetText(label);
button.Page = page;
button.IsTabable = false;
AddPage(button);
return button;
}
/// <summary>
/// Adds a page/tab.
/// </summary>
/// <param name="button">Page to add. (well, it's a TabButton which is a parent to the page).</param>
public void AddPage(TabButton button)
{
Base page = button.Page;
page.Parent = this;
page.IsHidden = true;
page.Margin = new Margin(6, 6, 6, 6);
page.Dock = Pos.Fill;
button.Parent = m_TabStrip;
button.Dock = Pos.Left;
button.SizeToContents();
if (button.TabControl != null)
button.TabControl.UnsubscribeTabEvent(button);
button.TabControl = this;
button.Clicked += OnTabPressed;
if (null == m_CurrentButton)
{
button.Press();
}
if (TabAdded != null)
TabAdded.Invoke(this);
Invalidate();
}
private void UnsubscribeTabEvent(TabButton button)
{
button.Clicked -= OnTabPressed;
}
/// <summary>
/// Handler for tab selection.
/// </summary>
/// <param name="control">Event source (TabButton).</param>
internal virtual void OnTabPressed(Base control)
{
TabButton button = control as TabButton;
if (null == button) return;
Base page = button.Page;
if (null == page) return;
if (m_CurrentButton == button)
return;
if (null != m_CurrentButton)
{
Base page2 = m_CurrentButton.Page;
if (page2 != null)
{
page2.IsHidden = true;
}
m_CurrentButton.Redraw();
m_CurrentButton = null;
}
m_CurrentButton = button;
page.IsHidden = false;
m_TabStrip.Invalidate();
Invalidate();
}
/// <summary>
/// Function invoked after layout.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected override void PostLayout(Skin.Base skin)
{
base.PostLayout(skin);
HandleOverflow();
}
/// <summary>
/// Handler for tab removing.
/// </summary>
/// <param name="button"></param>
internal virtual void OnLoseTab(TabButton button)
{
if (m_CurrentButton == button)
m_CurrentButton = null;
//TODO: Select a tab if any exist.
if (TabRemoved != null)
TabRemoved.Invoke(this);
Invalidate();
}
/// <summary>
/// Number of tabs in the control.
/// </summary>
public int TabCount { get { return m_TabStrip.Children.Count; } }
private void HandleOverflow()
{
Point TabsSize = m_TabStrip.GetChildrenSize();
// Only enable the scrollers if the tabs are at the top.
// This is a limitation we should explore.
// Really TabControl should have derivitives for tabs placed elsewhere where we could specialize
// some functions like this for each direction.
bool needed = TabsSize.X > Width && m_TabStrip.Dock == Pos.Top;
m_Scroll[0].IsHidden = !needed;
m_Scroll[1].IsHidden = !needed;
if (!needed) return;
m_ScrollOffset = Util.Clamp(m_ScrollOffset, 0, TabsSize.X - Width + 32);
#if false
//
// This isn't frame rate independent.
// Could be better. Get rid of m_ScrollOffset and just use m_TabStrip.GetMargin().left ?
// Then get a margin animation type and do it properly!
// TODO!
//
m_TabStrip.SetMargin( Margin( Gwen::Approach( m_TabStrip.GetMargin().left, m_iScrollOffset * -1, 2 ), 0, 0, 0 ) );
InvalidateParent();
#else
m_TabStrip.Margin = new Margin(m_ScrollOffset*-1, 0, 0, 0);
#endif
m_Scroll[0].SetPosition(Width - 30, 5);
m_Scroll[1].SetPosition(m_Scroll[0].Right, 5);
}
protected virtual void ScrollPressedLeft(Base control)
{
m_ScrollOffset -= 120;
}
protected virtual void ScrollPressedRight(Base control)
{
m_ScrollOffset += 120;
}
}
}