1b960e451SClemens Zeidler/*
2b960e451SClemens Zeidler * Copyright 2010, Haiku.
3b960e451SClemens Zeidler * Distributed under the terms of the MIT License.
4b960e451SClemens Zeidler *
5b960e451SClemens Zeidler * Authors:
6b960e451SClemens Zeidler *		Clemens Zeidler <haiku@clemens-zeidler.de>
7b960e451SClemens Zeidler */
8b960e451SClemens Zeidler
9b960e451SClemens Zeidler#include "Tiling.h"
10b960e451SClemens Zeidler
11b960e451SClemens Zeidler
12b960e451SClemens Zeidler#include "SATWindow.h"
13b960e451SClemens Zeidler#include "StackAndTile.h"
14b960e451SClemens Zeidler#include "Window.h"
15b960e451SClemens Zeidler
16b960e451SClemens Zeidler
17b960e451SClemens Zeidlerusing namespace std;
18b960e451SClemens Zeidler
19b960e451SClemens Zeidler
2001d68c97SClemens Zeidler//#define DEBUG_TILING
21b960e451SClemens Zeidler
2201d68c97SClemens Zeidler#ifdef DEBUG_TILING
23b960e451SClemens Zeidler#	define STRACE_TILING(x...) debug_printf("SAT Tiling: "x)
24b960e451SClemens Zeidler#else
25b960e451SClemens Zeidler#	define STRACE_TILING(x...) ;
26b960e451SClemens Zeidler#endif
27b960e451SClemens Zeidler
28b960e451SClemens Zeidler
29b960e451SClemens ZeidlerSATTiling::SATTiling(SATWindow* window)
30b960e451SClemens Zeidler	:
31b960e451SClemens Zeidler	fSATWindow(window),
32b960e451SClemens Zeidler	fFreeAreaGroup(NULL)
33b960e451SClemens Zeidler{
34b960e451SClemens Zeidler	_ResetSearchResults();
35b960e451SClemens Zeidler}
36b960e451SClemens Zeidler
37b960e451SClemens Zeidler
38b960e451SClemens ZeidlerSATTiling::~SATTiling()
39b960e451SClemens Zeidler{
40b960e451SClemens Zeidler
41b960e451SClemens Zeidler}
42b960e451SClemens Zeidler
43b960e451SClemens Zeidler
44b960e451SClemens Zeidlerbool
45b960e451SClemens ZeidlerSATTiling::FindSnappingCandidates(SATGroup* group)
46b960e451SClemens Zeidler{
47b960e451SClemens Zeidler	_ResetSearchResults();
48b960e451SClemens Zeidler
497c5525e8SClemens Zeidler	if (_IsTileableWindow(fSATWindow->GetWindow()) == false
507c5525e8SClemens Zeidler		|| (group->CountItems() == 1
517c5525e8SClemens Zeidler			&& _IsTileableWindow(group->WindowAt(0)->GetWindow()) == false))
527c5525e8SClemens Zeidler		return false;
53b960e451SClemens Zeidler	if (fSATWindow->GetGroup() == group)
54b960e451SClemens Zeidler		return false;
55b960e451SClemens Zeidler
56b960e451SClemens Zeidler	if (_FindFreeAreaInGroup(group)) {
57b960e451SClemens Zeidler		fFreeAreaGroup = group;
58b960e451SClemens Zeidler		_HighlightWindows(fFreeAreaGroup, true);
59b960e451SClemens Zeidler		return true;
60b960e451SClemens Zeidler	}
61b960e451SClemens Zeidler
62b960e451SClemens Zeidler	return false;
63b960e451SClemens Zeidler}
64b960e451SClemens Zeidler
65b960e451SClemens Zeidler
66b960e451SClemens Zeidlerbool
67b960e451SClemens ZeidlerSATTiling::JoinCandidates()
68b960e451SClemens Zeidler{
69b960e451SClemens Zeidler	if (!fFreeAreaGroup)
70b960e451SClemens Zeidler		return false;
71b960e451SClemens Zeidler
72b960e451SClemens Zeidler	if (!fFreeAreaGroup->AddWindow(fSATWindow, fFreeAreaLeft, fFreeAreaTop,
73b960e451SClemens Zeidler		fFreeAreaRight, fFreeAreaBottom)) {
74b960e451SClemens Zeidler		_ResetSearchResults();
75b960e451SClemens Zeidler		return false;
76b960e451SClemens Zeidler	}
77b960e451SClemens Zeidler
78b960e451SClemens Zeidler	fFreeAreaGroup->WindowAt(0)->DoGroupLayout();
79b960e451SClemens Zeidler
80b960e451SClemens Zeidler	_ResetSearchResults();
81b960e451SClemens Zeidler	return true;
82b960e451SClemens Zeidler}
83b960e451SClemens Zeidler
84b960e451SClemens Zeidler
857c5525e8SClemens Zeidlervoid
867c5525e8SClemens ZeidlerSATTiling::WindowLookChanged(window_look look)
877c5525e8SClemens Zeidler{
887c5525e8SClemens Zeidler	SATGroup* group = fSATWindow->GetGroup();
897c5525e8SClemens Zeidler	if (group == NULL)
907c5525e8SClemens Zeidler		return;
917c5525e8SClemens Zeidler	if (_IsTileableWindow(fSATWindow->GetWindow()) == false)
927c5525e8SClemens Zeidler		group->RemoveWindow(fSATWindow);
937c5525e8SClemens Zeidler}
947c5525e8SClemens Zeidler
957c5525e8SClemens Zeidler
967c5525e8SClemens Zeidlerbool
977c5525e8SClemens ZeidlerSATTiling::_IsTileableWindow(Window* window)
987c5525e8SClemens Zeidler{
997c5525e8SClemens Zeidler	if (window->Look() == B_DOCUMENT_WINDOW_LOOK)
1007c5525e8SClemens Zeidler		return true;
1017c5525e8SClemens Zeidler	if (window->Look() == B_TITLED_WINDOW_LOOK)
1027c5525e8SClemens Zeidler		return true;
1037c5525e8SClemens Zeidler	if (window->Look() == B_FLOATING_WINDOW_LOOK)
1047c5525e8SClemens Zeidler		return true;
1057c5525e8SClemens Zeidler	if (window->Look() == B_MODAL_WINDOW_LOOK)
1067c5525e8SClemens Zeidler		return true;
1077c5525e8SClemens Zeidler	if (window->Look() == B_BORDERED_WINDOW_LOOK)
1087c5525e8SClemens Zeidler		return true;
1097c5525e8SClemens Zeidler	return false;
1107c5525e8SClemens Zeidler}
1117c5525e8SClemens Zeidler
1127c5525e8SClemens Zeidler
113b960e451SClemens Zeidlerbool
114b960e451SClemens ZeidlerSATTiling::_FindFreeAreaInGroup(SATGroup* group)
115b960e451SClemens Zeidler{
116b960e451SClemens Zeidler	if (_FindFreeAreaInGroup(group, Corner::kLeftTop))
117b960e451SClemens Zeidler		return true;
118b960e451SClemens Zeidler	if (_FindFreeAreaInGroup(group, Corner::kRightTop))
119b960e451SClemens Zeidler		return true;
120b960e451SClemens Zeidler	if (_FindFreeAreaInGroup(group, Corner::kLeftBottom))
121b960e451SClemens Zeidler		return true;
122b960e451SClemens Zeidler	if (_FindFreeAreaInGroup(group, Corner::kRightBottom))
123b960e451SClemens Zeidler		return true;
124b960e451SClemens Zeidler
125b960e451SClemens Zeidler	return false;
126b960e451SClemens Zeidler}
127b960e451SClemens Zeidler
128b960e451SClemens Zeidler
129b960e451SClemens Zeidlerbool
130b960e451SClemens ZeidlerSATTiling::_FindFreeAreaInGroup(SATGroup* group, Corner::position_t cor)
131b960e451SClemens Zeidler{
132b960e451SClemens Zeidler	BRect windowFrame = fSATWindow->CompleteWindowFrame();
133b960e451SClemens Zeidler
134b960e451SClemens Zeidler	const TabList* verticalTabs = group->VerticalTabs();
135b960e451SClemens Zeidler	for (int i = 0; i < verticalTabs->CountItems(); i++) {
136b960e451SClemens Zeidler		Tab* tab = verticalTabs->ItemAt(i);
137b960e451SClemens Zeidler		const CrossingList* crossingList = tab->GetCrossingList();
138b960e451SClemens Zeidler		for (int c = 0; c < crossingList->CountItems(); c++) {
139b960e451SClemens Zeidler			Crossing* crossing = crossingList->ItemAt(c);
140b960e451SClemens Zeidler			if (_InteresstingCrossing(crossing, cor, windowFrame)) {
141b960e451SClemens Zeidler				if (_FindFreeArea(group, crossing, cor, windowFrame)) {
142b960e451SClemens Zeidler					STRACE_TILING("SATTiling: free area found; corner %i\n",
143b960e451SClemens Zeidler						cor);
144b960e451SClemens Zeidler					return true;
145b960e451SClemens Zeidler				}
146b960e451SClemens Zeidler			}
147b960e451SClemens Zeidler		}
148b960e451SClemens Zeidler	}
149b960e451SClemens Zeidler
150b960e451SClemens Zeidler	return false;
151b960e451SClemens Zeidler}
152b960e451SClemens Zeidler
153b960e451SClemens Zeidler
154b960e451SClemens Zeidlerconst float kNoMatch = 999.f;
155b960e451SClemens Zeidlerconst float kMaxMatchingDistance = 12.f;
156b960e451SClemens Zeidler
157b960e451SClemens Zeidler
158b960e451SClemens Zeidlerbool
159b960e451SClemens ZeidlerSATTiling::_InteresstingCrossing(Crossing* crossing,
160b960e451SClemens Zeidler	Corner::position_t cor, BRect& windowFrame)
161b960e451SClemens Zeidler{
162b960e451SClemens Zeidler	const Corner* corner = crossing->GetOppositeCorner(cor);
163b960e451SClemens Zeidler	if (corner->status != Corner::kFree)
164b960e451SClemens Zeidler		return false;
165b960e451SClemens Zeidler
166b960e451SClemens Zeidler	float hTabPosition = crossing->HorizontalTab()->Position();
167b960e451SClemens Zeidler	float vTabPosition = crossing->VerticalTab()->Position();
168b960e451SClemens Zeidler	float hBorder = 0., vBorder = 0.;
169b960e451SClemens Zeidler	float vDistance = -1., hDistance = -1.;
170b960e451SClemens Zeidler	bool windowAtH = false, windowAtV = false;
171b960e451SClemens Zeidler	switch (cor) {
172b960e451SClemens Zeidler		case Corner::kLeftTop:
173b960e451SClemens Zeidler			if (crossing->RightBottomCorner()->status == Corner::kUsed)
174b960e451SClemens Zeidler				return false;
175b960e451SClemens Zeidler			vBorder = windowFrame.left;
176b960e451SClemens Zeidler			hBorder = windowFrame.top;
177b960e451SClemens Zeidler			if (crossing->LeftBottomCorner()->status == Corner::kUsed)
178b960e451SClemens Zeidler				windowAtV = true;
179b960e451SClemens Zeidler			if (crossing->RightTopCorner()->status == Corner::kUsed)
180b960e451SClemens Zeidler				windowAtH = true;
181b960e451SClemens Zeidler			vDistance = vTabPosition - vBorder;
182b960e451SClemens Zeidler			hDistance = hTabPosition - hBorder;
183b960e451SClemens Zeidler			break;
184b960e451SClemens Zeidler		case Corner::kRightTop:
185b960e451SClemens Zeidler			if (crossing->LeftBottomCorner()->status == Corner::kUsed)
186b960e451SClemens Zeidler				return false;
187b960e451SClemens Zeidler			vBorder = windowFrame.right;
188b960e451SClemens Zeidler			hBorder = windowFrame.top;
189b960e451SClemens Zeidler			if (crossing->RightBottomCorner()->status == Corner::kUsed)
190b960e451SClemens Zeidler				windowAtV = true;
191b960e451SClemens Zeidler			if (crossing->LeftTopCorner()->status == Corner::kUsed)
192b960e451SClemens Zeidler				windowAtH = true;
193b960e451SClemens Zeidler			vDistance = vBorder - vTabPosition;
194b960e451SClemens Zeidler			hDistance = hTabPosition - hBorder;
195b960e451SClemens Zeidler			break;
196b960e451SClemens Zeidler		case Corner::kLeftBottom:
197b960e451SClemens Zeidler			if (crossing->RightTopCorner()->status == Corner::kUsed)
198b960e451SClemens Zeidler				return false;
199b960e451SClemens Zeidler			vBorder = windowFrame.left;
200b960e451SClemens Zeidler			hBorder = windowFrame.bottom;
201b960e451SClemens Zeidler			if (crossing->LeftTopCorner()->status == Corner::kUsed)
202b960e451SClemens Zeidler				windowAtV = true;
203b960e451SClemens Zeidler			if (crossing->RightBottomCorner()->status == Corner::kUsed)
204b960e451SClemens Zeidler				windowAtH = true;
205b960e451SClemens Zeidler			vDistance = vTabPosition - vBorder;
206b960e451SClemens Zeidler			hDistance = hBorder - hTabPosition;
207b960e451SClemens Zeidler			break;
208b960e451SClemens Zeidler		case Corner::kRightBottom:
209b960e451SClemens Zeidler			if (crossing->LeftTopCorner()->status == Corner::kUsed)
210b960e451SClemens Zeidler				return false;
211b960e451SClemens Zeidler			vBorder = windowFrame.right;
212b960e451SClemens Zeidler			hBorder = windowFrame.bottom;
213b960e451SClemens Zeidler			if (crossing->RightTopCorner()->status == Corner::kUsed)
214b960e451SClemens Zeidler				windowAtV = true;
215b960e451SClemens Zeidler			if (crossing->LeftBottomCorner()->status == Corner::kUsed)
216b960e451SClemens Zeidler				windowAtH = true;
217b960e451SClemens Zeidler			vDistance = vBorder - vTabPosition;
218b960e451SClemens Zeidler			hDistance = hBorder - hTabPosition;
219b960e451SClemens Zeidler			break;
220b960e451SClemens Zeidler	};
221b960e451SClemens Zeidler
222b960e451SClemens Zeidler	bool hValid = false;
223b960e451SClemens Zeidler	if (windowAtH && fabs(hDistance) < kMaxMatchingDistance
224b960e451SClemens Zeidler		&& vDistance  < kMaxMatchingDistance)
225b960e451SClemens Zeidler		hValid = true;
226b960e451SClemens Zeidler	bool vValid = false;
227b960e451SClemens Zeidler	if (windowAtV && fabs(vDistance) < kMaxMatchingDistance
228b960e451SClemens Zeidler		&& hDistance  < kMaxMatchingDistance)
229b960e451SClemens Zeidler		vValid = true;
230b960e451SClemens Zeidler	if (!hValid && !vValid)
231b960e451SClemens Zeidler		return false;
232b960e451SClemens Zeidler
233b960e451SClemens Zeidler	return true;
234b960e451SClemens Zeidler};
235b960e451SClemens Zeidler
236b960e451SClemens Zeidler
237b960e451SClemens Zeidlerconst float kBigAreaError = 1E+17;
238b960e451SClemens Zeidler
239b960e451SClemens Zeidler
240b960e451SClemens Zeidlerbool
241b960e451SClemens ZeidlerSATTiling::_FindFreeArea(SATGroup* group, const Crossing* crossing,
242b960e451SClemens Zeidler	Corner::position_t corner, BRect& windowFrame)
243b960e451SClemens Zeidler{
244b960e451SClemens Zeidler	fFreeAreaLeft = fFreeAreaRight = fFreeAreaTop = fFreeAreaBottom = NULL;
245b960e451SClemens Zeidler
246b960e451SClemens Zeidler	const TabList* hTabs = group->HorizontalTabs();
247b960e451SClemens Zeidler	const TabList* vTabs = group->VerticalTabs();
248b960e451SClemens Zeidler	int32 hIndex = hTabs->IndexOf(crossing->HorizontalTab());
249b960e451SClemens Zeidler	if (hIndex < 0)
250b960e451SClemens Zeidler		return false;
251b960e451SClemens Zeidler	int32 vIndex = vTabs->IndexOf(crossing->VerticalTab());
252b960e451SClemens Zeidler	if (vIndex < 0)
253b960e451SClemens Zeidler		return false;
254b960e451SClemens Zeidler
255b960e451SClemens Zeidler	Tab** endHTab = NULL, **endVTab = NULL;
256b960e451SClemens Zeidler	int8 vSearchDirection = 1, hSearchDirection = 1;
257b960e451SClemens Zeidler	switch (corner) {
258b960e451SClemens Zeidler		case Corner::kLeftTop:
259b960e451SClemens Zeidler			fFreeAreaLeft = crossing->VerticalTab();
260b960e451SClemens Zeidler			fFreeAreaTop = crossing->HorizontalTab();
261b960e451SClemens Zeidler			endHTab = &fFreeAreaBottom;
262b960e451SClemens Zeidler			endVTab = &fFreeAreaRight;
263b960e451SClemens Zeidler			vSearchDirection = 1;
264b960e451SClemens Zeidler			hSearchDirection = 1;
265b960e451SClemens Zeidler			break;
266b960e451SClemens Zeidler		case Corner::kRightTop:
267b960e451SClemens Zeidler			fFreeAreaRight = crossing->VerticalTab();
268b960e451SClemens Zeidler			fFreeAreaTop = crossing->HorizontalTab();
269b960e451SClemens Zeidler			endHTab = &fFreeAreaBottom;
270b960e451SClemens Zeidler			endVTab = &fFreeAreaLeft;
271b960e451SClemens Zeidler			vSearchDirection = -1;
272b960e451SClemens Zeidler			hSearchDirection = 1;
273b960e451SClemens Zeidler			break;
274b960e451SClemens Zeidler		case Corner::kLeftBottom:
275b960e451SClemens Zeidler			fFreeAreaLeft = crossing->VerticalTab();
276b960e451SClemens Zeidler			fFreeAreaBottom = crossing->HorizontalTab();
277b960e451SClemens Zeidler			endHTab = &fFreeAreaTop;
278b960e451SClemens Zeidler			endVTab = &fFreeAreaRight;
279b960e451SClemens Zeidler			vSearchDirection = 1;
280b960e451SClemens Zeidler			hSearchDirection = -1;
281b960e451SClemens Zeidler			break;
282b960e451SClemens Zeidler		case Corner::kRightBottom:
283b960e451SClemens Zeidler			fFreeAreaRight = crossing->VerticalTab();
284b960e451SClemens Zeidler			fFreeAreaBottom = crossing->HorizontalTab();
285b960e451SClemens Zeidler			endHTab = &fFreeAreaTop;
286b960e451SClemens Zeidler			endVTab = &fFreeAreaLeft;
287b960e451SClemens Zeidler			vSearchDirection = -1;
288b960e451SClemens Zeidler			hSearchDirection = -1;
289b960e451SClemens Zeidler			break;
290b960e451SClemens Zeidler	};
291b960e451SClemens Zeidler
292b960e451SClemens Zeidler	Tab* bestLeftTab = NULL, *bestRightTab = NULL, *bestTopTab = NULL,
293b960e451SClemens Zeidler		*bestBottomTab = NULL;
294b960e451SClemens Zeidler	float bestError = kBigAreaError;
295b960e451SClemens Zeidler	float error;
296b960e451SClemens Zeidler	bool stop = false;
297b960e451SClemens Zeidler	bool found = false;
298b960e451SClemens Zeidler	int32 v = vIndex;
299b960e451SClemens Zeidler	do {
300b960e451SClemens Zeidler		v += vSearchDirection;
301b960e451SClemens Zeidler		*endVTab = vTabs->ItemAt(v);
302b960e451SClemens Zeidler		int32 h = hIndex;
303b960e451SClemens Zeidler		do {
304b960e451SClemens Zeidler			h += hSearchDirection;
305b960e451SClemens Zeidler			*endHTab = hTabs->ItemAt(h);
306b960e451SClemens Zeidler			if (!_CheckArea(group, corner, windowFrame, error)) {
307b960e451SClemens Zeidler				if (h == hIndex + hSearchDirection)
308b960e451SClemens Zeidler					stop = true;
309b960e451SClemens Zeidler				break;
310b960e451SClemens Zeidler			}
311b960e451SClemens Zeidler			found = true;
312b960e451SClemens Zeidler			if (error < bestError) {
313b960e451SClemens Zeidler				bestError = error;
314b960e451SClemens Zeidler				bestLeftTab = fFreeAreaLeft;
315b960e451SClemens Zeidler				bestRightTab = fFreeAreaRight;
316b960e451SClemens Zeidler				bestTopTab = fFreeAreaTop;
317b960e451SClemens Zeidler				bestBottomTab = fFreeAreaBottom;
318b960e451SClemens Zeidler			}
319b960e451SClemens Zeidler		} while (*endHTab);
320b960e451SClemens Zeidler		if (stop)
321b960e451SClemens Zeidler			break;
322b960e451SClemens Zeidler	} while (*endVTab);
323b960e451SClemens Zeidler	if (!found)
324b960e451SClemens Zeidler		return false;
325b960e451SClemens Zeidler
326b960e451SClemens Zeidler	fFreeAreaLeft = bestLeftTab;
327b960e451SClemens Zeidler	fFreeAreaRight = bestRightTab;
328b960e451SClemens Zeidler	fFreeAreaTop = bestTopTab;
329b960e451SClemens Zeidler	fFreeAreaBottom = bestBottomTab;
330b960e451SClemens Zeidler
331b960e451SClemens Zeidler	return true;
332b960e451SClemens Zeidler}
333b960e451SClemens Zeidler
334b960e451SClemens Zeidler
335b960e451SClemens Zeidlerbool
336b960e451SClemens ZeidlerSATTiling::_HasOverlapp(SATGroup* group)
337b960e451SClemens Zeidler{
338b960e451SClemens Zeidler	BRect areaRect = _FreeAreaSize();
339b960e451SClemens Zeidler	areaRect.InsetBy(1., 1.);
340b960e451SClemens Zeidler
341b960e451SClemens Zeidler	const TabList* hTabs = group->HorizontalTabs();
342b960e451SClemens Zeidler	for (int32 h = 0; h < hTabs->CountItems(); h++) {
343b960e451SClemens Zeidler		Tab* hTab = hTabs->ItemAt(h);
344b960e451SClemens Zeidler		if (hTab->Position() >= areaRect.bottom)
345b960e451SClemens Zeidler			return false;
346b960e451SClemens Zeidler		const CrossingList* crossings = hTab->GetCrossingList();
347b960e451SClemens Zeidler		for (int32 i = 0; i <  crossings->CountItems(); i++) {
348b960e451SClemens Zeidler			Crossing* leftTopCrossing = crossings->ItemAt(i);
349b960e451SClemens Zeidler			Tab* vTab = leftTopCrossing->VerticalTab();
350b960e451SClemens Zeidler			if (vTab->Position() > areaRect.right)
351b960e451SClemens Zeidler				continue;
352b960e451SClemens Zeidler			Corner* corner = leftTopCrossing->RightBottomCorner();
353b960e451SClemens Zeidler			if (corner->status != Corner::kUsed)
354b960e451SClemens Zeidler				continue;
355b960e451SClemens Zeidler			BRect rect = corner->windowArea->Frame();
356b960e451SClemens Zeidler			if (areaRect.Intersects(rect))
357b960e451SClemens Zeidler				return true;
358b960e451SClemens Zeidler		}
359b960e451SClemens Zeidler	}
360b960e451SClemens Zeidler	return false;
361b960e451SClemens Zeidler}
362b960e451SClemens Zeidler
363b960e451SClemens Zeidler
364b960e451SClemens Zeidlerbool
365b960e451SClemens ZeidlerSATTiling::_CheckArea(SATGroup* group, Corner::position_t corner,
366b960e451SClemens Zeidler	BRect& windowFrame, float& error)
367b960e451SClemens Zeidler{
368b960e451SClemens Zeidler	error = kBigAreaError;
369b960e451SClemens Zeidler	if (!_CheckMinFreeAreaSize())
370b960e451SClemens Zeidler		return false;
371b960e451SClemens Zeidler	// check if corner is in the free area
372b960e451SClemens Zeidler	if (!_IsCornerInFreeArea(corner, windowFrame))
373b960e451SClemens Zeidler		return false;
374b960e451SClemens Zeidler
375b960e451SClemens Zeidler	error = _FreeAreaError(windowFrame);
376b960e451SClemens Zeidler	if (!_HasOverlapp(group))
377b960e451SClemens Zeidler		return true;
378b960e451SClemens Zeidler	return false;
379b960e451SClemens Zeidler}
380b960e451SClemens Zeidler
381b960e451SClemens Zeidler
382b960e451SClemens Zeidlerbool
383b960e451SClemens ZeidlerSATTiling::_CheckMinFreeAreaSize()
384b960e451SClemens Zeidler{
385b960e451SClemens Zeidler	// check if the area has a minimum size
386b960e451SClemens Zeidler	if (fFreeAreaLeft && fFreeAreaRight
387b960e451SClemens Zeidler		&& fFreeAreaRight->Position() - fFreeAreaLeft->Position()
388b960e451SClemens Zeidler			< 2 * kMaxMatchingDistance)
389b960e451SClemens Zeidler		return false;
390b960e451SClemens Zeidler	if (fFreeAreaBottom && fFreeAreaTop
391b960e451SClemens Zeidler		&& fFreeAreaBottom->Position() - fFreeAreaTop->Position()
392b960e451SClemens Zeidler			< 2 * kMaxMatchingDistance)
393b960e451SClemens Zeidler		return false;
394b960e451SClemens Zeidler	return true;
395b960e451SClemens Zeidler}
396b960e451SClemens Zeidler
397b960e451SClemens Zeidler
398b960e451SClemens Zeidlerfloat
399b960e451SClemens ZeidlerSATTiling::_FreeAreaError(BRect& windowFrame)
400b960e451SClemens Zeidler{
401b960e451SClemens Zeidler	const float kEndTabError = 9999999;
402b960e451SClemens Zeidler	float error = 0.;
403b960e451SClemens Zeidler	if (fFreeAreaLeft && fFreeAreaRight)
404b960e451SClemens Zeidler		error += pow(fFreeAreaRight->Position() - fFreeAreaLeft->Position()
405b960e451SClemens Zeidler			- windowFrame.Width(), 2);
406b960e451SClemens Zeidler	else
407b960e451SClemens Zeidler		error += kEndTabError;
408b960e451SClemens Zeidler	if (fFreeAreaBottom && fFreeAreaTop)
409b960e451SClemens Zeidler		error += pow(fFreeAreaBottom->Position() - fFreeAreaTop->Position()
410b960e451SClemens Zeidler			- windowFrame.Height(), 2);
411b960e451SClemens Zeidler	else
412b960e451SClemens Zeidler		error += kEndTabError;
413b960e451SClemens Zeidler	return error;
414b960e451SClemens Zeidler}
415b960e451SClemens Zeidler
416b960e451SClemens Zeidler
417b960e451SClemens Zeidlerbool
418b960e451SClemens ZeidlerSATTiling::_IsCornerInFreeArea(Corner::position_t corner, BRect& frame)
419b960e451SClemens Zeidler{
420b960e451SClemens Zeidler	BRect freeArea = _FreeAreaSize();
421b960e451SClemens Zeidler
422b960e451SClemens Zeidler	switch (corner) {
423b960e451SClemens Zeidler		case Corner::kLeftTop:
424b960e451SClemens Zeidler			if (freeArea.bottom - kMaxMatchingDistance > frame.top
425b960e451SClemens Zeidler				&& freeArea.right - kMaxMatchingDistance > frame.left)
426b960e451SClemens Zeidler				return true;
427b960e451SClemens Zeidler			break;
428b960e451SClemens Zeidler		case Corner::kRightTop:
429b960e451SClemens Zeidler			if (freeArea.bottom - kMaxMatchingDistance > frame.top
430b960e451SClemens Zeidler				&& freeArea.left + kMaxMatchingDistance < frame.right)
431b960e451SClemens Zeidler				return true;
432b960e451SClemens Zeidler			break;
433b960e451SClemens Zeidler		case Corner::kLeftBottom:
434b960e451SClemens Zeidler			if (freeArea.top + kMaxMatchingDistance < frame.bottom
435b960e451SClemens Zeidler				&& freeArea.right - kMaxMatchingDistance > frame.left)
436b960e451SClemens Zeidler				return true;
437b960e451SClemens Zeidler			break;
438b960e451SClemens Zeidler		case Corner::kRightBottom:
439b960e451SClemens Zeidler			if (freeArea.top + kMaxMatchingDistance < frame.bottom
440b960e451SClemens Zeidler				&& freeArea.left + kMaxMatchingDistance < frame.right)
441b960e451SClemens Zeidler				return true;
442b960e451SClemens Zeidler			break;
443b960e451SClemens Zeidler	}
444b960e451SClemens Zeidler
445b960e451SClemens Zeidler	return false;
446b960e451SClemens Zeidler}
447b960e451SClemens Zeidler
448b960e451SClemens Zeidler
449b960e451SClemens ZeidlerBRect
450b960e451SClemens ZeidlerSATTiling::_FreeAreaSize()
451b960e451SClemens Zeidler{
452b960e451SClemens Zeidler	// not to big to be be able to add/sub small float values
453b960e451SClemens Zeidler	const float kBigValue = 9999999.;
454b960e451SClemens Zeidler	float left = fFreeAreaLeft ? fFreeAreaLeft->Position() : -kBigValue;
455b960e451SClemens Zeidler	float right = fFreeAreaRight ? fFreeAreaRight->Position() : kBigValue;
456b960e451SClemens Zeidler	float top = fFreeAreaTop ? fFreeAreaTop->Position() : -kBigValue;
457b960e451SClemens Zeidler	float bottom = fFreeAreaBottom ? fFreeAreaBottom->Position() : kBigValue;
458b960e451SClemens Zeidler	return BRect(left, top, right, bottom);
459b960e451SClemens Zeidler}
460b960e451SClemens Zeidler
461b960e451SClemens Zeidler
462b960e451SClemens Zeidlervoid
463b960e451SClemens ZeidlerSATTiling::_HighlightWindows(SATGroup* group, bool highlight)
464b960e451SClemens Zeidler{
465b960e451SClemens Zeidler	const TabList* hTabs = group->HorizontalTabs();
466b960e451SClemens Zeidler	const TabList* vTabs = group->VerticalTabs();
467b960e451SClemens Zeidler	// height light windows at all four sites
468ac701f7eSClemens Zeidler	bool leftWindowsFound = _SearchHighlightWindow(fFreeAreaLeft, fFreeAreaTop, fFreeAreaBottom, hTabs,
469ac701f7eSClemens Zeidler		fFreeAreaTop ? Corner::kLeftBottom : Corner::kLeftTop,
470ac701f7eSClemens Zeidler		Decorator::REGION_RIGHT_BORDER, highlight);
471b960e451SClemens Zeidler
472ac701f7eSClemens Zeidler	bool topWindowsFound = _SearchHighlightWindow(fFreeAreaTop, fFreeAreaLeft, fFreeAreaRight, vTabs,
473ac701f7eSClemens Zeidler		fFreeAreaLeft ? Corner::kRightTop : Corner::kLeftTop,
474ac701f7eSClemens Zeidler		Decorator::REGION_BOTTOM_BORDER, highlight);
475b960e451SClemens Zeidler
476ac701f7eSClemens Zeidler	bool rightWindowsFound = _SearchHighlightWindow(fFreeAreaRight, fFreeAreaTop, fFreeAreaBottom, hTabs,
477ac701f7eSClemens Zeidler		fFreeAreaTop ? Corner::kRightBottom : Corner::kRightTop,
478ac701f7eSClemens Zeidler		Decorator::REGION_LEFT_BORDER, highlight);
479b960e451SClemens Zeidler
480ac701f7eSClemens Zeidler	bool bottomWindowsFound = _SearchHighlightWindow(fFreeAreaBottom, fFreeAreaLeft, fFreeAreaRight,
481caefa867SClemens Zeidler		vTabs, fFreeAreaLeft ? Corner::kRightBottom : Corner::kLeftBottom,
482ac701f7eSClemens Zeidler		Decorator::REGION_TOP_BORDER, highlight);
483ac701f7eSClemens Zeidler
484ac701f7eSClemens Zeidler	if (leftWindowsFound)
485ac701f7eSClemens Zeidler		fSATWindow->HighlightBorders(Decorator::REGION_LEFT_BORDER, highlight);
486ac701f7eSClemens Zeidler	if (topWindowsFound)
487ac701f7eSClemens Zeidler		fSATWindow->HighlightBorders(Decorator::REGION_TOP_BORDER, highlight);
488ac701f7eSClemens Zeidler	if (rightWindowsFound)
489ac701f7eSClemens Zeidler		fSATWindow->HighlightBorders(Decorator::REGION_RIGHT_BORDER, highlight);
490ac701f7eSClemens Zeidler	if (bottomWindowsFound) {
491ac701f7eSClemens Zeidler		fSATWindow->HighlightBorders(Decorator::REGION_BOTTOM_BORDER,
492ac701f7eSClemens Zeidler			highlight);
493ac701f7eSClemens Zeidler	}
494b960e451SClemens Zeidler}
495b960e451SClemens Zeidler
496b960e451SClemens Zeidler
497ac701f7eSClemens Zeidlerbool
498b960e451SClemens ZeidlerSATTiling::_SearchHighlightWindow(Tab* tab, Tab* firstOrthTab,
499b960e451SClemens Zeidler	Tab* secondOrthTab, const TabList* orthTabs, Corner::position_t areaCorner,
500ac701f7eSClemens Zeidler	Decorator::Region region, bool highlight)
501b960e451SClemens Zeidler{
502ac701f7eSClemens Zeidler	bool windowsFound = false;
503ac701f7eSClemens Zeidler
504b960e451SClemens Zeidler	if (!tab)
505ac701f7eSClemens Zeidler		return false;
506b960e451SClemens Zeidler
507b960e451SClemens Zeidler	int8 searchDir = 1;
508b960e451SClemens Zeidler	Tab* startOrthTab = NULL;
509b960e451SClemens Zeidler	Tab* endOrthTab = NULL;
510b960e451SClemens Zeidler	if (firstOrthTab) {
511b960e451SClemens Zeidler		searchDir = 1;
512b960e451SClemens Zeidler		startOrthTab = firstOrthTab;
513b960e451SClemens Zeidler		endOrthTab = secondOrthTab;
514b960e451SClemens Zeidler	}
515b960e451SClemens Zeidler	else if (secondOrthTab) {
516b960e451SClemens Zeidler		searchDir = -1;
517b960e451SClemens Zeidler		startOrthTab = secondOrthTab;
518b960e451SClemens Zeidler		endOrthTab = firstOrthTab;
519b960e451SClemens Zeidler	}
520b960e451SClemens Zeidler	else
521ac701f7eSClemens Zeidler		return false;
522b960e451SClemens Zeidler
523b960e451SClemens Zeidler	int32 index = orthTabs->IndexOf(startOrthTab);
524b960e451SClemens Zeidler	if (index < 0)
525ac701f7eSClemens Zeidler		return false;
526b960e451SClemens Zeidler
527b960e451SClemens Zeidler	for (; index < orthTabs->CountItems() && index >= 0; index += searchDir) {
528b960e451SClemens Zeidler		Tab* orthTab = orthTabs->ItemAt(index);
529caefa867SClemens Zeidler		if (orthTab == endOrthTab)
530caefa867SClemens Zeidler 			break;
531b960e451SClemens Zeidler		Crossing* crossing = tab->FindCrossing(orthTab);
532b960e451SClemens Zeidler		if (!crossing)
533b960e451SClemens Zeidler			continue;
534b960e451SClemens Zeidler		Corner* corner = crossing->GetCorner(areaCorner);
535ac701f7eSClemens Zeidler		if (corner->windowArea) {
536ac701f7eSClemens Zeidler			_HighlightWindows(corner->windowArea, region,  highlight);
537ac701f7eSClemens Zeidler			windowsFound = true;
538ac701f7eSClemens Zeidler		}
539b960e451SClemens Zeidler	}
540ac701f7eSClemens Zeidler	return windowsFound;
541b960e451SClemens Zeidler}
542b960e451SClemens Zeidler
543b960e451SClemens Zeidler
544b960e451SClemens Zeidlervoid
545ac701f7eSClemens ZeidlerSATTiling::_HighlightWindows(WindowArea* area, Decorator::Region region,
546ac701f7eSClemens Zeidler	bool highlight)
547b960e451SClemens Zeidler{
548ac701f7eSClemens Zeidler	const SATWindowList& list = area->LayerOrder();
549ac701f7eSClemens Zeidler	SATWindow* topWindow = list.ItemAt(list.CountItems() - 1);
550ac701f7eSClemens Zeidler	if (topWindow == NULL)
551ac701f7eSClemens Zeidler		return;
552ac701f7eSClemens Zeidler	topWindow->HighlightBorders(region, highlight);
553b960e451SClemens Zeidler}
554b960e451SClemens Zeidler
555b960e451SClemens Zeidler
556b960e451SClemens Zeidlervoid
557b960e451SClemens ZeidlerSATTiling::_ResetSearchResults()
558b960e451SClemens Zeidler{
559b960e451SClemens Zeidler	if (!fFreeAreaGroup)
560b960e451SClemens Zeidler		return;
561b960e451SClemens Zeidler
562b960e451SClemens Zeidler	_HighlightWindows(fFreeAreaGroup, false);
563b960e451SClemens Zeidler	fFreeAreaGroup = NULL;
564b960e451SClemens Zeidler}
565