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/DockBase.h"
10 #include "Gwen/Controls/DockedTabControl.h"
11 #include "Gwen/Controls/Highlight.h"
12 #include "Gwen/DragAndDrop.h"
13 #include "Gwen/Controls/Resizer.h"
14
15 using namespace Gwen;
16 using namespace Gwen::Controls;
17
GWEN_CONTROL_CONSTRUCTOR(DockBase)18 GWEN_CONTROL_CONSTRUCTOR(DockBase)
19 {
20 SetPadding(Padding(1, 1, 1, 1));
21 SetSize(200, 200);
22
23 m_DockedTabControl = NULL;
24 m_Left = NULL;
25 m_Right = NULL;
26 m_Top = NULL;
27 m_Bottom = NULL;
28
29 m_bDrawHover = false;
30 }
31
GetTabControl()32 TabControl* DockBase::GetTabControl()
33 {
34 return m_DockedTabControl;
35 }
36
SetupChildDock(int iPos)37 void DockBase::SetupChildDock(int iPos)
38 {
39 if (!m_DockedTabControl)
40 {
41 m_DockedTabControl = new DockedTabControl(this);
42 m_DockedTabControl->onLoseTab.Add(this, &DockBase::OnTabRemoved);
43 m_DockedTabControl->SetTabStripPosition(Pos::Bottom);
44 m_DockedTabControl->SetShowTitlebar(true);
45 }
46
47 Dock(iPos);
48
49 int iSizeDirection = Pos::Left;
50 if (iPos == Pos::Left) iSizeDirection = Pos::Right;
51 if (iPos == Pos::Top) iSizeDirection = Pos::Bottom;
52 if (iPos == Pos::Bottom) iSizeDirection = Pos::Top;
53
54 ControlsInternal::Resizer* sizer = new ControlsInternal::Resizer(this);
55 sizer->Dock(iSizeDirection);
56 sizer->SetResizeDir(iSizeDirection);
57 sizer->SetSize(2, 2);
58 sizer->SetTarget(this);
59 }
60
Render(Skin::Base *)61 void DockBase::Render(Skin::Base* /*skin*/)
62 {
63 //Gwen::Render->SetDrawColor( Colors::Black );
64 //Gwen::Render->DrawLinedRect( GetRenderBounds() );
65 }
66
GetChildDockPtr(int iPos)67 DockBase** DockBase::GetChildDockPtr(int iPos)
68 {
69 if (iPos == Pos::Left) return &m_Left;
70 if (iPos == Pos::Right) return &m_Right;
71 if (iPos == Pos::Top) return &m_Top;
72 if (iPos == Pos::Bottom) return &m_Bottom;
73
74 return NULL;
75 }
76
GetChildDock(int iPos)77 DockBase* DockBase::GetChildDock(int iPos)
78 {
79 DockBase** pDock = GetChildDockPtr(iPos);
80
81 if (!(*pDock))
82 {
83 (*pDock) = new DockBase(this);
84 (*pDock)->SetupChildDock(iPos);
85 }
86 else
87 {
88 (*pDock)->SetHidden(false);
89 }
90
91 return *pDock;
92 }
93
GetDroppedTabDirection(int x,int y)94 int DockBase::GetDroppedTabDirection(int x, int y)
95 {
96 int w = Width();
97 int h = Height();
98
99 float top = (float)y / (float)h;
100 float left = (float)x / (float)w;
101 float right = (float)(w - x) / (float)w;
102 float bottom = (float)(h - y) / (float)h;
103
104 float minimum = GwenUtil_Min(GwenUtil_Min(GwenUtil_Min(top, left), right), bottom);
105 m_bDropFar = (minimum < 0.2f);
106 if (minimum > 0.3) return Pos::Fill;
107
108 if (top == minimum && (!m_Top || m_Top->Hidden())) return Pos::Top;
109 if (left == minimum && (!m_Left || m_Left->Hidden())) return Pos::Left;
110 if (right == minimum && (!m_Right || m_Right->Hidden())) return Pos::Right;
111 if (bottom == minimum && (!m_Bottom || m_Bottom->Hidden())) return Pos::Bottom;
112
113 return Pos::Fill;
114 }
115
DragAndDrop_CanAcceptPackage(Gwen::DragAndDrop::Package * pPackage)116 bool DockBase::DragAndDrop_CanAcceptPackage(Gwen::DragAndDrop::Package* pPackage)
117 {
118 // A TAB button dropped
119 if (pPackage->name == "TabButtonMove")
120 return true;
121
122 // a TAB window dropped
123 if (pPackage->name == "TabWindowMove")
124 return true;
125
126 return false;
127 }
128
AddTabToDock(TabButton * pTabButton,DockedTabControl * pControl)129 void AddTabToDock(TabButton* pTabButton, DockedTabControl* pControl)
130 {
131 pControl->AddPage(pTabButton);
132 }
133
DragAndDrop_HandleDrop(Gwen::DragAndDrop::Package * pPackage,int x,int y)134 bool DockBase::DragAndDrop_HandleDrop(Gwen::DragAndDrop::Package* pPackage, int x, int y)
135 {
136 Gwen::Point pPos = CanvasPosToLocal(Gwen::Point(x, y));
137 int dir = GetDroppedTabDirection(pPos.x, pPos.y);
138
139 DockedTabControl* pAddTo = m_DockedTabControl;
140 if (dir == Pos::Fill && pAddTo == NULL) return false;
141
142 if (dir != Pos::Fill)
143 {
144 DockBase* pDock = GetChildDock(dir);
145 pAddTo = pDock->m_DockedTabControl;
146
147 if (!m_bDropFar)
148 pDock->BringToFront();
149 else
150 pDock->SendToBack();
151 }
152
153 if (pPackage->name == "TabButtonMove")
154 {
155 TabButton* pTabButton = DragAndDrop::SourceControl->DynamicCastTabButton();
156 if (!pTabButton) return false;
157
158 AddTabToDock(pTabButton, pAddTo);
159 }
160
161 if (pPackage->name == "TabWindowMove")
162 {
163 DockedTabControl* pTabControl = DragAndDrop::SourceControl->DynamicCastDockedTabControl();
164 if (!pTabControl) return false;
165 if (pTabControl == pAddTo) return false;
166
167 pTabControl->MoveTabsTo(pAddTo);
168 }
169
170 Invalidate();
171
172 return true;
173 }
174
IsEmpty()175 bool DockBase::IsEmpty()
176 {
177 if (m_DockedTabControl && m_DockedTabControl->TabCount() > 0) return false;
178
179 if (m_Left && !m_Left->IsEmpty()) return false;
180 if (m_Right && !m_Right->IsEmpty()) return false;
181 if (m_Top && !m_Top->IsEmpty()) return false;
182 if (m_Bottom && !m_Bottom->IsEmpty()) return false;
183
184 return true;
185 }
186
OnTabRemoved(Gwen::Controls::Base *)187 void DockBase::OnTabRemoved(Gwen::Controls::Base* /*pControl*/)
188 {
189 DoRedundancyCheck();
190 DoConsolidateCheck();
191 }
192
DoRedundancyCheck()193 void DockBase::DoRedundancyCheck()
194 {
195 if (!IsEmpty()) return;
196
197 DockBase* pDockParent = GetParent()->DynamicCastDockBase();
198 if (!pDockParent) return;
199
200 pDockParent->OnRedundantChildDock(this);
201 }
202
DoConsolidateCheck()203 void DockBase::DoConsolidateCheck()
204 {
205 if (IsEmpty()) return;
206 if (!m_DockedTabControl) return;
207 if (m_DockedTabControl->TabCount() > 0) return;
208
209 if (m_Bottom && !m_Bottom->IsEmpty())
210 {
211 m_Bottom->m_DockedTabControl->MoveTabsTo(m_DockedTabControl);
212 return;
213 }
214
215 if (m_Top && !m_Top->IsEmpty())
216 {
217 m_Top->m_DockedTabControl->MoveTabsTo(m_DockedTabControl);
218 return;
219 }
220
221 if (m_Left && !m_Left->IsEmpty())
222 {
223 m_Left->m_DockedTabControl->MoveTabsTo(m_DockedTabControl);
224 return;
225 }
226
227 if (m_Right && !m_Right->IsEmpty())
228 {
229 m_Right->m_DockedTabControl->MoveTabsTo(m_DockedTabControl);
230 return;
231 }
232 }
233
OnRedundantChildDock(DockBase * pDockBase)234 void DockBase::OnRedundantChildDock(DockBase* pDockBase)
235 {
236 pDockBase->SetHidden(true);
237 DoRedundancyCheck();
238 DoConsolidateCheck();
239 }
240
DragAndDrop_HoverEnter(Gwen::DragAndDrop::Package *,int,int)241 void DockBase::DragAndDrop_HoverEnter(Gwen::DragAndDrop::Package* /*pPackage*/, int /*x*/, int /*y*/)
242 {
243 m_bDrawHover = true;
244 }
245
DragAndDrop_HoverLeave(Gwen::DragAndDrop::Package *)246 void DockBase::DragAndDrop_HoverLeave(Gwen::DragAndDrop::Package* /*pPackage*/)
247 {
248 m_bDrawHover = false;
249 }
250
DragAndDrop_Hover(Gwen::DragAndDrop::Package *,int x,int y)251 void DockBase::DragAndDrop_Hover(Gwen::DragAndDrop::Package* /*pPackage*/, int x, int y)
252 {
253 Gwen::Point pPos = CanvasPosToLocal(Gwen::Point(x, y));
254 int dir = GetDroppedTabDirection(pPos.x, pPos.y);
255
256 if (dir == Pos::Fill)
257 {
258 if (!m_DockedTabControl)
259 {
260 m_HoverRect = Gwen::Rect(0, 0, 0, 0);
261 return;
262 }
263
264 m_HoverRect = GetInnerBounds();
265 return;
266 }
267
268 m_HoverRect = GetRenderBounds();
269
270 int HelpBarWidth = 0;
271
272 if (dir == Pos::Left)
273 {
274 HelpBarWidth = m_HoverRect.w * 0.25f;
275 m_HoverRect.w = HelpBarWidth;
276 }
277
278 if (dir == Pos::Right)
279 {
280 HelpBarWidth = m_HoverRect.w * 0.25f;
281 m_HoverRect.x = m_HoverRect.w - HelpBarWidth;
282 m_HoverRect.w = HelpBarWidth;
283 }
284
285 if (dir == Pos::Top)
286 {
287 HelpBarWidth = m_HoverRect.h * 0.25f;
288 m_HoverRect.h = HelpBarWidth;
289 }
290
291 if (dir == Pos::Bottom)
292 {
293 HelpBarWidth = m_HoverRect.h * 0.25f;
294 m_HoverRect.y = m_HoverRect.h - HelpBarWidth;
295 m_HoverRect.h = HelpBarWidth;
296 }
297
298 if ((dir == Pos::Top || dir == Pos::Bottom) && !m_bDropFar)
299 {
300 if (m_Left && m_Left->Visible())
301 {
302 m_HoverRect.x += m_Left->Width();
303 m_HoverRect.w -= m_Left->Width();
304 }
305
306 if (m_Right && m_Right->Visible())
307 {
308 m_HoverRect.w -= m_Right->Width();
309 }
310 }
311
312 if ((dir == Pos::Left || dir == Pos::Right) && !m_bDropFar)
313 {
314 if (m_Top && m_Top->Visible())
315 {
316 m_HoverRect.y += m_Top->Height();
317 m_HoverRect.h -= m_Top->Height();
318 }
319
320 if (m_Bottom && m_Bottom->Visible())
321 {
322 m_HoverRect.h -= m_Bottom->Height();
323 }
324 }
325 }
326
RenderOver(Skin::Base * skin)327 void DockBase::RenderOver(Skin::Base* skin)
328 {
329 if (!m_bDrawHover) return;
330
331 Gwen::Renderer::Base* render = skin->GetRender();
332
333 render->SetDrawColor(Gwen::Color(255, 100, 255, 20));
334 render->DrawFilledRect(GetRenderBounds());
335
336 if (m_HoverRect.w == 0) return;
337
338 render->SetDrawColor(Gwen::Color(255, 100, 255, 100));
339 render->DrawFilledRect(m_HoverRect);
340
341 render->SetDrawColor(Gwen::Color(255, 100, 255, 200));
342 render->DrawLinedRect(m_HoverRect);
343 }