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