1 /*
2 	GWEN
3 	Copyright (c) 2010 Facepunch Studios
4 	See license in Gwen.h
5 */
6 
7 #include "Gwen/Gwen.h"
8 #include "Gwen/Skin.h"
9 #include "Gwen/Controls/TabControl.h"
10 #include "Gwen/Controls/Highlight.h"
11 #include "Gwen/DragAndDrop.h"
12 #include "Gwen/Controls/WindowControl.h"
13 #include "Gwen/Controls/ScrollBarButton.h"
14 
15 namespace Gwen
16 {
17 namespace Controls
18 {
19 class TabControlInner : public Base
20 {
21 public:
GWEN_CONTROL_INLINE(TabControlInner,Base)22 	GWEN_CONTROL_INLINE(TabControlInner, Base)
23 	{
24 		m_ButtonRect = Gwen::Rect(0, 0, 0, 0);
25 	}
26 
Render(Skin::Base * skin)27 	void Render(Skin::Base* skin)
28 	{
29 		skin->DrawTabControl(this, m_ButtonRect);
30 	}
31 
UpdateCurrentButton(Gwen::Rect rct)32 	void UpdateCurrentButton(Gwen::Rect rct)
33 	{
34 		m_ButtonRect = rct;
35 	}
36 
37 	Gwen::Rect m_ButtonRect;
38 };
39 };  // namespace Controls
40 };  // namespace Gwen
41 
42 using namespace Gwen;
43 using namespace Gwen::Controls;
44 
GWEN_CONTROL_CONSTRUCTOR(TabControl)45 GWEN_CONTROL_CONSTRUCTOR(TabControl)
46 {
47 	m_iScrollOffset = 0;
48 
49 	m_pCurrentButton = NULL;
50 
51 	m_TabStrip = new TabStrip(this);
52 	m_TabStrip->Dock(Pos::Top);
53 	m_TabStrip->SetWidth(100);
54 	m_TabStrip->SetHeight(20);
55 
56 	// Make this some special control?
57 	m_pScroll[0] = new ControlsInternal::ScrollBarButton(this);
58 	m_pScroll[0]->SetDirectionLeft();
59 	m_pScroll[0]->onPress.Add(this, &TabControl::ScrollPressLeft);
60 	m_pScroll[0]->SetSize(14, 16);
61 
62 	m_pScroll[1] = new ControlsInternal::ScrollBarButton(this);
63 	m_pScroll[1]->SetDirectionRight();
64 	m_pScroll[1]->onPress.Add(this, &TabControl::ScrollPressRight);
65 	m_pScroll[1]->SetSize(14, 16);
66 
67 	m_InnerPanel = new TabControlInner(this);
68 	m_InnerPanel->Dock(Pos::Fill);
69 
70 	SetTabable(false);
71 }
72 
AddPage(const UnicodeString & strText,Controls::Base * pPage)73 TabButton* TabControl::AddPage(const UnicodeString& strText, Controls::Base* pPage)
74 {
75 	if (!pPage)
76 	{
77 		pPage = new Base(this);
78 	}
79 	else
80 	{
81 		pPage->SetParent(this);
82 	}
83 
84 	TabButton* pButton = new TabButton(m_TabStrip);
85 	pButton->SetText(strText);
86 	pButton->SetPage(pPage);
87 	pButton->SetTabable(false);
88 
89 	AddPage(pButton);
90 	return pButton;
91 }
92 
AddPage(TabButton * pButton)93 void TabControl::AddPage(TabButton* pButton)
94 {
95 	Base* pPage = pButton->GetPage();
96 	pPage->SetParent(this);
97 	pPage->SetHidden(true);
98 	pPage->SetMargin(Margin(6, 6, 6, 6));
99 	pPage->Dock(Pos::Fill);
100 
101 	pButton->SetParent(m_TabStrip);
102 	pButton->Dock(Pos::Left);
103 	pButton->SizeToContents();
104 	if (pButton->GetTabControl()) pButton->onPress.RemoveHandler(pButton->GetTabControl());
105 	pButton->SetTabControl(this);
106 	pButton->onPress.Add(this, &TabControl::OnTabPressed);
107 
108 	if (!m_pCurrentButton)
109 	{
110 		pButton->OnPress();
111 	}
112 
113 	onAddTab.Call(this);
114 
115 	Invalidate();
116 }
117 
OnTabPressed(Controls::Base * control)118 void TabControl::OnTabPressed(Controls::Base* control)
119 {
120 	if (!control)
121 		return;
122 
123 	TabButton* pButton = control->DynamicCastTabButton();
124 	if (!pButton) return;
125 
126 	Base* pPage = pButton->GetPage();
127 	if (!pPage) return;
128 
129 	if (m_pCurrentButton == pButton)
130 		return;
131 
132 	if (m_pCurrentButton)
133 	{
134 		Base* pPage = m_pCurrentButton->GetPage();
135 		if (pPage)
136 		{
137 			pPage->SetHidden(true);
138 		}
139 		m_pCurrentButton = NULL;
140 	}
141 
142 	m_pCurrentButton = pButton;
143 
144 	pPage->SetHidden(false);
145 
146 	m_TabStrip->Invalidate();
147 	Invalidate();
148 }
149 
PostLayout(Skin::Base * skin)150 void TabControl::PostLayout(Skin::Base* skin)
151 {
152 	BaseClass::PostLayout(skin);
153 
154 	HandleOverflow();
155 
156 	if (m_TabStrip->Hidden())
157 	{
158 		m_InnerPanel->DynamicCastTabControlInner()->UpdateCurrentButton(Gwen::Rect(0, 0, 0, 0));
159 	}
160 	else if (m_pCurrentButton)
161 	{
162 		Gwen::Rect rct;
163 
164 		Gwen::Point p = m_pCurrentButton->LocalPosToCanvas(Gwen::Point(0, 0));
165 		p = m_InnerPanel->CanvasPosToLocal(p);
166 
167 		rct = Gwen::Rect(p.x + 1, p.y + 1, m_pCurrentButton->Width() - 2, m_pCurrentButton->Height() - 2);
168 		m_InnerPanel->DynamicCastTabControlInner()->UpdateCurrentButton(rct);
169 	}
170 }
171 
OnLoseTab(TabButton * pButton)172 void TabControl::OnLoseTab(TabButton* pButton)
173 {
174 	if (m_pCurrentButton == pButton)
175 		m_pCurrentButton = NULL;
176 
177 	//TODO: Select a tab if any exist.
178 
179 	onLoseTab.Call(this);
180 
181 	Invalidate();
182 }
183 
TabCount(void)184 int TabControl::TabCount(void)
185 {
186 	return m_TabStrip->NumChildren();
187 }
188 
SetTabStripPosition(int iDock)189 void TabControl::SetTabStripPosition(int iDock)
190 {
191 	m_TabStrip->SetTabPosition(iDock);
192 }
193 
DoesAllowDrag()194 bool TabControl::DoesAllowDrag()
195 {
196 	return m_TabStrip->AllowsTabReorder();
197 }
198 
HandleOverflow()199 void TabControl::HandleOverflow()
200 {
201 	Gwen::Point TabsSize = m_TabStrip->ChildrenSize();
202 
203 	// Only enable the scrollers if the tabs are at the top.
204 	// This is a limitation we should explore.
205 	// Really TabControl should have derivitives for tabs placed elsewhere where we could specialize
206 	// some functions like this for each direction.
207 	bool bNeeded = TabsSize.x > Width() && m_TabStrip->GetDock() == Pos::Top;
208 
209 	m_pScroll[0]->SetHidden(!bNeeded);
210 	m_pScroll[1]->SetHidden(!bNeeded);
211 
212 	if (!bNeeded) return;
213 
214 	m_iScrollOffset = Gwen::Clamp(m_iScrollOffset, 0, TabsSize.x - Width() + 32);
215 
216 #if 0
217 		//
218 		// This isn't frame rate independent.
219 		// Could be better. Get rid of m_iScrollOffset and just use m_TabStrip->GetMargin().left ?
220 		// Then get a margin animation type and do it properly!
221 		// TODO!
222 		//
223 		m_TabStrip->SetMargin( Margin( Gwen::Approach( m_TabStrip->GetMargin().left, m_iScrollOffset * -1, 2 ), 0, 0, 0 ) );
224 		InvalidateParent();
225 #else
226 	m_TabStrip->SetMargin(Margin(m_iScrollOffset * -1, 0, 0, 0));
227 #endif
228 
229 	m_pScroll[0]->SetPos(Width() - 30, 5);
230 	m_pScroll[1]->SetPos(m_pScroll[0]->Right(), 5);
231 }
232 
ScrollPressLeft(Base * pFrom)233 void TabControl::ScrollPressLeft(Base* pFrom)
234 {
235 	m_iScrollOffset -= 120;
236 }
237 
ScrollPressRight(Base * pFrom)238 void TabControl::ScrollPressRight(Base* pFrom)
239 {
240 	m_iScrollOffset += 120;
241 }