1/*
2 * Copyright 2001-2015 Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan Aßmus, superstippi@gmx.de
7 *		DarkWyrm, bpmagic@columbus.rr.com
8 *		John Scipione, jscipione@gmail.com
9 *		Ingo Weinhold, ingo_weinhold@gmx.de
10 *		Clemens Zeidler, haiku@clemens-zeidler.de
11 *		Joseph Groover <looncraz@looncraz.net>
12 */
13
14
15/*!	Base class for window decorators */
16
17
18#include "Decorator.h"
19
20#include <stdio.h>
21
22#include <Region.h>
23
24#include "Desktop.h"
25#include "DesktopSettings.h"
26#include "DrawingEngine.h"
27
28
29Decorator::Tab::Tab()
30	:
31	tabRect(),
32
33	zoomRect(),
34	closeRect(),
35	minimizeRect(),
36
37	closePressed(false),
38	zoomPressed(false),
39	minimizePressed(false),
40
41	look(B_TITLED_WINDOW_LOOK),
42	flags(0),
43	isFocused(false),
44	title(""),
45
46	tabOffset(0),
47	tabLocation(0.0f),
48	textOffset(10.0f),
49
50	truncatedTitle(""),
51	truncatedTitleLength(0),
52
53	buttonFocus(false),
54	isHighlighted(false),
55
56	minTabSize(0.0f),
57	maxTabSize(0.0f)
58{
59	closeBitmaps[0] = closeBitmaps[1] = closeBitmaps[2] = closeBitmaps[3]
60		= minimizeBitmaps[0] = minimizeBitmaps[1] = minimizeBitmaps[2]
61		= minimizeBitmaps[3] = zoomBitmaps[0] = zoomBitmaps[1] = zoomBitmaps[2]
62		= zoomBitmaps[3] = NULL;
63}
64
65
66/*!	\brief Constructor
67
68	Does general initialization of internal data members and creates a colorset
69	object.
70
71	\param settings DesktopSettings pointer.
72	\param frame Decorator frame rectangle
73*/
74Decorator::Decorator(DesktopSettings& settings, BRect frame,
75					Desktop* desktop)
76	:
77	fDrawingEngine(NULL),
78	fDrawState(),
79
80	fTitleBarRect(),
81	fFrame(frame),
82	fResizeRect(),
83	fBorderRect(),
84
85	fLeftBorder(),
86	fTopBorder(),
87	fBottomBorder(),
88	fRightBorder(),
89
90	fBorderWidth(-1),
91
92	fTopTab(NULL),
93
94	fDesktop(desktop),
95	fFootprintValid(false)
96{
97	memset(&fRegionHighlights, HIGHLIGHT_NONE, sizeof(fRegionHighlights));
98}
99
100
101/*!	\brief Destructor
102
103	Frees the color set and the title string
104*/
105Decorator::~Decorator()
106{
107}
108
109
110Decorator::Tab*
111Decorator::AddTab(DesktopSettings& settings, const char* title,
112	window_look look, uint32 flags, int32 index, BRegion* updateRegion)
113{
114	Decorator::Tab* tab = _AllocateNewTab();
115	if (tab == NULL)
116		return NULL;
117	tab->title = title;
118	tab->look = look;
119	tab->flags = flags;
120
121	bool ok = false;
122	if (index >= 0) {
123		if (fTabList.AddItem(tab, index) == true)
124			ok = true;
125	} else if (fTabList.AddItem(tab) == true)
126		ok = true;
127
128	if (ok == false) {
129		delete tab;
130		return NULL;
131	}
132
133	Decorator::Tab* oldTop = fTopTab;
134	fTopTab = tab;
135	if (_AddTab(settings, index, updateRegion) == false) {
136		fTabList.RemoveItem(tab);
137		delete tab;
138		fTopTab = oldTop;
139		return NULL;
140	}
141
142	_InvalidateFootprint();
143	return tab;
144}
145
146
147bool
148Decorator::RemoveTab(int32 index, BRegion* updateRegion)
149{
150	Decorator::Tab* tab = fTabList.RemoveItemAt(index);
151	if (tab == NULL)
152		return false;
153
154	_RemoveTab(index, updateRegion);
155
156	delete tab;
157	_InvalidateFootprint();
158	return true;
159}
160
161
162bool
163Decorator::MoveTab(int32 from, int32 to, bool isMoving, BRegion* updateRegion)
164{
165	if (_MoveTab(from, to, isMoving, updateRegion) == false)
166		return false;
167	if (fTabList.MoveItem(from, to) == false) {
168		// move the tab back
169		_MoveTab(from, to, isMoving, updateRegion);
170		return false;
171	}
172	return true;
173}
174
175
176int32
177Decorator::TabAt(const BPoint& where) const
178{
179	for (int32 i = 0; i < fTabList.CountItems(); i++) {
180		Decorator::Tab* tab = fTabList.ItemAt(i);
181		if (tab->tabRect.Contains(where))
182			return i;
183	}
184
185	return -1;
186}
187
188
189void
190Decorator::SetTopTab(int32 tab)
191{
192	fTopTab = fTabList.ItemAt(tab);
193}
194
195
196/*!	\brief Assigns a display driver to the decorator
197	\param driver A valid DrawingEngine object
198*/
199void
200Decorator::SetDrawingEngine(DrawingEngine* engine)
201{
202	fDrawingEngine = engine;
203	// lots of subclasses will depend on the driver for text support, so call
204	// _DoLayout() after we have it
205	if (fDrawingEngine != NULL)
206		_DoLayout();
207}
208
209
210/*!	\brief Sets the decorator's window flags
211
212	While this call will not update the screen, it will affect how future
213	updates work and immediately affects input handling.
214
215	\param flags New value for the flags
216*/
217void
218Decorator::SetFlags(int32 tab, uint32 flags, BRegion* updateRegion)
219{
220	// we're nice to our subclasses - we make sure B_NOT_{H|V|}_RESIZABLE
221	// are in sync (it's only a semantical simplification, not a necessity)
222	if ((flags & (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE))
223			== (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE))
224		flags |= B_NOT_RESIZABLE;
225	if (flags & B_NOT_RESIZABLE)
226		flags |= B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE;
227
228	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
229	if (decoratorTab == NULL)
230		return;
231	_SetFlags(decoratorTab, flags, updateRegion);
232	_InvalidateFootprint();
233		// the border might have changed (smaller/larger tab)
234}
235
236
237/*!	\brief Called whenever the system fonts are changed.
238*/
239void
240Decorator::FontsChanged(DesktopSettings& settings, BRegion* updateRegion)
241{
242
243	_FontsChanged(settings, updateRegion);
244	_InvalidateFootprint();
245}
246
247
248/*!	\brief Called when a system colors change.
249*/
250void
251Decorator::ColorsChanged(DesktopSettings& settings, BRegion* updateRegion)
252{
253	UpdateColors(settings);
254
255	if (updateRegion != NULL)
256		updateRegion->Include(&GetFootprint());
257
258	_InvalidateBitmaps();
259}
260
261
262/*!	\brief Sets the decorator's window look
263	\param look New value for the look
264*/
265void
266Decorator::SetLook(int32 tab, DesktopSettings& settings, window_look look,
267	BRegion* updateRect)
268{
269	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
270	if (decoratorTab == NULL)
271		return;
272
273	_SetLook(decoratorTab, settings, look, updateRect);
274	_InvalidateFootprint();
275		// the border very likely changed
276}
277
278
279/*!	\brief Returns the decorator's window look
280	\return the decorator's window look
281*/
282window_look
283Decorator::Look(int32 tab) const
284{
285	return TabAt(tab)->look;
286}
287
288
289/*!	\brief Returns the decorator's window flags
290	\return the decorator's window flags
291*/
292uint32
293Decorator::Flags(int32 tab) const
294{
295	return TabAt(tab)->flags;
296}
297
298
299/*!	\brief Returns the decorator's border rectangle
300	\return the decorator's border rectangle
301*/
302BRect
303Decorator::BorderRect() const
304{
305	return fBorderRect;
306}
307
308
309BRect
310Decorator::TitleBarRect() const
311{
312	return fTitleBarRect;
313}
314
315
316/*!	\brief Returns the decorator's tab rectangle
317	\return the decorator's tab rectangle
318*/
319BRect
320Decorator::TabRect(int32 tab) const
321{
322	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
323	if (decoratorTab == NULL)
324		return BRect();
325	return decoratorTab->tabRect;
326}
327
328
329BRect
330Decorator::TabRect(Decorator::Tab* tab) const
331{
332	return tab->tabRect;
333}
334
335
336/*!	\brief Sets the close button's value.
337
338	Note that this does not update the button's look - it just updates the
339	internal button value
340
341	\param tab The tab index
342	\param pressed Whether the button is down or not
343*/
344void
345Decorator::SetClose(int32 tab, bool pressed)
346{
347	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
348	if (decoratorTab == NULL)
349		return;
350
351	if (pressed != decoratorTab->closePressed) {
352		decoratorTab->closePressed = pressed;
353		DrawClose(tab);
354	}
355}
356
357
358/*!	\brief Sets the minimize button's value.
359
360	Note that this does not update the button's look - it just updates the
361	internal button value
362
363	\param is_down Whether the button is down or not
364*/
365void
366Decorator::SetMinimize(int32 tab, bool pressed)
367{
368	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
369	if (decoratorTab == NULL)
370		return;
371
372	if (pressed != decoratorTab->minimizePressed) {
373		decoratorTab->minimizePressed = pressed;
374		DrawMinimize(tab);
375	}
376}
377
378/*!	\brief Sets the zoom button's value.
379
380	Note that this does not update the button's look - it just updates the
381	internal button value
382
383	\param is_down Whether the button is down or not
384*/
385void
386Decorator::SetZoom(int32 tab, bool pressed)
387{
388	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
389	if (decoratorTab == NULL)
390		return;
391
392	if (pressed != decoratorTab->zoomPressed) {
393		decoratorTab->zoomPressed = pressed;
394		DrawZoom(tab);
395	}
396}
397
398
399/*!	\brief Updates the value of the decorator title
400	\param string New title value
401*/
402void
403Decorator::SetTitle(int32 tab, const char* string, BRegion* updateRegion)
404{
405	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
406	if (decoratorTab == NULL)
407		return;
408
409	decoratorTab->title.SetTo(string);
410	_SetTitle(decoratorTab, string, updateRegion);
411
412	_InvalidateFootprint();
413		// the border very likely changed
414
415	// TODO: redraw?
416}
417
418
419/*!	\brief Returns the decorator's title
420	\return the decorator's title
421*/
422const char*
423Decorator::Title(int32 tab) const
424{
425	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
426	if (decoratorTab == NULL)
427		return "";
428
429	return decoratorTab->title;
430}
431
432
433const char*
434Decorator::Title(Decorator::Tab* tab) const
435{
436	return tab->title;
437}
438
439
440float
441Decorator::TabLocation(int32 tab) const
442{
443	Decorator::Tab* decoratorTab = _TabAt(tab);
444	if (decoratorTab == NULL)
445		return 0.0f;
446
447	return (float)decoratorTab->tabOffset;
448}
449
450
451bool
452Decorator::SetTabLocation(int32 tab, float location, bool isShifting,
453	BRegion* updateRegion)
454{
455	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
456	if (decoratorTab == NULL)
457		return false;
458	if (_SetTabLocation(decoratorTab, location, isShifting, updateRegion)) {
459		_InvalidateFootprint();
460		return true;
461	}
462	return false;
463}
464
465
466
467/*!	\brief Changes the focus value of the decorator
468
469	While this call will not update the screen, it will affect how future
470	updates work.
471
472	\param active True if active, false if not
473*/
474void
475Decorator::SetFocus(int32 tab, bool active)
476{
477	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
478	if (decoratorTab == NULL)
479		return;
480	decoratorTab->isFocused = active;
481	_SetFocus(decoratorTab);
482	// TODO: maybe it would be cleaner to handle the redraw here.
483}
484
485
486bool
487Decorator::IsFocus(int32 tab) const
488{
489	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
490	if (decoratorTab == NULL)
491		return false;
492
493	return decoratorTab->isFocused;
494};
495
496
497bool
498Decorator::IsFocus(Decorator::Tab* tab) const
499{
500	return tab->isFocused;
501}
502
503
504//	#pragma mark - virtual methods
505
506
507/*!	\brief Returns a cached footprint if available otherwise recalculate it
508*/
509const BRegion&
510Decorator::GetFootprint()
511{
512	if (!fFootprintValid) {
513		_GetFootprint(&fFootprint);
514		fFootprintValid = true;
515	}
516	return fFootprint;
517}
518
519
520/*!	\brief Returns our Desktop object pointer
521*/
522::Desktop*
523Decorator::GetDesktop()
524{
525	return fDesktop;
526}
527
528
529/*!	\brief Performs hit-testing for the decorator.
530
531	The base class provides a basic implementation, recognizing only button and
532	tab hits. Derived classes must override/enhance it to handle borders and
533	corners correctly.
534
535	\param where The point to be tested.
536	\return Either of the following, depending on what was hit:
537		- \c REGION_NONE: None of the decorator regions.
538		- \c REGION_TAB: The window tab (but none of the buttons embedded).
539		- \c REGION_CLOSE_BUTTON: The close button.
540		- \c REGION_ZOOM_BUTTON: The zoom button.
541		- \c REGION_MINIMIZE_BUTTON: The minimize button.
542		- \c REGION_LEFT_BORDER: The left border.
543		- \c REGION_RIGHT_BORDER: The right border.
544		- \c REGION_TOP_BORDER: The top border.
545		- \c REGION_BOTTOM_BORDER: The bottom border.
546		- \c REGION_LEFT_TOP_CORNER: The left-top corner.
547		- \c REGION_LEFT_BOTTOM_CORNER: The left-bottom corner.
548		- \c REGION_RIGHT_TOP_CORNER: The right-top corner.
549		- \c REGION_RIGHT_BOTTOM_CORNER The right-bottom corner.
550*/
551Decorator::Region
552Decorator::RegionAt(BPoint where, int32& tabIndex) const
553{
554	tabIndex = -1;
555
556	for (int32 i = 0; i < fTabList.CountItems(); i++) {
557		Decorator::Tab* tab = fTabList.ItemAt(i);
558		if (tab->closeRect.Contains(where)) {
559			tabIndex = i;
560			return REGION_CLOSE_BUTTON;
561		}
562		if (tab->zoomRect.Contains(where)) {
563			tabIndex = i;
564			return REGION_ZOOM_BUTTON;
565		}
566		if (tab->tabRect.Contains(where)) {
567			tabIndex = i;
568			return REGION_TAB;
569		}
570	}
571
572	return REGION_NONE;
573}
574
575
576/*!	\brief Moves the decorator frame and all default rectangles
577
578	If a subclass implements this method, be sure to call Decorator::MoveBy
579	to ensure that internal members are also updated. All members of the
580	Decorator class are automatically moved in this method
581
582	\param x X Offset
583	\param y y Offset
584*/
585void
586Decorator::MoveBy(float x, float y)
587{
588	MoveBy(BPoint(x, y));
589}
590
591
592/*!	\brief Moves the decorator frame and all default rectangles
593
594	If a subclass implements this method, be sure to call Decorator::MoveBy
595	to ensure that internal members are also updated. All members of the
596	Decorator class are automatically moved in this method
597
598	\param offset BPoint containing the offsets
599*/
600void
601Decorator::MoveBy(BPoint offset)
602{
603	if (fFootprintValid)
604		fFootprint.OffsetBy(offset.x, offset.y);
605
606	_MoveBy(offset);
607}
608
609
610/*!	\brief Resizes the decorator frame
611
612	This is a required function for subclasses to implement - the default does
613	nothing. Note that window resize flags should be followed and fFrame should
614	be resized accordingly. It would also be a wise idea to ensure that the
615	window's rectangles are not inverted.
616
617	\param x x offset
618	\param y y offset
619*/
620void
621Decorator::ResizeBy(float x, float y, BRegion* dirty)
622{
623	ResizeBy(BPoint(x, y), dirty);
624}
625
626
627void
628Decorator::ResizeBy(BPoint offset, BRegion* dirty)
629{
630	_ResizeBy(offset, dirty);
631	_InvalidateFootprint();
632}
633
634
635void
636Decorator::ExtendDirtyRegion(Region region, BRegion& dirty)
637{
638	switch (region) {
639		case REGION_TAB:
640			dirty.Include(fTitleBarRect);
641			break;
642
643		case REGION_CLOSE_BUTTON:
644			if ((fTopTab->flags & B_NOT_CLOSABLE) == 0) {
645				for (int32 i = 0; i < fTabList.CountItems(); i++)
646					dirty.Include(fTabList.ItemAt(i)->closeRect);
647			}
648			break;
649
650		case REGION_MINIMIZE_BUTTON:
651			if ((fTopTab->flags & B_NOT_MINIMIZABLE) == 0) {
652				for (int32 i = 0; i < fTabList.CountItems(); i++)
653					dirty.Include(fTabList.ItemAt(i)->minimizeRect);
654			}
655			break;
656
657		case REGION_ZOOM_BUTTON:
658			if ((fTopTab->flags & B_NOT_ZOOMABLE) == 0) {
659				for (int32 i = 0; i < fTabList.CountItems(); i++)
660					dirty.Include(fTabList.ItemAt(i)->zoomRect);
661			}
662			break;
663
664		case REGION_LEFT_BORDER:
665			if (fLeftBorder.IsValid()) {
666				// fLeftBorder doesn't include the corners, so we have to add
667				// them manually.
668				BRect rect(fLeftBorder);
669				rect.top = fTopBorder.top;
670				rect.bottom = fBottomBorder.bottom;
671				dirty.Include(rect);
672			}
673			break;
674
675		case REGION_RIGHT_BORDER:
676			if (fRightBorder.IsValid()) {
677				// fRightBorder doesn't include the corners, so we have to add
678				// them manually.
679				BRect rect(fRightBorder);
680				rect.top = fTopBorder.top;
681				rect.bottom = fBottomBorder.bottom;
682				dirty.Include(rect);
683			}
684			break;
685
686		case REGION_TOP_BORDER:
687			dirty.Include(fTopBorder);
688			break;
689
690		case REGION_BOTTOM_BORDER:
691			dirty.Include(fBottomBorder);
692			break;
693
694		case REGION_RIGHT_BOTTOM_CORNER:
695			if ((fTopTab->flags & B_NOT_RESIZABLE) == 0)
696				dirty.Include(fResizeRect);
697			break;
698
699		default:
700			break;
701	}
702}
703
704
705/*!	\brief Sets a specific highlight for a decorator region.
706
707	Can be overridden by derived classes, but the base class version must be
708	called, if the highlight shall be applied.
709
710	\param region The decorator region.
711	\param highlight The value identifying the kind of highlight.
712	\param dirty The dirty region to be extended, if the highlight changes. Can
713		be \c NULL.
714	\return \c true, if the highlight could be applied.
715*/
716bool
717Decorator::SetRegionHighlight(Region region, uint8 highlight, BRegion* dirty,
718	int32 tab)
719{
720	int32 index = (int32)region - 1;
721	if (index < 0 || index >= REGION_COUNT - 1)
722		return false;
723
724	if (fRegionHighlights[index] == highlight)
725		return true;
726	fRegionHighlights[index] = highlight;
727
728	if (dirty != NULL)
729		ExtendDirtyRegion(region, *dirty);
730
731	return true;
732}
733
734
735bool
736Decorator::SetSettings(const BMessage& settings, BRegion* updateRegion)
737{
738	if (_SetSettings(settings, updateRegion)) {
739		_InvalidateFootprint();
740		return true;
741	}
742	return false;
743}
744
745
746bool
747Decorator::GetSettings(BMessage* settings) const
748{
749	if (!fTitleBarRect.IsValid())
750		return false;
751
752	if (settings->AddRect("tab frame", fTitleBarRect) != B_OK)
753		return false;
754
755	if (settings->AddFloat("border width", fBorderWidth) != B_OK)
756		return false;
757
758	// TODO only add the location of the tab of the window who requested the
759	// settings
760	for (int32 i = 0; i < fTabList.CountItems(); i++) {
761		Decorator::Tab* tab = _TabAt(i);
762		if (settings->AddFloat("tab location", (float)tab->tabOffset) != B_OK)
763			return false;
764	}
765
766	return true;
767}
768
769
770void
771Decorator::GetSizeLimits(int32* minWidth, int32* minHeight,
772	int32* maxWidth, int32* maxHeight) const
773{
774	float minTabSize = 0;
775	if (CountTabs() > 0)
776		minTabSize = _TabAt(0)->minTabSize;
777
778	if (fTitleBarRect.IsValid()) {
779		*minWidth = (int32)roundf(max_c(*minWidth,
780			minTabSize - 2 * fBorderWidth));
781	}
782	if (fResizeRect.IsValid()) {
783		*minHeight = (int32)roundf(max_c(*minHeight,
784			fResizeRect.Height() - fBorderWidth));
785	}
786}
787
788
789//! draws the tab, title, and buttons
790void
791Decorator::DrawTab(int32 tabIndex)
792{
793	Decorator::Tab* tab = fTabList.ItemAt(tabIndex);
794	if (tab == NULL)
795		return;
796
797	_DrawTab(tab, tab->tabRect);
798	_DrawZoom(tab, false, tab->zoomRect);
799	_DrawMinimize(tab, false, tab->minimizeRect);
800	_DrawTitle(tab, tab->tabRect);
801	_DrawClose(tab, false, tab->closeRect);
802}
803
804
805//! draws the title
806void
807Decorator::DrawTitle(int32 tab)
808{
809	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
810	if (decoratorTab == NULL)
811		return;
812	_DrawTitle(decoratorTab, decoratorTab->tabRect);
813}
814
815
816//! Draws the close button
817void
818Decorator::DrawClose(int32 tab)
819{
820	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
821	if (decoratorTab == NULL)
822		return;
823
824	_DrawClose(decoratorTab, true, decoratorTab->closeRect);
825}
826
827
828//! draws the minimize button
829void
830Decorator::DrawMinimize(int32 tab)
831{
832	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
833	if (decoratorTab == NULL)
834		return;
835
836	_DrawTab(decoratorTab, decoratorTab->minimizeRect);
837}
838
839
840//! draws the zoom button
841void
842Decorator::DrawZoom(int32 tab)
843{
844	Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
845	if (decoratorTab == NULL)
846		return;
847	_DrawZoom(decoratorTab, true, decoratorTab->zoomRect);
848}
849
850
851rgb_color
852Decorator::UIColor(color_which which)
853{
854	DesktopSettings settings(fDesktop);
855	return settings.UIColor(which);
856}
857
858
859float
860Decorator::BorderWidth()
861{
862	return fBorderWidth;
863}
864
865
866float
867Decorator::TabHeight()
868{
869	if (fTitleBarRect.IsValid())
870		return fTitleBarRect.Height();
871
872	return fBorderWidth;
873}
874
875
876// #pragma mark - Protected methods
877
878
879Decorator::Tab*
880Decorator::_AllocateNewTab()
881{
882	Decorator::Tab* tab = new(std::nothrow) Decorator::Tab;
883	if (tab == NULL)
884		return NULL;
885
886	// Set appropriate colors based on the current focus value. In this case,
887	// each decorator defaults to not having the focus.
888	_SetFocus(tab);
889	return tab;
890}
891
892
893void
894Decorator::_DrawTabs(BRect rect)
895{
896	Decorator::Tab* focusTab = NULL;
897	for (int32 i = 0; i < fTabList.CountItems(); i++) {
898		Decorator::Tab* tab = fTabList.ItemAt(i);
899		if (tab->isFocused) {
900			focusTab = tab;
901			continue;
902		}
903		_DrawTab(tab, rect);
904	}
905
906	if (focusTab != NULL)
907		_DrawTab(focusTab, rect);
908}
909
910
911//! Hook function called when the decorator changes focus
912void
913Decorator::_SetFocus(Decorator::Tab* tab)
914{
915}
916
917
918bool
919Decorator::_SetTabLocation(Decorator::Tab* tab, float location, bool isShifting,
920	BRegion* /*updateRegion*/)
921{
922	return false;
923}
924
925
926Decorator::Tab*
927Decorator::_TabAt(int32 index) const
928{
929	return static_cast<Decorator::Tab*>(fTabList.ItemAt(index));
930}
931
932
933void
934Decorator::_FontsChanged(DesktopSettings& settings, BRegion* updateRegion)
935{
936	// get previous extent
937	if (updateRegion != NULL)
938		updateRegion->Include(&GetFootprint());
939
940	_InvalidateBitmaps();
941
942	_UpdateFont(settings);
943	_DoLayout();
944
945	_InvalidateFootprint();
946	if (updateRegion != NULL)
947		updateRegion->Include(&GetFootprint());
948}
949
950
951void
952Decorator::_SetLook(Decorator::Tab* tab, DesktopSettings& settings,
953	window_look look, BRegion* updateRegion)
954{
955	// TODO: we could be much smarter about the update region
956
957	// get previous extent
958	if (updateRegion != NULL)
959		updateRegion->Include(&GetFootprint());
960
961	tab->look = look;
962
963	_UpdateFont(settings);
964	_DoLayout();
965
966	_InvalidateFootprint();
967	if (updateRegion != NULL)
968		updateRegion->Include(&GetFootprint());
969}
970
971
972void
973Decorator::_SetFlags(Decorator::Tab* tab, uint32 flags, BRegion* updateRegion)
974{
975	// TODO: we could be much smarter about the update region
976
977	// get previous extent
978	if (updateRegion != NULL)
979		updateRegion->Include(&GetFootprint());
980
981	tab->flags = flags;
982	_DoLayout();
983
984	_InvalidateFootprint();
985	if (updateRegion != NULL)
986		updateRegion->Include(&GetFootprint());
987}
988
989
990void
991Decorator::_MoveBy(BPoint offset)
992{
993	for (int32 i = 0; i < fTabList.CountItems(); i++) {
994		Decorator::Tab* tab = fTabList.ItemAt(i);
995
996		tab->zoomRect.OffsetBy(offset);
997		tab->closeRect.OffsetBy(offset);
998		tab->minimizeRect.OffsetBy(offset);
999		tab->tabRect.OffsetBy(offset);
1000	}
1001	fTitleBarRect.OffsetBy(offset);
1002	fFrame.OffsetBy(offset);
1003	fResizeRect.OffsetBy(offset);
1004	fBorderRect.OffsetBy(offset);
1005}
1006
1007
1008bool
1009Decorator::_SetSettings(const BMessage& settings, BRegion* updateRegion)
1010{
1011	return false;
1012}
1013
1014
1015/*!	\brief Returns the "footprint" of the entire window, including decorator
1016
1017	This function is required by all subclasses.
1018
1019	\param region Region to be changed to represent the window's screen
1020		footprint
1021*/
1022void
1023Decorator::_GetFootprint(BRegion *region)
1024{
1025}
1026
1027
1028void
1029Decorator::_InvalidateFootprint()
1030{
1031	fFootprintValid = false;
1032}
1033
1034
1035void
1036Decorator::_InvalidateBitmaps()
1037{
1038	for (int32 i = 0; i < fTabList.CountItems(); i++) {
1039		Decorator::Tab* tab = static_cast<Decorator::Tab*>(_TabAt(i));
1040		for (int32 index = 0; index < 4; index++) {
1041			tab->closeBitmaps[index] = NULL;
1042			tab->minimizeBitmaps[index] = NULL;
1043			tab->zoomBitmaps[index] = NULL;
1044		}
1045	}
1046}
1047