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 }