1 /*
2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
3 * Copyright 2012-2020 Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 *
6 * Authors:
7 * Stephan Aßmus, superstippi@gmx.de
8 * John Scipione, jscipione@gmail.com
9 */
10
11
12 #include <HaikuControlLook.h>
13
14 #include <algorithm>
15
16 #include <Bitmap.h>
17 #include <Control.h>
18 #include <GradientLinear.h>
19 #include <LayoutUtils.h>
20 #include <Region.h>
21 #include <Shape.h>
22 #include <String.h>
23 #include <TabView.h>
24 #include <View.h>
25 #include <Window.h>
26 #include <WindowPrivate.h>
27
28
29 namespace BPrivate {
30
31 static const float kEdgeBevelLightTint = 0.59;
32 static const float kEdgeBevelShadowTint = 1.0735;
33 static const float kHoverTintFactor = 0.85;
34
35 static const int32 kButtonPopUpIndicatorWidth = B_USE_ITEM_SPACING;
36
37
HaikuControlLook()38 HaikuControlLook::HaikuControlLook()
39 :
40 fCachedOutline(false)
41 {
42 }
43
44
~HaikuControlLook()45 HaikuControlLook::~HaikuControlLook()
46 {
47 }
48
49
50 BAlignment
DefaultLabelAlignment() const51 HaikuControlLook::DefaultLabelAlignment() const
52 {
53 return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER);
54 }
55
56
57 float
DefaultLabelSpacing() const58 HaikuControlLook::DefaultLabelSpacing() const
59 {
60 return ceilf(be_plain_font->Size() / 2.0);
61 }
62
63
64 float
DefaultItemSpacing() const65 HaikuControlLook::DefaultItemSpacing() const
66 {
67 return ceilf(be_plain_font->Size() * 0.85);
68 }
69
70
71 uint32
Flags(BControl * control) const72 HaikuControlLook::Flags(BControl* control) const
73 {
74 uint32 flags = B_IS_CONTROL;
75
76 if (!control->IsEnabled())
77 flags |= B_DISABLED;
78
79 if (control->IsFocus() && control->Window() != NULL
80 && control->Window()->IsActive()) {
81 flags |= B_FOCUSED;
82 }
83
84 switch (control->Value()) {
85 case B_CONTROL_ON:
86 flags |= B_ACTIVATED;
87 break;
88 case B_CONTROL_PARTIALLY_ON:
89 flags |= B_PARTIALLY_ACTIVATED;
90 break;
91 }
92
93 if (control->Parent() != NULL
94 && (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) {
95 // In this constellation, assume we want to render the control
96 // against the already existing view contents of the parent view.
97 flags |= B_BLEND_FRAME;
98 }
99
100 return flags;
101 }
102
103
104 // #pragma mark -
105
106
107 void
DrawButtonFrame(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)108 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
109 const rgb_color& base, const rgb_color& background, uint32 flags,
110 uint32 borders)
111 {
112 _DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base,
113 background, 1.0, 1.0, flags, borders);
114 }
115
116
117 void
DrawButtonFrame(BView * view,BRect & rect,const BRect & updateRect,float radius,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)118 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
119 float radius, const rgb_color& base, const rgb_color& background, uint32 flags,
120 uint32 borders)
121 {
122 _DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius,
123 base, background, 1.0, 1.0, flags, borders);
124 }
125
126
127 void
DrawButtonFrame(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)128 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect,
129 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
130 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
131 const rgb_color& background, uint32 flags,
132 uint32 borders)
133 {
134 _DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius,
135 leftBottomRadius, rightBottomRadius, base, background,
136 1.0, 1.0, flags, borders);
137 }
138
139
140 void
DrawButtonBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)141 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
142 const BRect& updateRect, const rgb_color& base, uint32 flags,
143 uint32 borders, orientation orientation)
144 {
145 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
146 base, false, flags, borders, orientation);
147 }
148
149
150 void
DrawButtonBackground(BView * view,BRect & rect,const BRect & updateRect,float radius,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)151 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
152 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
153 uint32 borders, orientation orientation)
154 {
155 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
156 radius, base, false, flags, borders, orientation);
157 }
158
159
160 void
DrawButtonBackground(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)161 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
162 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
163 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
164 uint32 flags, uint32 borders, orientation orientation)
165 {
166 _DrawButtonBackground(view, rect, updateRect, leftTopRadius,
167 rightTopRadius, leftBottomRadius, rightBottomRadius, base, false, flags,
168 borders, orientation);
169 }
170
171
172 void
DrawMenuBarBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)173 HaikuControlLook::DrawMenuBarBackground(BView* view, BRect& rect,
174 const BRect& updateRect, const rgb_color& base, uint32 flags,
175 uint32 borders)
176 {
177 if (!ShouldDraw(view, rect, updateRect))
178 return;
179
180 // the surface edges
181
182 // colors
183 float topTint;
184 float bottomTint;
185
186 if ((flags & B_ACTIVATED) != 0) {
187 rgb_color bevelColor1 = tint_color(base, 1.40);
188 rgb_color bevelColor2 = tint_color(base, 1.25);
189
190 topTint = 1.25;
191 bottomTint = 1.20;
192
193 _DrawFrame(view, rect,
194 bevelColor1, bevelColor1,
195 bevelColor2, bevelColor2,
196 borders & B_TOP_BORDER);
197 } else {
198 rgb_color cornerColor = tint_color(base, 0.9);
199 rgb_color bevelColorTop = tint_color(base, 0.5);
200 rgb_color bevelColorLeft = tint_color(base, 0.7);
201 rgb_color bevelColorRightBottom = tint_color(base, 1.08);
202
203 topTint = 0.69;
204 bottomTint = 1.03;
205
206 _DrawFrame(view, rect,
207 bevelColorLeft, bevelColorTop,
208 bevelColorRightBottom, bevelColorRightBottom,
209 cornerColor, cornerColor,
210 borders);
211 }
212
213 // draw surface top
214 _FillGradient(view, rect, base, topTint, bottomTint);
215 }
216
217
218 void
DrawMenuFieldFrame(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)219 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
220 const BRect& updateRect, const rgb_color& base,
221 const rgb_color& background, uint32 flags, uint32 borders)
222 {
223 _DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base,
224 background, 0.6, 1.0, flags, borders);
225 }
226
227
228 void
DrawMenuFieldFrame(BView * view,BRect & rect,const BRect & updateRect,float radius,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)229 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
230 const BRect& updateRect, float radius, const rgb_color& base,
231 const rgb_color& background, uint32 flags, uint32 borders)
232 {
233 _DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius,
234 base, background, 0.6, 1.0, flags, borders);
235 }
236
237
238 void
DrawMenuFieldFrame(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,const rgb_color & background,uint32 flags,uint32 borders)239 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
240 const BRect& updateRect, float leftTopRadius,
241 float rightTopRadius, float leftBottomRadius,
242 float rightBottomRadius, const rgb_color& base,
243 const rgb_color& background, uint32 flags, uint32 borders)
244 {
245 _DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius,
246 leftBottomRadius, rightBottomRadius, base, background, 0.6, 1.0,
247 flags, borders);
248 }
249
250
251 void
DrawMenuFieldBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,bool popupIndicator,uint32 flags)252 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
253 const BRect& updateRect, const rgb_color& base, bool popupIndicator,
254 uint32 flags)
255 {
256 _DrawMenuFieldBackgroundOutside(view, rect, updateRect,
257 0.0f, 0.0f, 0.0f, 0.0f, base, popupIndicator, flags);
258 }
259
260
261 void
DrawMenuFieldBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)262 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
263 const BRect& updateRect, const rgb_color& base, uint32 flags,
264 uint32 borders)
265 {
266 _DrawMenuFieldBackgroundInside(view, rect, updateRect,
267 0.0f, 0.0f, 0.0f, 0.0f, base, flags, borders);
268 }
269
270
271 void
DrawMenuFieldBackground(BView * view,BRect & rect,const BRect & updateRect,float radius,const rgb_color & base,bool popupIndicator,uint32 flags)272 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
273 const BRect& updateRect, float radius, const rgb_color& base,
274 bool popupIndicator, uint32 flags)
275 {
276 _DrawMenuFieldBackgroundOutside(view, rect, updateRect, radius, radius,
277 radius, radius, base, popupIndicator, flags);
278 }
279
280
281 void
DrawMenuFieldBackground(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,bool popupIndicator,uint32 flags)282 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
283 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
284 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
285 bool popupIndicator, uint32 flags)
286 {
287 _DrawMenuFieldBackgroundOutside(view, rect, updateRect, leftTopRadius,
288 rightTopRadius, leftBottomRadius, rightBottomRadius, base,
289 popupIndicator, flags);
290 }
291
292
293 void
DrawMenuBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)294 HaikuControlLook::DrawMenuBackground(BView* view, BRect& rect,
295 const BRect& updateRect, const rgb_color& base, uint32 flags,
296 uint32 borders)
297 {
298 if (!ShouldDraw(view, rect, updateRect))
299 return;
300
301 // inner bevel colors
302 rgb_color bevelLightColor;
303 rgb_color bevelShadowColor;
304
305 if ((flags & B_DISABLED) != 0) {
306 bevelLightColor = tint_color(base, 0.80);
307 bevelShadowColor = tint_color(base, 1.07);
308 } else {
309 bevelLightColor = tint_color(base, 0.6);
310 bevelShadowColor = tint_color(base, 1.12);
311 }
312
313 // draw inner bevel
314 _DrawFrame(view, rect,
315 bevelLightColor, bevelLightColor,
316 bevelShadowColor, bevelShadowColor,
317 borders);
318
319 // draw surface top
320 view->SetHighColor(base);
321 view->FillRect(rect);
322 }
323
324
325 void
DrawMenuItemBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)326 HaikuControlLook::DrawMenuItemBackground(BView* view, BRect& rect,
327 const BRect& updateRect, const rgb_color& base, uint32 flags,
328 uint32 borders)
329 {
330 if (!ShouldDraw(view, rect, updateRect))
331 return;
332
333 // surface edges
334 float topTint;
335 float bottomTint;
336 rgb_color selectedColor = base;
337
338 if ((flags & B_ACTIVATED) != 0) {
339 topTint = 0.9;
340 bottomTint = 1.05;
341 } else if ((flags & B_DISABLED) != 0) {
342 topTint = 0.80;
343 bottomTint = 1.07;
344 } else {
345 topTint = 0.6;
346 bottomTint = 1.12;
347 }
348
349 rgb_color bevelLightColor = tint_color(selectedColor, topTint);
350 rgb_color bevelShadowColor = tint_color(selectedColor, bottomTint);
351
352 // draw surface edges
353 _DrawFrame(view, rect,
354 bevelLightColor, bevelLightColor,
355 bevelShadowColor, bevelShadowColor,
356 borders);
357
358 // draw surface top
359 view->SetLowColor(selectedColor);
360 // _FillGradient(view, rect, selectedColor, topTint, bottomTint);
361 _FillGradient(view, rect, selectedColor, bottomTint, topTint);
362 }
363
364
365 void
DrawStatusBar(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,const rgb_color & barColor,float progressPosition)366 HaikuControlLook::DrawStatusBar(BView* view, BRect& rect, const BRect& updateRect,
367 const rgb_color& base, const rgb_color& barColor, float progressPosition)
368 {
369 if (!ShouldDraw(view, rect, updateRect))
370 return;
371
372 _DrawOuterResessedFrame(view, rect, base, 0.6);
373
374 // colors
375 rgb_color dark1BorderColor = tint_color(base, 1.3);
376 rgb_color dark2BorderColor = tint_color(base, 1.2);
377 rgb_color dark1FilledBorderColor = tint_color(barColor, 1.20);
378 rgb_color dark2FilledBorderColor = tint_color(barColor, 1.45);
379
380 BRect filledRect(rect);
381 filledRect.right = progressPosition - 1;
382
383 BRect nonfilledRect(rect);
384 nonfilledRect.left = progressPosition;
385
386 bool filledSurface = filledRect.Width() > 0;
387 bool nonfilledSurface = nonfilledRect.Width() > 0;
388
389 if (filledSurface) {
390 _DrawFrame(view, filledRect,
391 dark1FilledBorderColor, dark1FilledBorderColor,
392 dark2FilledBorderColor, dark2FilledBorderColor);
393
394 _FillGlossyGradient(view, filledRect, barColor, 0.55, 0.68, 0.76, 0.90);
395 }
396
397 if (nonfilledSurface) {
398 _DrawFrame(view, nonfilledRect, dark1BorderColor, dark1BorderColor,
399 dark2BorderColor, dark2BorderColor,
400 B_TOP_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER);
401
402 if (nonfilledRect.left < nonfilledRect.right) {
403 // shadow from fill bar, or left border
404 rgb_color leftBorder = dark1BorderColor;
405 if (filledSurface)
406 leftBorder = tint_color(base, 0.50);
407 view->SetHighColor(leftBorder);
408 view->StrokeLine(nonfilledRect.LeftTop(),
409 nonfilledRect.LeftBottom());
410 nonfilledRect.left++;
411 }
412
413 _FillGradient(view, nonfilledRect, base, 0.25, 0.06);
414 }
415 }
416
417
418 void
DrawCheckBox(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags)419 HaikuControlLook::DrawCheckBox(BView* view, BRect& rect, const BRect& updateRect,
420 const rgb_color& base, uint32 flags)
421 {
422 if (!ShouldDraw(view, rect, updateRect))
423 return;
424
425 rgb_color dark1BorderColor;
426 rgb_color dark2BorderColor;
427 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
428
429 if ((flags & B_DISABLED) != 0) {
430 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags);
431
432 dark1BorderColor = tint_color(base, 1.15);
433 dark2BorderColor = tint_color(base, 1.15);
434 } else if ((flags & B_CLICKED) != 0) {
435 dark1BorderColor = tint_color(base, 1.50);
436 dark2BorderColor = tint_color(base, 1.48);
437
438 _DrawFrame(view, rect,
439 dark1BorderColor, dark1BorderColor,
440 dark2BorderColor, dark2BorderColor);
441
442 dark2BorderColor = dark1BorderColor;
443 } else {
444 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags);
445
446 dark1BorderColor = tint_color(base, 1.40);
447 dark2BorderColor = tint_color(base, 1.38);
448 }
449
450 if ((flags & B_FOCUSED) != 0) {
451 dark1BorderColor = navigationColor;
452 dark2BorderColor = navigationColor;
453 }
454
455 _DrawFrame(view, rect,
456 dark1BorderColor, dark1BorderColor,
457 dark2BorderColor, dark2BorderColor);
458
459 if ((flags & B_DISABLED) != 0)
460 _FillGradient(view, rect, base, 0.4, 0.2);
461 else
462 _FillGradient(view, rect, base, 0.15, 0.0);
463
464 rgb_color markColor;
465 if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) {
466 view->SetHighColor(markColor);
467
468 BFont font;
469 view->GetFont(&font);
470 float inset = std::max(2.0f, roundf(font.Size() / 6));
471 rect.InsetBy(inset, inset);
472
473 float penSize = std::max(1.0f, ceilf(rect.Width() / 3.5f));
474 if (penSize > 1.0f && fmodf(penSize, 2.0f) == 0.0f) {
475 // Tweak ends to "include" the pixel at the index,
476 // we need to do this in order to produce results like R5,
477 // where coordinates were inclusive
478 rect.right++;
479 rect.bottom++;
480 }
481
482 view->SetPenSize(penSize);
483 view->SetDrawingMode(B_OP_OVER);
484 view->StrokeLine(rect.LeftTop(), rect.RightBottom());
485 view->StrokeLine(rect.LeftBottom(), rect.RightTop());
486 }
487 }
488
489
490 void
DrawRadioButton(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags)491 HaikuControlLook::DrawRadioButton(BView* view, BRect& rect, const BRect& updateRect,
492 const rgb_color& base, uint32 flags)
493 {
494 if (!ShouldDraw(view, rect, updateRect))
495 return;
496
497 rgb_color borderColor;
498 rgb_color bevelLight;
499 rgb_color bevelShadow;
500 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
501
502 if ((flags & B_DISABLED) != 0) {
503 borderColor = tint_color(base, 1.15);
504 bevelLight = base;
505 bevelShadow = base;
506 } else if ((flags & B_CLICKED) != 0) {
507 borderColor = tint_color(base, 1.50);
508 bevelLight = borderColor;
509 bevelShadow = borderColor;
510 } else {
511 borderColor = tint_color(base, 1.45);
512 bevelLight = tint_color(base, 0.55);
513 bevelShadow = tint_color(base, 1.11);
514 }
515
516 if ((flags & B_FOCUSED) != 0) {
517 borderColor = navigationColor;
518 }
519
520 BGradientLinear bevelGradient;
521 bevelGradient.AddColor(bevelShadow, 0);
522 bevelGradient.AddColor(bevelLight, 255);
523 bevelGradient.SetStart(rect.LeftTop());
524 bevelGradient.SetEnd(rect.RightBottom());
525
526 view->FillEllipse(rect, bevelGradient);
527 rect.InsetBy(1, 1);
528
529 bevelGradient.MakeEmpty();
530 bevelGradient.AddColor(borderColor, 0);
531 bevelGradient.AddColor(tint_color(borderColor, 0.8), 255);
532 view->FillEllipse(rect, bevelGradient);
533 rect.InsetBy(1, 1);
534
535 float topTint;
536 float bottomTint;
537 if ((flags & B_DISABLED) != 0) {
538 topTint = 0.4;
539 bottomTint = 0.2;
540 } else {
541 topTint = 0.15;
542 bottomTint = 0.0;
543 }
544
545 BGradientLinear gradient;
546 _MakeGradient(gradient, rect, base, topTint, bottomTint);
547 view->FillEllipse(rect, gradient);
548
549 rgb_color markColor;
550 if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) {
551 view->SetHighColor(markColor);
552 BFont font;
553 view->GetFont(&font);
554 float inset = roundf(font.Size() / 4);
555 rect.InsetBy(inset, inset);
556 view->FillEllipse(rect);
557 }
558 }
559
560
561 void
DrawScrollBarBorder(BView * view,BRect rect,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation)562 HaikuControlLook::DrawScrollBarBorder(BView* view, BRect rect,
563 const BRect& updateRect, const rgb_color& base, uint32 flags,
564 orientation orientation)
565 {
566 if (!ShouldDraw(view, rect, updateRect))
567 return;
568
569 view->PushState();
570
571 // set clipping constraints to rect
572 view->ClipToRect(rect);
573
574 bool isEnabled = (flags & B_DISABLED) == 0;
575 bool isFocused = (flags & B_FOCUSED) != 0;
576
577 view->SetHighColor(tint_color(base, B_DARKEN_2_TINT));
578
579 // stroke a line around the entire scrollbar
580 // take care of border highlighting, scroll target is focus view
581 if (isEnabled && isFocused) {
582 rgb_color borderColor = view->HighColor();
583 rgb_color highlightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
584
585 view->BeginLineArray(4);
586
587 view->AddLine(BPoint(rect.left + 1, rect.bottom),
588 BPoint(rect.right, rect.bottom), borderColor);
589 view->AddLine(BPoint(rect.right, rect.top + 1),
590 BPoint(rect.right, rect.bottom - 1), borderColor);
591
592 if (orientation == B_HORIZONTAL) {
593 view->AddLine(BPoint(rect.left, rect.top + 1),
594 BPoint(rect.left, rect.bottom), borderColor);
595 } else {
596 view->AddLine(BPoint(rect.left, rect.top),
597 BPoint(rect.left, rect.bottom), highlightColor);
598 }
599
600 if (orientation == B_HORIZONTAL) {
601 view->AddLine(BPoint(rect.left, rect.top),
602 BPoint(rect.right, rect.top), highlightColor);
603 } else {
604 view->AddLine(BPoint(rect.left + 1, rect.top),
605 BPoint(rect.right, rect.top), borderColor);
606 }
607
608 view->EndLineArray();
609 } else
610 view->StrokeRect(rect);
611
612 view->PopState();
613 }
614
615
616 void
DrawScrollBarButton(BView * view,BRect rect,const BRect & updateRect,const rgb_color & base,uint32 flags,int32 direction,orientation orientation,bool down)617 HaikuControlLook::DrawScrollBarButton(BView* view, BRect rect,
618 const BRect& updateRect, const rgb_color& base, uint32 flags,
619 int32 direction, orientation orientation, bool down)
620 {
621 if (!ShouldDraw(view, rect, updateRect))
622 return;
623
624 view->PushState();
625
626 // clip to button
627 view->ClipToRect(rect);
628
629 bool isEnabled = (flags & B_DISABLED) == 0;
630
631 rgb_color buttonColor = isEnabled ? base
632 : tint_color(base, B_LIGHTEN_1_TINT);
633 DrawButtonBackground(view, rect, updateRect, buttonColor, flags,
634 BControlLook::B_ALL_BORDERS, orientation);
635
636 rect.InsetBy(-1, -1);
637 DrawArrowShape(view, rect, updateRect, base, direction, flags, 1.9f);
638 // almost but not quite B_DARKEN_MAX_TINT
639
640 // revert clipping constraints
641 view->PopState();
642 }
643
644 void
DrawScrollBarBackground(BView * view,BRect & rect1,BRect & rect2,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation)645 HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect1,
646 BRect& rect2, const BRect& updateRect, const rgb_color& base, uint32 flags,
647 orientation orientation)
648 {
649 DrawScrollBarBackground(view, rect1, updateRect, base, flags, orientation);
650 DrawScrollBarBackground(view, rect2, updateRect, base, flags, orientation);
651 }
652
653
654 void
DrawScrollBarBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation)655 HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect,
656 const BRect& updateRect, const rgb_color& base, uint32 flags,
657 orientation orientation)
658 {
659 if (!ShouldDraw(view, rect, updateRect))
660 return;
661
662 view->PushState();
663
664 // set clipping constraints to rect
665 view->ClipToRect(rect);
666
667 bool isEnabled = (flags & B_DISABLED) == 0;
668
669 // fill background, we'll draw arrows and thumb on top
670 view->SetDrawingMode(B_OP_COPY);
671
672 float gradient1Tint;
673 float gradient2Tint;
674 float darkEdge1Tint;
675 float darkEdge2Tint;
676 float shadowTint;
677
678 if (isEnabled) {
679 gradient1Tint = 1.10;
680 gradient2Tint = 1.05;
681 darkEdge1Tint = B_DARKEN_3_TINT;
682 darkEdge2Tint = B_DARKEN_2_TINT;
683 shadowTint = gradient1Tint;
684 } else {
685 gradient1Tint = 0.9;
686 gradient2Tint = 0.8;
687 darkEdge1Tint = B_DARKEN_2_TINT;
688 darkEdge2Tint = B_DARKEN_2_TINT;
689 shadowTint = gradient1Tint;
690 }
691
692 rgb_color darkEdge1 = tint_color(base, darkEdge1Tint);
693 rgb_color darkEdge2 = tint_color(base, darkEdge2Tint);
694 rgb_color shadow = tint_color(base, shadowTint);
695
696 if (orientation == B_HORIZONTAL) {
697 // dark vertical line on left edge
698 if (rect.Width() > 0) {
699 view->SetHighColor(darkEdge1);
700 view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
701 rect.left++;
702 }
703 // dark vertical line on right edge
704 if (rect.Width() >= 0) {
705 view->SetHighColor(darkEdge2);
706 view->StrokeLine(rect.RightTop(), rect.RightBottom());
707 rect.right--;
708 }
709 // vertical shadow line after left edge
710 if (rect.Width() >= 0) {
711 view->SetHighColor(shadow);
712 view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
713 rect.left++;
714 }
715 // fill
716 if (rect.Width() >= 0) {
717 _FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
718 orientation);
719 }
720 } else {
721 // dark vertical line on top edge
722 if (rect.Height() > 0) {
723 view->SetHighColor(darkEdge1);
724 view->StrokeLine(rect.LeftTop(), rect.RightTop());
725 rect.top++;
726 }
727 // dark vertical line on bottom edge
728 if (rect.Height() >= 0) {
729 view->SetHighColor(darkEdge2);
730 view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
731 rect.bottom--;
732 }
733 // horizontal shadow line after top edge
734 if (rect.Height() >= 0) {
735 view->SetHighColor(shadow);
736 view->StrokeLine(rect.LeftTop(), rect.RightTop());
737 rect.top++;
738 }
739 // fill
740 if (rect.Height() >= 0) {
741 _FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
742 orientation);
743 }
744 }
745
746 view->PopState();
747 }
748
749
750 void
DrawScrollBarThumb(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation,uint32 knobStyle)751 HaikuControlLook::DrawScrollBarThumb(BView* view, BRect& rect,
752 const BRect& updateRect, const rgb_color& base, uint32 flags,
753 orientation orientation, uint32 knobStyle)
754 {
755 if (!ShouldDraw(view, rect, updateRect))
756 return;
757
758 view->PushState();
759
760 // set clipping constraints to rect
761 view->ClipToRect(rect);
762
763 // flags
764 bool isEnabled = (flags & B_DISABLED) == 0;
765
766 // colors
767 rgb_color thumbColor = ui_color(B_SCROLL_BAR_THUMB_COLOR);
768 const float bgTint = 1.06;
769
770 rgb_color light, dark, dark1, dark2;
771 if (isEnabled) {
772 light = tint_color(base, B_LIGHTEN_MAX_TINT);
773 dark = tint_color(base, B_DARKEN_3_TINT);
774 dark1 = tint_color(base, B_DARKEN_1_TINT);
775 dark2 = tint_color(base, B_DARKEN_2_TINT);
776 } else {
777 light = tint_color(base, B_LIGHTEN_MAX_TINT);
778 dark = tint_color(base, B_DARKEN_2_TINT);
779 dark1 = tint_color(base, B_LIGHTEN_2_TINT);
780 dark2 = tint_color(base, B_LIGHTEN_1_TINT);
781 }
782
783 // draw thumb over background
784 view->SetDrawingMode(B_OP_OVER);
785 view->SetHighColor(dark1);
786
787 // draw scroll thumb
788 if (isEnabled) {
789 // fill the clickable surface of the thumb
790 DrawButtonBackground(view, rect, updateRect, thumbColor, 0,
791 B_ALL_BORDERS, orientation);
792 } else {
793 // thumb bevel
794 view->BeginLineArray(4);
795 view->AddLine(BPoint(rect.left, rect.bottom),
796 BPoint(rect.left, rect.top), light);
797 view->AddLine(BPoint(rect.left + 1, rect.top),
798 BPoint(rect.right, rect.top), light);
799 view->AddLine(BPoint(rect.right, rect.top + 1),
800 BPoint(rect.right, rect.bottom), dark2);
801 view->AddLine(BPoint(rect.right - 1, rect.bottom),
802 BPoint(rect.left + 1, rect.bottom), dark2);
803 view->EndLineArray();
804
805 // thumb fill
806 rect.InsetBy(1, 1);
807 view->SetHighColor(dark1);
808 view->FillRect(rect);
809 }
810
811 // draw knob style
812 if (knobStyle != B_KNOB_NONE) {
813 rgb_color knobLight = isEnabled
814 ? tint_color(thumbColor, B_LIGHTEN_MAX_TINT)
815 : tint_color(dark1, bgTint);
816 rgb_color knobDark = isEnabled
817 ? tint_color(thumbColor, 1.22)
818 : tint_color(knobLight, B_DARKEN_1_TINT);
819
820 if (knobStyle == B_KNOB_DOTS) {
821 // draw dots on the scroll bar thumb
822 float hcenter = rect.left + rect.Width() / 2;
823 float vmiddle = rect.top + rect.Height() / 2;
824 BRect knob(hcenter, vmiddle, hcenter, vmiddle);
825
826 if (orientation == B_HORIZONTAL) {
827 view->SetHighColor(knobDark);
828 view->FillRect(knob);
829 view->SetHighColor(knobLight);
830 view->FillRect(knob.OffsetByCopy(1, 1));
831
832 float spacer = rect.Height();
833
834 if (rect.left + 3 < hcenter - spacer) {
835 view->SetHighColor(knobDark);
836 view->FillRect(knob.OffsetByCopy(-spacer, 0));
837 view->SetHighColor(knobLight);
838 view->FillRect(knob.OffsetByCopy(-spacer + 1, 1));
839 }
840
841 if (rect.right - 3 > hcenter + spacer) {
842 view->SetHighColor(knobDark);
843 view->FillRect(knob.OffsetByCopy(spacer, 0));
844 view->SetHighColor(knobLight);
845 view->FillRect(knob.OffsetByCopy(spacer + 1, 1));
846 }
847 } else {
848 // B_VERTICAL
849 view->SetHighColor(knobDark);
850 view->FillRect(knob);
851 view->SetHighColor(knobLight);
852 view->FillRect(knob.OffsetByCopy(1, 1));
853
854 float spacer = rect.Width();
855
856 if (rect.top + 3 < vmiddle - spacer) {
857 view->SetHighColor(knobDark);
858 view->FillRect(knob.OffsetByCopy(0, -spacer));
859 view->SetHighColor(knobLight);
860 view->FillRect(knob.OffsetByCopy(1, -spacer + 1));
861 }
862
863 if (rect.bottom - 3 > vmiddle + spacer) {
864 view->SetHighColor(knobDark);
865 view->FillRect(knob.OffsetByCopy(0, spacer));
866 view->SetHighColor(knobLight);
867 view->FillRect(knob.OffsetByCopy(1, spacer + 1));
868 }
869 }
870 } else if (knobStyle == B_KNOB_LINES) {
871 // draw lines on the scroll bar thumb
872 if (orientation == B_HORIZONTAL) {
873 float middle = rect.Width() / 2;
874
875 view->BeginLineArray(6);
876 view->AddLine(
877 BPoint(rect.left + middle - 3, rect.top + 2),
878 BPoint(rect.left + middle - 3, rect.bottom - 2),
879 knobDark);
880 view->AddLine(
881 BPoint(rect.left + middle, rect.top + 2),
882 BPoint(rect.left + middle, rect.bottom - 2),
883 knobDark);
884 view->AddLine(
885 BPoint(rect.left + middle + 3, rect.top + 2),
886 BPoint(rect.left + middle + 3, rect.bottom - 2),
887 knobDark);
888 view->AddLine(
889 BPoint(rect.left + middle - 2, rect.top + 2),
890 BPoint(rect.left + middle - 2, rect.bottom - 2),
891 knobLight);
892 view->AddLine(
893 BPoint(rect.left + middle + 1, rect.top + 2),
894 BPoint(rect.left + middle + 1, rect.bottom - 2),
895 knobLight);
896 view->AddLine(
897 BPoint(rect.left + middle + 4, rect.top + 2),
898 BPoint(rect.left + middle + 4, rect.bottom - 2),
899 knobLight);
900 view->EndLineArray();
901 } else {
902 // B_VERTICAL
903 float middle = rect.Height() / 2;
904
905 view->BeginLineArray(6);
906 view->AddLine(
907 BPoint(rect.left + 2, rect.top + middle - 3),
908 BPoint(rect.right - 2, rect.top + middle - 3),
909 knobDark);
910 view->AddLine(
911 BPoint(rect.left + 2, rect.top + middle),
912 BPoint(rect.right - 2, rect.top + middle),
913 knobDark);
914 view->AddLine(
915 BPoint(rect.left + 2, rect.top + middle + 3),
916 BPoint(rect.right - 2, rect.top + middle + 3),
917 knobDark);
918 view->AddLine(
919 BPoint(rect.left + 2, rect.top + middle - 2),
920 BPoint(rect.right - 2, rect.top + middle - 2),
921 knobLight);
922 view->AddLine(
923 BPoint(rect.left + 2, rect.top + middle + 1),
924 BPoint(rect.right - 2, rect.top + middle + 1),
925 knobLight);
926 view->AddLine(
927 BPoint(rect.left + 2, rect.top + middle + 4),
928 BPoint(rect.right - 2, rect.top + middle + 4),
929 knobLight);
930 view->EndLineArray();
931 }
932 }
933 }
934
935 view->PopState();
936 }
937
938
939 void
DrawScrollViewFrame(BView * view,BRect & rect,const BRect & updateRect,BRect verticalScrollBarFrame,BRect horizontalScrollBarFrame,const rgb_color & base,border_style borderStyle,uint32 flags,uint32 _borders)940 HaikuControlLook::DrawScrollViewFrame(BView* view, BRect& rect,
941 const BRect& updateRect, BRect verticalScrollBarFrame,
942 BRect horizontalScrollBarFrame, const rgb_color& base,
943 border_style borderStyle, uint32 flags, uint32 _borders)
944 {
945 // calculate scroll corner rect before messing with the "rect"
946 BRect scrollCornerFillRect(rect.right, rect.bottom,
947 rect.right, rect.bottom);
948
949 if (horizontalScrollBarFrame.IsValid())
950 scrollCornerFillRect.left = horizontalScrollBarFrame.right + 1;
951
952 if (verticalScrollBarFrame.IsValid())
953 scrollCornerFillRect.top = verticalScrollBarFrame.bottom + 1;
954
955 if (borderStyle == B_NO_BORDER) {
956 if (scrollCornerFillRect.IsValid()) {
957 view->SetHighColor(base);
958 view->FillRect(scrollCornerFillRect);
959 }
960 return;
961 }
962
963 bool excludeScrollCorner = borderStyle == B_FANCY_BORDER
964 && horizontalScrollBarFrame.IsValid()
965 && verticalScrollBarFrame.IsValid();
966
967 uint32 borders = _borders;
968 if (excludeScrollCorner) {
969 rect.bottom = horizontalScrollBarFrame.top;
970 rect.right = verticalScrollBarFrame.left;
971 borders &= ~(B_RIGHT_BORDER | B_BOTTOM_BORDER);
972 }
973
974 rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT);
975
976 if (borderStyle == B_FANCY_BORDER)
977 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
978
979 if ((flags & B_FOCUSED) != 0) {
980 rgb_color focusColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
981 _DrawFrame(view, rect, focusColor, focusColor, focusColor, focusColor,
982 borders);
983 } else {
984 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
985 scrollbarFrameColor, scrollbarFrameColor, borders);
986 }
987
988 if (excludeScrollCorner) {
989 horizontalScrollBarFrame.InsetBy(-1, -1);
990 // do not overdraw the top edge
991 horizontalScrollBarFrame.top += 2;
992 borders = _borders;
993 borders &= ~B_TOP_BORDER;
994 _DrawOuterResessedFrame(view, horizontalScrollBarFrame, base,
995 1.0, 1.0, flags, borders);
996 _DrawFrame(view, horizontalScrollBarFrame, scrollbarFrameColor,
997 scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
998 borders);
999
1000 verticalScrollBarFrame.InsetBy(-1, -1);
1001 // do not overdraw the left edge
1002 verticalScrollBarFrame.left += 2;
1003 borders = _borders;
1004 borders &= ~B_LEFT_BORDER;
1005 _DrawOuterResessedFrame(view, verticalScrollBarFrame, base,
1006 1.0, 1.0, flags, borders);
1007 _DrawFrame(view, verticalScrollBarFrame, scrollbarFrameColor,
1008 scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
1009 borders);
1010
1011 // exclude recessed frame
1012 scrollCornerFillRect.top++;
1013 scrollCornerFillRect.left++;
1014 }
1015
1016 if (scrollCornerFillRect.IsValid()) {
1017 view->SetHighColor(base);
1018 view->FillRect(scrollCornerFillRect);
1019 }
1020 }
1021
1022
1023 void
DrawArrowShape(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 direction,uint32 flags,float tint)1024 HaikuControlLook::DrawArrowShape(BView* view, BRect& rect,
1025 const BRect& updateRect, const rgb_color& base, uint32 direction,
1026 uint32 flags, float tint)
1027 {
1028 BPoint tri1, tri2, tri3;
1029 float hInset = rect.Width() / 3;
1030 float vInset = rect.Height() / 3;
1031 rect.InsetBy(hInset, vInset);
1032
1033 switch (direction) {
1034 case B_LEFT_ARROW:
1035 tri1.Set(rect.right, rect.top);
1036 tri2.Set(rect.right - rect.Width() / 1.33,
1037 (rect.top + rect.bottom + 1) / 2);
1038 tri3.Set(rect.right, rect.bottom + 1);
1039 break;
1040 case B_RIGHT_ARROW:
1041 tri1.Set(rect.left + 1, rect.bottom + 1);
1042 tri2.Set(rect.left + 1 + rect.Width() / 1.33,
1043 (rect.top + rect.bottom + 1) / 2);
1044 tri3.Set(rect.left + 1, rect.top);
1045 break;
1046 case B_UP_ARROW:
1047 tri1.Set(rect.left, rect.bottom);
1048 tri2.Set((rect.left + rect.right + 1) / 2,
1049 rect.bottom - rect.Height() / 1.33);
1050 tri3.Set(rect.right + 1, rect.bottom);
1051 break;
1052 case B_DOWN_ARROW:
1053 default:
1054 tri1.Set(rect.left, rect.top + 1);
1055 tri2.Set((rect.left + rect.right + 1) / 2,
1056 rect.top + 1 + rect.Height() / 1.33);
1057 tri3.Set(rect.right + 1, rect.top + 1);
1058 break;
1059 case B_LEFT_UP_ARROW:
1060 tri1.Set(rect.left, rect.bottom);
1061 tri2.Set(rect.left, rect.top);
1062 tri3.Set(rect.right - 1, rect.top);
1063 break;
1064 case B_RIGHT_UP_ARROW:
1065 tri1.Set(rect.left + 1, rect.top);
1066 tri2.Set(rect.right, rect.top);
1067 tri3.Set(rect.right, rect.bottom);
1068 break;
1069 case B_RIGHT_DOWN_ARROW:
1070 tri1.Set(rect.right, rect.top);
1071 tri2.Set(rect.right, rect.bottom);
1072 tri3.Set(rect.left + 1, rect.bottom);
1073 break;
1074 case B_LEFT_DOWN_ARROW:
1075 tri1.Set(rect.right - 1, rect.bottom);
1076 tri2.Set(rect.left, rect.bottom);
1077 tri3.Set(rect.left, rect.top);
1078 break;
1079 }
1080
1081 BShape arrowShape;
1082 arrowShape.MoveTo(tri1);
1083 arrowShape.LineTo(tri2);
1084 arrowShape.LineTo(tri3);
1085
1086 if ((flags & B_DISABLED) != 0)
1087 tint = (tint + B_NO_TINT + B_NO_TINT) / 3;
1088
1089 view->SetHighColor(tint_color(base, tint));
1090
1091 float penSize = view->PenSize();
1092 drawing_mode mode = view->DrawingMode();
1093
1094 view->MovePenTo(BPoint(0, 0));
1095
1096 view->SetPenSize(ceilf(hInset / 2.0));
1097 view->SetDrawingMode(B_OP_OVER);
1098 view->StrokeShape(&arrowShape);
1099
1100 view->SetPenSize(penSize);
1101 view->SetDrawingMode(mode);
1102 }
1103
1104
1105 rgb_color
SliderBarColor(const rgb_color & base)1106 HaikuControlLook::SliderBarColor(const rgb_color& base)
1107 {
1108 return tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_1_TINT);
1109 }
1110
1111
1112 void
DrawSliderBar(BView * view,BRect rect,const BRect & updateRect,const rgb_color & base,rgb_color leftFillColor,rgb_color rightFillColor,float sliderScale,uint32 flags,orientation orientation)1113 HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
1114 const rgb_color& base, rgb_color leftFillColor, rgb_color rightFillColor,
1115 float sliderScale, uint32 flags, orientation orientation)
1116 {
1117 if (!ShouldDraw(view, rect, updateRect))
1118 return;
1119
1120 // separate the bar in two sides
1121 float sliderPosition;
1122 BRect leftBarSide = rect;
1123 BRect rightBarSide = rect;
1124
1125 if (orientation == B_HORIZONTAL) {
1126 sliderPosition = floorf(rect.left + 2 + (rect.Width() - 2)
1127 * sliderScale);
1128 leftBarSide.right = sliderPosition - 1;
1129 rightBarSide.left = sliderPosition;
1130 } else {
1131 // NOTE: position is reverse of coords
1132 sliderPosition = floorf(rect.top + 2 + (rect.Height() - 2)
1133 * (1.0 - sliderScale));
1134 leftBarSide.top = sliderPosition;
1135 rightBarSide.bottom = sliderPosition - 1;
1136 }
1137
1138 view->PushState();
1139 view->ClipToRect(leftBarSide);
1140 DrawSliderBar(view, rect, updateRect, base, leftFillColor, flags,
1141 orientation);
1142 view->PopState();
1143
1144 view->PushState();
1145 view->ClipToRect(rightBarSide);
1146 DrawSliderBar(view, rect, updateRect, base, rightFillColor, flags,
1147 orientation);
1148 view->PopState();
1149 }
1150
1151
1152 void
DrawSliderBar(BView * view,BRect rect,const BRect & updateRect,const rgb_color & base,rgb_color fillColor,uint32 flags,orientation orientation)1153 HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
1154 const rgb_color& base, rgb_color fillColor, uint32 flags,
1155 orientation orientation)
1156 {
1157 if (!ShouldDraw(view, rect, updateRect))
1158 return;
1159
1160 // separate the rect into corners
1161 BRect leftCorner(rect);
1162 BRect rightCorner(rect);
1163 BRect barRect(rect);
1164
1165 if (orientation == B_HORIZONTAL) {
1166 leftCorner.right = leftCorner.left + leftCorner.Height();
1167 rightCorner.left = rightCorner.right - rightCorner.Height();
1168 barRect.left += ceilf(barRect.Height() / 2);
1169 barRect.right -= ceilf(barRect.Height() / 2);
1170 } else {
1171 leftCorner.bottom = leftCorner.top + leftCorner.Width();
1172 rightCorner.top = rightCorner.bottom - rightCorner.Width();
1173 barRect.top += ceilf(barRect.Width() / 2);
1174 barRect.bottom -= ceilf(barRect.Width() / 2);
1175 }
1176
1177 // fill the background for the corners, exclude the middle bar for now
1178 view->PushState();
1179 view->ClipToRect(rect);
1180 view->ClipToInverseRect(barRect);
1181
1182 if ((flags & B_BLEND_FRAME) == 0) {
1183 view->SetHighColor(base);
1184 view->FillRect(rect);
1185 }
1186
1187 // figure out the tints to be used
1188 float edgeLightTint;
1189 float edgeShadowTint;
1190 float frameLightTint;
1191 float frameShadowTint;
1192 float fillLightTint;
1193 float fillShadowTint;
1194 uint8 edgeLightAlpha;
1195 uint8 edgeShadowAlpha;
1196 uint8 frameLightAlpha;
1197 uint8 frameShadowAlpha;
1198
1199 if ((flags & B_DISABLED) != 0) {
1200 edgeLightTint = 1.0;
1201 edgeShadowTint = 1.0;
1202 frameLightTint = 1.20;
1203 frameShadowTint = 1.25;
1204 fillLightTint = 0.9;
1205 fillShadowTint = 1.05;
1206 edgeLightAlpha = 12;
1207 edgeShadowAlpha = 12;
1208 frameLightAlpha = 40;
1209 frameShadowAlpha = 45;
1210
1211 fillColor.red = uint8(fillColor.red * 0.4 + base.red * 0.6);
1212 fillColor.green = uint8(fillColor.green * 0.4 + base.green * 0.6);
1213 fillColor.blue = uint8(fillColor.blue * 0.4 + base.blue * 0.6);
1214 } else {
1215 edgeLightTint = 0.65;
1216 edgeShadowTint = 1.07;
1217 frameLightTint = 1.40;
1218 frameShadowTint = 1.50;
1219 fillLightTint = 0.8;
1220 fillShadowTint = 1.1;
1221 edgeLightAlpha = 15;
1222 edgeShadowAlpha = 15;
1223 frameLightAlpha = 92;
1224 frameShadowAlpha = 107;
1225 }
1226
1227 rgb_color edgeLightColor;
1228 rgb_color edgeShadowColor;
1229 rgb_color frameLightColor;
1230 rgb_color frameShadowColor;
1231 rgb_color fillLightColor = tint_color(fillColor, fillLightTint);
1232 rgb_color fillShadowColor = tint_color(fillColor, fillShadowTint);
1233
1234 drawing_mode oldMode = view->DrawingMode();
1235
1236 if ((flags & B_BLEND_FRAME) != 0) {
1237 edgeLightColor = (rgb_color){ 255, 255, 255, edgeLightAlpha };
1238 edgeShadowColor = (rgb_color){ 0, 0, 0, edgeShadowAlpha };
1239 frameLightColor = (rgb_color){ 0, 0, 0, frameLightAlpha };
1240 frameShadowColor = (rgb_color){ 0, 0, 0, frameShadowAlpha };
1241
1242 view->SetDrawingMode(B_OP_ALPHA);
1243 } else {
1244 edgeLightColor = tint_color(base, edgeLightTint);
1245 edgeShadowColor = tint_color(base, edgeShadowTint);
1246 frameLightColor = tint_color(fillColor, frameLightTint);
1247 frameShadowColor = tint_color(fillColor, frameShadowTint);
1248 }
1249
1250 if (orientation == B_HORIZONTAL) {
1251 _DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
1252 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
1253 fillShadowColor, 1.0, 1.0, 0.0, -1.0, orientation);
1254
1255 _DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
1256 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
1257 fillShadowColor, 0.0, 1.0, -1.0, -1.0, orientation);
1258 } else {
1259 _DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
1260 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
1261 fillShadowColor, 1.0, 1.0, -1.0, 0.0, orientation);
1262
1263 _DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
1264 edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
1265 fillShadowColor, 1.0, 0.0, -1.0, -1.0, orientation);
1266 }
1267
1268 view->PopState();
1269 if ((flags & B_BLEND_FRAME) != 0)
1270 view->SetDrawingMode(B_OP_ALPHA);
1271
1272 view->BeginLineArray(4);
1273 if (orientation == B_HORIZONTAL) {
1274 view->AddLine(barRect.LeftTop(), barRect.RightTop(),
1275 edgeShadowColor);
1276 view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
1277 edgeLightColor);
1278 barRect.InsetBy(0, 1);
1279 view->AddLine(barRect.LeftTop(), barRect.RightTop(),
1280 frameShadowColor);
1281 view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
1282 frameLightColor);
1283 barRect.InsetBy(0, 1);
1284 } else {
1285 view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
1286 edgeShadowColor);
1287 view->AddLine(barRect.RightTop(), barRect.RightBottom(),
1288 edgeLightColor);
1289 barRect.InsetBy(1, 0);
1290 view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
1291 frameShadowColor);
1292 view->AddLine(barRect.RightTop(), barRect.RightBottom(),
1293 frameLightColor);
1294 barRect.InsetBy(1, 0);
1295 }
1296 view->EndLineArray();
1297
1298 view->SetDrawingMode(oldMode);
1299
1300 _FillGradient(view, barRect, fillColor, fillShadowTint, fillLightTint,
1301 orientation);
1302 }
1303
1304
1305 void
DrawSliderThumb(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation)1306 HaikuControlLook::DrawSliderThumb(BView* view, BRect& rect, const BRect& updateRect,
1307 const rgb_color& base, uint32 flags, orientation orientation)
1308 {
1309 if (!ShouldDraw(view, rect, updateRect))
1310 return;
1311
1312 // figure out frame color
1313 rgb_color frameLightColor;
1314 rgb_color frameShadowColor;
1315 rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
1316
1317 if ((flags & B_FOCUSED) != 0) {
1318 // focused
1319 frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1320 frameShadowColor = frameLightColor;
1321 } else {
1322 // figure out the tints to be used
1323 float frameLightTint;
1324 float frameShadowTint;
1325
1326 if ((flags & B_DISABLED) != 0) {
1327 frameLightTint = 1.30;
1328 frameShadowTint = 1.35;
1329 shadowColor.alpha = 30;
1330 } else {
1331 frameLightTint = 1.6;
1332 frameShadowTint = 1.65;
1333 }
1334
1335 frameLightColor = tint_color(base, frameLightTint);
1336 frameShadowColor = tint_color(base, frameShadowTint);
1337 }
1338
1339 BRect originalRect(rect);
1340 rect.right--;
1341 rect.bottom--;
1342
1343 _DrawFrame(view, rect, frameLightColor, frameLightColor,
1344 frameShadowColor, frameShadowColor);
1345
1346 flags &= ~B_ACTIVATED;
1347 DrawButtonBackground(view, rect, updateRect, base, flags);
1348
1349 // thumb shadow
1350 view->SetDrawingMode(B_OP_ALPHA);
1351 view->SetHighColor(shadowColor);
1352 originalRect.left++;
1353 originalRect.top++;
1354 view->StrokeLine(originalRect.LeftBottom(), originalRect.RightBottom());
1355 originalRect.bottom--;
1356 view->StrokeLine(originalRect.RightTop(), originalRect.RightBottom());
1357
1358 // thumb edge
1359 if (orientation == B_HORIZONTAL) {
1360 rect.InsetBy(0, floorf(rect.Height() / 4));
1361 rect.left = floorf((rect.left + rect.right) / 2);
1362 rect.right = rect.left + 1;
1363 shadowColor = tint_color(base, B_DARKEN_2_TINT);
1364 shadowColor.alpha = 128;
1365 view->SetHighColor(shadowColor);
1366 view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
1367 rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT);
1368 lightColor.alpha = 128;
1369 view->SetHighColor(lightColor);
1370 view->StrokeLine(rect.RightTop(), rect.RightBottom());
1371 } else {
1372 rect.InsetBy(floorf(rect.Width() / 4), 0);
1373 rect.top = floorf((rect.top + rect.bottom) / 2);
1374 rect.bottom = rect.top + 1;
1375 shadowColor = tint_color(base, B_DARKEN_2_TINT);
1376 shadowColor.alpha = 128;
1377 view->SetHighColor(shadowColor);
1378 view->StrokeLine(rect.LeftTop(), rect.RightTop());
1379 rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT);
1380 lightColor.alpha = 128;
1381 view->SetHighColor(lightColor);
1382 view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
1383 }
1384
1385 view->SetDrawingMode(B_OP_COPY);
1386 }
1387
1388
1389 void
DrawSliderTriangle(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,orientation orientation)1390 HaikuControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1391 const BRect& updateRect, const rgb_color& base, uint32 flags,
1392 orientation orientation)
1393 {
1394 DrawSliderTriangle(view, rect, updateRect, base, base, flags, orientation);
1395 }
1396
1397
1398 void
DrawSliderTriangle(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,const rgb_color & fill,uint32 flags,orientation orientation)1399 HaikuControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1400 const BRect& updateRect, const rgb_color& base, const rgb_color& fill,
1401 uint32 flags, orientation orientation)
1402 {
1403 if (!ShouldDraw(view, rect, updateRect))
1404 return;
1405
1406 // figure out frame color
1407 rgb_color frameLightColor;
1408 rgb_color frameShadowColor;
1409 rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
1410
1411 float topTint = 0.49;
1412 float middleTint1 = 0.62;
1413 float middleTint2 = 0.76;
1414 float bottomTint = 0.90;
1415
1416 if ((flags & B_DISABLED) != 0) {
1417 topTint = (topTint + B_NO_TINT) / 2;
1418 middleTint1 = (middleTint1 + B_NO_TINT) / 2;
1419 middleTint2 = (middleTint2 + B_NO_TINT) / 2;
1420 bottomTint = (bottomTint + B_NO_TINT) / 2;
1421 } else if ((flags & B_HOVER) != 0) {
1422 topTint *= kHoverTintFactor;
1423 middleTint1 *= kHoverTintFactor;
1424 middleTint2 *= kHoverTintFactor;
1425 bottomTint *= kHoverTintFactor;
1426 }
1427
1428 if ((flags & B_FOCUSED) != 0) {
1429 // focused
1430 frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1431 frameShadowColor = frameLightColor;
1432 } else {
1433 // figure out the tints to be used
1434 float frameLightTint;
1435 float frameShadowTint;
1436
1437 if ((flags & B_DISABLED) != 0) {
1438 frameLightTint = 1.30;
1439 frameShadowTint = 1.35;
1440 shadowColor.alpha = 30;
1441 } else {
1442 frameLightTint = 1.6;
1443 frameShadowTint = 1.65;
1444 }
1445
1446 frameLightColor = tint_color(base, frameLightTint);
1447 frameShadowColor = tint_color(base, frameShadowTint);
1448 }
1449
1450 // make room for the shadow
1451 rect.right--;
1452 rect.bottom--;
1453
1454 uint32 viewFlags = view->Flags();
1455 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
1456 view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN);
1457
1458 float centerh = (rect.left + rect.right) / 2;
1459 float centerv = (rect.top + rect.bottom) / 2;
1460
1461 BShape shape;
1462 if (orientation == B_HORIZONTAL) {
1463 shape.MoveTo(BPoint(rect.left + 0.5, rect.bottom + 0.5));
1464 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom + 0.5));
1465 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom - 1 + 0.5));
1466 shape.LineTo(BPoint(centerh + 0.5, rect.top + 0.5));
1467 shape.LineTo(BPoint(rect.left + 0.5, rect.bottom - 1 + 0.5));
1468 } else {
1469 shape.MoveTo(BPoint(rect.right + 0.5, rect.top + 0.5));
1470 shape.LineTo(BPoint(rect.right + 0.5, rect.bottom + 0.5));
1471 shape.LineTo(BPoint(rect.right - 1 + 0.5, rect.bottom + 0.5));
1472 shape.LineTo(BPoint(rect.left + 0.5, centerv + 0.5));
1473 shape.LineTo(BPoint(rect.right - 1 + 0.5, rect.top + 0.5));
1474 }
1475 shape.Close();
1476
1477 view->MovePenTo(BPoint(1, 1));
1478
1479 view->SetDrawingMode(B_OP_ALPHA);
1480 view->SetHighColor(shadowColor);
1481 view->StrokeShape(&shape);
1482
1483 view->MovePenTo(B_ORIGIN);
1484
1485 view->SetDrawingMode(B_OP_COPY);
1486 view->SetHighColor(frameLightColor);
1487 view->StrokeShape(&shape);
1488
1489 rect.InsetBy(1, 1);
1490 shape.Clear();
1491 if (orientation == B_HORIZONTAL) {
1492 shape.MoveTo(BPoint(rect.left, rect.bottom + 1));
1493 shape.LineTo(BPoint(rect.right + 1, rect.bottom + 1));
1494 shape.LineTo(BPoint(centerh + 0.5, rect.top));
1495 } else {
1496 shape.MoveTo(BPoint(rect.right + 1, rect.top));
1497 shape.LineTo(BPoint(rect.right + 1, rect.bottom + 1));
1498 shape.LineTo(BPoint(rect.left, centerv + 0.5));
1499 }
1500 shape.Close();
1501
1502 BGradientLinear gradient;
1503 if ((flags & B_DISABLED) != 0) {
1504 _MakeGradient(gradient, rect, fill, topTint, bottomTint);
1505 } else {
1506 _MakeGlossyGradient(gradient, rect, fill, topTint, middleTint1,
1507 middleTint2, bottomTint);
1508 }
1509
1510 view->FillShape(&shape, gradient);
1511
1512 view->SetFlags(viewFlags);
1513 }
1514
1515
1516 void
DrawSliderHashMarks(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,int32 count,hash_mark_location location,uint32 flags,orientation orientation)1517 HaikuControlLook::DrawSliderHashMarks(BView* view, BRect& rect,
1518 const BRect& updateRect, const rgb_color& base, int32 count,
1519 hash_mark_location location, uint32 flags, orientation orientation)
1520 {
1521 if (!ShouldDraw(view, rect, updateRect))
1522 return;
1523
1524 rgb_color lightColor;
1525 rgb_color darkColor;
1526
1527 if ((flags & B_DISABLED) != 0) {
1528 lightColor = tint_color(base, 0.9);
1529 darkColor = tint_color(base, 1.07);
1530 } else {
1531 lightColor = tint_color(base, 0.8);
1532 darkColor = tint_color(base, 1.14);
1533 }
1534
1535 int32 hashMarkCount = std::max(count, (int32)2);
1536 // draw at least two hashmarks at min/max if
1537 // fHashMarks != B_HASH_MARKS_NONE
1538 float factor;
1539 float startPos;
1540 if (orientation == B_HORIZONTAL) {
1541 factor = (rect.Width() - 2) / (hashMarkCount - 1);
1542 startPos = rect.left + 1;
1543 } else {
1544 factor = (rect.Height() - 2) / (hashMarkCount - 1);
1545 startPos = rect.top + 1;
1546 }
1547
1548 if (location & B_HASH_MARKS_TOP) {
1549 view->BeginLineArray(hashMarkCount * 2);
1550
1551 if (orientation == B_HORIZONTAL) {
1552 float pos = startPos;
1553 for (int32 i = 0; i < hashMarkCount; i++) {
1554 view->AddLine(BPoint(pos, rect.top),
1555 BPoint(pos, rect.top + 4), darkColor);
1556 view->AddLine(BPoint(pos + 1, rect.top),
1557 BPoint(pos + 1, rect.top + 4), lightColor);
1558
1559 pos += factor;
1560 }
1561 } else {
1562 float pos = startPos;
1563 for (int32 i = 0; i < hashMarkCount; i++) {
1564 view->AddLine(BPoint(rect.left, pos),
1565 BPoint(rect.left + 4, pos), darkColor);
1566 view->AddLine(BPoint(rect.left, pos + 1),
1567 BPoint(rect.left + 4, pos + 1), lightColor);
1568
1569 pos += factor;
1570 }
1571 }
1572
1573 view->EndLineArray();
1574 }
1575
1576 if ((location & B_HASH_MARKS_BOTTOM) != 0) {
1577 view->BeginLineArray(hashMarkCount * 2);
1578
1579 if (orientation == B_HORIZONTAL) {
1580 float pos = startPos;
1581 for (int32 i = 0; i < hashMarkCount; i++) {
1582 view->AddLine(BPoint(pos, rect.bottom - 4),
1583 BPoint(pos, rect.bottom), darkColor);
1584 view->AddLine(BPoint(pos + 1, rect.bottom - 4),
1585 BPoint(pos + 1, rect.bottom), lightColor);
1586
1587 pos += factor;
1588 }
1589 } else {
1590 float pos = startPos;
1591 for (int32 i = 0; i < hashMarkCount; i++) {
1592 view->AddLine(BPoint(rect.right - 4, pos),
1593 BPoint(rect.right, pos), darkColor);
1594 view->AddLine(BPoint(rect.right - 4, pos + 1),
1595 BPoint(rect.right, pos + 1), lightColor);
1596
1597 pos += factor;
1598 }
1599 }
1600
1601 view->EndLineArray();
1602 }
1603 }
1604
1605
1606 void
DrawTabFrame(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders,border_style borderStyle,uint32 side)1607 HaikuControlLook::DrawTabFrame(BView* view, BRect& rect,
1608 const BRect& updateRect, const rgb_color& base, uint32 flags,
1609 uint32 borders, border_style borderStyle, uint32 side)
1610 {
1611 if (!ShouldDraw(view, rect, updateRect))
1612 return;
1613
1614 if (side == BTabView::kTopSide || side == BTabView::kBottomSide) {
1615 // draw an inactive tab frame behind all tabs
1616 borders = B_TOP_BORDER | B_BOTTOM_BORDER;
1617 if (borderStyle != B_NO_BORDER)
1618 borders |= B_LEFT_BORDER | B_RIGHT_BORDER;
1619
1620 // DrawInactiveTab draws 2px border
1621 // draw tab frame wider to align B_PLAIN_BORDER with it
1622 if (borderStyle == B_PLAIN_BORDER)
1623 rect.InsetBy(-1, 0);
1624 } else if (side == BTabView::kLeftSide || side == BTabView::kRightSide) {
1625 // draw an inactive tab frame behind all tabs
1626 borders = B_LEFT_BORDER | B_RIGHT_BORDER;
1627 if (borderStyle != B_NO_BORDER)
1628 borders |= B_TOP_BORDER | B_BOTTOM_BORDER;
1629
1630 // DrawInactiveTab draws 2px border
1631 // draw tab frame wider to align B_PLAIN_BORDER with it
1632 if (borderStyle == B_PLAIN_BORDER)
1633 rect.InsetBy(0, -1);
1634 }
1635
1636 DrawInactiveTab(view, rect, rect, base, 0, borders, side);
1637 }
1638
1639
1640 void
DrawActiveTab(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders,uint32 side,int32,int32,int32,int32)1641 HaikuControlLook::DrawActiveTab(BView* view, BRect& rect,
1642 const BRect& updateRect, const rgb_color& base, uint32 flags,
1643 uint32 borders, uint32 side, int32, int32, int32, int32)
1644 {
1645 if (!ShouldDraw(view, rect, updateRect))
1646 return;
1647
1648 // Snap the rectangle to pixels to avoid rounding errors.
1649 rect.left = floorf(rect.left);
1650 rect.right = floorf(rect.right);
1651 rect.top = floorf(rect.top);
1652 rect.bottom = floorf(rect.bottom);
1653
1654 // save the clipping constraints of the view
1655 view->PushState();
1656
1657 // set clipping constraints to rect
1658 view->ClipToRect(rect);
1659
1660 rgb_color edgeShadowColor;
1661 rgb_color edgeLightColor;
1662 rgb_color frameShadowColor;
1663 rgb_color frameLightColor;
1664 rgb_color bevelShadowColor;
1665 rgb_color bevelLightColor;
1666 BGradientLinear fillGradient;
1667 fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3));
1668 fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3));
1669
1670 if ((flags & B_DISABLED) != 0) {
1671 edgeLightColor = base;
1672 edgeShadowColor = base;
1673 frameLightColor = tint_color(base, 1.25);
1674 frameShadowColor = tint_color(base, 1.30);
1675 bevelLightColor = tint_color(base, 0.8);
1676 bevelShadowColor = tint_color(base, 1.07);
1677 fillGradient.AddColor(tint_color(base, 0.85), 0);
1678 fillGradient.AddColor(base, 255);
1679 } else {
1680 edgeLightColor = tint_color(base, 0.80);
1681 edgeShadowColor = tint_color(base, 1.03);
1682 frameLightColor = tint_color(base, 1.30);
1683 frameShadowColor = tint_color(base, 1.30);
1684 bevelLightColor = tint_color(base, 0.6);
1685 bevelShadowColor = tint_color(base, 1.07);
1686 fillGradient.AddColor(tint_color(base, 0.75), 0);
1687 fillGradient.AddColor(tint_color(base, 1.03), 255);
1688 }
1689
1690 static const float kRoundCornerRadius = 4.0f;
1691
1692 // left top corner dimensions
1693 BRect leftTopCorner(rect);
1694 leftTopCorner.right = floorf(leftTopCorner.left + kRoundCornerRadius);
1695 leftTopCorner.bottom = floorf(rect.top + kRoundCornerRadius);
1696
1697 // right top corner dimensions
1698 BRect rightTopCorner(rect);
1699 rightTopCorner.left = floorf(rightTopCorner.right - kRoundCornerRadius);
1700 rightTopCorner.bottom = floorf(rect.top + kRoundCornerRadius);
1701
1702 // left bottom corner dimensions
1703 BRect leftBottomCorner(rect);
1704 leftBottomCorner.right = floorf(leftBottomCorner.left + kRoundCornerRadius);
1705 leftBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius);
1706
1707 // right bottom corner dimensions
1708 BRect rightBottomCorner(rect);
1709 rightBottomCorner.left = floorf(rightBottomCorner.right
1710 - kRoundCornerRadius);
1711 rightBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius);
1712
1713 BRect roundCorner[2];
1714
1715 switch (side) {
1716 case B_TOP_BORDER:
1717 roundCorner[0] = leftTopCorner;
1718 roundCorner[1] = rightTopCorner;
1719
1720 // draw the left top corner
1721 _DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base,
1722 edgeShadowColor, frameLightColor, bevelLightColor,
1723 fillGradient);
1724 // draw the right top corner
1725 _DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base,
1726 edgeShadowColor, edgeLightColor, frameLightColor,
1727 frameShadowColor, bevelLightColor, bevelShadowColor,
1728 fillGradient);
1729 break;
1730 case B_BOTTOM_BORDER:
1731 roundCorner[0] = leftBottomCorner;
1732 roundCorner[1] = rightBottomCorner;
1733
1734 // draw the left bottom corner
1735 _DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base,
1736 edgeShadowColor, edgeLightColor, frameLightColor,
1737 frameShadowColor, bevelLightColor, bevelShadowColor,
1738 fillGradient);
1739 // draw the right bottom corner
1740 _DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect,
1741 base, edgeLightColor, frameShadowColor, bevelShadowColor,
1742 fillGradient);
1743 break;
1744 case B_LEFT_BORDER:
1745 roundCorner[0] = leftTopCorner;
1746 roundCorner[1] = leftBottomCorner;
1747
1748 // draw the left top corner
1749 _DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base,
1750 edgeShadowColor, frameLightColor, bevelLightColor,
1751 fillGradient);
1752 // draw the left bottom corner
1753 _DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base,
1754 edgeShadowColor, edgeLightColor, frameLightColor,
1755 frameShadowColor, bevelLightColor, bevelShadowColor,
1756 fillGradient);
1757 break;
1758 case B_RIGHT_BORDER:
1759 roundCorner[0] = rightTopCorner;
1760 roundCorner[1] = rightBottomCorner;
1761
1762 // draw the right top corner
1763 _DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base,
1764 edgeShadowColor, edgeLightColor, frameLightColor,
1765 frameShadowColor, bevelLightColor, bevelShadowColor,
1766 fillGradient);
1767 // draw the right bottom corner
1768 _DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect,
1769 base, edgeLightColor, frameShadowColor, bevelShadowColor,
1770 fillGradient);
1771 break;
1772 }
1773
1774 // clip out the corners
1775 view->ClipToInverseRect(roundCorner[0]);
1776 view->ClipToInverseRect(roundCorner[1]);
1777
1778 uint32 bordersToDraw = 0;
1779 switch (side) {
1780 case B_TOP_BORDER:
1781 bordersToDraw = (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER);
1782 break;
1783 case B_BOTTOM_BORDER:
1784 bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER);
1785 break;
1786 case B_LEFT_BORDER:
1787 bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER);
1788 break;
1789 case B_RIGHT_BORDER:
1790 bordersToDraw = (B_RIGHT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER);
1791 break;
1792 }
1793
1794 // draw the rest of frame and fill
1795 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
1796 edgeLightColor, borders);
1797 if (side == B_TOP_BORDER || side == B_BOTTOM_BORDER) {
1798 if ((borders & B_LEFT_BORDER) == 0)
1799 rect.left++;
1800 if ((borders & B_RIGHT_BORDER) == 0)
1801 rect.right--;
1802 } else if (side == B_LEFT_BORDER || side == B_RIGHT_BORDER) {
1803 if ((borders & B_TOP_BORDER) == 0)
1804 rect.top++;
1805 if ((borders & B_BOTTOM_BORDER) == 0)
1806 rect.bottom--;
1807 }
1808
1809 _DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
1810 frameShadowColor, bordersToDraw);
1811
1812 _DrawFrame(view, rect, bevelLightColor, bevelLightColor, bevelShadowColor,
1813 bevelShadowColor);
1814
1815 view->FillRect(rect, fillGradient);
1816
1817 // restore the clipping constraints of the view
1818 view->PopState();
1819 }
1820
1821
1822 void
DrawInactiveTab(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders,uint32 side,int32,int32,int32,int32)1823 HaikuControlLook::DrawInactiveTab(BView* view, BRect& rect,
1824 const BRect& updateRect, const rgb_color& base, uint32 flags,
1825 uint32 borders, uint32 side, int32, int32, int32, int32)
1826 {
1827 if (!ShouldDraw(view, rect, updateRect))
1828 return;
1829
1830 rgb_color edgeShadowColor;
1831 rgb_color edgeLightColor;
1832 rgb_color frameShadowColor;
1833 rgb_color frameLightColor;
1834 rgb_color bevelShadowColor;
1835 rgb_color bevelLightColor;
1836 BGradientLinear fillGradient;
1837 fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3));
1838 fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3));
1839
1840 if ((flags & B_DISABLED) != 0) {
1841 edgeLightColor = base;
1842 edgeShadowColor = base;
1843 frameLightColor = tint_color(base, 1.25);
1844 frameShadowColor = tint_color(base, 1.30);
1845 bevelLightColor = tint_color(base, 0.8);
1846 bevelShadowColor = tint_color(base, 1.07);
1847 fillGradient.AddColor(tint_color(base, 0.85), 0);
1848 fillGradient.AddColor(base, 255);
1849 } else {
1850 edgeLightColor = tint_color(base, 0.80);
1851 edgeShadowColor = tint_color(base, 1.03);
1852 frameLightColor = tint_color(base, 1.30);
1853 frameShadowColor = tint_color(base, 1.30);
1854 bevelLightColor = tint_color(base, 1.10);
1855 bevelShadowColor = tint_color(base, 1.17);
1856 fillGradient.AddColor(tint_color(base, 1.12), 0);
1857 fillGradient.AddColor(tint_color(base, 1.08), 255);
1858 }
1859
1860 BRect background = rect;
1861 bool isVertical;
1862 switch (side) {
1863 default:
1864 case BTabView::kTopSide:
1865 rect.top += 4;
1866 background.bottom = rect.top;
1867 isVertical = false;
1868 break;
1869
1870 case BTabView::kBottomSide:
1871 rect.bottom -= 4;
1872 background.top = rect.bottom;
1873 isVertical = false;
1874 break;
1875
1876 case BTabView::kLeftSide:
1877 rect.left += 4;
1878 background.right = rect.left;
1879 isVertical = true;
1880 break;
1881
1882 case BTabView::kRightSide:
1883 rect.right -= 4;
1884 background.left = rect.right;
1885 isVertical = true;
1886 break;
1887 }
1888
1889 // active tabs stand out at the top, but this is an inactive tab
1890 view->SetHighColor(base);
1891 view->FillRect(background);
1892
1893 // frame and fill
1894 // Note that _DrawFrame also insets the rect, so each of the calls here
1895 // operate on a smaller rect than the previous ones
1896 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
1897 edgeLightColor, borders);
1898
1899 _DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
1900 frameShadowColor, borders);
1901
1902 if (rect.IsValid()) {
1903 if (isVertical) {
1904 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor,
1905 bevelLightColor, bevelLightColor, B_TOP_BORDER & ~borders);
1906 } else {
1907 _DrawFrame(view, rect, bevelShadowColor, bevelShadowColor,
1908 bevelLightColor, bevelLightColor, B_LEFT_BORDER & ~borders);
1909 }
1910 } else {
1911 if (isVertical) {
1912 if ((B_LEFT_BORDER & ~borders) != 0)
1913 rect.left++;
1914 } else {
1915 if ((B_TOP_BORDER & ~borders) != 0)
1916 rect.top++;
1917 }
1918 }
1919
1920 view->FillRect(rect, fillGradient);
1921 }
1922
1923
1924 void
DrawSplitter(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,orientation orientation,uint32 flags,uint32 borders)1925 HaikuControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect,
1926 const rgb_color& base, orientation orientation, uint32 flags,
1927 uint32 borders)
1928 {
1929 if (!ShouldDraw(view, rect, updateRect))
1930 return;
1931
1932 rgb_color background;
1933 if ((flags & (B_CLICKED | B_ACTIVATED)) != 0)
1934 background = tint_color(base, B_DARKEN_1_TINT);
1935 else
1936 background = base;
1937
1938 rgb_color light = tint_color(background, 0.6);
1939 rgb_color shadow = tint_color(background, 1.21);
1940
1941 // frame
1942 if (borders != 0 && rect.Width() > 3 && rect.Height() > 3)
1943 DrawRaisedBorder(view, rect, updateRect, background, flags, borders);
1944
1945 // dots and rest of background
1946 if (orientation == B_HORIZONTAL) {
1947 if (rect.Width() > 2) {
1948 // background on left/right
1949 BRegion region(rect);
1950 rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5);
1951 rect.right = rect.left + 1;
1952 region.Exclude(rect);
1953 view->SetHighColor(background);
1954 view->FillRegion(®ion);
1955 }
1956
1957 BPoint dot = rect.LeftTop();
1958 BPoint stop = rect.LeftBottom();
1959 int32 num = 1;
1960 while (dot.y <= stop.y) {
1961 rgb_color col1;
1962 rgb_color col2;
1963 switch (num) {
1964 case 1:
1965 col1 = background;
1966 col2 = background;
1967 break;
1968 case 2:
1969 col1 = shadow;
1970 col2 = background;
1971 break;
1972 case 3:
1973 default:
1974 col1 = background;
1975 col2 = light;
1976 num = 0;
1977 break;
1978 }
1979 view->SetHighColor(col1);
1980 view->StrokeLine(dot, dot, B_SOLID_HIGH);
1981 view->SetHighColor(col2);
1982 dot.x++;
1983 view->StrokeLine(dot, dot, B_SOLID_HIGH);
1984 dot.x -= 1.0;
1985 // next pixel
1986 num++;
1987 dot.y++;
1988 }
1989 } else {
1990 if (rect.Height() > 2) {
1991 // background on left/right
1992 BRegion region(rect);
1993 rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5);
1994 rect.bottom = rect.top + 1;
1995 region.Exclude(rect);
1996 view->SetHighColor(background);
1997 view->FillRegion(®ion);
1998 }
1999
2000 BPoint dot = rect.LeftTop();
2001 BPoint stop = rect.RightTop();
2002 int32 num = 1;
2003 while (dot.x <= stop.x) {
2004 rgb_color col1;
2005 rgb_color col2;
2006 switch (num) {
2007 case 1:
2008 col1 = background;
2009 col2 = background;
2010 break;
2011 case 2:
2012 col1 = shadow;
2013 col2 = background;
2014 break;
2015 case 3:
2016 default:
2017 col1 = background;
2018 col2 = light;
2019 num = 0;
2020 break;
2021 }
2022 view->SetHighColor(col1);
2023 view->StrokeLine(dot, dot, B_SOLID_HIGH);
2024 view->SetHighColor(col2);
2025 dot.y++;
2026 view->StrokeLine(dot, dot, B_SOLID_HIGH);
2027 dot.y -= 1.0;
2028 // next pixel
2029 num++;
2030 dot.x++;
2031 }
2032 }
2033 }
2034
2035
2036 // #pragma mark -
2037
2038
2039 void
DrawBorder(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,border_style borderStyle,uint32 flags,uint32 borders)2040 HaikuControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect,
2041 const rgb_color& base, border_style borderStyle, uint32 flags,
2042 uint32 borders)
2043 {
2044 if (borderStyle == B_NO_BORDER)
2045 return;
2046
2047 rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT);
2048 if (base.red + base.green + base.blue <= 128 * 3) {
2049 scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT);
2050 }
2051
2052 if ((flags & B_FOCUSED) != 0)
2053 scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
2054
2055 if (borderStyle == B_FANCY_BORDER)
2056 _DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
2057
2058 _DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
2059 scrollbarFrameColor, scrollbarFrameColor, borders);
2060 }
2061
2062
2063 void
DrawRaisedBorder(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)2064 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect,
2065 const BRect& updateRect, const rgb_color& base, uint32 flags,
2066 uint32 borders)
2067 {
2068 rgb_color lightColor;
2069 rgb_color shadowColor;
2070
2071 if ((flags & B_DISABLED) != 0) {
2072 lightColor = base;
2073 shadowColor = base;
2074 } else {
2075 lightColor = tint_color(base, 0.85);
2076 shadowColor = tint_color(base, 1.07);
2077 }
2078
2079 _DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor,
2080 borders);
2081 }
2082
2083
2084 void
DrawTextControlBorder(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders)2085 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect,
2086 const BRect& updateRect, const rgb_color& base, uint32 flags,
2087 uint32 borders)
2088 {
2089 if (!ShouldDraw(view, rect, updateRect))
2090 return;
2091
2092 rgb_color dark1BorderColor;
2093 rgb_color dark2BorderColor;
2094 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
2095 rgb_color invalidColor = ui_color(B_FAILURE_COLOR);
2096
2097 if ((flags & B_DISABLED) != 0) {
2098 _DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders);
2099
2100 if ((flags & B_BLEND_FRAME) != 0)
2101 dark1BorderColor = (rgb_color){ 0, 0, 0, 40 };
2102 else
2103 dark1BorderColor = tint_color(base, 1.15);
2104 dark2BorderColor = dark1BorderColor;
2105 } else if ((flags & B_CLICKED) != 0) {
2106 dark1BorderColor = tint_color(base, 1.50);
2107 dark2BorderColor = tint_color(base, 1.49);
2108
2109 // BCheckBox uses this to indicate the clicked state...
2110 _DrawFrame(view, rect,
2111 dark1BorderColor, dark1BorderColor,
2112 dark2BorderColor, dark2BorderColor);
2113
2114 dark2BorderColor = dark1BorderColor;
2115 } else {
2116 _DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders);
2117
2118 if ((flags & B_BLEND_FRAME) != 0) {
2119 dark1BorderColor = (rgb_color){ 0, 0, 0, 102 };
2120 dark2BorderColor = (rgb_color){ 0, 0, 0, 97 };
2121 } else {
2122 dark1BorderColor = tint_color(base, 1.40);
2123 dark2BorderColor = tint_color(base, 1.38);
2124 }
2125 }
2126
2127 if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) {
2128 dark1BorderColor = navigationColor;
2129 dark2BorderColor = navigationColor;
2130 }
2131
2132 if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) {
2133 dark1BorderColor = invalidColor;
2134 dark2BorderColor = invalidColor;
2135 }
2136
2137 if ((flags & B_BLEND_FRAME) != 0) {
2138 drawing_mode oldMode = view->DrawingMode();
2139 view->SetDrawingMode(B_OP_ALPHA);
2140
2141 _DrawFrame(view, rect,
2142 dark1BorderColor, dark1BorderColor,
2143 dark2BorderColor, dark2BorderColor, borders);
2144
2145 view->SetDrawingMode(oldMode);
2146 } else {
2147 _DrawFrame(view, rect,
2148 dark1BorderColor, dark1BorderColor,
2149 dark2BorderColor, dark2BorderColor, borders);
2150 }
2151 }
2152
2153
2154 void
DrawGroupFrame(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 borders)2155 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
2156 const rgb_color& base, uint32 borders)
2157 {
2158 rgb_color frameColor = tint_color(base, 1.30);
2159 rgb_color bevelLight = tint_color(base, 0.8);
2160 rgb_color bevelShadow = tint_color(base, 1.03);
2161
2162 _DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight,
2163 borders);
2164
2165 _DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor,
2166 borders);
2167
2168 _DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow,
2169 borders);
2170 }
2171
2172
2173 void
DrawLabel(BView * view,const char * label,BRect rect,const BRect & updateRect,const rgb_color & base,uint32 flags,const rgb_color * textColor)2174 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2175 const BRect& updateRect, const rgb_color& base, uint32 flags,
2176 const rgb_color* textColor)
2177 {
2178 DrawLabel(view, label, NULL, rect, updateRect, base, flags,
2179 DefaultLabelAlignment(), textColor);
2180 }
2181
2182
2183 void
DrawLabel(BView * view,const char * label,BRect rect,const BRect & updateRect,const rgb_color & base,uint32 flags,const BAlignment & alignment,const rgb_color * textColor)2184 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2185 const BRect& updateRect, const rgb_color& base, uint32 flags,
2186 const BAlignment& alignment, const rgb_color* textColor)
2187 {
2188 DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment,
2189 textColor);
2190 }
2191
2192
2193 void
DrawLabel(BView * view,const char * label,const rgb_color & base,uint32 flags,const BPoint & where,const rgb_color * textColor)2194 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base,
2195 uint32 flags, const BPoint& where, const rgb_color* textColor)
2196 {
2197 // setup the text color
2198
2199 BWindow* window = view->Window();
2200 bool isDesktop = window != NULL && window->Feel() == kDesktopWindowFeel
2201 && window->Look() == kDesktopWindowLook && view->Parent() != NULL
2202 && view->Parent()->Parent() == NULL && (flags & B_IGNORE_OUTLINE) == 0;
2203
2204 rgb_color low;
2205 rgb_color color;
2206 rgb_color glowColor;
2207
2208 if (textColor != NULL)
2209 glowColor = *textColor;
2210 else if (view->Parent() != NULL)
2211 glowColor = view->Parent()->HighColor();
2212 else if ((flags & B_IS_CONTROL) != 0)
2213 glowColor = ui_color(B_CONTROL_TEXT_COLOR);
2214 else
2215 glowColor = ui_color(B_PANEL_TEXT_COLOR);
2216
2217 color = glowColor;
2218
2219 if (isDesktop)
2220 low = view->Parent()->ViewColor();
2221 else
2222 low = base;
2223
2224 if ((flags & B_DISABLED) != 0) {
2225 color.red = (uint8)(((int32)low.red + color.red + 1) / 2);
2226 color.green = (uint8)(((int32)low.green + color.green + 1) / 2);
2227 color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2);
2228 }
2229
2230 drawing_mode oldMode = view->DrawingMode();
2231
2232 if (isDesktop) {
2233 // enforce proper use of desktop label colors
2234 if (low.IsDark()) {
2235 if (textColor == NULL)
2236 color = make_color(255, 255, 255);
2237
2238 glowColor = make_color(0, 0, 0);
2239 } else {
2240 if (textColor == NULL)
2241 color = make_color(0, 0, 0);
2242
2243 glowColor = make_color(255, 255, 255);
2244 }
2245
2246 // drawing occurs on the desktop
2247 if (fCachedWorkspace != current_workspace()) {
2248 int8 indice = 0;
2249 int32 mask;
2250 bool tmpOutline;
2251 while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces",
2252 indice, &mask) == B_OK
2253 && fBackgroundInfo.FindBool("be:bgndimginfoerasetext",
2254 indice, &tmpOutline) == B_OK) {
2255
2256 if (((1 << current_workspace()) & mask) != 0) {
2257 fCachedOutline = tmpOutline;
2258 fCachedWorkspace = current_workspace();
2259 break;
2260 }
2261 indice++;
2262 }
2263 }
2264
2265 if (fCachedOutline) {
2266 BFont font;
2267 view->GetFont(&font);
2268
2269 view->SetDrawingMode(B_OP_ALPHA);
2270 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
2271 // Draw glow or outline
2272 if (glowColor.IsLight()) {
2273 font.SetFalseBoldWidth(2.0);
2274 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2275
2276 glowColor.alpha = 30;
2277 view->SetHighColor(glowColor);
2278 view->DrawString(label, where);
2279
2280 font.SetFalseBoldWidth(1.0);
2281 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2282
2283 glowColor.alpha = 65;
2284 view->SetHighColor(glowColor);
2285 view->DrawString(label, where);
2286
2287 font.SetFalseBoldWidth(0.0);
2288 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2289 } else {
2290 font.SetFalseBoldWidth(1.0);
2291 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2292
2293 glowColor.alpha = 30;
2294 view->SetHighColor(glowColor);
2295 view->DrawString(label, where);
2296
2297 font.SetFalseBoldWidth(0.0);
2298 view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2299
2300 glowColor.alpha = 200;
2301 view->SetHighColor(glowColor);
2302 view->DrawString(label, BPoint(where.x + 1, where.y + 1));
2303 }
2304 }
2305 }
2306
2307 view->SetHighColor(color);
2308 view->SetDrawingMode(B_OP_OVER);
2309 view->DrawString(label, where);
2310 view->SetDrawingMode(oldMode);
2311 }
2312
2313
2314 void
DrawLabel(BView * view,const char * label,const BBitmap * icon,BRect rect,const BRect & updateRect,const rgb_color & base,uint32 flags,const BAlignment & alignment,const rgb_color * textColor)2315 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon,
2316 BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags,
2317 const BAlignment& alignment, const rgb_color* textColor)
2318 {
2319 if (!ShouldDraw(view, rect, updateRect))
2320 return;
2321
2322 if (label == NULL && icon == NULL)
2323 return;
2324
2325 if (label == NULL) {
2326 // icon only
2327 BRect alignedRect = BLayoutUtils::AlignInFrame(rect,
2328 icon->Bounds().Size(), alignment);
2329 drawing_mode oldMode = view->DrawingMode();
2330 view->SetDrawingMode(B_OP_OVER);
2331 view->DrawBitmap(icon, alignedRect.LeftTop());
2332 view->SetDrawingMode(oldMode);
2333 return;
2334 }
2335
2336 // label, possibly with icon
2337 float availableWidth = rect.Width() + 1;
2338 float width = 0;
2339 float textOffset = 0;
2340 float height = 0;
2341
2342 if (icon != NULL) {
2343 width = icon->Bounds().Width() + DefaultLabelSpacing() + 1;
2344 height = icon->Bounds().Height() + 1;
2345 textOffset = width;
2346 availableWidth -= textOffset;
2347 }
2348
2349 // truncate the label if necessary and get the width and height
2350 BString truncatedLabel(label);
2351
2352 BFont font;
2353 view->GetFont(&font);
2354
2355 font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth);
2356 width += ceilf(font.StringWidth(truncatedLabel.String()));
2357
2358 font_height fontHeight;
2359 font.GetHeight(&fontHeight);
2360 float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
2361 height = std::max(height, textHeight);
2362
2363 // handle alignment
2364 BRect alignedRect(BLayoutUtils::AlignOnRect(rect,
2365 BSize(width - 1, height - 1), alignment));
2366
2367 if (icon != NULL) {
2368 BPoint location(alignedRect.LeftTop());
2369 if (icon->Bounds().Height() + 1 < height)
2370 location.y += ceilf((height - icon->Bounds().Height() - 1) / 2);
2371
2372 drawing_mode oldMode = view->DrawingMode();
2373 view->SetDrawingMode(B_OP_OVER);
2374 view->DrawBitmap(icon, location);
2375 view->SetDrawingMode(oldMode);
2376 }
2377
2378 BPoint location(alignedRect.left + textOffset,
2379 alignedRect.top + ceilf(fontHeight.ascent));
2380 if (textHeight < height)
2381 location.y += ceilf((height - textHeight) / 2);
2382
2383 DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor);
2384 }
2385
2386
2387 void
GetFrameInsets(frame_type frameType,uint32 flags,float & _left,float & _top,float & _right,float & _bottom)2388 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left,
2389 float& _top, float& _right, float& _bottom)
2390 {
2391 // All frames have the same inset on each side.
2392 float inset = 0;
2393
2394 switch (frameType) {
2395 case B_BUTTON_FRAME:
2396 inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2;
2397 break;
2398 case B_GROUP_FRAME:
2399 case B_MENU_FIELD_FRAME:
2400 inset = 3;
2401 break;
2402 case B_SCROLL_VIEW_FRAME:
2403 case B_TEXT_CONTROL_FRAME:
2404 inset = 2;
2405 break;
2406 }
2407
2408 inset = ceilf(inset * (be_plain_font->Size() / 12.0f));
2409
2410 _left = inset;
2411 _top = inset;
2412 _right = inset;
2413 _bottom = inset;
2414 }
2415
2416
2417 void
GetBackgroundInsets(background_type backgroundType,uint32 flags,float & _left,float & _top,float & _right,float & _bottom)2418 HaikuControlLook::GetBackgroundInsets(background_type backgroundType,
2419 uint32 flags, float& _left, float& _top, float& _right, float& _bottom)
2420 {
2421 // Most backgrounds have the same inset on each side.
2422 float inset = 0;
2423
2424 switch (backgroundType) {
2425 case B_BUTTON_BACKGROUND:
2426 case B_MENU_BACKGROUND:
2427 case B_MENU_BAR_BACKGROUND:
2428 case B_MENU_FIELD_BACKGROUND:
2429 case B_MENU_ITEM_BACKGROUND:
2430 inset = 1;
2431 break;
2432 case B_BUTTON_WITH_POP_UP_BACKGROUND:
2433 _left = 1;
2434 _top = 1;
2435 _right = 1 + ComposeSpacing(kButtonPopUpIndicatorWidth);
2436 _bottom = 1;
2437 return;
2438 case B_HORIZONTAL_SCROLL_BAR_BACKGROUND:
2439 _left = 2;
2440 _top = 0;
2441 _right = 1;
2442 _bottom = 0;
2443 return;
2444 case B_VERTICAL_SCROLL_BAR_BACKGROUND:
2445 _left = 0;
2446 _top = 2;
2447 _right = 0;
2448 _bottom = 1;
2449 return;
2450 }
2451
2452 _left = inset;
2453 _top = inset;
2454 _right = inset;
2455 _bottom = inset;
2456 }
2457
2458
2459 void
DrawButtonWithPopUpBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)2460 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2461 const BRect& updateRect, const rgb_color& base, uint32 flags,
2462 uint32 borders, orientation orientation)
2463 {
2464 _DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
2465 base, true, flags, borders, orientation);
2466 }
2467
2468
2469 void
DrawButtonWithPopUpBackground(BView * view,BRect & rect,const BRect & updateRect,float radius,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)2470 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2471 const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
2472 uint32 borders, orientation orientation)
2473 {
2474 _DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
2475 radius, base, true, flags, borders, orientation);
2476 }
2477
2478
2479 void
DrawButtonWithPopUpBackground(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,uint32 flags,uint32 borders,orientation orientation)2480 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2481 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2482 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2483 uint32 flags, uint32 borders, orientation orientation)
2484 {
2485 _DrawButtonBackground(view, rect, updateRect, leftTopRadius,
2486 rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
2487 borders, orientation);
2488 }
2489
2490
2491 // #pragma mark -
2492
2493
2494 void
_DrawButtonFrame(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,const rgb_color & background,float contrast,float brightness,uint32 flags,uint32 borders)2495 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect,
2496 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2497 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2498 const rgb_color& background, float contrast, float brightness,
2499 uint32 flags, uint32 borders)
2500 {
2501 if (!rect.IsValid())
2502 return;
2503
2504 // save the clipping constraints of the view
2505 view->PushState();
2506
2507 // set clipping constraints to rect
2508 view->ClipToRect(rect);
2509
2510 // If the button is flat and neither activated nor otherwise highlighted
2511 // (mouse hovering or focussed), draw it flat.
2512 if ((flags & B_FLAT) != 0
2513 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2514 && ((flags & (B_HOVER | B_FOCUSED)) == 0
2515 || (flags & B_DISABLED) != 0)) {
2516 _DrawFrame(view, rect, background, background, background,
2517 background, borders);
2518 _DrawFrame(view, rect, background, background, background,
2519 background, borders);
2520 view->PopState();
2521 return;
2522 }
2523
2524 // outer edge colors
2525 rgb_color edgeLightColor;
2526 rgb_color edgeShadowColor;
2527
2528 // default button frame color
2529 rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR);
2530 rgb_color cornerBgColor;
2531
2532 if ((flags & B_DISABLED) != 0) {
2533 defaultIndicatorColor = disable_color(defaultIndicatorColor,
2534 background);
2535 }
2536
2537 drawing_mode oldMode = view->DrawingMode();
2538
2539 if ((flags & B_DEFAULT_BUTTON) != 0) {
2540 cornerBgColor = defaultIndicatorColor;
2541 edgeLightColor = _EdgeLightColor(defaultIndicatorColor,
2542 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2543 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2544 edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor,
2545 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2546 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2547
2548 // draw default button indicator
2549 // Allow a 1-pixel border of the background to come through.
2550 rect.InsetBy(1, 1);
2551
2552 view->SetHighColor(defaultIndicatorColor);
2553 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2554 rect.InsetBy(1, 1);
2555
2556 view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2557 rect.InsetBy(1, 1);
2558 } else {
2559 cornerBgColor = background;
2560 if ((flags & B_BLEND_FRAME) != 0) {
2561 // set the background color to transparent for the case
2562 // that we are on the desktop
2563 cornerBgColor.alpha = 0;
2564 view->SetDrawingMode(B_OP_ALPHA);
2565 }
2566
2567 edgeLightColor = _EdgeLightColor(background,
2568 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2569 brightness * 1.0, flags);
2570 edgeShadowColor = _EdgeShadowColor(background,
2571 contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0,
2572 brightness * 1.0, flags);
2573 }
2574
2575 // frame colors
2576 rgb_color frameLightColor = _FrameLightColor(base, flags);
2577 rgb_color frameShadowColor = _FrameShadowColor(base, flags);
2578
2579 // rounded corners
2580
2581 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2582 && leftTopRadius > 0) {
2583 // draw left top rounded corner
2584 BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2585 floorf(rect.left + leftTopRadius),
2586 floorf(rect.top + leftTopRadius));
2587 BRect cornerRect(leftTopCorner);
2588 _DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect,
2589 cornerBgColor, edgeShadowColor, frameLightColor);
2590 view->ClipToInverseRect(cornerRect);
2591 }
2592
2593 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2594 && rightTopRadius > 0) {
2595 // draw right top rounded corner
2596 BRect rightTopCorner(floorf(rect.right - rightTopRadius),
2597 floorf(rect.top), floorf(rect.right),
2598 floorf(rect.top + rightTopRadius));
2599 BRect cornerRect(rightTopCorner);
2600 _DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect,
2601 cornerBgColor, edgeShadowColor, edgeLightColor,
2602 frameLightColor, frameShadowColor);
2603 view->ClipToInverseRect(cornerRect);
2604 }
2605
2606 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2607 && leftBottomRadius > 0) {
2608 // draw left bottom rounded corner
2609 BRect leftBottomCorner(floorf(rect.left),
2610 floorf(rect.bottom - leftBottomRadius),
2611 floorf(rect.left + leftBottomRadius), floorf(rect.bottom));
2612 BRect cornerRect(leftBottomCorner);
2613 _DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect,
2614 cornerBgColor, edgeShadowColor, edgeLightColor,
2615 frameLightColor, frameShadowColor);
2616 view->ClipToInverseRect(cornerRect);
2617 }
2618
2619 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2620 && rightBottomRadius > 0) {
2621 // draw right bottom rounded corner
2622 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius),
2623 floorf(rect.bottom - rightBottomRadius), floorf(rect.right),
2624 floorf(rect.bottom));
2625 BRect cornerRect(rightBottomCorner);
2626 _DrawRoundCornerFrameRightBottom(view, rightBottomCorner,
2627 updateRect, cornerBgColor, edgeLightColor, frameShadowColor);
2628 view->ClipToInverseRect(cornerRect);
2629 }
2630
2631 // draw outer edge
2632 if ((flags & B_DEFAULT_BUTTON) != 0) {
2633 _DrawOuterResessedFrame(view, rect, defaultIndicatorColor,
2634 contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2635 brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9),
2636 flags, borders);
2637 } else {
2638 _DrawOuterResessedFrame(view, rect, background,
2639 contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2640 brightness * 1.0, flags, borders);
2641 }
2642
2643 view->SetDrawingMode(oldMode);
2644
2645 // draw frame
2646 if ((flags & B_BLEND_FRAME) != 0) {
2647 drawing_mode oldDrawingMode = view->DrawingMode();
2648 view->SetDrawingMode(B_OP_ALPHA);
2649
2650 _DrawFrame(view, rect, frameLightColor, frameLightColor,
2651 frameShadowColor, frameShadowColor, borders);
2652
2653 view->SetDrawingMode(oldDrawingMode);
2654 } else {
2655 _DrawFrame(view, rect, frameLightColor, frameLightColor,
2656 frameShadowColor, frameShadowColor, borders);
2657 }
2658
2659 // restore the clipping constraints of the view
2660 view->PopState();
2661 }
2662
2663
2664 void
_DrawOuterResessedFrame(BView * view,BRect & rect,const rgb_color & base,float contrast,float brightness,uint32 flags,uint32 borders)2665 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
2666 const rgb_color& base, float contrast, float brightness, uint32 flags,
2667 uint32 borders)
2668 {
2669 rgb_color edgeLightColor = _EdgeLightColor(base, contrast,
2670 brightness, flags);
2671 rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast,
2672 brightness, flags);
2673
2674 if ((flags & B_BLEND_FRAME) != 0) {
2675 // assumes the background has already been painted
2676 drawing_mode oldDrawingMode = view->DrawingMode();
2677 view->SetDrawingMode(B_OP_ALPHA);
2678
2679 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2680 edgeLightColor, edgeLightColor, borders);
2681
2682 view->SetDrawingMode(oldDrawingMode);
2683 } else {
2684 _DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2685 edgeLightColor, edgeLightColor, borders);
2686 }
2687 }
2688
2689
2690 void
_DrawFrame(BView * view,BRect & rect,const rgb_color & left,const rgb_color & top,const rgb_color & right,const rgb_color & bottom,uint32 borders)2691 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2692 const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2693 uint32 borders)
2694 {
2695 view->BeginLineArray(4);
2696
2697 if (borders & B_LEFT_BORDER) {
2698 view->AddLine(
2699 BPoint(rect.left, rect.bottom),
2700 BPoint(rect.left, rect.top), left);
2701 rect.left++;
2702 }
2703 if (borders & B_TOP_BORDER) {
2704 view->AddLine(
2705 BPoint(rect.left, rect.top),
2706 BPoint(rect.right, rect.top), top);
2707 rect.top++;
2708 }
2709 if (borders & B_RIGHT_BORDER) {
2710 view->AddLine(
2711 BPoint(rect.right, rect.top),
2712 BPoint(rect.right, rect.bottom), right);
2713 rect.right--;
2714 }
2715 if (borders & B_BOTTOM_BORDER) {
2716 view->AddLine(
2717 BPoint(rect.left, rect.bottom),
2718 BPoint(rect.right, rect.bottom), bottom);
2719 rect.bottom--;
2720 }
2721
2722 view->EndLineArray();
2723 }
2724
2725
2726 void
_DrawFrame(BView * view,BRect & rect,const rgb_color & left,const rgb_color & top,const rgb_color & right,const rgb_color & bottom,const rgb_color & rightTop,const rgb_color & leftBottom,uint32 borders)2727 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2728 const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2729 const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders)
2730 {
2731 view->BeginLineArray(6);
2732
2733 if (borders & B_TOP_BORDER) {
2734 if (borders & B_RIGHT_BORDER) {
2735 view->AddLine(
2736 BPoint(rect.left, rect.top),
2737 BPoint(rect.right - 1, rect.top), top);
2738 view->AddLine(
2739 BPoint(rect.right, rect.top),
2740 BPoint(rect.right, rect.top), rightTop);
2741 } else {
2742 view->AddLine(
2743 BPoint(rect.left, rect.top),
2744 BPoint(rect.right, rect.top), top);
2745 }
2746 rect.top++;
2747 }
2748
2749 if (borders & B_LEFT_BORDER) {
2750 view->AddLine(
2751 BPoint(rect.left, rect.top),
2752 BPoint(rect.left, rect.bottom - 1), left);
2753 view->AddLine(
2754 BPoint(rect.left, rect.bottom),
2755 BPoint(rect.left, rect.bottom), leftBottom);
2756 rect.left++;
2757 }
2758
2759 if (borders & B_BOTTOM_BORDER) {
2760 view->AddLine(
2761 BPoint(rect.left, rect.bottom),
2762 BPoint(rect.right, rect.bottom), bottom);
2763 rect.bottom--;
2764 }
2765
2766 if (borders & B_RIGHT_BORDER) {
2767 view->AddLine(
2768 BPoint(rect.right, rect.bottom),
2769 BPoint(rect.right, rect.top), right);
2770 rect.right--;
2771 }
2772
2773 view->EndLineArray();
2774 }
2775
2776
2777 void
_DrawButtonBackground(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,bool popupIndicator,uint32 flags,uint32 borders,orientation orientation)2778 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect,
2779 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2780 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2781 bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
2782 {
2783 if (!rect.IsValid())
2784 return;
2785
2786 // save the clipping constraints of the view
2787 view->PushState();
2788
2789 // set clipping constraints to rect
2790 view->ClipToRect(rect);
2791
2792 // If the button is flat and neither activated nor otherwise highlighted
2793 // (mouse hovering or focussed), draw it flat.
2794 if ((flags & B_FLAT) != 0
2795 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2796 && ((flags & (B_HOVER | B_FOCUSED)) == 0
2797 || (flags & B_DISABLED) != 0)) {
2798 _DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator,
2799 flags, borders, orientation);
2800 } else {
2801 BRegion clipping(rect);
2802 _DrawNonFlatButtonBackground(view, rect, updateRect, clipping,
2803 leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius,
2804 base, popupIndicator, flags, borders, orientation);
2805 }
2806
2807 // restore the clipping constraints of the view
2808 view->PopState();
2809 }
2810
2811
2812 void
_DrawFlatButtonBackground(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & base,bool popupIndicator,uint32 flags,uint32 borders,orientation orientation)2813 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect,
2814 const BRect& updateRect, const rgb_color& base, bool popupIndicator,
2815 uint32 flags, uint32 borders, orientation orientation)
2816 {
2817 _DrawFrame(view, rect, base, base, base, base, borders);
2818 // Not an actual frame, but the method insets our rect as needed.
2819
2820 view->SetHighColor(base);
2821 view->FillRect(rect);
2822
2823 if (popupIndicator) {
2824 BRect indicatorRect(rect);
2825 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth);
2826 indicatorRect.left = rect.right + 3;
2827 // 2 pixels for the separator
2828
2829 view->SetHighColor(base);
2830 view->FillRect(indicatorRect);
2831
2832 _DrawPopUpMarker(view, indicatorRect, base, flags);
2833 }
2834 }
2835
2836
2837 void
_DrawNonFlatButtonBackground(BView * view,BRect & rect,const BRect & updateRect,BRegion & clipping,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,bool popupIndicator,uint32 flags,uint32 borders,orientation orientation)2838 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect,
2839 const BRect& updateRect, BRegion& clipping, float leftTopRadius,
2840 float rightTopRadius, float leftBottomRadius, float rightBottomRadius,
2841 const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders,
2842 orientation orientation)
2843 {
2844 // inner bevel colors
2845 rgb_color bevelLightColor = _BevelLightColor(base, flags);
2846 rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
2847
2848 // button background color
2849 rgb_color buttonBgColor;
2850 if ((flags & B_DISABLED) != 0)
2851 buttonBgColor = tint_color(base, 0.7);
2852 else
2853 buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT);
2854
2855 // surface top gradient
2856 BGradientLinear fillGradient;
2857 _MakeButtonGradient(fillGradient, rect, base, flags, orientation);
2858
2859 // rounded corners
2860
2861 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2862 && leftTopRadius > 0) {
2863 // draw left top rounded corner
2864 BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2865 floorf(rect.left + leftTopRadius - 2.0),
2866 floorf(rect.top + leftTopRadius - 2.0));
2867 clipping.Exclude(leftTopCorner);
2868 BRect cornerRect(leftTopCorner);
2869 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
2870 bevelLightColor, fillGradient);
2871 view->ClipToInverseRect(cornerRect);
2872 }
2873
2874 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2875 && rightTopRadius > 0) {
2876 // draw right top rounded corner
2877 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
2878 floorf(rect.top), floorf(rect.right),
2879 floorf(rect.top + rightTopRadius - 2.0));
2880 clipping.Exclude(rightTopCorner);
2881 BRect cornerRect(rightTopCorner);
2882 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner,
2883 updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2884 view->ClipToInverseRect(cornerRect);
2885 }
2886
2887 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2888 && leftBottomRadius > 0) {
2889 // draw left bottom rounded corner
2890 BRect leftBottomCorner(floorf(rect.left),
2891 floorf(rect.bottom - leftBottomRadius + 2.0),
2892 floorf(rect.left + leftBottomRadius - 2.0),
2893 floorf(rect.bottom));
2894 clipping.Exclude(leftBottomCorner);
2895 BRect cornerRect(leftBottomCorner);
2896 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
2897 updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2898 view->ClipToInverseRect(cornerRect);
2899 }
2900
2901 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2902 && rightBottomRadius > 0) {
2903 // draw right bottom rounded corner
2904 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
2905 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
2906 floorf(rect.bottom));
2907 clipping.Exclude(rightBottomCorner);
2908 BRect cornerRect(rightBottomCorner);
2909 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
2910 updateRect, bevelShadowColor, fillGradient);
2911 view->ClipToInverseRect(cornerRect);
2912 }
2913
2914 // draw inner bevel
2915
2916 if ((flags & B_ACTIVATED) != 0) {
2917 view->BeginLineArray(4);
2918
2919 // shadow along left/top borders
2920 if (borders & B_LEFT_BORDER) {
2921 view->AddLine(BPoint(rect.left, rect.top),
2922 BPoint(rect.left, rect.bottom), bevelLightColor);
2923 rect.left++;
2924 }
2925 if (borders & B_TOP_BORDER) {
2926 view->AddLine(BPoint(rect.left, rect.top),
2927 BPoint(rect.right, rect.top), bevelLightColor);
2928 rect.top++;
2929 }
2930
2931 // softer shadow along left/top borders
2932 if (borders & B_LEFT_BORDER) {
2933 view->AddLine(BPoint(rect.left, rect.top),
2934 BPoint(rect.left, rect.bottom), bevelShadowColor);
2935 rect.left++;
2936 }
2937 if (borders & B_TOP_BORDER) {
2938 view->AddLine(BPoint(rect.left, rect.top),
2939 BPoint(rect.right, rect.top), bevelShadowColor);
2940 rect.top++;
2941 }
2942
2943 view->EndLineArray();
2944 } else {
2945 _DrawFrame(view, rect,
2946 bevelLightColor, bevelLightColor,
2947 bevelShadowColor, bevelShadowColor,
2948 buttonBgColor, buttonBgColor, borders);
2949 }
2950
2951 if (popupIndicator) {
2952 BRect indicatorRect(rect);
2953 rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth);
2954 indicatorRect.left = rect.right + 3;
2955 // 2 pixels for the separator
2956
2957 // Even when depressed we want the pop-up indicator background and
2958 // separator to cover the area up to the top.
2959 if ((flags & B_ACTIVATED) != 0)
2960 indicatorRect.top--;
2961
2962 // draw the separator
2963 rgb_color separatorBaseColor = base;
2964 if ((flags & B_ACTIVATED) != 0)
2965 separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
2966
2967 rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor,
2968 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2969 rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor,
2970 (flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2971
2972 view->BeginLineArray(2);
2973
2974 view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top),
2975 BPoint(indicatorRect.left - 2, indicatorRect.bottom),
2976 separatorShadowColor);
2977 view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top),
2978 BPoint(indicatorRect.left - 1, indicatorRect.bottom),
2979 separatorLightColor);
2980
2981 view->EndLineArray();
2982
2983 // draw background and pop-up marker
2984 _DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect,
2985 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0);
2986
2987 if ((flags & B_ACTIVATED) != 0)
2988 indicatorRect.top++;
2989
2990 _DrawPopUpMarker(view, indicatorRect, base, flags);
2991 }
2992
2993 // fill in the background
2994 view->FillRect(rect, fillGradient);
2995 }
2996
2997
2998 void
_DrawPopUpMarker(BView * view,const BRect & rect,const rgb_color & base,uint32 flags)2999 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
3000 const rgb_color& base, uint32 flags)
3001 {
3002 BPoint center(roundf((rect.left + rect.right) / 2.0),
3003 roundf((rect.top + rect.bottom) / 2.0));
3004 const float metric = roundf(rect.Width() * 3.125f) / 10.0f,
3005 offset = ceilf((metric * 0.2f) * 10.0f) / 10.0f;
3006 BPoint triangle[3];
3007 triangle[0] = center + BPoint(-metric, -offset);
3008 triangle[1] = center + BPoint(metric, -offset);
3009 triangle[2] = center + BPoint(0.0, metric * 0.8f);
3010
3011 const uint32 viewFlags = view->Flags();
3012 view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
3013
3014 rgb_color markColor;
3015 if ((flags & B_DISABLED) != 0)
3016 markColor = tint_color(base, 1.35);
3017 else
3018 markColor = tint_color(base, 1.65);
3019
3020 view->SetHighColor(markColor);
3021 view->FillTriangle(triangle[0], triangle[1], triangle[2]);
3022
3023 view->SetFlags(viewFlags);
3024 }
3025
3026
3027 void
_DrawMenuFieldBackgroundOutside(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,bool popupIndicator,uint32 flags)3028 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
3029 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3030 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3031 bool popupIndicator, uint32 flags)
3032 {
3033 if (!ShouldDraw(view, rect, updateRect))
3034 return;
3035
3036 if (popupIndicator) {
3037 const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth);
3038 const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f);
3039
3040 BRect leftRect(rect);
3041 leftRect.right -= indicatorWidth - spacing;
3042
3043 BRect rightRect(rect);
3044 rightRect.left = rightRect.right - (indicatorWidth - spacing * 2);
3045
3046 _DrawMenuFieldBackgroundInside(view, leftRect, updateRect,
3047 leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags,
3048 B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
3049
3050 _DrawMenuFieldBackgroundInside(view, rightRect, updateRect,
3051 0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags,
3052 B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
3053
3054 _DrawPopUpMarker(view, rightRect, base, flags);
3055
3056 // draw a line on the left of the popup frame
3057 rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
3058 view->SetHighColor(bevelShadowColor);
3059 BPoint leftTopCorner(floorf(rightRect.left - spacing),
3060 floorf(rightRect.top - spacing));
3061 BPoint leftBottomCorner(floorf(rightRect.left - spacing),
3062 floorf(rightRect.bottom + spacing));
3063 for (float i = 0; i < spacing; i++) {
3064 view->StrokeLine(leftTopCorner + BPoint(i, 0),
3065 leftBottomCorner + BPoint(i, 0));
3066 }
3067
3068 rect = leftRect;
3069 } else {
3070 _DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius,
3071 rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags);
3072 }
3073 }
3074
3075
3076 void
_DrawMenuFieldBackgroundInside(BView * view,BRect & rect,const BRect & updateRect,float leftTopRadius,float rightTopRadius,float leftBottomRadius,float rightBottomRadius,const rgb_color & base,uint32 flags,uint32 borders)3077 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
3078 const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3079 float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3080 uint32 flags, uint32 borders)
3081 {
3082 if (!ShouldDraw(view, rect, updateRect))
3083 return;
3084
3085 // save the clipping constraints of the view
3086 view->PushState();
3087
3088 // set clipping constraints to rect
3089 view->ClipToRect(rect);
3090
3091 // frame colors
3092 rgb_color frameLightColor = _FrameLightColor(base, flags);
3093 rgb_color frameShadowColor = _FrameShadowColor(base, flags);
3094
3095 // indicator background color
3096 rgb_color indicatorBase;
3097 if ((borders & B_LEFT_BORDER) != 0)
3098 indicatorBase = base;
3099 else {
3100 if ((flags & B_DISABLED) != 0)
3101 indicatorBase = tint_color(base, 1.05);
3102 else
3103 indicatorBase = tint_color(base, 1.12);
3104 }
3105
3106 // bevel colors
3107 rgb_color cornerColor = tint_color(indicatorBase, 0.85);
3108 rgb_color bevelColor1 = tint_color(indicatorBase, 0.3);
3109 rgb_color bevelColor2 = tint_color(indicatorBase, 0.5);
3110 rgb_color bevelColor3 = tint_color(indicatorBase, 1.03);
3111
3112 if ((flags & B_DISABLED) != 0) {
3113 cornerColor = tint_color(indicatorBase, 0.8);
3114 bevelColor1 = tint_color(indicatorBase, 0.7);
3115 bevelColor2 = tint_color(indicatorBase, 0.8);
3116 bevelColor3 = tint_color(indicatorBase, 1.01);
3117 } else {
3118 cornerColor = tint_color(indicatorBase, 0.85);
3119 bevelColor1 = tint_color(indicatorBase, 0.3);
3120 bevelColor2 = tint_color(indicatorBase, 0.5);
3121 bevelColor3 = tint_color(indicatorBase, 1.03);
3122 }
3123
3124 // surface top gradient
3125 BGradientLinear fillGradient;
3126 _MakeButtonGradient(fillGradient, rect, indicatorBase, flags);
3127
3128 // rounded corners
3129
3130 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
3131 && leftTopRadius > 0) {
3132 // draw left top rounded corner
3133 BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
3134 floorf(rect.left + leftTopRadius - 2.0),
3135 floorf(rect.top + leftTopRadius - 2.0));
3136 BRect cornerRect(leftTopCorner);
3137
3138 view->PushState();
3139 view->ClipToRect(cornerRect);
3140
3141 BRect ellipseRect(leftTopCorner);
3142 ellipseRect.InsetBy(-1.0, -1.0);
3143 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3144 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3145
3146 // draw the frame (again)
3147 view->SetHighColor(frameLightColor);
3148 view->FillEllipse(ellipseRect);
3149
3150 // draw the bevel and background
3151 _DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
3152 bevelColor1, fillGradient);
3153
3154 view->PopState();
3155 view->ClipToInverseRect(cornerRect);
3156 }
3157
3158 if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
3159 && rightTopRadius > 0) {
3160 // draw right top rounded corner
3161 BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
3162 floorf(rect.top), floorf(rect.right),
3163 floorf(rect.top + rightTopRadius - 2.0));
3164 BRect cornerRect(rightTopCorner);
3165
3166 view->PushState();
3167 view->ClipToRect(cornerRect);
3168
3169 BRect ellipseRect(rightTopCorner);
3170 ellipseRect.InsetBy(-1.0, -1.0);
3171 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3172 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3173
3174 // draw the frame (again)
3175 if (frameLightColor == frameShadowColor) {
3176 view->SetHighColor(frameLightColor);
3177 view->FillEllipse(ellipseRect);
3178 } else {
3179 BGradientLinear gradient;
3180 gradient.AddColor(frameLightColor, 0);
3181 gradient.AddColor(frameShadowColor, 255);
3182 gradient.SetStart(rightTopCorner.LeftTop());
3183 gradient.SetEnd(rightTopCorner.RightBottom());
3184 view->FillEllipse(ellipseRect, gradient);
3185 }
3186
3187 // draw the bevel and background
3188 _DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect,
3189 bevelColor1, bevelColor3, fillGradient);
3190
3191 view->PopState();
3192 view->ClipToInverseRect(cornerRect);
3193 }
3194
3195 if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3196 && leftBottomRadius > 0) {
3197 // draw left bottom rounded corner
3198 BRect leftBottomCorner(floorf(rect.left),
3199 floorf(rect.bottom - leftBottomRadius + 2.0),
3200 floorf(rect.left + leftBottomRadius - 2.0),
3201 floorf(rect.bottom));
3202 BRect cornerRect(leftBottomCorner);
3203
3204 view->PushState();
3205 view->ClipToRect(cornerRect);
3206
3207 BRect ellipseRect(leftBottomCorner);
3208 ellipseRect.InsetBy(-1.0, -1.0);
3209 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3210 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3211
3212 // draw the frame (again)
3213 if (frameLightColor == frameShadowColor) {
3214 view->SetHighColor(frameLightColor);
3215 view->FillEllipse(ellipseRect);
3216 } else {
3217 BGradientLinear gradient;
3218 gradient.AddColor(frameLightColor, 0);
3219 gradient.AddColor(frameShadowColor, 255);
3220 gradient.SetStart(leftBottomCorner.LeftTop());
3221 gradient.SetEnd(leftBottomCorner.RightBottom());
3222 view->FillEllipse(ellipseRect, gradient);
3223 }
3224
3225 // draw the bevel and background
3226 _DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
3227 updateRect, bevelColor2, bevelColor3, fillGradient);
3228
3229 view->PopState();
3230 view->ClipToInverseRect(cornerRect);
3231 }
3232
3233 if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3234 && rightBottomRadius > 0) {
3235 // draw right bottom rounded corner
3236 BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
3237 floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
3238 floorf(rect.bottom));
3239 BRect cornerRect(rightBottomCorner);
3240
3241 view->PushState();
3242 view->ClipToRect(cornerRect);
3243
3244 BRect ellipseRect(rightBottomCorner);
3245 ellipseRect.InsetBy(-1.0, -1.0);
3246 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3247 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3248
3249 // draw the frame (again)
3250 view->SetHighColor(frameShadowColor);
3251 view->FillEllipse(ellipseRect);
3252
3253 // draw the bevel and background
3254 _DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
3255 updateRect, bevelColor3, fillGradient);
3256
3257 view->PopState();
3258 view->ClipToInverseRect(cornerRect);
3259 }
3260
3261 // draw the bevel
3262 _DrawFrame(view, rect,
3263 bevelColor2, bevelColor1,
3264 bevelColor3, bevelColor3,
3265 cornerColor, cornerColor,
3266 borders);
3267
3268 // fill in the background
3269 view->FillRect(rect, fillGradient);
3270
3271 // restore the clipping constraints of the view
3272 view->PopState();
3273 }
3274
3275
3276 void
_DrawRoundCornerLeftTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeColor,const rgb_color & frameColor,const rgb_color & bevelColor,const BGradientLinear & fillGradient)3277 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect,
3278 const BRect& updateRect, const rgb_color& background,
3279 const rgb_color& edgeColor, const rgb_color& frameColor,
3280 const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3281 {
3282 _DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect,
3283 background, edgeColor, frameColor);
3284 _DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect,
3285 bevelColor, fillGradient);
3286 }
3287
3288
3289 void
_DrawRoundCornerFrameLeftTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeColor,const rgb_color & frameColor)3290 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect,
3291 const BRect& updateRect, const rgb_color& background,
3292 const rgb_color& edgeColor, const rgb_color& frameColor)
3293 {
3294 view->PushState();
3295
3296 // constrain clipping region to corner
3297 view->ClipToRect(cornerRect);
3298
3299 // background
3300 view->SetHighColor(background);
3301 view->FillRect(cornerRect);
3302
3303 // outer edge
3304 BRect ellipseRect(cornerRect);
3305 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3306 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3307
3308 view->SetHighColor(edgeColor);
3309 view->FillEllipse(ellipseRect);
3310
3311 // frame
3312 ellipseRect.InsetBy(1, 1);
3313 cornerRect.left++;
3314 cornerRect.top++;
3315 view->SetHighColor(frameColor);
3316 view->FillEllipse(ellipseRect);
3317
3318 // prepare for bevel
3319 cornerRect.left++;
3320 cornerRect.top++;
3321
3322 view->PopState();
3323 }
3324
3325
3326 void
_DrawRoundCornerBackgroundLeftTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & bevelColor,const BGradientLinear & fillGradient)3327 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect,
3328 const BRect& updateRect, const rgb_color& bevelColor,
3329 const BGradientLinear& fillGradient)
3330 {
3331 view->PushState();
3332
3333 // constrain clipping region to corner
3334 view->ClipToRect(cornerRect);
3335
3336 BRect ellipseRect(cornerRect);
3337 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3338 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3339
3340 // bevel
3341 view->SetHighColor(bevelColor);
3342 view->FillEllipse(ellipseRect);
3343
3344 // gradient
3345 ellipseRect.InsetBy(1, 1);
3346 view->FillEllipse(ellipseRect, fillGradient);
3347
3348 view->PopState();
3349 }
3350
3351
3352 void
_DrawRoundCornerRightTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeTopColor,const rgb_color & edgeRightColor,const rgb_color & frameTopColor,const rgb_color & frameRightColor,const rgb_color & bevelTopColor,const rgb_color & bevelRightColor,const BGradientLinear & fillGradient)3353 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect,
3354 const BRect& updateRect, const rgb_color& background,
3355 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3356 const rgb_color& frameTopColor, const rgb_color& frameRightColor,
3357 const rgb_color& bevelTopColor, const rgb_color& bevelRightColor,
3358 const BGradientLinear& fillGradient)
3359 {
3360 _DrawRoundCornerFrameRightTop(view, cornerRect, updateRect,
3361 background, edgeTopColor, edgeRightColor, frameTopColor,
3362 frameRightColor);
3363 _DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect,
3364 bevelTopColor, bevelRightColor, fillGradient);
3365 }
3366
3367
3368 void
_DrawRoundCornerFrameRightTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeTopColor,const rgb_color & edgeRightColor,const rgb_color & frameTopColor,const rgb_color & frameRightColor)3369 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect,
3370 const BRect& updateRect, const rgb_color& background,
3371 const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3372 const rgb_color& frameTopColor, const rgb_color& frameRightColor)
3373 {
3374 view->PushState();
3375
3376 // constrain clipping region to corner
3377 view->ClipToRect(cornerRect);
3378
3379 // background
3380 view->SetHighColor(background);
3381 view->FillRect(cornerRect);
3382
3383 // outer edge
3384 BRect ellipseRect(cornerRect);
3385 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3386 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3387
3388 BGradientLinear gradient;
3389 gradient.AddColor(edgeTopColor, 0);
3390 gradient.AddColor(edgeRightColor, 255);
3391 gradient.SetStart(cornerRect.LeftTop());
3392 gradient.SetEnd(cornerRect.RightBottom());
3393 view->FillEllipse(ellipseRect, gradient);
3394
3395 // frame
3396 ellipseRect.InsetBy(1, 1);
3397 cornerRect.right--;
3398 cornerRect.top++;
3399 if (frameTopColor == frameRightColor) {
3400 view->SetHighColor(frameTopColor);
3401 view->FillEllipse(ellipseRect);
3402 } else {
3403 gradient.SetColor(0, frameTopColor);
3404 gradient.SetColor(1, frameRightColor);
3405 gradient.SetStart(cornerRect.LeftTop());
3406 gradient.SetEnd(cornerRect.RightBottom());
3407 view->FillEllipse(ellipseRect, gradient);
3408 }
3409
3410 // prepare for bevel
3411 cornerRect.right--;
3412 cornerRect.top++;
3413
3414 view->PopState();
3415 }
3416
3417
3418 void
_DrawRoundCornerBackgroundRightTop(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & bevelTopColor,const rgb_color & bevelRightColor,const BGradientLinear & fillGradient)3419 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect,
3420 const BRect& updateRect, const rgb_color& bevelTopColor,
3421 const rgb_color& bevelRightColor, const BGradientLinear& fillGradient)
3422 {
3423 view->PushState();
3424
3425 // constrain clipping region to corner
3426 view->ClipToRect(cornerRect);
3427
3428 BRect ellipseRect(cornerRect);
3429 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3430 ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3431
3432 // bevel
3433 BGradientLinear gradient;
3434 gradient.AddColor(bevelTopColor, 0);
3435 gradient.AddColor(bevelRightColor, 255);
3436 gradient.SetStart(cornerRect.LeftTop());
3437 gradient.SetEnd(cornerRect.RightBottom());
3438 view->FillEllipse(ellipseRect, gradient);
3439
3440 // gradient
3441 ellipseRect.InsetBy(1, 1);
3442 view->FillEllipse(ellipseRect, fillGradient);
3443
3444 view->PopState();
3445 }
3446
3447
3448 void
_DrawRoundCornerLeftBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeLeftColor,const rgb_color & edgeBottomColor,const rgb_color & frameLeftColor,const rgb_color & frameBottomColor,const rgb_color & bevelLeftColor,const rgb_color & bevelBottomColor,const BGradientLinear & fillGradient)3449 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect,
3450 const BRect& updateRect, const rgb_color& background,
3451 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3452 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor,
3453 const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor,
3454 const BGradientLinear& fillGradient)
3455 {
3456 _DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect,
3457 background, edgeLeftColor, edgeBottomColor, frameLeftColor,
3458 frameBottomColor);
3459 _DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect,
3460 bevelLeftColor, bevelBottomColor, fillGradient);
3461 }
3462
3463
3464 void
_DrawRoundCornerFrameLeftBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeLeftColor,const rgb_color & edgeBottomColor,const rgb_color & frameLeftColor,const rgb_color & frameBottomColor)3465 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect,
3466 const BRect& updateRect, const rgb_color& background,
3467 const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3468 const rgb_color& frameLeftColor, const rgb_color& frameBottomColor)
3469 {
3470 view->PushState();
3471
3472 // constrain clipping region to corner
3473 view->ClipToRect(cornerRect);
3474
3475 // background
3476 view->SetHighColor(background);
3477 view->FillRect(cornerRect);
3478
3479 // outer edge
3480 BRect ellipseRect(cornerRect);
3481 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3482 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3483
3484 BGradientLinear gradient;
3485 gradient.AddColor(edgeLeftColor, 0);
3486 gradient.AddColor(edgeBottomColor, 255);
3487 gradient.SetStart(cornerRect.LeftTop());
3488 gradient.SetEnd(cornerRect.RightBottom());
3489 view->FillEllipse(ellipseRect, gradient);
3490
3491 // frame
3492 ellipseRect.InsetBy(1, 1);
3493 cornerRect.left++;
3494 cornerRect.bottom--;
3495 if (frameLeftColor == frameBottomColor) {
3496 view->SetHighColor(frameLeftColor);
3497 view->FillEllipse(ellipseRect);
3498 } else {
3499 gradient.SetColor(0, frameLeftColor);
3500 gradient.SetColor(1, frameBottomColor);
3501 gradient.SetStart(cornerRect.LeftTop());
3502 gradient.SetEnd(cornerRect.RightBottom());
3503 view->FillEllipse(ellipseRect, gradient);
3504 }
3505
3506 // prepare for bevel
3507 cornerRect.left++;
3508 cornerRect.bottom--;
3509
3510 view->PopState();
3511 }
3512
3513
3514 void
_DrawRoundCornerBackgroundLeftBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & bevelLeftColor,const rgb_color & bevelBottomColor,const BGradientLinear & fillGradient)3515 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect,
3516 const BRect& updateRect, const rgb_color& bevelLeftColor,
3517 const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient)
3518 {
3519 view->PushState();
3520
3521 // constrain clipping region to corner
3522 view->ClipToRect(cornerRect);
3523
3524 BRect ellipseRect(cornerRect);
3525 ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3526 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3527
3528 // bevel
3529 BGradientLinear gradient;
3530 gradient.AddColor(bevelLeftColor, 0);
3531 gradient.AddColor(bevelBottomColor, 255);
3532 gradient.SetStart(cornerRect.LeftTop());
3533 gradient.SetEnd(cornerRect.RightBottom());
3534 view->FillEllipse(ellipseRect, gradient);
3535
3536 // gradient
3537 ellipseRect.InsetBy(1, 1);
3538 view->FillEllipse(ellipseRect, fillGradient);
3539
3540 view->PopState();
3541 }
3542
3543
3544 void
_DrawRoundCornerRightBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeColor,const rgb_color & frameColor,const rgb_color & bevelColor,const BGradientLinear & fillGradient)3545 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect,
3546 const BRect& updateRect, const rgb_color& background,
3547 const rgb_color& edgeColor, const rgb_color& frameColor,
3548 const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3549 {
3550 _DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect,
3551 background, edgeColor, frameColor);
3552 _DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect,
3553 bevelColor, fillGradient);
3554 }
3555
3556
3557 void
_DrawRoundCornerFrameRightBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & background,const rgb_color & edgeColor,const rgb_color & frameColor)3558 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect,
3559 const BRect& updateRect, const rgb_color& background,
3560 const rgb_color& edgeColor, const rgb_color& frameColor)
3561 {
3562 view->PushState();
3563
3564 // constrain clipping region to corner
3565 view->ClipToRect(cornerRect);
3566
3567 // background
3568 view->SetHighColor(background);
3569 view->FillRect(cornerRect);
3570
3571 // outer edge
3572 BRect ellipseRect(cornerRect);
3573 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3574 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3575
3576 view->SetHighColor(edgeColor);
3577 view->FillEllipse(ellipseRect);
3578
3579 // frame
3580 ellipseRect.InsetBy(1, 1);
3581 cornerRect.right--;
3582 cornerRect.bottom--;
3583 view->SetHighColor(frameColor);
3584 view->FillEllipse(ellipseRect);
3585
3586 // prepare for bevel
3587 cornerRect.right--;
3588 cornerRect.bottom--;
3589
3590 view->PopState();
3591 }
3592
3593
3594 void
_DrawRoundCornerBackgroundRightBottom(BView * view,BRect & cornerRect,const BRect & updateRect,const rgb_color & bevelColor,const BGradientLinear & fillGradient)3595 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view,
3596 BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor,
3597 const BGradientLinear& fillGradient)
3598 {
3599 view->PushState();
3600
3601 // constrain clipping region to corner
3602 view->ClipToRect(cornerRect);
3603
3604 BRect ellipseRect(cornerRect);
3605 ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3606 ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3607
3608 // bevel
3609 view->SetHighColor(bevelColor);
3610 view->FillEllipse(ellipseRect);
3611
3612 // gradient
3613 ellipseRect.InsetBy(1, 1);
3614 view->FillEllipse(ellipseRect, fillGradient);
3615
3616 view->PopState();
3617 }
3618
3619
3620 void
_DrawRoundBarCorner(BView * view,BRect & rect,const BRect & updateRect,const rgb_color & edgeLightColor,const rgb_color & edgeShadowColor,const rgb_color & frameLightColor,const rgb_color & frameShadowColor,const rgb_color & fillLightColor,const rgb_color & fillShadowColor,float leftInset,float topInset,float rightInset,float bottomInset,orientation orientation)3621 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect,
3622 const BRect& updateRect,
3623 const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor,
3624 const rgb_color& frameLightColor, const rgb_color& frameShadowColor,
3625 const rgb_color& fillLightColor, const rgb_color& fillShadowColor,
3626 float leftInset, float topInset, float rightInset, float bottomInset,
3627 orientation orientation)
3628 {
3629 if (!ShouldDraw(view, rect, updateRect))
3630 return;
3631
3632 BGradientLinear gradient;
3633 gradient.AddColor(edgeShadowColor, 0);
3634 gradient.AddColor(edgeLightColor, 255);
3635 gradient.SetStart(rect.LeftTop());
3636 if (orientation == B_HORIZONTAL)
3637 gradient.SetEnd(rect.LeftBottom());
3638 else
3639 gradient.SetEnd(rect.RightTop());
3640
3641 view->FillEllipse(rect, gradient);
3642
3643 rect.left += leftInset;
3644 rect.top += topInset;
3645 rect.right += rightInset;
3646 rect.bottom += bottomInset;
3647
3648 gradient.MakeEmpty();
3649 gradient.AddColor(frameShadowColor, 0);
3650 gradient.AddColor(frameLightColor, 255);
3651 gradient.SetStart(rect.LeftTop());
3652 if (orientation == B_HORIZONTAL)
3653 gradient.SetEnd(rect.LeftBottom());
3654 else
3655 gradient.SetEnd(rect.RightTop());
3656
3657 view->FillEllipse(rect, gradient);
3658
3659 rect.left += leftInset;
3660 rect.top += topInset;
3661 rect.right += rightInset;
3662 rect.bottom += bottomInset;
3663
3664 gradient.MakeEmpty();
3665 gradient.AddColor(fillShadowColor, 0);
3666 gradient.AddColor(fillLightColor, 255);
3667 gradient.SetStart(rect.LeftTop());
3668 if (orientation == B_HORIZONTAL)
3669 gradient.SetEnd(rect.LeftBottom());
3670 else
3671 gradient.SetEnd(rect.RightTop());
3672
3673 view->FillEllipse(rect, gradient);
3674 }
3675
3676
3677 rgb_color
_EdgeLightColor(const rgb_color & base,float contrast,float brightness,uint32 flags)3678 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast,
3679 float brightness, uint32 flags)
3680 {
3681 rgb_color edgeLightColor;
3682
3683 if ((flags & B_BLEND_FRAME) != 0) {
3684 uint8 alpha = uint8(20 * contrast);
3685 uint8 white = uint8(255 * brightness);
3686
3687 edgeLightColor = (rgb_color){ white, white, white, alpha };
3688 } else {
3689 // colors
3690 float tintLight = kEdgeBevelLightTint;
3691
3692 if (contrast == 0.0)
3693 tintLight = B_NO_TINT;
3694 else if (contrast != 1.0)
3695 tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast;
3696
3697 edgeLightColor = tint_color(base, tintLight);
3698
3699 if (brightness < 1.0) {
3700 edgeLightColor.red = uint8(edgeLightColor.red * brightness);
3701 edgeLightColor.green = uint8(edgeLightColor.green * brightness);
3702 edgeLightColor.blue = uint8(edgeLightColor.blue * brightness);
3703 }
3704 }
3705
3706 return edgeLightColor;
3707 }
3708
3709
3710 rgb_color
_EdgeShadowColor(const rgb_color & base,float contrast,float brightness,uint32 flags)3711 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast,
3712 float brightness, uint32 flags)
3713 {
3714 rgb_color edgeShadowColor;
3715
3716 if ((flags & B_BLEND_FRAME) != 0) {
3717 uint8 alpha = uint8(20 * contrast);
3718 edgeShadowColor = (rgb_color){ 0, 0, 0, alpha };
3719 } else {
3720 float tintShadow = kEdgeBevelShadowTint;
3721
3722 if (contrast == 0.0)
3723 tintShadow = B_NO_TINT;
3724 else if (contrast != 1.0)
3725 tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast;
3726
3727 edgeShadowColor = tint_color(base, tintShadow);
3728
3729 if (brightness < 1.0) {
3730 edgeShadowColor.red = uint8(edgeShadowColor.red * brightness);
3731 edgeShadowColor.green = uint8(edgeShadowColor.green * brightness);
3732 edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness);
3733 }
3734 }
3735
3736 return edgeShadowColor;
3737 }
3738
3739
3740 rgb_color
_FrameLightColor(const rgb_color & base,uint32 flags)3741 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags)
3742 {
3743 if ((flags & B_FOCUSED) != 0)
3744 return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3745
3746 if ((flags & B_ACTIVATED) != 0)
3747 return _FrameShadowColor(base, flags & ~B_ACTIVATED);
3748
3749 rgb_color frameLightColor;
3750
3751 if ((flags & B_DISABLED) != 0) {
3752 // TODO: B_BLEND_FRAME
3753 frameLightColor = tint_color(base, 1.145);
3754
3755 if ((flags & B_DEFAULT_BUTTON) != 0)
3756 frameLightColor = tint_color(frameLightColor, 1.14);
3757 } else {
3758 if ((flags & B_BLEND_FRAME) != 0)
3759 frameLightColor = (rgb_color){ 0, 0, 0, 75 };
3760 else
3761 frameLightColor = tint_color(base, 1.33);
3762
3763 if ((flags & B_DEFAULT_BUTTON) != 0)
3764 frameLightColor = tint_color(frameLightColor, 1.35);
3765 }
3766
3767 return frameLightColor;
3768 }
3769
3770
3771 rgb_color
_FrameShadowColor(const rgb_color & base,uint32 flags)3772 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags)
3773 {
3774 if ((flags & B_FOCUSED) != 0)
3775 return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3776
3777 if ((flags & B_ACTIVATED) != 0)
3778 return _FrameLightColor(base, flags & ~B_ACTIVATED);
3779
3780 rgb_color frameShadowColor;
3781
3782 if ((flags & B_DISABLED) != 0) {
3783 // TODO: B_BLEND_FRAME
3784 frameShadowColor = tint_color(base, 1.24);
3785
3786 if ((flags & B_DEFAULT_BUTTON) != 0) {
3787 frameShadowColor = tint_color(base, 1.145);
3788 frameShadowColor = tint_color(frameShadowColor, 1.12);
3789 }
3790 } else {
3791 if ((flags & B_DEFAULT_BUTTON) != 0) {
3792 if ((flags & B_BLEND_FRAME) != 0)
3793 frameShadowColor = (rgb_color){ 0, 0, 0, 75 };
3794 else
3795 frameShadowColor = tint_color(base, 1.33);
3796
3797 frameShadowColor = tint_color(frameShadowColor, 1.5);
3798 } else {
3799 if ((flags & B_BLEND_FRAME) != 0)
3800 frameShadowColor = (rgb_color){ 0, 0, 0, 95 };
3801 else
3802 frameShadowColor = tint_color(base, 1.47);
3803 }
3804 }
3805
3806 return frameShadowColor;
3807 }
3808
3809
3810 rgb_color
_BevelLightColor(const rgb_color & base,uint32 flags)3811 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags)
3812 {
3813 rgb_color bevelLightColor = tint_color(base, 0.2);
3814
3815 if ((flags & B_DISABLED) != 0)
3816 bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT);
3817
3818 if ((flags & B_ACTIVATED) != 0)
3819 bevelLightColor = tint_color(base, B_DARKEN_1_TINT);
3820
3821 return bevelLightColor;
3822 }
3823
3824
3825 rgb_color
_BevelShadowColor(const rgb_color & base,uint32 flags)3826 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags)
3827 {
3828 rgb_color bevelShadowColor = tint_color(base, 1.08);
3829
3830 if ((flags & B_DISABLED) != 0)
3831 bevelShadowColor = base;
3832
3833 if ((flags & B_ACTIVATED) != 0)
3834 bevelShadowColor = tint_color(base, B_DARKEN_1_TINT);
3835
3836 return bevelShadowColor;
3837 }
3838
3839
3840 void
_FillGradient(BView * view,const BRect & rect,const rgb_color & base,float topTint,float bottomTint,orientation orientation)3841 HaikuControlLook::_FillGradient(BView* view, const BRect& rect,
3842 const rgb_color& base, float topTint, float bottomTint,
3843 orientation orientation)
3844 {
3845 BGradientLinear gradient;
3846 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3847 view->FillRect(rect, gradient);
3848 }
3849
3850
3851 void
_FillGlossyGradient(BView * view,const BRect & rect,const rgb_color & base,float topTint,float middle1Tint,float middle2Tint,float bottomTint,orientation orientation)3852 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect,
3853 const rgb_color& base, float topTint, float middle1Tint,
3854 float middle2Tint, float bottomTint, orientation orientation)
3855 {
3856 BGradientLinear gradient;
3857 _MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint,
3858 middle2Tint, bottomTint, orientation);
3859 view->FillRect(rect, gradient);
3860 }
3861
3862
3863 void
_MakeGradient(BGradientLinear & gradient,const BRect & rect,const rgb_color & base,float topTint,float bottomTint,orientation orientation) const3864 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
3865 const rgb_color& base, float topTint, float bottomTint,
3866 orientation orientation) const
3867 {
3868 gradient.AddColor(tint_color(base, topTint), 0);
3869 gradient.AddColor(tint_color(base, bottomTint), 255);
3870 gradient.SetStart(rect.LeftTop());
3871 if (orientation == B_HORIZONTAL)
3872 gradient.SetEnd(rect.LeftBottom());
3873 else
3874 gradient.SetEnd(rect.RightTop());
3875 }
3876
3877
3878 void
_MakeGlossyGradient(BGradientLinear & gradient,const BRect & rect,const rgb_color & base,float topTint,float middle1Tint,float middle2Tint,float bottomTint,orientation orientation) const3879 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
3880 const rgb_color& base, float topTint, float middle1Tint,
3881 float middle2Tint, float bottomTint,
3882 orientation orientation) const
3883 {
3884 gradient.AddColor(tint_color(base, topTint), 0);
3885 gradient.AddColor(tint_color(base, middle1Tint), 132);
3886 gradient.AddColor(tint_color(base, middle2Tint), 136);
3887 gradient.AddColor(tint_color(base, bottomTint), 255);
3888 gradient.SetStart(rect.LeftTop());
3889 if (orientation == B_HORIZONTAL)
3890 gradient.SetEnd(rect.LeftBottom());
3891 else
3892 gradient.SetEnd(rect.RightTop());
3893 }
3894
3895
3896 void
_MakeButtonGradient(BGradientLinear & gradient,BRect & rect,const rgb_color & base,uint32 flags,orientation orientation) const3897 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect,
3898 const rgb_color& base, uint32 flags, orientation orientation) const
3899 {
3900 float topTint = 0.49;
3901 float middleTint1 = 0.62;
3902 float middleTint2 = 0.76;
3903 float bottomTint = 0.90;
3904
3905 if ((flags & B_ACTIVATED) != 0) {
3906 topTint = 1.11;
3907 bottomTint = 1.08;
3908 }
3909
3910 if ((flags & B_DISABLED) != 0) {
3911 topTint = (topTint + B_NO_TINT) / 2;
3912 middleTint1 = (middleTint1 + B_NO_TINT) / 2;
3913 middleTint2 = (middleTint2 + B_NO_TINT) / 2;
3914 bottomTint = (bottomTint + B_NO_TINT) / 2;
3915 } else if ((flags & B_HOVER) != 0) {
3916 topTint *= kHoverTintFactor;
3917 middleTint1 *= kHoverTintFactor;
3918 middleTint2 *= kHoverTintFactor;
3919 bottomTint *= kHoverTintFactor;
3920 }
3921
3922 if ((flags & B_ACTIVATED) != 0) {
3923 _MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3924 } else {
3925 _MakeGlossyGradient(gradient, rect, base, topTint, middleTint1,
3926 middleTint2, bottomTint, orientation);
3927 }
3928 }
3929
3930
3931 bool
_RadioButtonAndCheckBoxMarkColor(const rgb_color & base,rgb_color & color,uint32 flags) const3932 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
3933 rgb_color& color, uint32 flags) const
3934 {
3935 if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) {
3936 // no mark to be drawn at all
3937 return false;
3938 }
3939
3940 color = ui_color(B_CONTROL_MARK_COLOR);
3941
3942 float mix = 1.0;
3943
3944 if ((flags & B_DISABLED) != 0) {
3945 // activated, but disabled
3946 mix = 0.4;
3947 } else if ((flags & B_CLICKED) != 0) {
3948 if ((flags & B_ACTIVATED) != 0) {
3949 // losing activation
3950 mix = 0.7;
3951 } else {
3952 // becoming activated (or losing partial activation)
3953 mix = 0.3;
3954 }
3955 } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) {
3956 // partially activated
3957 mix = 0.5;
3958 } else {
3959 // simply activated
3960 }
3961
3962 color.red = uint8(color.red * mix + base.red * (1.0 - mix));
3963 color.green = uint8(color.green * mix + base.green * (1.0 - mix));
3964 color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix));
3965
3966 return true;
3967 }
3968
3969 } // namespace BPrivate
3970