1 /*
2 * Copyright 2001-2014 Haiku, Inc. All rights reserved.
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 * Clemens Zeidler, haiku@clemens-zeidler.de
10 */
11
12
13 /*! Decorator resembling BeOS R5 */
14
15
16 #include "BeDecorator.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <new>
21 #include <stdio.h>
22
23 #include <WindowPrivate.h>
24
25 #include <Autolock.h>
26 #include <Debug.h>
27 #include <GradientLinear.h>
28 #include <Rect.h>
29 #include <Region.h>
30 #include <View.h>
31
32 #include "BitmapDrawingEngine.h"
33 #include "Desktop.h"
34 #include "DesktopSettings.h"
35 #include "DrawingEngine.h"
36 #include "DrawState.h"
37 #include "FontManager.h"
38 #include "PatternHandler.h"
39 #include "RGBColor.h"
40 #include "ServerBitmap.h"
41
42
43 //#define DEBUG_DECORATOR
44 #ifdef DEBUG_DECORATOR
45 # define STRACE(x) printf x
46 #else
47 # define STRACE(x) ;
48 #endif
49
50
51 static const float kBorderResizeLength = 22.0;
52 static const float kResizeKnobSize = 18.0;
53
54
55 static const unsigned char f = 0xff; // way to write 0xff shorter
56
57 static const unsigned char kInnerShadowBits[] = {
58 f, f, f, f, f, f, f, f, f, 0,
59 f, f, f, f, f, f, 0, f, 0, f,
60 f, f, f, f, f, 0, f, 0, f, 0,
61 f, f, f, f, 0, f, 0, 0, 0, 0,
62 f, f, f, 0, f, 0, 0, 0, 0, 0,
63 f, f, 0, f, 0, 0, 0, 0, 0, 0,
64 f, 0, f, 0, 0, 0, 0, 0, 0, 0,
65 f, f, 0, 0, 0, 0, 0, 0, 0, 0,
66 f, 0, f, 0, 0, 0, 0, 0, 0, 0,
67 0, f, 0, 0, 0, 0, 0, 0, 0, 0
68 };
69
70 static const unsigned char kOuterShadowBits[] = {
71 f, f, f, f, f, f, f, f, f, f,
72 f, f, f, f, f, f, f, f, f, f,
73 f, f, f, f, f, f, f, f, f, f,
74 f, f, f, f, f, f, f, f, f, f,
75 f, f, f, f, f, f, f, f, f, 0,
76 f, f, f, f, f, f, f, 0, 0, 0,
77 f, f, f, f, f, f, 0, f, 0, 0,
78 f, f, f, f, f, 0, f, 0, 0, 0,
79 f, f, f, f, f, 0, 0, 0, 0, 0,
80 f, f, f, f, 0, 0, 0, 0, 0, 0
81 };
82
83 static const unsigned char kBigInnerShadowBits[] = {
84 f, f, f, f, f, f, f,
85 f, f, f, f, f, f, 0,
86 f, f, f, f, f, 0, 0,
87 f, f, f, f, 0, f, 0,
88 f, f, f, 0, f, 0, 0,
89 f, f, 0, f, 0, 0, 0,
90 f, 0, 0, 0, 0, 0, 0
91 };
92
93 static const unsigned char kBigOuterShadowBits[] = {
94 f, f, f, f, f, f, f,
95 f, f, f, f, f, f, 0,
96 f, f, f, f, f, f, 0,
97 f, f, f, f, f, f, 0,
98 f, f, f, f, f, f, 0,
99 f, f, f, f, f, f, 0,
100 f, 0, 0, 0, 0, 0, 0
101 };
102
103 static const unsigned char kSmallInnerShadowBits[] = {
104 f, f, f, 0, 0,
105 f, f, 0, f, 0,
106 f, 0, f, 0, 0,
107 0, f, 0, 0, 0,
108 0, 0, 0, 0, 0
109 };
110
111 static const unsigned char kSmallOuterShadowBits[] = {
112 f, f, f, f, f,
113 f, f, f, f, f,
114 f, f, f, f, f,
115 f, f, f, f, 0,
116 f, f, 0, 0, 0
117 };
118
119 static const unsigned char kGlintBits[] = {
120 0, f, 0,
121 f, 0, f,
122 0, f, f
123 };
124
125
126 // #pragma mark - BeDecorAddOn
127
128
BeDecorAddOn(image_id id,const char * name)129 BeDecorAddOn::BeDecorAddOn(image_id id, const char* name)
130 :
131 DecorAddOn(id, name)
132 {
133 }
134
135
136 Decorator*
_AllocateDecorator(DesktopSettings & settings,BRect rect,Desktop * desktop)137 BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
138 Desktop* desktop)
139 {
140 return new (std::nothrow)BeDecorator(settings, rect, desktop);
141 }
142
143
144 // #pragma mark - BeDecorator
145
146
147 // TODO: get rid of DesktopSettings here, and introduce private accessor
148 // methods to the Decorator base class
BeDecorator(DesktopSettings & settings,BRect rect,Desktop * desktop)149 BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect,
150 Desktop* desktop)
151 :
152 SATDecorator(settings, rect, desktop),
153 fCStatus(B_NO_INIT)
154 {
155 STRACE(("BeDecorator:\n"));
156 STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
157 rect.left, rect.top, rect.right, rect.bottom));
158
159 fCloseBitmap = _CreateTemporaryBitmap(BRect(0, 0, 9, 9));
160 fBigZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 6, 6));
161 fSmallZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 4, 4));
162 fGlintBitmap = _CreateTemporaryBitmap(BRect(0, 0, 2, 2));
163 // glint bitmap is used by close and zoom buttons
164
165 if (fCloseBitmap == NULL || fBigZoomBitmap == NULL
166 || fSmallZoomBitmap == NULL || fGlintBitmap == NULL) {
167 fCStatus = B_NO_MEMORY;
168 } else
169 fCStatus = B_OK;
170 }
171
172
~BeDecorator()173 BeDecorator::~BeDecorator()
174 {
175 STRACE(("BeDecorator: ~BeDecorator()\n"));
176 //delete[] fFrameColors;
177
178 if (fCloseBitmap != NULL)
179 fCloseBitmap->ReleaseReference();
180
181 if (fBigZoomBitmap != NULL)
182 fBigZoomBitmap->ReleaseReference();
183
184 if (fSmallZoomBitmap != NULL)
185 fSmallZoomBitmap->ReleaseReference();
186
187 if (fGlintBitmap != NULL)
188 fGlintBitmap->ReleaseReference();
189 }
190
191
192 // #pragma mark - Public methods
193
194
195 /*! Returns the frame colors for the specified decorator component.
196
197 The meaning of the color array elements depends on the specified component.
198 For some components some array elements are unused.
199
200 \param component The component for which to return the frame colors.
201 \param highlight The highlight set for the component.
202 \param colors An array of colors to be initialized by the function.
203 */
204 void
GetComponentColors(Component component,uint8 highlight,ComponentColors _colors,Decorator::Tab * _tab)205 BeDecorator::GetComponentColors(Component component, uint8 highlight,
206 ComponentColors _colors, Decorator::Tab* _tab)
207 {
208 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
209 switch (component) {
210 case COMPONENT_TAB:
211 if (highlight == HIGHLIGHT_STACK_AND_TILE) {
212 _colors[COLOR_TAB_FRAME_LIGHT]
213 = tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
214 _colors[COLOR_TAB_FRAME_DARK]
215 = tint_color(fFocusFrameColor, B_DARKEN_4_TINT);
216 _colors[COLOR_TAB] = tint_color(fFocusTabColor,
217 B_DARKEN_1_TINT);
218 _colors[COLOR_TAB_LIGHT] = tint_color(fFocusTabColorLight,
219 B_DARKEN_1_TINT);
220 _colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel;
221 _colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow;
222 _colors[COLOR_TAB_TEXT] = fFocusTextColor;
223 } else if (tab && tab->buttonFocus) {
224 _colors[COLOR_TAB_FRAME_LIGHT]
225 = tint_color(fFocusFrameColor, B_DARKEN_2_TINT);
226 _colors[COLOR_TAB_FRAME_DARK]
227 = tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
228 _colors[COLOR_TAB] = fFocusTabColor;
229 _colors[COLOR_TAB_LIGHT] = fFocusTabColorLight;
230 _colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel;
231 _colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow;
232 _colors[COLOR_TAB_TEXT] = fFocusTextColor;
233 } else {
234 _colors[COLOR_TAB_FRAME_LIGHT]
235 = tint_color(fNonFocusFrameColor, B_DARKEN_2_TINT);
236 _colors[COLOR_TAB_FRAME_DARK]
237 = tint_color(fNonFocusFrameColor, B_DARKEN_3_TINT);
238 _colors[COLOR_TAB] = fNonFocusTabColor;
239 _colors[COLOR_TAB_LIGHT] = fNonFocusTabColorLight;
240 _colors[COLOR_TAB_BEVEL] = fNonFocusTabColorBevel;
241 _colors[COLOR_TAB_SHADOW] = fNonFocusTabColorShadow;
242 _colors[COLOR_TAB_TEXT] = fNonFocusTextColor;
243 }
244 break;
245
246 case COMPONENT_CLOSE_BUTTON:
247 case COMPONENT_ZOOM_BUTTON:
248 if (highlight == HIGHLIGHT_STACK_AND_TILE) {
249 _colors[COLOR_BUTTON] = tint_color(fFocusTabColor,
250 B_DARKEN_1_TINT);
251 _colors[COLOR_BUTTON_LIGHT] = tint_color(fFocusTabColorLight,
252 B_DARKEN_1_TINT);
253 } else if (tab && tab->buttonFocus) {
254 _colors[COLOR_BUTTON] = fFocusTabColor;
255 _colors[COLOR_BUTTON_LIGHT] = fFocusTabColorLight;
256 } else {
257 _colors[COLOR_BUTTON] = fNonFocusTabColor;
258 _colors[COLOR_BUTTON_LIGHT] = fNonFocusTabColorLight;
259 }
260 break;
261
262 case COMPONENT_LEFT_BORDER:
263 case COMPONENT_RIGHT_BORDER:
264 case COMPONENT_TOP_BORDER:
265 case COMPONENT_BOTTOM_BORDER:
266 case COMPONENT_RESIZE_CORNER:
267 default:
268 {
269 rgb_color base;
270 if (highlight == HIGHLIGHT_STACK_AND_TILE)
271 base = tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
272 else if (tab && tab->buttonFocus)
273 base = fFocusFrameColor;
274 else
275 base = fNonFocusFrameColor;
276
277 //_colors[0].SetColor(152, 152, 152);
278 //_colors[1].SetColor(255, 255, 255);
279 //_colors[2].SetColor(216, 216, 216);
280 //_colors[3].SetColor(136, 136, 136);
281 //_colors[4].SetColor(152, 152, 152);
282 //_colors[5].SetColor(96, 96, 96);
283
284 _colors[0].red = std::max(0, base.red - 72);
285 _colors[0].green = std::max(0, base.green - 72);
286 _colors[0].blue = std::max(0, base.blue - 72);
287 _colors[0].alpha = 255;
288
289 _colors[1].red = std::min(255, base.red + 64);
290 _colors[1].green = std::min(255, base.green + 64);
291 _colors[1].blue = std::min(255, base.blue + 64);
292 _colors[1].alpha = 255;
293
294 _colors[2].red = std::max(0, base.red - 8);
295 _colors[2].green = std::max(0, base.green - 8);
296 _colors[2].blue = std::max(0, base.blue - 8);
297 _colors[2].alpha = 255;
298
299 _colors[3].red = std::max(0, base.red - 88);
300 _colors[3].green = std::max(0, base.green - 88);
301 _colors[3].blue = std::max(0, base.blue - 88);
302 _colors[3].alpha = 255;
303
304 _colors[4].red = std::max(0, base.red - 72);
305 _colors[4].green = std::max(0, base.green - 72);
306 _colors[4].blue = std::max(0, base.blue - 72);
307 _colors[4].alpha = 255;
308
309 _colors[5].red = std::max(0, base.red - 128);
310 _colors[5].green = std::max(0, base.green - 128);
311 _colors[5].blue = std::max(0, base.blue - 128);
312 _colors[5].alpha = 255;
313
314 // for the resize-border highlight dye everything bluish.
315 if (highlight == HIGHLIGHT_RESIZE_BORDER) {
316 for (int32 i = 0; i < 6; i++) {
317 _colors[i].red = std::max((int)_colors[i].red - 80, 0);
318 _colors[i].green = std::max((int)_colors[i].green - 80, 0);
319 _colors[i].blue = 255;
320 }
321 }
322 break;
323 }
324 }
325 }
326
327
328 // #pragma mark - Protected methods
329
330
331 void
_DrawFrame(BRect invalid)332 BeDecorator::_DrawFrame(BRect invalid)
333 {
334 STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top,
335 invalid.right, invalid.bottom));
336
337 // NOTE: the DrawingEngine needs to be locked for the entire
338 // time for the clipping to stay valid for this decorator
339
340 if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
341 return;
342
343 if (fBorderWidth <= 0)
344 return;
345
346 // Draw the border frame
347 BRect r = BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom());
348 switch ((int)fTopTab->look) {
349 case B_TITLED_WINDOW_LOOK:
350 case B_DOCUMENT_WINDOW_LOOK:
351 case B_MODAL_WINDOW_LOOK:
352 {
353 // top
354 if (invalid.Intersects(fTopBorder)) {
355 ComponentColors colors;
356 _GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab);
357
358 for (int8 i = 0; i < 5; i++) {
359 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
360 BPoint(r.right - i, r.top + i), colors[i]);
361 }
362 if (fTitleBarRect.IsValid()) {
363 // grey along the bottom of the tab
364 // (overwrites "white" from frame)
365 fDrawingEngine->StrokeLine(
366 BPoint(fTitleBarRect.left + 2,
367 fTitleBarRect.bottom + 1),
368 BPoint(fTitleBarRect.right - 2,
369 fTitleBarRect.bottom + 1),
370 colors[2]);
371 }
372 }
373 // left
374 if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
375 ComponentColors colors;
376 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
377
378 for (int8 i = 0; i < 5; i++) {
379 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
380 BPoint(r.left + i, r.bottom - i), colors[i]);
381 }
382 }
383 // bottom
384 if (invalid.Intersects(fBottomBorder)) {
385 ComponentColors colors;
386 _GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab);
387
388 for (int8 i = 0; i < 5; i++) {
389 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i),
390 BPoint(r.right - i, r.bottom - i),
391 colors[(4 - i) == 4 ? 5 : (4 - i)]);
392 }
393 }
394 // right
395 if (invalid.Intersects(
396 fRightBorder.InsetByCopy(0, -fBorderWidth))) {
397 ComponentColors colors;
398 _GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab);
399
400 for (int8 i = 0; i < 5; i++) {
401 fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i),
402 BPoint(r.right - i, r.bottom - i),
403 colors[(4 - i) == 4 ? 5 : (4 - i)]);
404 }
405 }
406 break;
407 }
408
409 case B_FLOATING_WINDOW_LOOK:
410 case kLeftTitledWindowLook:
411 {
412 // top
413 if (invalid.Intersects(fTopBorder)) {
414 ComponentColors colors;
415 _GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab);
416
417 for (int8 i = 0; i < 3; i++) {
418 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
419 BPoint(r.right - i, r.top + i), colors[i * 2]);
420 }
421 if (fTitleBarRect.IsValid()
422 && fTopTab->look != kLeftTitledWindowLook) {
423 // grey along the bottom of the tab
424 // (overwrites "white" from frame)
425 fDrawingEngine->StrokeLine(
426 BPoint(fTitleBarRect.left + 2,
427 fTitleBarRect.bottom + 1),
428 BPoint(fTitleBarRect.right - 2,
429 fTitleBarRect.bottom + 1), colors[2]);
430 }
431 }
432 // left
433 if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
434 ComponentColors colors;
435 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
436
437 for (int8 i = 0; i < 3; i++) {
438 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
439 BPoint(r.left + i, r.bottom - i), colors[i * 2]);
440 }
441 if (fTopTab->look == kLeftTitledWindowLook
442 && fTitleBarRect.IsValid()) {
443 // grey along the right side of the tab
444 // (overwrites "white" from frame)
445 fDrawingEngine->StrokeLine(
446 BPoint(fTitleBarRect.right + 1,
447 fTitleBarRect.top + 2),
448 BPoint(fTitleBarRect.right + 1,
449 fTitleBarRect.bottom - 2), colors[2]);
450 }
451 }
452 // bottom
453 if (invalid.Intersects(fBottomBorder)) {
454 ComponentColors colors;
455 _GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab);
456
457 for (int8 i = 0; i < 3; i++) {
458 fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i),
459 BPoint(r.right - i, r.bottom - i),
460 colors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
461 }
462 }
463 // right
464 if (invalid.Intersects(fRightBorder.InsetByCopy(0, -fBorderWidth))) {
465 ComponentColors colors;
466 _GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab);
467
468 for (int8 i = 0; i < 3; i++) {
469 fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i),
470 BPoint(r.right - i, r.bottom - i),
471 colors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
472 }
473 }
474 break;
475 }
476
477 case B_BORDERED_WINDOW_LOOK:
478 {
479 // TODO: Draw the borders individually!
480 ComponentColors colors;
481 _GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
482
483 fDrawingEngine->StrokeRect(r, colors[5]);
484 break;
485 }
486
487 default:
488 // don't draw a border frame
489 break;
490 }
491
492 // Draw the resize knob if we're supposed to
493 if (!(fTopTab->flags & B_NOT_RESIZABLE)) {
494 r = fResizeRect;
495
496 ComponentColors colors;
497 _GetComponentColors(COMPONENT_RESIZE_CORNER, colors, fTopTab);
498
499 switch ((int)fTopTab->look) {
500 case B_DOCUMENT_WINDOW_LOOK:
501 {
502 if (!invalid.Intersects(r))
503 break;
504
505 float x = r.right - 3;
506 float y = r.bottom - 3;
507
508 BRect bg(x - 13, y - 13, x, y);
509
510 BGradientLinear gradient;
511 gradient.SetStart(bg.LeftTop());
512 gradient.SetEnd(bg.RightBottom());
513 gradient.AddColor(colors[1], 0);
514 gradient.AddColor(colors[2], 255);
515
516 fDrawingEngine->FillRect(bg, gradient);
517
518 fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15),
519 BPoint(x - 15, y - 2), colors[0]);
520 fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14),
521 BPoint(x - 14, y - 1), colors[1]);
522 fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15),
523 BPoint(x - 2, y - 15), colors[0]);
524 fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14),
525 BPoint(x - 1, y - 14), colors[1]);
526
527 if (fTopTab && !IsFocus(fTopTab))
528 break;
529
530 static const rgb_color kWhite
531 = (rgb_color){ 255, 255, 255, 255 };
532 for (int8 i = 1; i <= 4; i++) {
533 for (int8 j = 1; j <= i; j++) {
534 BPoint pt1(x - (3 * j) + 1, y - (3 * (5 - i)) + 1);
535 BPoint pt2(x - (3 * j) + 2, y - (3 * (5 - i)) + 2);
536 fDrawingEngine->StrokePoint(pt1, colors[0]);
537 fDrawingEngine->StrokePoint(pt2, kWhite);
538 }
539 }
540 break;
541 }
542
543 case B_TITLED_WINDOW_LOOK:
544 case B_FLOATING_WINDOW_LOOK:
545 case B_MODAL_WINDOW_LOOK:
546 case kLeftTitledWindowLook:
547 {
548 if (!invalid.Intersects(BRect(fRightBorder.right
549 - kBorderResizeLength,
550 fBottomBorder.bottom - kBorderResizeLength,
551 fRightBorder.right - 1, fBottomBorder.bottom - 1))) {
552 break;
553 }
554
555 fDrawingEngine->StrokeLine(BPoint(fRightBorder.left,
556 fBottomBorder.bottom - kBorderResizeLength),
557 BPoint(fRightBorder.right - 1,
558 fBottomBorder.bottom - kBorderResizeLength),
559 colors[0]);
560 fDrawingEngine->StrokeLine(
561 BPoint(fRightBorder.right - kBorderResizeLength,
562 fBottomBorder.top),
563 BPoint(fRightBorder.right - kBorderResizeLength,
564 fBottomBorder.bottom - 1),
565 colors[0]);
566 break;
567 }
568
569 default:
570 // don't draw resize corner
571 break;
572 }
573 }
574 }
575
576
577 /*! \brief Actually draws the tab
578
579 This function is called when the tab itself needs drawn. Other items,
580 like the window title or buttons, should not be drawn here.
581
582 \param tab The \a tab to update.
583 \param invalid The area of the \a tab to update.
584 */
585 void
_DrawTab(Decorator::Tab * tab,BRect invalid)586 BeDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid)
587 {
588 STRACE(("_DrawTab(%.1f, %.1f, %.1f, %.1f)\n",
589 invalid.left, invalid.top, invalid.right, invalid.bottom));
590 const BRect& tabRect = tab->tabRect;
591 // If a window has a tab, this will draw it and any buttons which are
592 // in it.
593 if (!tabRect.IsValid() || !invalid.Intersects(tabRect))
594 return;
595
596 ComponentColors colors;
597 _GetComponentColors(COMPONENT_TAB, colors, tab);
598
599 // outer frame
600 fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.LeftBottom(),
601 colors[COLOR_TAB_FRAME_LIGHT]);
602 fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.RightTop(),
603 colors[COLOR_TAB_FRAME_LIGHT]);
604 if (tab->look != kLeftTitledWindowLook) {
605 fDrawingEngine->StrokeLine(tabRect.RightTop(), tabRect.RightBottom(),
606 colors[COLOR_TAB_FRAME_DARK]);
607 } else {
608 fDrawingEngine->StrokeLine(tabRect.LeftBottom(),
609 tabRect.RightBottom(), colors[COLOR_TAB_FRAME_DARK]);
610 }
611
612 float tabBotton = tabRect.bottom;
613 if (fTopTab != tab)
614 tabBotton -= 1;
615
616 // bevel
617 fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1),
618 BPoint(tabRect.left + 1,
619 tabBotton - (tab->look == kLeftTitledWindowLook ? 1 : 0)),
620 colors[COLOR_TAB_BEVEL]);
621 fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1),
622 BPoint(tabRect.right - (tab->look == kLeftTitledWindowLook ? 0 : 1),
623 tabRect.top + 1),
624 colors[COLOR_TAB_BEVEL]);
625
626 if (tab->look != kLeftTitledWindowLook) {
627 fDrawingEngine->StrokeLine(BPoint(tabRect.right - 1, tabRect.top + 2),
628 BPoint(tabRect.right - 1, tabBotton),
629 colors[COLOR_TAB_SHADOW]);
630 } else {
631 fDrawingEngine->StrokeLine(
632 BPoint(tabRect.left + 2, tabRect.bottom - 1),
633 BPoint(tabRect.right, tabRect.bottom - 1),
634 colors[COLOR_TAB_SHADOW]);
635 }
636
637 // fill
638 if (fTopTab->look != kLeftTitledWindowLook) {
639 fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2,
640 tabRect.right - 2, tabRect.bottom), colors[COLOR_TAB]);
641 } else {
642 fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2,
643 tabRect.right, tabRect.bottom - 2), colors[COLOR_TAB]);
644 }
645
646 _DrawTitle(tab, tabRect);
647
648 _DrawButtons(tab, invalid);
649 }
650
651
652 /*! \brief Actually draws the title
653
654 The main tasks for this function are to ensure that the decorator draws
655 the title only in its own area and drawing the title itself.
656 Using B_OP_COPY for drawing the title is recommended because of the marked
657 performance hit of the other drawing modes, but it is not a requirement.
658
659 \param _tab The \a tab to update.
660 \param r area of the title to update.
661 */
662 void
_DrawTitle(Decorator::Tab * _tab,BRect r)663 BeDecorator::_DrawTitle(Decorator::Tab* _tab, BRect r)
664 {
665 STRACE(("_DrawTitle(%f, %f, %f, %f)\n", r.left, r.top, r.right, r.bottom));
666
667 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
668
669 const BRect& tabRect = tab->tabRect;
670 const BRect& closeRect = tab->closeRect;
671 const BRect& zoomRect = tab->zoomRect;
672
673 ComponentColors colors;
674 _GetComponentColors(COMPONENT_TAB, colors, tab);
675
676 fDrawingEngine->SetDrawingMode(B_OP_OVER);
677 fDrawingEngine->SetHighColor(colors[COLOR_TAB_TEXT]);
678 fDrawingEngine->SetLowColor(colors[COLOR_TAB]);
679 fDrawingEngine->SetFont(fDrawState.Font());
680
681 // figure out position of text
682 font_height fontHeight;
683 fDrawState.Font().GetHeight(fontHeight);
684
685 BPoint titlePos;
686 if (fTopTab->look != kLeftTitledWindowLook) {
687 titlePos.x = closeRect.IsValid() ? closeRect.right + tab->textOffset
688 : tabRect.left + tab->textOffset;
689 titlePos.y = floorf(((tabRect.top + 2.0) + tabRect.bottom
690 + fontHeight.ascent + fontHeight.descent) / 2.0
691 - fontHeight.descent + 0.5);
692 } else {
693 titlePos.x = floorf(((tabRect.left + 2.0) + tabRect.right
694 + fontHeight.ascent + fontHeight.descent) / 2.0
695 - fontHeight.descent + 0.5);
696 titlePos.y = zoomRect.IsValid() ? zoomRect.top - tab->textOffset
697 : tabRect.bottom - tab->textOffset;
698 }
699
700 fDrawingEngine->SetFont(fDrawState.Font());
701
702 fDrawingEngine->DrawString(tab->truncatedTitle.String(),
703 tab->truncatedTitleLength, titlePos);
704
705 fDrawingEngine->SetDrawingMode(B_OP_COPY);
706 }
707
708
709 /*! \brief Actually draws the close button
710
711 Unless a subclass has a particularly large button, it is probably
712 unnecessary to check the update rectangle.
713
714 \param _tab The \a tab to update.
715 \param direct Draw without double buffering.
716 \param rect The area of the button to update.
717 */
718 void
_DrawClose(Decorator::Tab * _tab,bool direct,BRect rect)719 BeDecorator::_DrawClose(Decorator::Tab* _tab, bool direct, BRect rect)
720 {
721 STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
722 rect.bottom));
723
724 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
725
726 int32 index = (tab->buttonFocus ? 0 : 1) + (tab->closePressed ? 0 : 2);
727 ServerBitmap* bitmap = tab->closeBitmaps[index];
728 if (bitmap == NULL) {
729 bitmap = _GetBitmapForButton(tab, COMPONENT_CLOSE_BUTTON,
730 tab->closePressed, rect.IntegerWidth(), rect.IntegerHeight());
731 tab->closeBitmaps[index] = bitmap;
732 }
733
734 _DrawButtonBitmap(bitmap, direct, rect);
735 }
736
737
738 /*! \brief Actually draws the zoom button
739
740 Unless a subclass has a particularly large button, it is probably
741 unnecessary to check the update rectangle.
742
743 \param _tab The \a tab to update.
744 \param direct Draw without double buffering.
745 \param rect The area of the button to update.
746 */
747 void
_DrawZoom(Decorator::Tab * _tab,bool direct,BRect rect)748 BeDecorator::_DrawZoom(Decorator::Tab* _tab, bool direct, BRect rect)
749 {
750 STRACE(("_DrawZoom(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
751 rect.bottom));
752
753 if (rect.IntegerWidth() < 1)
754 return;
755
756 Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
757 int32 index = (tab->buttonFocus ? 0 : 1) + (tab->zoomPressed ? 0 : 2);
758 ServerBitmap* bitmap = tab->zoomBitmaps[index];
759 if (bitmap == NULL) {
760 bitmap = _GetBitmapForButton(tab, COMPONENT_ZOOM_BUTTON,
761 tab->zoomPressed, rect.IntegerWidth(), rect.IntegerHeight());
762 tab->zoomBitmaps[index] = bitmap;
763 }
764
765 _DrawButtonBitmap(bitmap, direct, rect);
766 }
767
768
769 void
_DrawMinimize(Decorator::Tab * tab,bool direct,BRect rect)770 BeDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect)
771 {
772 // This decorator doesn't have this button
773 }
774
775
776 void
_GetButtonSizeAndOffset(const BRect & tabRect,float * _offset,float * _size,float * _inset) const777 BeDecorator::_GetButtonSizeAndOffset(const BRect& tabRect, float* _offset,
778 float* _size, float* _inset) const
779 {
780 float tabSize = fTopTab->look == kLeftTitledWindowLook ?
781 tabRect.Width() : tabRect.Height();
782
783 *_offset = 5.0f;
784 *_inset = 0.0f;
785
786 *_size = std::max(0.0f, tabSize - 7.0f);
787 }
788
789
790 // #pragma mark - Private methods
791
792
793 /*!
794 \brief Draws a bevel around a rectangle.
795 \param rect The rectangular area to draw in.
796 \param down Whether or not the button is pressed down.
797 \param light The light color to use.
798 \param shadow The shadow color to use.
799 */
800 void
_DrawBevelRect(DrawingEngine * engine,const BRect rect,bool down,rgb_color light,rgb_color shadow)801 BeDecorator::_DrawBevelRect(DrawingEngine* engine, const BRect rect, bool down,
802 rgb_color light, rgb_color shadow)
803 {
804 if (down) {
805 BRect inner(rect.InsetByCopy(1.0f, 1.0f));
806
807 engine->StrokeLine(rect.LeftBottom(), rect.LeftTop(), shadow);
808 engine->StrokeLine(rect.LeftTop(), rect.RightTop(), shadow);
809 engine->StrokeLine(inner.LeftBottom(), inner.LeftTop(), shadow);
810 engine->StrokeLine(inner.LeftTop(), inner.RightTop(), shadow);
811
812 engine->StrokeLine(rect.RightTop(), rect.RightBottom(), light);
813 engine->StrokeLine(rect.RightBottom(), rect.LeftBottom(), light);
814 engine->StrokeLine(inner.RightTop(), inner.RightBottom(), light);
815 engine->StrokeLine(inner.RightBottom(), inner.LeftBottom(), light);
816 } else {
817 BRect r1(rect);
818 r1.left += 1.0f;
819 r1.top += 1.0f;
820
821 BRect r2(rect);
822 r2.bottom -= 1.0f;
823 r2.right -= 1.0f;
824
825 engine->StrokeRect(r2, shadow);
826 // inner dark box
827 engine->StrokeRect(rect, shadow);
828 // outer dark box
829 engine->StrokeRect(r1, light);
830 // light box
831 }
832 }
833
834
835 /*!
836 \brief Draws a framed rectangle with a gradient.
837 \param rect The rectangular area to draw in.
838 \param startColor The start color of the gradient.
839 \param endColor The end color of the gradient.
840 */
841 void
_DrawBlendedRect(DrawingEngine * engine,const BRect rect,bool down,rgb_color colorA,rgb_color colorB,rgb_color colorC,rgb_color colorD)842 BeDecorator::_DrawBlendedRect(DrawingEngine* engine, const BRect rect,
843 bool down, rgb_color colorA, rgb_color colorB, rgb_color colorC,
844 rgb_color colorD)
845 {
846 BRect fillRect(rect.InsetByCopy(1.0f, 1.0f));
847
848 BGradientLinear gradient;
849 if (down) {
850 gradient.SetStart(fillRect.RightBottom());
851 gradient.SetEnd(fillRect.LeftTop());
852 } else {
853 gradient.SetStart(fillRect.LeftTop());
854 gradient.SetEnd(fillRect.RightBottom());
855 }
856
857 gradient.AddColor(colorA, 0);
858 gradient.AddColor(colorB, 95);
859 gradient.AddColor(colorC, 159);
860 gradient.AddColor(colorD, 255);
861
862 engine->FillRect(fillRect, gradient);
863 }
864
865
866 void
_DrawButtonBitmap(ServerBitmap * bitmap,bool direct,BRect rect)867 BeDecorator::_DrawButtonBitmap(ServerBitmap* bitmap, bool direct, BRect rect)
868 {
869 if (bitmap == NULL)
870 return;
871
872 bool copyToFrontEnabled = fDrawingEngine->CopyToFrontEnabled();
873 fDrawingEngine->SetCopyToFrontEnabled(direct);
874 drawing_mode oldMode;
875 fDrawingEngine->SetDrawingMode(B_OP_OVER, oldMode);
876 fDrawingEngine->DrawBitmap(bitmap, rect.OffsetToCopy(0, 0), rect);
877 fDrawingEngine->SetDrawingMode(oldMode);
878 fDrawingEngine->SetCopyToFrontEnabled(copyToFrontEnabled);
879 }
880
881
882 ServerBitmap*
_GetBitmapForButton(Decorator::Tab * tab,Component item,bool down,int32 width,int32 height)883 BeDecorator::_GetBitmapForButton(Decorator::Tab* tab, Component item,
884 bool down, int32 width, int32 height)
885 {
886 uint8* data;
887 size_t size;
888 size_t offset;
889
890 // TODO: the list of shared bitmaps is never freed
891 struct decorator_bitmap {
892 Component item;
893 bool down;
894 int32 width;
895 int32 height;
896 rgb_color baseColor;
897 rgb_color lightColor;
898 UtilityBitmap* bitmap;
899 decorator_bitmap* next;
900 };
901
902 static BLocker sBitmapListLock("decorator lock", true);
903 static decorator_bitmap* sBitmapList = NULL;
904
905 // BeOS R5 colors
906 // button: active: 255, 203, 0 inactive: 232, 232, 232
907 // light1: active: 255, 238, 0 inactive: 255, 255, 255
908 // light2: active: 255, 255, 26 inactive: 255, 255, 255
909 // shadow1: active: 235, 183, 0 inactive: 211, 211, 211
910 // shadow2 is a bit lighter on zoom than on close button
911
912 ComponentColors colors;
913 _GetComponentColors(item, colors, tab);
914
915 const rgb_color buttonColor(colors[COLOR_BUTTON]);
916
917 bool isGrayscale = buttonColor.red == buttonColor.green
918 && buttonColor.green == buttonColor.blue;
919
920 rgb_color buttonColorLight1(buttonColor);
921 buttonColorLight1.red = std::min(255, buttonColor.red + 35),
922 buttonColorLight1.green = std::min(255, buttonColor.green + 35),
923 buttonColorLight1.blue = std::min(255, buttonColor.blue
924 + (isGrayscale ? 35 : 0));
925 // greyscale color stays grayscale
926
927 rgb_color buttonColorLight2(buttonColor);
928 buttonColorLight2.red = std::min(255, buttonColor.red + 52),
929 buttonColorLight2.green = std::min(255, buttonColor.green + 52),
930 buttonColorLight2.blue = std::min(255, buttonColor.blue + 26);
931
932 rgb_color buttonColorShadow1(buttonColor);
933 buttonColorShadow1.red = std::max(0, buttonColor.red - 21),
934 buttonColorShadow1.green = std::max(0, buttonColor.green - 21),
935 buttonColorShadow1.blue = std::max(0, buttonColor.blue - 21);
936
937 BAutolock locker(sBitmapListLock);
938
939 // search our list for a matching bitmap
940 // TODO: use a hash map instead?
941 decorator_bitmap* current = sBitmapList;
942 while (current) {
943 if (current->item == item && current->down == down
944 && current->width == width && current->height == height
945 && current->baseColor == colors[COLOR_BUTTON]
946 && current->lightColor == colors[COLOR_BUTTON_LIGHT]) {
947 return current->bitmap;
948 }
949
950 current = current->next;
951 }
952
953 static BitmapDrawingEngine* sBitmapDrawingEngine = NULL;
954
955 // didn't find any bitmap, create a new one
956 if (sBitmapDrawingEngine == NULL)
957 sBitmapDrawingEngine = new(std::nothrow) BitmapDrawingEngine();
958 if (sBitmapDrawingEngine == NULL
959 || sBitmapDrawingEngine->SetSize(width, height) != B_OK) {
960 return NULL;
961 }
962
963 BRect rect(0, 0, width - 1, height - 1);
964
965 STRACE(("BeDecorator creating bitmap for %s %s at size %ldx%ld\n",
966 item == COMPONENT_CLOSE_BUTTON ? "close" : "zoom",
967 down ? "down" : "up", width, height));
968 switch (item) {
969 case COMPONENT_CLOSE_BUTTON:
970 {
971 // BeOS R5 shadow2: active: 183, 131, 0 inactive: 160, 160, 160
972 rgb_color buttonColorShadow2(buttonColor);
973 buttonColorShadow2.red = std::max(0, buttonColor.red - 72),
974 buttonColorShadow2.green = std::max(0, buttonColor.green - 72),
975 buttonColorShadow2.blue = std::max(0, buttonColor.blue - 72);
976
977 // fill the background
978 sBitmapDrawingEngine->FillRect(rect, buttonColor);
979
980 // draw outer bevel
981 _DrawBevelRect(sBitmapDrawingEngine, rect, tab->closePressed,
982 buttonColorLight2, buttonColorShadow2);
983
984 if (fCStatus != B_OK) {
985 // If we ran out of memory while initializing bitmaps
986 // fall back to a linear gradient.
987 rect.InsetBy(1, 1);
988 _DrawBlendedRect(sBitmapDrawingEngine, rect, tab->closePressed,
989 buttonColorLight2, buttonColorLight1, buttonColor,
990 buttonColorShadow1);
991
992 break;
993 }
994
995 // inset by bevel
996 rect.InsetBy(2, 2);
997
998 // fill bg
999 sBitmapDrawingEngine->FillRect(rect, buttonColorLight1);
1000
1001 // treat background color as transparent
1002 sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1003 sBitmapDrawingEngine->SetLowColor(buttonColorLight1);
1004
1005 if (tab->closePressed) {
1006 // Draw glint in bottom right, then combined inner and outer
1007 // shadow in top left.
1008 // Read the source bitmap in forward while writing the
1009 // destination in reverse to rotate the bitmap by 180°.
1010
1011 data = fGlintBitmap->Bits();
1012 size = sizeof(kGlintBits);
1013 for (size_t i = 0; i < size; i++) {
1014 offset = (size - 1 - i) * 4;
1015 if (kGlintBits[i] == 0) {
1016 // draw glint color
1017 data[offset + 0] = buttonColorLight2.blue;
1018 data[offset + 1] = buttonColorLight2.green;
1019 data[offset + 2] = buttonColorLight2.red;
1020 } else {
1021 // draw background color
1022 data[offset + 0] = buttonColorLight1.blue;
1023 data[offset + 1] = buttonColorLight1.green;
1024 data[offset + 2] = buttonColorLight1.red;
1025 }
1026 }
1027 // glint is 3x3
1028 const BRect rightBottom(BRect(rect.right - 2, rect.bottom - 2,
1029 rect.right, rect.bottom));
1030 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
1031 fGlintBitmap->Bounds(), rightBottom);
1032
1033 data = fCloseBitmap->Bits();
1034 size = sizeof(kOuterShadowBits);
1035 for (size_t i = 0; i < size; i++) {
1036 offset = (size - 1 - i) * 4;
1037 if (kOuterShadowBits[i] == 0) {
1038 // draw outer shadow
1039 data[offset + 0] = buttonColorShadow1.blue;
1040 data[offset + 1] = buttonColorShadow1.green;
1041 data[offset + 2] = buttonColorShadow1.red;
1042 } else if (kInnerShadowBits[i] == 0) {
1043 // draw inner shadow
1044 data[offset + 0] = buttonColor.blue;
1045 data[offset + 1] = buttonColor.green;
1046 data[offset + 2] = buttonColor.red;
1047 } else {
1048 // draw background color
1049 data[offset + 0] = buttonColorLight1.blue;
1050 data[offset + 1] = buttonColorLight1.green;
1051 data[offset + 2] = buttonColorLight1.red;
1052 }
1053 }
1054 // shadow is 10x10
1055 const BRect leftTop(rect.left, rect.top,
1056 rect.left + 9, rect.top + 9);
1057 sBitmapDrawingEngine->DrawBitmap(fCloseBitmap,
1058 fCloseBitmap->Bounds(), leftTop);
1059 } else {
1060 // draw glint, then draw combined outer and inner shadows
1061
1062 data = fGlintBitmap->Bits();
1063 size = sizeof(kGlintBits);
1064 for (size_t i = 0; i < size; i++) {
1065 offset = i * 4 + 0;
1066 if (kGlintBits[i] == 0) {
1067 // draw glint color
1068 data[offset + 0] = buttonColorLight2.blue;
1069 data[offset + 1] = buttonColorLight2.green;
1070 data[offset + 2] = buttonColorLight2.red;
1071 } else {
1072 // draw background color
1073 data[offset + 0] = buttonColorLight1.blue;
1074 data[offset + 1] = buttonColorLight1.green;
1075 data[offset + 2] = buttonColorLight1.red;
1076 }
1077 }
1078 // glint is 3x3
1079 const BRect leftTop(rect.left, rect.top,
1080 rect.left + 2, rect.top + 2);
1081 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
1082 fGlintBitmap->Bounds(), leftTop);
1083
1084 data = fCloseBitmap->Bits();
1085 size = sizeof(kOuterShadowBits);
1086 for (size_t i = 0; i < size; i++) {
1087 offset = i * 4 + 0;
1088 if (kOuterShadowBits[i] == 0) {
1089 // draw outer shadow
1090 data[offset + 0] = buttonColorShadow1.blue;
1091 data[offset + 1] = buttonColorShadow1.green;
1092 data[offset + 2] = buttonColorShadow1.red;
1093 } else if (kInnerShadowBits[i] == 0) {
1094 // draw inner shadow
1095 data[offset + 0] = buttonColor.blue;
1096 data[offset + 1] = buttonColor.green;
1097 data[offset + 2] = buttonColor.red;
1098 } else {
1099 // draw background color
1100 data[offset + 0] = buttonColorLight1.blue;
1101 data[offset + 1] = buttonColorLight1.green;
1102 data[offset + 2] = buttonColorLight1.red;
1103 }
1104 }
1105 // shadow is 10x10
1106 const BRect rightBottom(BRect(rect.right - 9, rect.bottom - 9,
1107 rect.right, rect.bottom));
1108 sBitmapDrawingEngine->DrawBitmap(fCloseBitmap,
1109 fCloseBitmap->Bounds(), rightBottom);
1110 }
1111
1112 // restore drawing mode
1113 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1114
1115 break;
1116 }
1117
1118 case COMPONENT_ZOOM_BUTTON:
1119 {
1120 // BeOS R5 shadow2: active: 210, 158, 0 inactive: 187, 187, 187
1121 rgb_color buttonColorShadow2(buttonColor);
1122 buttonColorShadow2.red = std::max(0, buttonColor.red - 45),
1123 buttonColorShadow2.green = std::max(0, buttonColor.green - 45),
1124 buttonColorShadow2.blue = std::max(0, buttonColor.blue - 45);
1125
1126 // fill the background
1127 sBitmapDrawingEngine->FillRect(rect, buttonColor);
1128
1129 // big rect
1130 BRect bigRect(rect);
1131 bigRect.left += floorf(width * 3.0f / 14.0f);
1132 bigRect.top += floorf(height * 3.0f / 14.0f);
1133
1134 // small rect
1135 BRect smallRect(rect);
1136 smallRect.right -= floorf(width * 5.0f / 14.0f);
1137 smallRect.bottom -= floorf(height * 5.0f / 14.0f);
1138
1139 // draw big rect bevel
1140 _DrawBevelRect(sBitmapDrawingEngine, bigRect, tab->zoomPressed,
1141 buttonColorLight2, buttonColorShadow2);
1142
1143 if (fCStatus != B_OK) {
1144 // If we ran out of memory while initializing bitmaps
1145 // fall back to a linear gradient.
1146
1147 // already drew bigRect bevel, fill with linear gradient
1148 bigRect.InsetBy(1, 1);
1149 _DrawBlendedRect(sBitmapDrawingEngine, bigRect,
1150 tab->zoomPressed, buttonColorLight2, buttonColorLight1,
1151 buttonColor, buttonColorShadow1);
1152
1153 // draw small rect bevel then fill with linear gradient
1154 _DrawBevelRect(sBitmapDrawingEngine, smallRect,
1155 tab->zoomPressed, buttonColorLight2, buttonColorShadow2);
1156 if (!tab->zoomPressed) {
1157 // undraw bottom left and top right corners
1158 sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(),
1159 buttonColor);
1160 sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(),
1161 buttonColor);
1162 }
1163 smallRect.InsetBy(1, 1);
1164 _DrawBlendedRect(sBitmapDrawingEngine, smallRect,
1165 tab->zoomPressed, buttonColorLight2, buttonColorLight1,
1166 buttonColor, buttonColorShadow1);
1167
1168 break;
1169 }
1170
1171 // inset past bevel
1172 bigRect.InsetBy(2, 2);
1173
1174 // fill big rect bg
1175 sBitmapDrawingEngine->FillRect(bigRect, buttonColorLight1);
1176
1177 // some elements are covered by the small rect
1178 // so only draw the parts that get shown
1179 if (tab->zoomPressed) {
1180 // draw glint
1181 // Read the source bitmap in forward while writing the
1182 // destination in reverse to rotate the bitmap by 180°.
1183 data = fGlintBitmap->Bits();
1184 size = sizeof(kGlintBits);
1185 for (size_t i = 0; i < sizeof(kGlintBits); i++) {
1186 offset = (size - 1 - i) * 4;
1187 if (kGlintBits[i] == 0) {
1188 // draw glint
1189 data[offset + 0] = buttonColorLight2.blue;
1190 data[offset + 1] = buttonColorLight2.green;
1191 data[offset + 2] = buttonColorLight2.red;
1192 } else {
1193 // draw background color
1194 data[offset + 0] = buttonColorLight1.blue;
1195 data[offset + 1] = buttonColorLight1.green;
1196 data[offset + 2] = buttonColorLight1.red;
1197 }
1198 }
1199 // glint is 3x3
1200 const BRect rightBottom(BRect(bigRect.right - 2,
1201 bigRect.bottom - 2, bigRect.right, bigRect.bottom));
1202 sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
1203 fGlintBitmap->Bounds(), rightBottom);
1204 } else {
1205 // draw combined inner and outer shadow
1206 data = fBigZoomBitmap->Bits();
1207 for (size_t i = 0; i < sizeof(kBigOuterShadowBits); i++) {
1208 offset = i * 4;
1209 if (kBigOuterShadowBits[i] == 0) {
1210 // draw outer shadow
1211 data[offset + 0] = buttonColorShadow1.blue;
1212 data[offset + 1] = buttonColorShadow1.green;
1213 data[offset + 2] = buttonColorShadow1.red;
1214 } else if (kBigInnerShadowBits[i] == 0) {
1215 // draw inner shadow
1216 data[offset + 0] = buttonColor.blue;
1217 data[offset + 1] = buttonColor.green;
1218 data[offset + 2] = buttonColor.red;
1219 } else {
1220 // draw background color
1221 data[offset + 0] = buttonColorLight1.blue;
1222 data[offset + 1] = buttonColorLight1.green;
1223 data[offset + 2] = buttonColorLight1.red;
1224 }
1225 }
1226 // shadow is 7x7
1227 const BRect rightBottom(BRect(bigRect.right - 6,
1228 bigRect.bottom - 6, bigRect.right, bigRect.bottom));
1229 sBitmapDrawingEngine->DrawBitmap(fBigZoomBitmap,
1230 fBigZoomBitmap->Bounds(), rightBottom);
1231 }
1232
1233 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1234
1235 // draw small rect bevel
1236 _DrawBevelRect(sBitmapDrawingEngine, smallRect, tab->zoomPressed,
1237 buttonColorLight2, buttonColorShadow2);
1238
1239 if (!tab->zoomPressed) {
1240 // undraw bottom left and top right corners
1241 sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(),
1242 buttonColor);
1243 sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(),
1244 buttonColor);
1245 }
1246
1247 // inset past bevel
1248 smallRect.InsetBy(2, 2);
1249
1250 // fill small rect bg
1251 sBitmapDrawingEngine->FillRect(smallRect, buttonColorLight1);
1252
1253 // treat background color as transparent
1254 sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
1255 sBitmapDrawingEngine->SetLowColor(buttonColorLight1);
1256
1257 // draw small bitmap
1258 data = fSmallZoomBitmap->Bits();
1259 size = sizeof(kSmallOuterShadowBits);
1260 if (tab->zoomPressed) {
1261 // draw combined inner and outer shadow
1262 // Read the source bitmap in forward while writing the
1263 // destination in reverse to rotate the bitmap by 180°.
1264 for (size_t i = 0; i < size; i++) {
1265 offset = (size - 1 - i) * 4;
1266 if (kSmallOuterShadowBits[i] == 0) {
1267 // draw outer shadow
1268 data[offset + 0] = buttonColorShadow1.blue;
1269 data[offset + 1] = buttonColorShadow1.green;
1270 data[offset + 2] = buttonColorShadow1.red;
1271 } else if (kSmallInnerShadowBits[i] == 0) {
1272 // draw inner shadow
1273 data[offset + 0] = buttonColor.blue;
1274 data[offset + 1] = buttonColor.green;
1275 data[offset + 2] = buttonColor.red;
1276 } else {
1277 // draw background color
1278 data[offset + 0] = buttonColorLight1.blue;
1279 data[offset + 1] = buttonColorLight1.green;
1280 data[offset + 2] = buttonColorLight1.red;
1281 }
1282 }
1283 // shadow is 5x5
1284 const BRect smallLeftTop(BRect(smallRect.left,
1285 smallRect.top, smallRect.left + 4, smallRect.top + 4));
1286 sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap,
1287 fSmallZoomBitmap->Bounds(), smallLeftTop);
1288 } else {
1289 // draw combined inner and outer shadow
1290 for (size_t i = 0; i < size; i++) {
1291 offset = i * 4;
1292 if (kSmallOuterShadowBits[i] == 0) {
1293 // draw outer shadow
1294 data[offset + 0] = buttonColorShadow1.blue;
1295 data[offset + 1] = buttonColorShadow1.green;
1296 data[offset + 2] = buttonColorShadow1.red;
1297 } else if (kSmallInnerShadowBits[i] == 0) {
1298 // draw inner shadow
1299 data[offset + 0] = buttonColor.blue;
1300 data[offset + 1] = buttonColor.green;
1301 data[offset + 2] = buttonColor.red;
1302 } else {
1303 // draw background color
1304 data[offset + 0] = buttonColorLight1.blue;
1305 data[offset + 1] = buttonColorLight1.green;
1306 data[offset + 2] = buttonColorLight1.red;
1307 }
1308 }
1309 // shadow is 5x5
1310 const BRect smallRightBottom(BRect(smallRect.right - 4,
1311 smallRect.bottom - 4, smallRect.right, smallRect.bottom));
1312 sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap,
1313 fSmallZoomBitmap->Bounds(), smallRightBottom);
1314 }
1315
1316 // draw glint last (single pixel)
1317 sBitmapDrawingEngine->StrokePoint(tab->zoomPressed
1318 ? smallRect.RightBottom() : smallRect.LeftTop(),
1319 buttonColorLight2);
1320
1321 // restore drawing mode
1322 sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
1323
1324 break;
1325 }
1326
1327 default:
1328 break;
1329 }
1330
1331 UtilityBitmap* bitmap = sBitmapDrawingEngine->ExportToBitmap(width, height,
1332 B_RGB32);
1333 if (bitmap == NULL)
1334 return NULL;
1335
1336 // bitmap ready, put it into the list
1337 decorator_bitmap* entry = new(std::nothrow) decorator_bitmap;
1338 if (entry == NULL) {
1339 delete bitmap;
1340 return NULL;
1341 }
1342
1343 entry->item = item;
1344 entry->down = down;
1345 entry->width = width;
1346 entry->height = height;
1347 entry->bitmap = bitmap;
1348 entry->baseColor = colors[COLOR_BUTTON];
1349 entry->lightColor = colors[COLOR_BUTTON_LIGHT];
1350 entry->next = sBitmapList;
1351 sBitmapList = entry;
1352 return bitmap;
1353 }
1354
1355
1356 ServerBitmap*
_CreateTemporaryBitmap(BRect bounds) const1357 BeDecorator::_CreateTemporaryBitmap(BRect bounds) const
1358 {
1359 UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds,
1360 B_RGB32, 0);
1361 if (bitmap == NULL)
1362 return NULL;
1363
1364 if (!bitmap->IsValid()) {
1365 delete bitmap;
1366 return NULL;
1367 }
1368
1369 memset(bitmap->Bits(), 0, bitmap->BitsLength());
1370 // background opacity is 0
1371
1372 return bitmap;
1373 }
1374
1375
1376 void
_GetComponentColors(Component component,ComponentColors _colors,Decorator::Tab * tab)1377 BeDecorator::_GetComponentColors(Component component,
1378 ComponentColors _colors, Decorator::Tab* tab)
1379 {
1380 // get the highlight for our component
1381 Region region = REGION_NONE;
1382 switch (component) {
1383 case COMPONENT_TAB:
1384 region = REGION_TAB;
1385 break;
1386 case COMPONENT_CLOSE_BUTTON:
1387 region = REGION_CLOSE_BUTTON;
1388 break;
1389 case COMPONENT_ZOOM_BUTTON:
1390 region = REGION_ZOOM_BUTTON;
1391 break;
1392 case COMPONENT_LEFT_BORDER:
1393 region = REGION_LEFT_BORDER;
1394 break;
1395 case COMPONENT_RIGHT_BORDER:
1396 region = REGION_RIGHT_BORDER;
1397 break;
1398 case COMPONENT_TOP_BORDER:
1399 region = REGION_TOP_BORDER;
1400 break;
1401 case COMPONENT_BOTTOM_BORDER:
1402 region = REGION_BOTTOM_BORDER;
1403 break;
1404 case COMPONENT_RESIZE_CORNER:
1405 region = REGION_RIGHT_BOTTOM_CORNER;
1406 break;
1407 }
1408
1409 return GetComponentColors(component, RegionHighlight(region), _colors, tab);
1410 }
1411
1412
1413 extern "C" DecorAddOn* (instantiate_decor_addon)(image_id id, const char* name)
1414 {
1415 return new (std::nothrow)BeDecorAddOn(id, name);
1416 }
1417