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 }