2 * Copyright 2001-2015 Haiku, Inc.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus, superstippi@gmx.de
7 * DarkWyrm, bpmagic@columbus.rr.com
8 * Ryan Leavengood, leavengood@gmail.com
9 * Philippe Saint-Pierre, stpere@gmail.com
10 * John Scipione, jscipione@gmail.com
11 * Ingo Weinhold, ingo_weinhold@gmx.de
12 * Clemens Zeidler, haiku@clemens-zeidler.de
13 * Joseph Groover <looncraz@looncraz.net>
17 /*! Default and fallback decorator for the app_server - the yellow tabs */
20 #include "DefaultDecorator.h"
29 #include <GradientLinear.h>
34 #include <WindowPrivate.h>
36 #include "BitmapDrawingEngine.h"
37 #include "DesktopSettings.h"
38 #include "DrawingEngine.h"
39 #include "DrawState.h"
40 #include "FontManager.h"
41 #include "PatternHandler.h"
42 #include "ServerBitmap.h"
45 //#define DEBUG_DECORATOR
46 #ifdef DEBUG_DECORATOR
47 # define STRACE(x) printf x
53 static const float kBorderResizeLength
= 22.0;
54 static const float kResizeKnobSize
= 18.0;
58 blend_color_value(uint8 a
, uint8 b
, float position
)
60 int16 delta
= (int16
)b
- a
;
61 int32 value
= a
+ (int32
)(position
* delta
);
74 // TODO: get rid of DesktopSettings here, and introduce private accessor
75 // methods to the Decorator base class
76 DefaultDecorator::DefaultDecorator(DesktopSettings
& settings
, BRect rect
,
79 TabDecorator(settings
, rect
, desktop
)
81 // TODO: If the decorator was created with a frame too small, it should
84 STRACE(("DefaultDecorator:\n"));
85 STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
86 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
));
90 DefaultDecorator::~DefaultDecorator()
92 STRACE(("DefaultDecorator: ~DefaultDecorator()\n"));
96 // #pragma mark - Public methods
99 /*! Returns the frame colors for the specified decorator component.
101 The meaning of the color array elements depends on the specified component.
102 For some components some array elements are unused.
104 \param component The component for which to return the frame colors.
105 \param highlight The highlight set for the component.
106 \param colors An array of colors to be initialized by the function.
109 DefaultDecorator::GetComponentColors(Component component
, uint8 highlight
,
110 ComponentColors _colors
, Decorator::Tab
* _tab
)
112 Decorator::Tab
* tab
= static_cast<Decorator::Tab
*>(_tab
);
115 if (tab
&& tab
->buttonFocus
) {
116 _colors
[COLOR_TAB_FRAME_LIGHT
]
117 = tint_color(fFocusFrameColor
, B_DARKEN_2_TINT
);
118 _colors
[COLOR_TAB_FRAME_DARK
]
119 = tint_color(fFocusFrameColor
, B_DARKEN_3_TINT
);
120 _colors
[COLOR_TAB
] = fFocusTabColor
;
121 _colors
[COLOR_TAB_LIGHT
] = fFocusTabColorLight
;
122 _colors
[COLOR_TAB_BEVEL
] = fFocusTabColorBevel
;
123 _colors
[COLOR_TAB_SHADOW
] = fFocusTabColorShadow
;
124 _colors
[COLOR_TAB_TEXT
] = fFocusTextColor
;
126 _colors
[COLOR_TAB_FRAME_LIGHT
]
127 = tint_color(fNonFocusFrameColor
, B_DARKEN_2_TINT
);
128 _colors
[COLOR_TAB_FRAME_DARK
]
129 = tint_color(fNonFocusFrameColor
, B_DARKEN_3_TINT
);
130 _colors
[COLOR_TAB
] = fNonFocusTabColor
;
131 _colors
[COLOR_TAB_LIGHT
] = fNonFocusTabColorLight
;
132 _colors
[COLOR_TAB_BEVEL
] = fNonFocusTabColorBevel
;
133 _colors
[COLOR_TAB_SHADOW
] = fNonFocusTabColorShadow
;
134 _colors
[COLOR_TAB_TEXT
] = fNonFocusTextColor
;
138 case COMPONENT_CLOSE_BUTTON
:
139 case COMPONENT_ZOOM_BUTTON
:
140 if (tab
&& tab
->buttonFocus
) {
141 _colors
[COLOR_BUTTON
] = fFocusTabColor
;
142 _colors
[COLOR_BUTTON_LIGHT
] = fFocusTabColorLight
;
144 _colors
[COLOR_BUTTON
] = fNonFocusTabColor
;
145 _colors
[COLOR_BUTTON_LIGHT
] = fNonFocusTabColorLight
;
149 case COMPONENT_LEFT_BORDER
:
150 case COMPONENT_RIGHT_BORDER
:
151 case COMPONENT_TOP_BORDER
:
152 case COMPONENT_BOTTOM_BORDER
:
153 case COMPONENT_RESIZE_CORNER
:
155 if (tab
&& tab
->buttonFocus
) {
156 _colors
[0] = tint_color(fFocusFrameColor
, B_DARKEN_2_TINT
);
157 _colors
[1] = tint_color(fFocusFrameColor
, B_LIGHTEN_2_TINT
);
158 _colors
[2] = fFocusFrameColor
;
159 _colors
[3] = tint_color(fFocusFrameColor
,
160 (B_DARKEN_1_TINT
+ B_NO_TINT
) / 2);
161 _colors
[4] = tint_color(fFocusFrameColor
, B_DARKEN_2_TINT
);
162 _colors
[5] = tint_color(fFocusFrameColor
, B_DARKEN_3_TINT
);
164 _colors
[0] = tint_color(fNonFocusFrameColor
, B_DARKEN_2_TINT
);
165 _colors
[1] = tint_color(fNonFocusFrameColor
, B_LIGHTEN_2_TINT
);
166 _colors
[2] = fNonFocusFrameColor
;
167 _colors
[3] = tint_color(fNonFocusFrameColor
,
168 (B_DARKEN_1_TINT
+ B_NO_TINT
) / 2);
169 _colors
[4] = tint_color(fNonFocusFrameColor
, B_DARKEN_2_TINT
);
170 _colors
[5] = tint_color(fNonFocusFrameColor
, B_DARKEN_3_TINT
);
173 // for the resize-border highlight dye everything bluish.
174 if (highlight
== HIGHLIGHT_RESIZE_BORDER
) {
175 for (int32 i
= 0; i
< 6; i
++) {
176 _colors
[i
].red
= std::max((int)_colors
[i
].red
- 80, 0);
177 _colors
[i
].green
= std::max((int)_colors
[i
].green
- 80, 0);
178 _colors
[i
].blue
= 255;
187 DefaultDecorator::UpdateColors(DesktopSettings
& settings
)
189 TabDecorator::UpdateColors(settings
);
193 // #pragma mark - Protected methods
197 DefaultDecorator::_DrawFrame(BRect rect
)
199 STRACE(("_DrawFrame(%f,%f,%f,%f)\n", rect
.left
, rect
.top
,
200 rect
.right
, rect
.bottom
));
202 // NOTE: the DrawingEngine needs to be locked for the entire
203 // time for the clipping to stay valid for this decorator
205 if (fTopTab
->look
== B_NO_BORDER_WINDOW_LOOK
)
208 if (fBorderWidth
<= 0)
211 // Draw the border frame
212 BRect r
= BRect(fTopBorder
.LeftTop(), fBottomBorder
.RightBottom());
213 switch ((int)fTopTab
->look
) {
214 case B_TITLED_WINDOW_LOOK
:
215 case B_DOCUMENT_WINDOW_LOOK
:
216 case B_MODAL_WINDOW_LOOK
:
219 if (rect
.Intersects(fTopBorder
)) {
220 ComponentColors colors
;
221 _GetComponentColors(COMPONENT_TOP_BORDER
, colors
, fTopTab
);
223 for (int8 i
= 0; i
< 5; i
++) {
224 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.top
+ i
),
225 BPoint(r
.right
- i
, r
.top
+ i
), colors
[i
]);
227 if (fTitleBarRect
.IsValid()) {
228 // grey along the bottom of the tab
229 // (overwrites "white" from frame)
230 fDrawingEngine
->StrokeLine(
231 BPoint(fTitleBarRect
.left
+ 2,
232 fTitleBarRect
.bottom
+ 1),
233 BPoint(fTitleBarRect
.right
- 2,
234 fTitleBarRect
.bottom
+ 1),
239 if (rect
.Intersects(fLeftBorder
.InsetByCopy(0, -fBorderWidth
))) {
240 ComponentColors colors
;
241 _GetComponentColors(COMPONENT_LEFT_BORDER
, colors
, fTopTab
);
243 for (int8 i
= 0; i
< 5; i
++) {
244 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.top
+ i
),
245 BPoint(r
.left
+ i
, r
.bottom
- i
), colors
[i
]);
249 if (rect
.Intersects(fBottomBorder
)) {
250 ComponentColors colors
;
251 _GetComponentColors(COMPONENT_BOTTOM_BORDER
, colors
, fTopTab
);
253 for (int8 i
= 0; i
< 5; i
++) {
254 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.bottom
- i
),
255 BPoint(r
.right
- i
, r
.bottom
- i
),
256 colors
[(4 - i
) == 4 ? 5 : (4 - i
)]);
260 if (rect
.Intersects(fRightBorder
.InsetByCopy(0, -fBorderWidth
))) {
261 ComponentColors colors
;
262 _GetComponentColors(COMPONENT_RIGHT_BORDER
, colors
, fTopTab
);
264 for (int8 i
= 0; i
< 5; i
++) {
265 fDrawingEngine
->StrokeLine(BPoint(r
.right
- i
, r
.top
+ i
),
266 BPoint(r
.right
- i
, r
.bottom
- i
),
267 colors
[(4 - i
) == 4 ? 5 : (4 - i
)]);
273 case B_FLOATING_WINDOW_LOOK
:
274 case kLeftTitledWindowLook
:
277 if (rect
.Intersects(fTopBorder
)) {
278 ComponentColors colors
;
279 _GetComponentColors(COMPONENT_TOP_BORDER
, colors
, fTopTab
);
281 for (int8 i
= 0; i
< 3; i
++) {
282 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.top
+ i
),
283 BPoint(r
.right
- i
, r
.top
+ i
), colors
[i
* 2]);
285 if (fTitleBarRect
.IsValid() && fTopTab
->look
!= kLeftTitledWindowLook
) {
286 // grey along the bottom of the tab
287 // (overwrites "white" from frame)
288 fDrawingEngine
->StrokeLine(
289 BPoint(fTitleBarRect
.left
+ 2,
290 fTitleBarRect
.bottom
+ 1),
291 BPoint(fTitleBarRect
.right
- 2,
292 fTitleBarRect
.bottom
+ 1), colors
[2]);
296 if (rect
.Intersects(fLeftBorder
.InsetByCopy(0, -fBorderWidth
))) {
297 ComponentColors colors
;
298 _GetComponentColors(COMPONENT_LEFT_BORDER
, colors
, fTopTab
);
300 for (int8 i
= 0; i
< 3; i
++) {
301 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.top
+ i
),
302 BPoint(r
.left
+ i
, r
.bottom
- i
), colors
[i
* 2]);
304 if (fTopTab
->look
== kLeftTitledWindowLook
305 && fTitleBarRect
.IsValid()) {
306 // grey along the right side of the tab
307 // (overwrites "white" from frame)
308 fDrawingEngine
->StrokeLine(
309 BPoint(fTitleBarRect
.right
+ 1,
310 fTitleBarRect
.top
+ 2),
311 BPoint(fTitleBarRect
.right
+ 1,
312 fTitleBarRect
.bottom
- 2), colors
[2]);
316 if (rect
.Intersects(fBottomBorder
)) {
317 ComponentColors colors
;
318 _GetComponentColors(COMPONENT_BOTTOM_BORDER
, colors
, fTopTab
);
320 for (int8 i
= 0; i
< 3; i
++) {
321 fDrawingEngine
->StrokeLine(BPoint(r
.left
+ i
, r
.bottom
- i
),
322 BPoint(r
.right
- i
, r
.bottom
- i
),
323 colors
[(2 - i
) == 2 ? 5 : (2 - i
) * 2]);
327 if (rect
.Intersects(fRightBorder
.InsetByCopy(0, -fBorderWidth
))) {
328 ComponentColors colors
;
329 _GetComponentColors(COMPONENT_RIGHT_BORDER
, colors
, fTopTab
);
331 for (int8 i
= 0; i
< 3; i
++) {
332 fDrawingEngine
->StrokeLine(BPoint(r
.right
- i
, r
.top
+ i
),
333 BPoint(r
.right
- i
, r
.bottom
- i
),
334 colors
[(2 - i
) == 2 ? 5 : (2 - i
) * 2]);
340 case B_BORDERED_WINDOW_LOOK
:
342 // TODO: Draw the borders individually!
343 ComponentColors colors
;
344 _GetComponentColors(COMPONENT_LEFT_BORDER
, colors
, fTopTab
);
346 fDrawingEngine
->StrokeRect(r
, colors
[5]);
351 // don't draw a border frame
355 // Draw the resize knob if we're supposed to
356 if (!(fTopTab
->flags
& B_NOT_RESIZABLE
)) {
359 ComponentColors colors
;
360 _GetComponentColors(COMPONENT_RESIZE_CORNER
, colors
, fTopTab
);
362 switch ((int)fTopTab
->look
) {
363 case B_DOCUMENT_WINDOW_LOOK
:
365 if (!rect
.Intersects(r
))
368 float x
= r
.right
- 3;
369 float y
= r
.bottom
- 3;
371 BRect
bg(x
- 13, y
- 13, x
, y
);
373 BGradientLinear gradient
;
374 gradient
.SetStart(bg
.LeftTop());
375 gradient
.SetEnd(bg
.RightBottom());
376 gradient
.AddColor(colors
[1], 0);
377 gradient
.AddColor(colors
[2], 255);
379 fDrawingEngine
->FillRect(bg
, gradient
);
381 fDrawingEngine
->StrokeLine(BPoint(x
- 15, y
- 15),
382 BPoint(x
- 15, y
- 2), colors
[0]);
383 fDrawingEngine
->StrokeLine(BPoint(x
- 14, y
- 14),
384 BPoint(x
- 14, y
- 1), colors
[1]);
385 fDrawingEngine
->StrokeLine(BPoint(x
- 15, y
- 15),
386 BPoint(x
- 2, y
- 15), colors
[0]);
387 fDrawingEngine
->StrokeLine(BPoint(x
- 14, y
- 14),
388 BPoint(x
- 1, y
- 14), colors
[1]);
390 if (fTopTab
&& !IsFocus(fTopTab
))
393 static const rgb_color kWhite
394 = (rgb_color
){ 255, 255, 255, 255 };
395 for (int8 i
= 1; i
<= 4; i
++) {
396 for (int8 j
= 1; j
<= i
; j
++) {
397 BPoint
pt1(x
- (3 * j
) + 1, y
- (3 * (5 - i
)) + 1);
398 BPoint
pt2(x
- (3 * j
) + 2, y
- (3 * (5 - i
)) + 2);
399 fDrawingEngine
->StrokePoint(pt1
, colors
[0]);
400 fDrawingEngine
->StrokePoint(pt2
, kWhite
);
406 case B_TITLED_WINDOW_LOOK
:
407 case B_FLOATING_WINDOW_LOOK
:
408 case B_MODAL_WINDOW_LOOK
:
409 case kLeftTitledWindowLook
:
411 if (!rect
.Intersects(BRect(fRightBorder
.right
- kBorderResizeLength
,
412 fBottomBorder
.bottom
- kBorderResizeLength
, fRightBorder
.right
- 1,
413 fBottomBorder
.bottom
- 1)))
416 fDrawingEngine
->StrokeLine(
417 BPoint(fRightBorder
.left
, fBottomBorder
.bottom
- kBorderResizeLength
),
418 BPoint(fRightBorder
.right
- 1, fBottomBorder
.bottom
- kBorderResizeLength
),
420 fDrawingEngine
->StrokeLine(
421 BPoint(fRightBorder
.right
- kBorderResizeLength
, fBottomBorder
.top
),
422 BPoint(fRightBorder
.right
- kBorderResizeLength
, fBottomBorder
.bottom
- 1),
428 // don't draw resize corner
435 /*! \brief Actually draws the tab
437 This function is called when the tab itself needs drawn. Other items,
438 like the window title or buttons, should not be drawn here.
440 \param tab The \a tab to update.
441 \param rect The area of the \a tab to update.
444 DefaultDecorator::_DrawTab(Decorator::Tab
* tab
, BRect invalid
)
446 STRACE(("_DrawTab(%.1f,%.1f,%.1f,%.1f)\n",
447 invalid
.left
, invalid
.top
, invalid
.right
, invalid
.bottom
));
448 const BRect
& tabRect
= tab
->tabRect
;
449 // If a window has a tab, this will draw it and any buttons which are
451 if (!tabRect
.IsValid() || !invalid
.Intersects(tabRect
))
454 ComponentColors colors
;
455 _GetComponentColors(COMPONENT_TAB
, colors
, tab
);
458 fDrawingEngine
->StrokeLine(tabRect
.LeftTop(), tabRect
.LeftBottom(),
459 colors
[COLOR_TAB_FRAME_LIGHT
]);
460 fDrawingEngine
->StrokeLine(tabRect
.LeftTop(), tabRect
.RightTop(),
461 colors
[COLOR_TAB_FRAME_LIGHT
]);
462 if (tab
->look
!= kLeftTitledWindowLook
) {
463 fDrawingEngine
->StrokeLine(tabRect
.RightTop(), tabRect
.RightBottom(),
464 colors
[COLOR_TAB_FRAME_DARK
]);
466 fDrawingEngine
->StrokeLine(tabRect
.LeftBottom(),
467 tabRect
.RightBottom(), colors
[COLOR_TAB_FRAME_DARK
]);
470 float tabBotton
= tabRect
.bottom
;
475 fDrawingEngine
->StrokeLine(BPoint(tabRect
.left
+ 1, tabRect
.top
+ 1),
476 BPoint(tabRect
.left
+ 1,
477 tabBotton
- (tab
->look
== kLeftTitledWindowLook
? 1 : 0)),
478 colors
[COLOR_TAB_BEVEL
]);
479 fDrawingEngine
->StrokeLine(BPoint(tabRect
.left
+ 1, tabRect
.top
+ 1),
480 BPoint(tabRect
.right
- (tab
->look
== kLeftTitledWindowLook
? 0 : 1),
482 colors
[COLOR_TAB_BEVEL
]);
484 if (tab
->look
!= kLeftTitledWindowLook
) {
485 fDrawingEngine
->StrokeLine(BPoint(tabRect
.right
- 1, tabRect
.top
+ 2),
486 BPoint(tabRect
.right
- 1, tabBotton
),
487 colors
[COLOR_TAB_SHADOW
]);
489 fDrawingEngine
->StrokeLine(
490 BPoint(tabRect
.left
+ 2, tabRect
.bottom
- 1),
491 BPoint(tabRect
.right
, tabRect
.bottom
- 1),
492 colors
[COLOR_TAB_SHADOW
]);
496 BGradientLinear gradient
;
497 gradient
.SetStart(tabRect
.LeftTop());
498 gradient
.AddColor(colors
[COLOR_TAB_LIGHT
], 0);
499 gradient
.AddColor(colors
[COLOR_TAB
], 255);
501 if (tab
->look
!= kLeftTitledWindowLook
) {
502 gradient
.SetEnd(tabRect
.LeftBottom());
503 fDrawingEngine
->FillRect(BRect(tabRect
.left
+ 2, tabRect
.top
+ 2,
504 tabRect
.right
- 2, tabBotton
), gradient
);
506 gradient
.SetEnd(tabRect
.RightTop());
507 fDrawingEngine
->FillRect(BRect(tabRect
.left
+ 2, tabRect
.top
+ 2,
508 tabRect
.right
, tabRect
.bottom
- 2), gradient
);
511 _DrawTitle(tab
, tabRect
);
513 _DrawButtons(tab
, invalid
);
517 /*! \brief Actually draws the title
519 The main tasks for this function are to ensure that the decorator draws
520 the title only in its own area and drawing the title itself.
521 Using B_OP_COPY for drawing the title is recommended because of the marked
522 performance hit of the other drawing modes, but it is not a requirement.
524 \param tab The \a tab to update.
525 \param rect area of the title to update.
528 DefaultDecorator::_DrawTitle(Decorator::Tab
* _tab
, BRect rect
)
530 STRACE(("_DrawTitle(%f,%f,%f,%f)\n", rect
.left
, rect
.top
, rect
.right
,
533 Decorator::Tab
* tab
= static_cast<Decorator::Tab
*>(_tab
);
535 const BRect
& tabRect
= tab
->tabRect
;
536 const BRect
& closeRect
= tab
->closeRect
;
537 const BRect
& zoomRect
= tab
->zoomRect
;
539 ComponentColors colors
;
540 _GetComponentColors(COMPONENT_TAB
, colors
, tab
);
542 fDrawingEngine
->SetDrawingMode(B_OP_OVER
);
543 fDrawingEngine
->SetHighColor(colors
[COLOR_TAB_TEXT
]);
544 fDrawingEngine
->SetFont(fDrawState
.Font());
546 // figure out position of text
547 font_height fontHeight
;
548 fDrawState
.Font().GetHeight(fontHeight
);
551 if (tab
->look
!= kLeftTitledWindowLook
) {
552 titlePos
.x
= closeRect
.IsValid() ? closeRect
.right
+ tab
->textOffset
553 : tabRect
.left
+ tab
->textOffset
;
554 titlePos
.y
= floorf(((tabRect
.top
+ 2.0) + tabRect
.bottom
555 + fontHeight
.ascent
+ fontHeight
.descent
) / 2.0
556 - fontHeight
.descent
+ 0.5);
558 titlePos
.x
= floorf(((tabRect
.left
+ 2.0) + tabRect
.right
559 + fontHeight
.ascent
+ fontHeight
.descent
) / 2.0
560 - fontHeight
.descent
+ 0.5);
561 titlePos
.y
= zoomRect
.IsValid() ? zoomRect
.top
- tab
->textOffset
562 : tabRect
.bottom
- tab
->textOffset
;
565 fDrawingEngine
->DrawString(tab
->truncatedTitle
, tab
->truncatedTitleLength
,
568 fDrawingEngine
->SetDrawingMode(B_OP_COPY
);
572 /*! \brief Actually draws the close button
574 Unless a subclass has a particularly large button, it is probably
575 unnecessary to check the update rectangle.
577 \param _tab The \a tab to update.
578 \param direct Draw without double buffering.
579 \param rect The area of the button to update.
582 DefaultDecorator::_DrawClose(Decorator::Tab
* _tab
, bool direct
, BRect rect
)
584 STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect
.left
, rect
.top
, rect
.right
,
587 Decorator::Tab
* tab
= static_cast<Decorator::Tab
*>(_tab
);
589 int32 index
= (tab
->buttonFocus
? 0 : 1) + (tab
->closePressed
? 0 : 2);
590 ServerBitmap
* bitmap
= tab
->closeBitmaps
[index
];
591 if (bitmap
== NULL
) {
592 bitmap
= _GetBitmapForButton(tab
, COMPONENT_CLOSE_BUTTON
,
593 tab
->closePressed
, rect
.IntegerWidth(), rect
.IntegerHeight());
594 tab
->closeBitmaps
[index
] = bitmap
;
597 _DrawButtonBitmap(bitmap
, direct
, rect
);
601 /*! \brief Actually draws the zoom button
603 Unless a subclass has a particularly large button, it is probably
604 unnecessary to check the update rectangle.
606 \param _tab The \a tab to update.
607 \param direct Draw without double buffering.
608 \param rect The area of the button to update.
611 DefaultDecorator::_DrawZoom(Decorator::Tab
* _tab
, bool direct
, BRect rect
)
613 STRACE(("_DrawZoom(%f,%f,%f,%f)\n", rect
.left
, rect
.top
, rect
.right
,
616 if (rect
.IntegerWidth() < 1)
619 Decorator::Tab
* tab
= static_cast<Decorator::Tab
*>(_tab
);
620 int32 index
= (tab
->buttonFocus
? 0 : 1) + (tab
->zoomPressed
? 0 : 2);
621 ServerBitmap
* bitmap
= tab
->zoomBitmaps
[index
];
622 if (bitmap
== NULL
) {
623 bitmap
= _GetBitmapForButton(tab
, COMPONENT_ZOOM_BUTTON
,
624 tab
->zoomPressed
, rect
.IntegerWidth(), rect
.IntegerHeight());
625 tab
->zoomBitmaps
[index
] = bitmap
;
628 _DrawButtonBitmap(bitmap
, direct
, rect
);
633 DefaultDecorator::_DrawMinimize(Decorator::Tab
* tab
, bool direct
, BRect rect
)
635 // This decorator doesn't have this button
639 // #pragma mark - Private methods
643 DefaultDecorator::_DrawButtonBitmap(ServerBitmap
* bitmap
, bool direct
,
649 bool copyToFrontEnabled
= fDrawingEngine
->CopyToFrontEnabled();
650 fDrawingEngine
->SetCopyToFrontEnabled(direct
);
651 drawing_mode oldMode
;
652 fDrawingEngine
->SetDrawingMode(B_OP_OVER
, oldMode
);
653 fDrawingEngine
->DrawBitmap(bitmap
, rect
.OffsetToCopy(0, 0), rect
);
654 fDrawingEngine
->SetDrawingMode(oldMode
);
655 fDrawingEngine
->SetCopyToFrontEnabled(copyToFrontEnabled
);
659 /*! \brief Draws a framed rectangle with a gradient.
660 \param engine The drawing engine to use.
661 \param rect The rectangular area to draw in.
662 \param down The rectangle should be drawn recessed or not.
663 \param colors A button color array of the colors to be used.
666 DefaultDecorator::_DrawBlendedRect(DrawingEngine
* engine
, const BRect rect
,
667 bool down
, const ComponentColors
& colors
)
669 // figure out which colors to use
670 rgb_color startColor
, endColor
;
672 startColor
= tint_color(colors
[COLOR_BUTTON
], B_DARKEN_1_TINT
);
673 endColor
= colors
[COLOR_BUTTON_LIGHT
];
675 startColor
= tint_color(colors
[COLOR_BUTTON
], B_LIGHTEN_MAX_TINT
);
676 endColor
= colors
[COLOR_BUTTON
];
680 BRect
fillRect(rect
.InsetByCopy(1.0f
, 1.0f
));
682 BGradientLinear gradient
;
683 gradient
.SetStart(fillRect
.LeftTop());
684 gradient
.SetEnd(fillRect
.RightBottom());
685 gradient
.AddColor(startColor
, 0);
686 gradient
.AddColor(endColor
, 255);
688 engine
->FillRect(fillRect
, gradient
);
691 engine
->StrokeRect(rect
, tint_color(colors
[COLOR_BUTTON
], B_DARKEN_2_TINT
));
696 DefaultDecorator::_GetBitmapForButton(Decorator::Tab
* tab
, Component item
,
697 bool down
, int32 width
, int32 height
)
699 // TODO: the list of shared bitmaps is never freed
700 struct decorator_bitmap
{
706 rgb_color lightColor
;
707 UtilityBitmap
* bitmap
;
708 decorator_bitmap
* next
;
711 static BLocker
sBitmapListLock("decorator lock", true);
712 static decorator_bitmap
* sBitmapList
= NULL
;
714 ComponentColors colors
;
715 _GetComponentColors(item
, colors
, tab
);
717 BAutolock
locker(sBitmapListLock
);
719 // search our list for a matching bitmap
720 // TODO: use a hash map instead?
721 decorator_bitmap
* current
= sBitmapList
;
723 if (current
->item
== item
&& current
->down
== down
724 && current
->width
== width
&& current
->height
== height
725 && current
->baseColor
== colors
[COLOR_BUTTON
]
726 && current
->lightColor
== colors
[COLOR_BUTTON_LIGHT
]) {
727 return current
->bitmap
;
730 current
= current
->next
;
733 static BitmapDrawingEngine
* sBitmapDrawingEngine
= NULL
;
735 // didn't find any bitmap, create a new one
736 if (sBitmapDrawingEngine
== NULL
)
737 sBitmapDrawingEngine
= new(std::nothrow
) BitmapDrawingEngine();
738 if (sBitmapDrawingEngine
== NULL
739 || sBitmapDrawingEngine
->SetSize(width
, height
) != B_OK
)
742 BRect
rect(0, 0, width
- 1, height
- 1);
744 STRACE(("DefaultDecorator creating bitmap for %s %s at size %ldx%ld\n",
745 item
== COMPONENT_CLOSE_BUTTON
? "close" : "zoom",
746 down
? "down" : "up", width
, height
));
748 case COMPONENT_CLOSE_BUTTON
:
749 _DrawBlendedRect(sBitmapDrawingEngine
, rect
, down
, colors
);
752 case COMPONENT_ZOOM_BUTTON
:
754 sBitmapDrawingEngine
->FillRect(rect
, B_TRANSPARENT_COLOR
);
755 // init the background
757 float inset
= floorf(width
/ 4.0);
758 BRect
zoomRect(rect
);
759 zoomRect
.left
+= inset
;
760 zoomRect
.top
+= inset
;
761 _DrawBlendedRect(sBitmapDrawingEngine
, zoomRect
, down
, colors
);
763 inset
= floorf(width
/ 2.1);
765 zoomRect
.right
-= inset
;
766 zoomRect
.bottom
-= inset
;
767 _DrawBlendedRect(sBitmapDrawingEngine
, zoomRect
, down
, colors
);
775 UtilityBitmap
* bitmap
= sBitmapDrawingEngine
->ExportToBitmap(width
, height
,
780 // bitmap ready, put it into the list
781 decorator_bitmap
* entry
= new(std::nothrow
) decorator_bitmap
;
789 entry
->width
= width
;
790 entry
->height
= height
;
791 entry
->bitmap
= bitmap
;
792 entry
->baseColor
= colors
[COLOR_BUTTON
];
793 entry
->lightColor
= colors
[COLOR_BUTTON_LIGHT
];
794 entry
->next
= sBitmapList
;
802 DefaultDecorator::_GetComponentColors(Component component
,
803 ComponentColors _colors
, Decorator::Tab
* tab
)
805 // get the highlight for our component
806 Region region
= REGION_NONE
;
811 case COMPONENT_CLOSE_BUTTON
:
812 region
= REGION_CLOSE_BUTTON
;
814 case COMPONENT_ZOOM_BUTTON
:
815 region
= REGION_ZOOM_BUTTON
;
817 case COMPONENT_LEFT_BORDER
:
818 region
= REGION_LEFT_BORDER
;
820 case COMPONENT_RIGHT_BORDER
:
821 region
= REGION_RIGHT_BORDER
;
823 case COMPONENT_TOP_BORDER
:
824 region
= REGION_TOP_BORDER
;
826 case COMPONENT_BOTTOM_BORDER
:
827 region
= REGION_BOTTOM_BORDER
;
829 case COMPONENT_RESIZE_CORNER
:
830 region
= REGION_RIGHT_BOTTOM_CORNER
;
834 return GetComponentColors(component
, RegionHighlight(region
), _colors
, tab
);