1/*
2 * Copyright 2009-2010, Haiku.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7/*! Decorator looking like Mac OS 9 */
8
9
10#include "MacDecorator.h"
11
12#include <new>
13#include <stdio.h>
14
15#include <GradientLinear.h>
16#include <Point.h>
17#include <View.h>
18
19#include "DesktopSettings.h"
20#include "DrawingEngine.h"
21#include "PatternHandler.h"
22#include "RGBColor.h"
23
24
25//#define DEBUG_DECORATOR
26#ifdef DEBUG_DECORATOR
27#	define STRACE(x) printf x
28#else
29#	define STRACE(x) ;
30#endif
31
32
33MacDecorAddOn::MacDecorAddOn(image_id id, const char* name)
34	:
35	DecorAddOn(id, name)
36{
37
38}
39
40
41Decorator*
42MacDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect)
43{
44	return new (std::nothrow)MacDecorator(settings, rect);
45}
46
47
48MacDecorator::MacDecorator(DesktopSettings& settings, BRect rect)
49	:
50	Decorator(settings, rect)
51{
52	_UpdateFont(settings);
53
54	frame_highcol = (rgb_color){ 255, 255, 255, 255 };
55	frame_midcol = (rgb_color){ 216, 216, 216, 255 };
56	frame_lowcol = (rgb_color){ 110, 110, 110, 255 };
57	frame_lowercol = (rgb_color){ 0, 0, 0, 255 };
58
59	fButtonHighColor = (rgb_color){ 232, 232, 232, 255 };
60	fButtonLowColor = (rgb_color){ 128, 128, 128, 255 };
61
62	fFocusTextColor = settings.UIColor(B_WINDOW_TEXT_COLOR);
63	fNonFocusTextColor = settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR);
64
65	_DoLayout();
66
67	textoffset=5;
68
69	STRACE(("MacDecorator()\n"));
70}
71
72
73MacDecorator::~MacDecorator()
74{
75	STRACE(("~MacDecorator()\n"));
76}
77
78
79// TODO : Add GetSettings
80
81
82void
83MacDecorator::Draw(BRect update)
84{
85	STRACE(("MacDecorator: Draw(%.1f,%.1f,%.1f,%.1f)\n",
86		update.left, update.top, update.right, update.bottom));
87
88	// We need to draw a few things: the tab, the borders,
89	// and the buttons
90	fDrawingEngine->SetDrawState(&fDrawState);
91
92	_DrawFrame(update);
93	_DrawTab(update);
94}
95
96
97void
98MacDecorator::Draw()
99{
100	STRACE("MacDecorator::Draw()\n");
101	fDrawingEngine->SetDrawState(&fDrawState);
102
103	_DrawFrame(fBorderRect);
104	_DrawTab(fTitleBarRect);
105}
106
107
108// TODO : add GetSizeLimits
109
110
111Decorator::Region
112MacDecorator::RegionAt(BPoint where, int32& tab) const
113{
114	// Let the base class version identify hits of the buttons and the tab.
115	Region region = Decorator::RegionAt(where, tab);
116	if (region != REGION_NONE)
117		return region;
118
119	// check the resize corner
120	if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
121		return REGION_RIGHT_BOTTOM_CORNER;
122
123	// hit-test the borders
124	if (!(fTopTab->flags & B_NOT_RESIZABLE)
125		&& (fTopTab->look == B_TITLED_WINDOW_LOOK
126			|| fTopTab->look == B_FLOATING_WINDOW_LOOK
127			|| fTopTab->look == B_MODAL_WINDOW_LOOK)
128		&& fBorderRect.Contains(where) && !fFrame.Contains(where)) {
129		return REGION_BOTTOM_BORDER;
130			// TODO: Determine the actual border!
131	}
132
133	return REGION_NONE;
134}
135
136
137void
138MacDecorator::_DoLayout()
139{
140	const int32 kDefaultBorderWidth = 6;
141	STRACE(("MacDecorator: Do Layout\n"));
142	// Here we determine the size of every rectangle that we use
143	// internally when we are given the size of the client rectangle.
144
145	bool hasTab = false;
146
147	if (fTopTab) {
148		switch (fTopTab->look) {
149			case B_MODAL_WINDOW_LOOK:
150				fBorderWidth = kDefaultBorderWidth;
151				break;
152
153			case B_TITLED_WINDOW_LOOK:
154			case B_DOCUMENT_WINDOW_LOOK:
155				hasTab = true;
156				fBorderWidth = kDefaultBorderWidth;
157				break;
158			case B_FLOATING_WINDOW_LOOK:
159				hasTab = true;
160				fBorderWidth = 3;
161				break;
162
163			case B_BORDERED_WINDOW_LOOK:
164				fBorderWidth = 1;
165				break;
166
167			default:
168				fBorderWidth = 0;
169		}
170	} else
171		fBorderWidth = 0;
172	fBorderRect=fFrame;
173	fBorderRect.InsetBy(-fBorderWidth, -fBorderWidth);
174
175	// calculate our tab rect
176	if (hasTab) {
177		fBorderRect.top +=3;
178
179		font_height fontHeight;
180		fDrawState.Font().GetHeight(fontHeight);
181
182		// TODO the tab is drawn in a fixed height for now
183		fTitleBarRect.Set(fFrame.left - fBorderWidth,
184			fFrame.top - 23,
185			((fFrame.right - fFrame.left) < 32.0 ?
186				fFrame.left + 32.0 : fFrame.right) + fBorderWidth,
187			fFrame.top - 3);
188
189		fTopTab->tabRect = fTitleBarRect; // TODO actually handle multiple tabs
190
191		fTopTab->zoomRect=fTitleBarRect;
192		fTopTab->zoomRect.left=fTopTab->zoomRect.right - 12;
193		fTopTab->zoomRect.bottom=fTopTab->zoomRect.top + 12;
194		fTopTab->zoomRect.OffsetBy(-4, 4);
195
196		fTopTab->closeRect=fTopTab->zoomRect;
197		fTopTab->minimizeRect=fTopTab->zoomRect;
198
199		fTopTab->closeRect.OffsetTo(fTitleBarRect.left + 4,
200			fTitleBarRect.top + 4);
201
202		fTopTab->zoomRect.OffsetBy(0 - (fTopTab->zoomRect.Width() + 4), 0);
203		if (Title(fTopTab) && fDrawingEngine) {
204			titlepixelwidth=fDrawingEngine->StringWidth(Title(fTopTab),
205				strlen(Title(fTopTab)));
206
207			if (titlepixelwidth<(fTopTab->zoomRect.left
208					- fTopTab->closeRect.right-10)) {
209				// start with offset from closerect.right
210				textoffset=int(((fTopTab->zoomRect.left - 5)
211					- (fTopTab->closeRect.right + 5)) / 2);
212				textoffset-=int(titlepixelwidth / 2);
213
214				// now make it the offset from fTabRect.left
215				textoffset+=int(fTopTab->closeRect.right + 5
216					- fTitleBarRect.left);
217			} else
218				textoffset=int(fTopTab->closeRect.right) + 5;
219		} else {
220			textoffset = 0;
221			titlepixelwidth = 0;
222		}
223	} else {
224		// no tab
225		if (fTopTab) {
226			fTopTab->tabRect.Set(0.0, 0.0, -1.0, -1.0);
227			fTopTab->closeRect.Set(0.0, 0.0, -1.0, -1.0);
228			fTopTab->zoomRect.Set(0.0, 0.0, -1.0, -1.0);
229			fTopTab->minimizeRect.Set(0.0, 0.0, -1.0, -1.0);
230		}
231	}
232}
233
234
235void
236MacDecorator::_DrawFrame(BRect invalid)
237{
238	if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
239		return;
240
241	if (fBorderWidth <= 0)
242		return;
243
244	BRect r = fBorderRect;
245	switch (fTopTab->look) {
246		case B_TITLED_WINDOW_LOOK:
247		case B_DOCUMENT_WINDOW_LOOK:
248		case B_MODAL_WINDOW_LOOK:
249		{
250			if (IsFocus(fTopTab)) {
251				BPoint offset = r.LeftTop();
252				BPoint pt2 = r.LeftBottom();
253
254				// Draw the left side of the frame
255				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
256				offset.x++;
257				pt2.x++;
258				pt2.y--;
259
260				fDrawingEngine->StrokeLine(offset,pt2,frame_highcol);
261				offset.x++;
262				pt2.x++;
263				pt2.y--;
264
265				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
266				offset.x++;
267				pt2.x++;
268				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
269				offset.x++;
270				pt2.x++;
271				pt2.y--;
272
273				fDrawingEngine->StrokeLine(offset,pt2,frame_lowcol);
274				offset.x++;
275				offset.y+=2;
276				BPoint topleftpt=offset;
277				pt2.x++;
278				pt2.y--;
279
280				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
281
282
283				offset=r.RightTop();
284				pt2=r.RightBottom();
285
286				// Draw the right side of the frame
287				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
288				offset.x--;
289				pt2.x--;
290
291				fDrawingEngine->StrokeLine(offset,pt2,frame_lowcol);
292				offset.x--;
293				pt2.x--;
294
295				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
296				offset.x--;
297				pt2.x--;
298				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
299				offset.x--;
300				pt2.x--;
301
302				fDrawingEngine->StrokeLine(offset,pt2,frame_highcol);
303				offset.x--;
304				offset.y+=2;
305				BPoint toprightpt=offset;
306				pt2.x--;
307
308				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
309
310				// Draw the top side of the frame that is not in the tab
311				offset=r.RightTop();
312				pt2=r.RightBottom();
313
314				fDrawingEngine->StrokeLine(topleftpt,toprightpt,frame_lowercol);
315				topleftpt.y--;
316				toprightpt.x++;
317				toprightpt.y--;
318
319				fDrawingEngine->StrokeLine(topleftpt,toprightpt,frame_lowcol);
320
321				offset=r.LeftBottom();
322				pt2=r.RightBottom();
323
324				// Draw the bottom side of the frame
325				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
326				offset.x++;
327				offset.y--;
328				pt2.x--;
329				pt2.y--;
330
331				fDrawingEngine->StrokeLine(offset,pt2,frame_lowcol);
332				offset.x++;
333				offset.y--;
334				pt2.x--;
335				pt2.y--;
336
337				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
338				offset.x++;
339				offset.y--;
340				pt2.x--;
341				pt2.y--;
342
343				fDrawingEngine->StrokeLine(offset,pt2,frame_midcol);
344				offset.x++;
345				offset.y--;
346				pt2.x--;
347				pt2.y--;
348
349				fDrawingEngine->StrokeLine(offset,pt2,frame_highcol);
350				offset.x+=2;
351				offset.y--;
352				pt2.x--;
353				pt2.y--;
354
355				fDrawingEngine->StrokeLine(offset,pt2,frame_lowercol);
356				offset.y--;
357				pt2.x--;
358				pt2.y--;
359			} else {
360				fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), frame_lowcol);
361				fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), frame_lowcol);
362				fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), frame_lowcol);
363
364				for (int i = 0; i < 4; i++) {
365					r.InsetBy(1, 1);
366					fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), frame_midcol);
367					fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), frame_midcol);
368					fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), frame_midcol);
369				}
370
371				r.InsetBy(1, 1);
372				fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), frame_lowcol);
373				fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), frame_lowcol);
374				fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), frame_lowcol);
375			}
376			break;
377		}
378		case B_BORDERED_WINDOW_LOOK:
379		fDrawingEngine->StrokeRect(r, frame_midcol);
380		break;
381
382		default:
383		// don't draw a border frame
384		break;
385	}
386}
387
388
389void
390MacDecorator::_DrawTab(BRect invalid)
391{
392	// If a window has a tab, this will draw it and any buttons which are
393	// in it.
394	if (!fTitleBarRect.IsValid() || !invalid.Intersects(fTitleBarRect))
395		return;
396
397	BRect rect(fTitleBarRect);
398	fDrawingEngine->SetHighColor(RGBColor(frame_midcol));
399	fDrawingEngine->FillRect(rect,frame_midcol);
400
401	if (IsFocus(fTopTab)) {
402		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop(),frame_lowercol);
403		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.LeftBottom(),frame_lowercol);
404		fDrawingEngine->StrokeLine(rect.RightBottom(),rect.RightTop(),frame_lowercol);
405
406		rect.InsetBy(1,1);
407		rect.bottom++;
408
409		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop(),frame_highcol);
410		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.LeftBottom(),frame_highcol);
411		fDrawingEngine->StrokeLine(rect.RightBottom(),rect.RightTop(),frame_lowcol);
412
413		// Draw the neat little lines on either side of the title if there's room
414		if (fTitleBarRect.left + textoffset > fTopTab->closeRect.right + 5) {
415			// Left side
416
417			BPoint offset(fTopTab->closeRect.right+5,fTopTab->closeRect.top),
418				pt2(fTitleBarRect.left+textoffset-5,fTopTab->closeRect.top);
419			fDrawState.SetHighColor(RGBColor(frame_highcol));
420			for (int32 i = 0; i < 6; i++) {
421				fDrawingEngine->StrokeLine(offset,pt2,fDrawState.HighColor());
422				offset.y+=2;
423				pt2.y+=2;
424			}
425
426			offset.Set(fTopTab->closeRect.right+6,fTopTab->closeRect.top+1),
427				pt2.Set(fTitleBarRect.left+textoffset-4,fTopTab->closeRect.top+1);
428			fDrawState.SetHighColor(RGBColor(frame_lowcol));
429			for (int32 i = 0; i < 6; i++) {
430				fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
431				offset.y += 2;
432				pt2.y += 2;
433			}
434
435			// Right side
436
437			offset.Set(fTitleBarRect.left + textoffset + titlepixelwidth + 6,
438				fTopTab->zoomRect.top), pt2.Set(fTopTab->zoomRect.left - 6,
439				fTopTab->zoomRect.top);
440			if (offset.x < pt2.x) {
441				fDrawState.SetHighColor(RGBColor(frame_highcol));
442				for (int32 i = 0; i < 6; i++) {
443					fDrawingEngine->StrokeLine(offset, pt2,
444						fDrawState.HighColor());
445					offset.y += 2;
446					pt2.y += 2;
447				}
448				offset.Set(fTitleBarRect.left+textoffset + titlepixelwidth + 7,
449					fTopTab->zoomRect.top + 1), pt2.Set(fTopTab->zoomRect.left - 5,
450					fTopTab->zoomRect.top + 1);
451				fDrawState.SetHighColor(frame_lowcol);
452				for(int32 i = 0; i < 6; i++) {
453					fDrawingEngine->StrokeLine(offset, pt2,
454						fDrawState.HighColor());
455					offset.y += 2;
456					pt2.y += 2;
457				}
458			}
459		}
460
461		// Draw the buttons if we're supposed to
462		if (!(fTopTab->flags & B_NOT_CLOSABLE))
463			_DrawClose(fTopTab->closeRect);
464		if (!(fTopTab->flags & B_NOT_ZOOMABLE))
465			_DrawZoom(fTopTab->zoomRect);
466	} else {
467		// Not focused - Just draw a plain light grey area with the title in the middle
468		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.RightTop(),frame_lowcol);
469		fDrawingEngine->StrokeLine(rect.LeftTop(),rect.LeftBottom(),frame_lowcol);
470		fDrawingEngine->StrokeLine(rect.RightBottom(),rect.RightTop(),frame_lowcol);
471	}
472
473	_DrawTitle(fTitleBarRect);
474}
475
476
477void
478MacDecorator::_DrawClose(BRect r)
479{
480	bool down = fTopTab->closePressed;
481
482	// Just like DrawZoom, but for a close button
483	BRect rect(r);
484
485	BPoint offset(r.LeftTop()), pt2(r.RightTop());
486
487	// Topleft dark grey border
488	pt2.x--;
489	fDrawingEngine->SetHighColor(RGBColor(136, 136, 136));
490	fDrawingEngine->StrokeLine(offset, pt2);
491
492	pt2 = r.LeftBottom();
493	pt2.y--;
494	fDrawingEngine->StrokeLine(offset, pt2);
495
496	// Bottomright white border
497	offset = r.RightBottom();
498	pt2 = r.RightTop();
499	pt2.y++;
500	fDrawingEngine->SetHighColor(RGBColor(255, 255, 255));
501	fDrawingEngine->StrokeLine(offset, pt2);
502
503	pt2 = r.LeftBottom();
504	pt2.x++;
505	fDrawingEngine->StrokeLine(offset, pt2);
506
507	// Black outline
508	rect.InsetBy(1, 1);
509	fDrawingEngine->SetHighColor(RGBColor(0, 0, 0));
510	fDrawingEngine->StrokeRect(rect);
511
512	// Double-shaded button
513	rect.InsetBy(1, 1);
514	_DrawBlendedRect(fDrawingEngine, rect, down);
515	rect.InsetBy(1, 1);
516	_DrawBlendedRect(fDrawingEngine, rect, !down);
517}
518
519
520void
521MacDecorator::_DrawTitle(BRect rect)
522{
523	if (IsFocus(fTopTab))
524		fDrawingEngine->SetHighColor(fFocusTextColor);
525	else
526		fDrawingEngine->SetHighColor(fNonFocusTextColor);
527
528	fDrawingEngine->SetLowColor(frame_midcol);
529
530	fTruncatedTitle = Title(fTopTab);
531	fDrawState.Font().TruncateString(&fTruncatedTitle, B_TRUNCATE_END,
532		(fTopTab->zoomRect.left - 5) - (fTopTab->closeRect.right + 5));
533	fTruncatedTitleLength = fTruncatedTitle.Length();
534	fDrawingEngine->SetFont(fDrawState.Font());
535
536	fDrawingEngine->DrawString(fTruncatedTitle,fTruncatedTitleLength,
537		BPoint(fTitleBarRect.left+textoffset,fTopTab->closeRect.bottom-1));
538}
539
540
541void
542MacDecorator::_DrawZoom(BRect r)
543{
544	bool down = fTopTab->zoomPressed;
545
546	// Just like DrawZoom, but for a close button
547	BRect rect(r);
548	BPoint offset(r.LeftTop()),pt2(r.RightTop());
549
550	pt2.x--;
551	fDrawState.SetHighColor(RGBColor(136, 136, 136));
552	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
553
554	pt2 = r.LeftBottom();
555	pt2.y--;
556	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
557
558	offset = r.RightBottom();
559	pt2 = r.RightTop();
560	pt2.y++;
561	fDrawState.SetHighColor(RGBColor(255, 255, 255));
562	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
563
564	pt2 = r.LeftBottom();
565	pt2.x++;
566	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
567
568	rect.InsetBy(1, 1);
569	fDrawState.SetHighColor(RGBColor(0, 0, 0));
570	fDrawingEngine->StrokeRect(rect, fDrawState.HighColor());
571
572	rect.InsetBy(1, 1);
573	_DrawBlendedRect(fDrawingEngine, rect, down);
574	rect.InsetBy(1,1);
575	_DrawBlendedRect(fDrawingEngine, rect, !down);
576
577	rect.top += 2;
578	rect.left--;
579	rect.right++;
580
581	fDrawState.SetHighColor(RGBColor(0, 0, 0));
582	fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(),
583		fDrawState.HighColor());
584}
585
586
587void
588MacDecorator::_DrawMinimize(BRect r)
589{
590	bool down = fTopTab->minimizePressed;
591
592	// Just like DrawZoom, but for a Minimize button
593	BRect rect(r);
594	BPoint offset(r.LeftTop()), pt2(r.RightTop());
595
596	pt2.x--;
597	fDrawState.SetHighColor(RGBColor(136, 136, 136));
598	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
599
600	pt2 = r.LeftBottom();
601	pt2.y--;
602	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
603
604	offset = r.RightBottom();
605	pt2 = r.RightTop();
606	pt2.y++;
607	fDrawState.SetHighColor(RGBColor(255, 255, 255));
608	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
609
610	pt2 = r.LeftBottom();
611	pt2.x++;
612	fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor());
613
614	rect.InsetBy(1, 1);
615	fDrawState.SetHighColor(RGBColor(0, 0, 0));
616	fDrawingEngine->StrokeRect(rect, fDrawState.HighColor());
617
618	rect.InsetBy(1, 1);
619	_DrawBlendedRect(fDrawingEngine, rect, down);
620	rect.InsetBy(1, 1);
621	_DrawBlendedRect(fDrawingEngine, rect, !down);
622
623	rect.top += 4;
624	rect.bottom -= 4;
625	rect.InsetBy(-2, 0);
626
627	fDrawState.SetHighColor(RGBColor(0, 0, 0));
628	fDrawingEngine->StrokeRect(rect, fDrawState.HighColor());
629}
630
631
632void
633MacDecorator::_SetTitle(Tab* tab, const char* string, BRegion* updateRegion)
634{
635	// TODO: we could be much smarter about the update region
636	// TODO may this change the other tabs too ? (to make space for a longer
637	// title ?)
638
639	BRect rect = TabRect(fTopTab);
640
641	_DoLayout();
642
643	if (updateRegion == NULL)
644		return;
645
646	rect = rect | TabRect(fTopTab);
647
648	rect.bottom++;
649		// the border will look differently when the title is adjacent
650
651	updateRegion->Include(rect);
652}
653
654
655void
656MacDecorator::_FontsChanged(DesktopSettings& settings,
657	BRegion* updateRegion)
658{
659	// get previous extent
660	if (updateRegion != NULL)
661		updateRegion->Include(&GetFootprint());
662
663	_UpdateFont(settings);
664	_DoLayout();
665
666	_InvalidateFootprint();
667	if (updateRegion != NULL)
668		updateRegion->Include(&GetFootprint());
669}
670
671
672void
673MacDecorator::_SetLook(DesktopSettings& settings, window_look look,
674	BRegion* updateRegion)
675{
676	// TODO: we could be much smarter about the update region
677
678	// get previous extent
679	if (updateRegion != NULL)
680		updateRegion->Include(&GetFootprint());
681
682	fTopTab->look = look;
683
684	_UpdateFont(settings);
685	_DoLayout();
686
687	_InvalidateFootprint();
688	if (updateRegion != NULL)
689		updateRegion->Include(&GetFootprint());
690}
691
692
693void
694MacDecorator::_SetFlags(uint32 flags, BRegion* updateRegion)
695{
696	// TODO: we could be much smarter about the update region
697
698	// get previous extent
699	if (updateRegion != NULL)
700		updateRegion->Include(&GetFootprint());
701
702	_DoLayout();
703
704	_InvalidateFootprint();
705	if (updateRegion != NULL)
706		updateRegion->Include(&GetFootprint());
707}
708
709
710// TODO : _SetFocus
711
712
713void
714MacDecorator::_MoveBy(BPoint offset)
715{
716	// TODO handle all tabs
717	fFrame.OffsetBy(offset);
718	fTopTab->closeRect.OffsetBy(offset);
719	fTitleBarRect.OffsetBy(offset);
720	fTopTab->tabRect = fTitleBarRect;
721	fResizeRect.OffsetBy(offset);
722	fTopTab->zoomRect.OffsetBy(offset);
723	fBorderRect.OffsetBy(offset);
724}
725
726
727void
728MacDecorator::_ResizeBy(BPoint offset, BRegion* dirty)
729{
730	// Move all internal rectangles the appropriate amount
731	fFrame.right += offset.x;
732	fFrame.bottom += offset.y;
733
734	fTitleBarRect.right += offset.x;
735	fBorderRect.right += offset.x;
736	fBorderRect.bottom += offset.y;
737	// fZoomRect.OffsetBy(offset.x, 0);
738	// fMinimizeRect.OffsetBy(offset.x, 0);
739	if (dirty) {
740		dirty->Include(fTitleBarRect);
741		dirty->Include(fBorderRect);
742	}
743
744
745	// TODO probably some other layouting stuff here
746	_DoLayout();
747}
748
749
750// TODO : _SetSettings
751
752
753void
754MacDecorator::_GetFootprint(BRegion* region)
755{
756	// This function calculates the decorator's footprint in coordinates
757	// relative to the view. This is most often used to set a Window
758	// object's visible region.
759	if (!region)
760		return;
761
762	region->MakeEmpty();
763
764	if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
765		return;
766
767	region->Set(fBorderRect);
768	region->Exclude(fFrame);
769
770	if (fTopTab->look == B_BORDERED_WINDOW_LOOK)
771		return;
772	region->Include(fTitleBarRect);
773}
774
775
776void
777MacDecorator::_UpdateFont(DesktopSettings& settings)
778{
779	ServerFont font;
780	if (fTopTab && fTopTab->look == B_FLOATING_WINDOW_LOOK)
781		settings.GetDefaultPlainFont(font);
782	else
783		settings.GetDefaultBoldFont(font);
784
785	font.SetFlags(B_FORCE_ANTIALIASING);
786	font.SetSpacing(B_STRING_SPACING);
787	fDrawState.SetFont(font);
788}
789
790
791/*!	\brief Draws a rectangle with a gradient.
792  \param down The rectangle should be drawn recessed or not
793*/
794void
795MacDecorator::_DrawBlendedRect(DrawingEngine* engine, BRect rect,
796		bool down/*, bool focus*/)
797{
798	// figure out which colors to use
799	rgb_color startColor, endColor;
800	if (down) {
801		startColor = fButtonLowColor;
802		endColor = frame_highcol;
803	} else {
804		startColor = fButtonHighColor;
805		endColor = frame_lowercol;
806	}
807
808	// fill
809	BGradientLinear gradient;
810	gradient.SetStart(rect.LeftTop());
811	gradient.SetEnd(rect.RightBottom());
812	gradient.AddColor(startColor, 0);
813	gradient.AddColor(endColor, 255);
814
815	engine->FillRect(rect, gradient);
816}
817
818
819Decorator::Tab*
820MacDecorator::_AllocateNewTab()
821{
822	Decorator::Tab* tab = new(std::nothrow) MacDecorator::Tab;
823	if (tab == NULL)
824		return NULL;
825	// Set appropriate colors based on the current focus value. In this case,
826	// each decorator defaults to not having the focus.
827	_SetFocus(tab);
828	return tab;
829}
830
831
832bool
833MacDecorator::_AddTab(DesktopSettings& settings, int32 index,
834	BRegion* updateRegion)
835{
836	_UpdateFont(settings);
837
838	_DoLayout();
839	if (updateRegion != NULL)
840		updateRegion->Include(fTitleBarRect);
841	return true;
842}
843
844
845bool
846MacDecorator::_RemoveTab(int32 index, BRegion* updateRegion)
847{
848	BRect oldTitle = fTitleBarRect;
849	_DoLayout();
850	if (updateRegion != NULL) {
851		updateRegion->Include(oldTitle);
852		updateRegion->Include(fTitleBarRect);
853	}
854	return true;
855}
856
857
858bool
859MacDecorator::_MoveTab(int32 from, int32 to, bool isMoving,
860	BRegion* updateRegion)
861{
862	return false; //TODO
863	#if 0
864	MacDecorator::Tab* toTab = _TabAt(to);
865	if (toTab == NULL)
866		return false;
867
868	if (from < to) {
869		fOldMovingTab.OffsetBy(toTab->tabRect.Width(), 0);
870		toTab->tabRect.OffsetBy(-fOldMovingTab.Width(), 0);
871	} else {
872		fOldMovingTab.OffsetBy(-toTab->tabRect.Width(), 0);
873		toTab->tabRect.OffsetBy(fOldMovingTab.Width(), 0);
874	}
875
876	toTab->tabOffset = uint32(toTab->tabRect.left - fLeftBorder.left);
877	_LayoutTabItems(toTab, toTab->tabRect);
878
879	_CalculateTabsRegion();
880
881	if (updateRegion != NULL)
882		updateRegion->Include(fTitleBarRect);
883	return true;
884	#endif
885}
886
887
888// #pragma mark -
889
890
891extern "C" DecorAddOn*
892instantiate_decor_addon(image_id id, const char* name)
893{
894	return new (std::nothrow)MacDecorAddOn(id, name);
895}
896