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