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