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