vfs: check userland buffers before reading them.
[haiku.git] / src / servers / app / decorator / DefaultDecorator.cpp
blob51ad0c063b09c9661c8b42bf9cef9acee10e7acd
1 /*
2 * Copyright 2001-2015 Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
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"
22 #include <algorithm>
23 #include <cmath>
24 #include <new>
25 #include <stdio.h>
27 #include <Autolock.h>
28 #include <Debug.h>
29 #include <GradientLinear.h>
30 #include <Rect.h>
31 #include <Region.h>
32 #include <View.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
48 #else
49 # define STRACE(x) ;
50 #endif
53 static const float kBorderResizeLength = 22.0;
54 static const float kResizeKnobSize = 18.0;
57 static inline uint8
58 blend_color_value(uint8 a, uint8 b, float position)
60 int16 delta = (int16)b - a;
61 int32 value = a + (int32)(position * delta);
62 if (value > 255)
63 return 255;
64 if (value < 0)
65 return 0;
67 return (uint8)value;
71 // #pragma mark -
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,
77 Desktop* desktop)
79 TabDecorator(settings, rect, desktop)
81 // TODO: If the decorator was created with a frame too small, it should
82 // resize itself!
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.
108 void
109 DefaultDecorator::GetComponentColors(Component component, uint8 highlight,
110 ComponentColors _colors, Decorator::Tab* _tab)
112 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
113 switch (component) {
114 case COMPONENT_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;
125 } else {
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;
136 break;
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;
143 } else {
144 _colors[COLOR_BUTTON] = fNonFocusTabColor;
145 _colors[COLOR_BUTTON_LIGHT] = fNonFocusTabColorLight;
147 break;
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:
154 default:
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);
163 } else {
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;
181 break;
186 void
187 DefaultDecorator::UpdateColors(DesktopSettings& settings)
189 TabDecorator::UpdateColors(settings);
193 // #pragma mark - Protected methods
196 void
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)
206 return;
208 if (fBorderWidth <= 0)
209 return;
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:
218 // top
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),
235 colors[2]);
238 // left
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]);
248 // bottom
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)]);
259 // right
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)]);
270 break;
273 case B_FLOATING_WINDOW_LOOK:
274 case kLeftTitledWindowLook:
276 // top
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]);
295 // left
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]);
315 // bottom
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]);
326 // right
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]);
337 break;
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]);
347 break;
350 default:
351 // don't draw a border frame
352 break;
355 // Draw the resize knob if we're supposed to
356 if (!(fTopTab->flags & B_NOT_RESIZABLE)) {
357 r = fResizeRect;
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))
366 break;
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))
391 break;
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);
403 break;
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)))
414 break;
416 fDrawingEngine->StrokeLine(
417 BPoint(fRightBorder.left, fBottomBorder.bottom - kBorderResizeLength),
418 BPoint(fRightBorder.right - 1, fBottomBorder.bottom - kBorderResizeLength),
419 colors[0]);
420 fDrawingEngine->StrokeLine(
421 BPoint(fRightBorder.right - kBorderResizeLength, fBottomBorder.top),
422 BPoint(fRightBorder.right - kBorderResizeLength, fBottomBorder.bottom - 1),
423 colors[0]);
424 break;
427 default:
428 // don't draw resize corner
429 break;
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.
443 void
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
450 // in it.
451 if (!tabRect.IsValid() || !invalid.Intersects(tabRect))
452 return;
454 ComponentColors colors;
455 _GetComponentColors(COMPONENT_TAB, colors, tab);
457 // outer frame
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]);
465 } else {
466 fDrawingEngine->StrokeLine(tabRect.LeftBottom(),
467 tabRect.RightBottom(), colors[COLOR_TAB_FRAME_DARK]);
470 float tabBotton = tabRect.bottom;
471 if (fTopTab != tab)
472 tabBotton -= 1;
474 // bevel
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),
481 tabRect.top + 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]);
488 } else {
489 fDrawingEngine->StrokeLine(
490 BPoint(tabRect.left + 2, tabRect.bottom - 1),
491 BPoint(tabRect.right, tabRect.bottom - 1),
492 colors[COLOR_TAB_SHADOW]);
495 // fill
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);
505 } else {
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.
527 void
528 DefaultDecorator::_DrawTitle(Decorator::Tab* _tab, BRect rect)
530 STRACE(("_DrawTitle(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
531 rect.bottom));
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);
550 BPoint titlePos;
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);
557 } else {
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,
566 titlePos);
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.
581 void
582 DefaultDecorator::_DrawClose(Decorator::Tab* _tab, bool direct, BRect rect)
584 STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
585 rect.bottom));
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.
610 void
611 DefaultDecorator::_DrawZoom(Decorator::Tab* _tab, bool direct, BRect rect)
613 STRACE(("_DrawZoom(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
614 rect.bottom));
616 if (rect.IntegerWidth() < 1)
617 return;
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);
632 void
633 DefaultDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect)
635 // This decorator doesn't have this button
639 // #pragma mark - Private methods
642 void
643 DefaultDecorator::_DrawButtonBitmap(ServerBitmap* bitmap, bool direct,
644 BRect rect)
646 if (bitmap == NULL)
647 return;
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.
665 void
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;
671 if (down) {
672 startColor = tint_color(colors[COLOR_BUTTON], B_DARKEN_1_TINT);
673 endColor = colors[COLOR_BUTTON_LIGHT];
674 } else {
675 startColor = tint_color(colors[COLOR_BUTTON], B_LIGHTEN_MAX_TINT);
676 endColor = colors[COLOR_BUTTON];
679 // fill
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);
690 // outline
691 engine->StrokeRect(rect, tint_color(colors[COLOR_BUTTON], B_DARKEN_2_TINT));
695 ServerBitmap*
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 {
701 Component item;
702 bool down;
703 int32 width;
704 int32 height;
705 rgb_color baseColor;
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;
722 while (current) {
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)
740 return NULL;
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));
747 switch (item) {
748 case COMPONENT_CLOSE_BUTTON:
749 _DrawBlendedRect(sBitmapDrawingEngine, rect, down, colors);
750 break;
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);
764 zoomRect = rect;
765 zoomRect.right -= inset;
766 zoomRect.bottom -= inset;
767 _DrawBlendedRect(sBitmapDrawingEngine, zoomRect, down, colors);
768 break;
771 default:
772 break;
775 UtilityBitmap* bitmap = sBitmapDrawingEngine->ExportToBitmap(width, height,
776 B_RGB32);
777 if (bitmap == NULL)
778 return NULL;
780 // bitmap ready, put it into the list
781 decorator_bitmap* entry = new(std::nothrow) decorator_bitmap;
782 if (entry == NULL) {
783 delete bitmap;
784 return NULL;
787 entry->item = item;
788 entry->down = down;
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;
795 sBitmapList = entry;
797 return bitmap;
801 void
802 DefaultDecorator::_GetComponentColors(Component component,
803 ComponentColors _colors, Decorator::Tab* tab)
805 // get the highlight for our component
806 Region region = REGION_NONE;
807 switch (component) {
808 case COMPONENT_TAB:
809 region = REGION_TAB;
810 break;
811 case COMPONENT_CLOSE_BUTTON:
812 region = REGION_CLOSE_BUTTON;
813 break;
814 case COMPONENT_ZOOM_BUTTON:
815 region = REGION_ZOOM_BUTTON;
816 break;
817 case COMPONENT_LEFT_BORDER:
818 region = REGION_LEFT_BORDER;
819 break;
820 case COMPONENT_RIGHT_BORDER:
821 region = REGION_RIGHT_BORDER;
822 break;
823 case COMPONENT_TOP_BORDER:
824 region = REGION_TOP_BORDER;
825 break;
826 case COMPONENT_BOTTOM_BORDER:
827 region = REGION_BOTTOM_BORDER;
828 break;
829 case COMPONENT_RESIZE_CORNER:
830 region = REGION_RIGHT_BOTTOM_CORNER;
831 break;
834 return GetComponentColors(component, RegionHighlight(region), _colors, tab);