using System; using System.Drawing; using Gwen.ControlInternal; namespace Gwen.Control { /// /// Control with multiple tabs that can be reordered and dragged. /// public class TabControl : Base { private readonly TabStrip m_TabStrip; private readonly ScrollBarButton[] m_Scroll; private TabButton m_CurrentButton; private int m_ScrollOffset; /// /// Invoked when a tab has been added. /// public event GwenEventHandler TabAdded; /// /// Invoked when a tab has been removed. /// public event GwenEventHandler TabRemoved; /// /// Determines if tabs can be reordered by dragging. /// public bool AllowReorder { get { return m_TabStrip.AllowReorder; } set { m_TabStrip.AllowReorder = value; } } /// /// Currently active tab button. /// public TabButton CurrentButton { get { return m_CurrentButton; } } /// /// Current tab strip position. /// public Pos TabStripPosition { get { return m_TabStrip.StripPosition; }set { m_TabStrip.StripPosition = value; } } /// /// Tab strip. /// public TabStrip TabStrip { get { return m_TabStrip; } } /// /// Initializes a new instance of the class. /// /// Parent control. 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; } /// /// Adds a new page/tab. /// /// Tab label. /// Page contents. /// Newly created control. 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; } /// /// Adds a page/tab. /// /// Page to add. (well, it's a TabButton which is a parent to the page). 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; } /// /// Handler for tab selection. /// /// Event source (TabButton). 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(); } /// /// Function invoked after layout. /// /// Skin to use. protected override void PostLayout(Skin.Base skin) { base.PostLayout(skin); HandleOverflow(); } /// /// Handler for tab removing. /// /// 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(); } /// /// Number of tabs in the control. /// 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; } } }