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