/* GWEN Copyright (c) 2010 Facepunch Studios See license in Gwen.h */ #include "Gwen/Gwen.h" #include "Gwen/Skin.h" #include "Gwen/Controls/TabControl.h" #include "Gwen/Controls/Highlight.h" #include "Gwen/DragAndDrop.h" #include "Gwen/Controls/WindowControl.h" #include "Gwen/Controls/ScrollBarButton.h" namespace Gwen { namespace Controls { class TabControlInner : public Base { public: GWEN_CONTROL_INLINE(TabControlInner, Base) { m_ButtonRect = Gwen::Rect(0, 0, 0, 0); } void Render(Skin::Base* skin) { skin->DrawTabControl(this, m_ButtonRect); } void UpdateCurrentButton(Gwen::Rect rct) { m_ButtonRect = rct; } Gwen::Rect m_ButtonRect; }; }; // namespace Controls }; // namespace Gwen using namespace Gwen; using namespace Gwen::Controls; GWEN_CONTROL_CONSTRUCTOR(TabControl) { m_iScrollOffset = 0; m_pCurrentButton = NULL; m_TabStrip = new TabStrip(this); m_TabStrip->Dock(Pos::Top); m_TabStrip->SetWidth(100); m_TabStrip->SetHeight(20); // Make this some special control? m_pScroll[0] = new ControlsInternal::ScrollBarButton(this); m_pScroll[0]->SetDirectionLeft(); m_pScroll[0]->onPress.Add(this, &TabControl::ScrollPressLeft); m_pScroll[0]->SetSize(14, 16); m_pScroll[1] = new ControlsInternal::ScrollBarButton(this); m_pScroll[1]->SetDirectionRight(); m_pScroll[1]->onPress.Add(this, &TabControl::ScrollPressRight); m_pScroll[1]->SetSize(14, 16); m_InnerPanel = new TabControlInner(this); m_InnerPanel->Dock(Pos::Fill); SetTabable(false); } TabButton* TabControl::AddPage(const UnicodeString& strText, Controls::Base* pPage) { if (!pPage) { pPage = new Base(this); } else { pPage->SetParent(this); } TabButton* pButton = new TabButton(m_TabStrip); pButton->SetText(strText); pButton->SetPage(pPage); pButton->SetTabable(false); AddPage(pButton); return pButton; } void TabControl::AddPage(TabButton* pButton) { Base* pPage = pButton->GetPage(); pPage->SetParent(this); pPage->SetHidden(true); pPage->SetMargin(Margin(6, 6, 6, 6)); pPage->Dock(Pos::Fill); pButton->SetParent(m_TabStrip); pButton->Dock(Pos::Left); pButton->SizeToContents(); if (pButton->GetTabControl()) pButton->onPress.RemoveHandler(pButton->GetTabControl()); pButton->SetTabControl(this); pButton->onPress.Add(this, &TabControl::OnTabPressed); if (!m_pCurrentButton) { pButton->OnPress(); } onAddTab.Call(this); Invalidate(); } void TabControl::OnTabPressed(Controls::Base* control) { if (!control) return; TabButton* pButton = control->DynamicCastTabButton(); if (!pButton) return; Base* pPage = pButton->GetPage(); if (!pPage) return; if (m_pCurrentButton == pButton) return; if (m_pCurrentButton) { Base* pPage = m_pCurrentButton->GetPage(); if (pPage) { pPage->SetHidden(true); } m_pCurrentButton = NULL; } m_pCurrentButton = pButton; pPage->SetHidden(false); m_TabStrip->Invalidate(); Invalidate(); } void TabControl::PostLayout(Skin::Base* skin) { BaseClass::PostLayout(skin); HandleOverflow(); if (m_TabStrip->Hidden()) { m_InnerPanel->DynamicCastTabControlInner()->UpdateCurrentButton(Gwen::Rect(0, 0, 0, 0)); } else if (m_pCurrentButton) { Gwen::Rect rct; Gwen::Point p = m_pCurrentButton->LocalPosToCanvas(Gwen::Point(0, 0)); p = m_InnerPanel->CanvasPosToLocal(p); rct = Gwen::Rect(p.x + 1, p.y + 1, m_pCurrentButton->Width() - 2, m_pCurrentButton->Height() - 2); m_InnerPanel->DynamicCastTabControlInner()->UpdateCurrentButton(rct); } } void TabControl::OnLoseTab(TabButton* pButton) { if (m_pCurrentButton == pButton) m_pCurrentButton = NULL; //TODO: Select a tab if any exist. onLoseTab.Call(this); Invalidate(); } int TabControl::TabCount(void) { return m_TabStrip->NumChildren(); } void TabControl::SetTabStripPosition(int iDock) { m_TabStrip->SetTabPosition(iDock); } bool TabControl::DoesAllowDrag() { return m_TabStrip->AllowsTabReorder(); } void TabControl::HandleOverflow() { Gwen::Point TabsSize = m_TabStrip->ChildrenSize(); // 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 bNeeded = TabsSize.x > Width() && m_TabStrip->GetDock() == Pos::Top; m_pScroll[0]->SetHidden(!bNeeded); m_pScroll[1]->SetHidden(!bNeeded); if (!bNeeded) return; m_iScrollOffset = Gwen::Clamp(m_iScrollOffset, 0, TabsSize.x - Width() + 32); #if 0 // // This isn't frame rate independent. // Could be better. Get rid of m_iScrollOffset 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->SetMargin(Margin(m_iScrollOffset * -1, 0, 0, 0)); #endif m_pScroll[0]->SetPos(Width() - 30, 5); m_pScroll[1]->SetPos(m_pScroll[0]->Right(), 5); } void TabControl::ScrollPressLeft(Base* pFrom) { m_iScrollOffset -= 120; } void TabControl::ScrollPressRight(Base* pFrom) { m_iScrollOffset += 120; }