xref: /haiku/src/kits/interface/HaikuControlLook.cpp (revision 1f52c921e27aa442370e1bd4adc021acf2b78b64)
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 (base.red + base.green + base.blue <= 128 * 3) {
1729 		scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT);
1730 	}
1731 
1732 	if ((flags & B_FOCUSED) != 0)
1733 		scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1734 
1735 	if (borderStyle == B_FANCY_BORDER)
1736 		_DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
1737 
1738 	_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
1739 		scrollbarFrameColor, scrollbarFrameColor, borders);
1740 }
1741 
1742 
1743 void
1744 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect,
1745 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1746 	uint32 borders)
1747 {
1748 	rgb_color lightColor;
1749 	rgb_color shadowColor;
1750 
1751 	if ((flags & B_DISABLED) != 0) {
1752 		lightColor = base;
1753 		shadowColor = base;
1754 	} else {
1755 		lightColor = tint_color(base, 0.85);
1756 		shadowColor = tint_color(base, 1.07);
1757 	}
1758 
1759 	_DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor,
1760 		borders);
1761 }
1762 
1763 
1764 void
1765 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect,
1766 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1767 	uint32 borders)
1768 {
1769 	if (!rect.Intersects(updateRect))
1770 		return;
1771 
1772 	rgb_color dark1BorderColor;
1773 	rgb_color dark2BorderColor;
1774 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1775 	rgb_color invalidColor = ui_color(B_FAILURE_COLOR);
1776 
1777 	if ((flags & B_DISABLED) != 0) {
1778 		_DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders);
1779 
1780 		if ((flags & B_BLEND_FRAME) != 0)
1781 			dark1BorderColor = (rgb_color){ 0, 0, 0, 40 };
1782 		else
1783 			dark1BorderColor = tint_color(base, 1.15);
1784 		dark2BorderColor = dark1BorderColor;
1785 	} else if ((flags & B_CLICKED) != 0) {
1786 		dark1BorderColor = tint_color(base, 1.50);
1787 		dark2BorderColor = tint_color(base, 1.49);
1788 
1789 		// BCheckBox uses this to indicate the clicked state...
1790 		_DrawFrame(view, rect,
1791 			dark1BorderColor, dark1BorderColor,
1792 			dark2BorderColor, dark2BorderColor);
1793 
1794 		dark2BorderColor = dark1BorderColor;
1795 	} else {
1796 		_DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders);
1797 
1798 		if ((flags & B_BLEND_FRAME) != 0) {
1799 			dark1BorderColor = (rgb_color){ 0, 0, 0, 102 };
1800 			dark2BorderColor = (rgb_color){ 0, 0, 0, 97 };
1801 		} else {
1802 			dark1BorderColor = tint_color(base, 1.40);
1803 			dark2BorderColor = tint_color(base, 1.38);
1804 		}
1805 	}
1806 
1807 	if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) {
1808 		dark1BorderColor = navigationColor;
1809 		dark2BorderColor = navigationColor;
1810 	}
1811 
1812 	if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) {
1813 		dark1BorderColor = invalidColor;
1814 		dark2BorderColor = invalidColor;
1815 	}
1816 
1817 	if ((flags & B_BLEND_FRAME) != 0) {
1818 		drawing_mode oldMode = view->DrawingMode();
1819 		view->SetDrawingMode(B_OP_ALPHA);
1820 
1821 		_DrawFrame(view, rect,
1822 			dark1BorderColor, dark1BorderColor,
1823 			dark2BorderColor, dark2BorderColor, borders);
1824 
1825 		view->SetDrawingMode(oldMode);
1826 	} else {
1827 		_DrawFrame(view, rect,
1828 			dark1BorderColor, dark1BorderColor,
1829 			dark2BorderColor, dark2BorderColor, borders);
1830 	}
1831 }
1832 
1833 
1834 void
1835 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
1836 	const rgb_color& base, uint32 borders)
1837 {
1838 	rgb_color frameColor = tint_color(base, 1.30);
1839 	rgb_color bevelLight = tint_color(base, 0.8);
1840 	rgb_color bevelShadow = tint_color(base, 1.03);
1841 
1842 	_DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight,
1843 		borders);
1844 
1845 	_DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor,
1846 		borders);
1847 
1848 	_DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow,
1849 		borders);
1850 }
1851 
1852 
1853 void
1854 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
1855 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1856 	const rgb_color* textColor)
1857 {
1858 	DrawLabel(view, label, NULL, rect, updateRect, base, flags,
1859 		DefaultLabelAlignment(), textColor);
1860 }
1861 
1862 
1863 void
1864 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
1865 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1866 	const BAlignment& alignment, const rgb_color* textColor)
1867 {
1868 	DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment,
1869 		textColor);
1870 }
1871 
1872 
1873 void
1874 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base,
1875 	uint32 flags, const BPoint& where, const rgb_color* textColor)
1876 {
1877 	// setup the text color
1878 
1879 	BWindow* window = view->Window();
1880 	bool isDesktop = window
1881 		&& window->Feel() == kDesktopWindowFeel
1882 		&& window->Look() == kDesktopWindowLook
1883 		&& view->Parent()
1884 		&& view->Parent()->Parent() == NULL
1885 		&& (flags & B_IGNORE_OUTLINE) == 0;
1886 
1887 	rgb_color low;
1888 	rgb_color color;
1889 	rgb_color glowColor;
1890 
1891 	if (textColor != NULL)
1892 		glowColor = *textColor;
1893 	else if ((flags & B_IS_CONTROL) != 0)
1894 		glowColor = ui_color(B_CONTROL_TEXT_COLOR);
1895 	else
1896 		glowColor = ui_color(B_PANEL_TEXT_COLOR);
1897 
1898 	color = glowColor;
1899 
1900 	if (isDesktop)
1901 		low = view->Parent()->ViewColor();
1902 	else
1903 		low = base;
1904 
1905 	if ((flags & B_DISABLED) != 0) {
1906 		color.red = (uint8)(((int32)low.red + color.red + 1) / 2);
1907 		color.green = (uint8)(((int32)low.green + color.green + 1) / 2);
1908 		color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2);
1909 	}
1910 
1911 	drawing_mode oldMode = view->DrawingMode();
1912 
1913 	if (isDesktop) {
1914 		// enforce proper use of desktop label colors
1915 		if (low.Brightness() < 100) {
1916 			if (textColor == NULL)
1917 				color = make_color(255, 255, 255);
1918 
1919 			glowColor = make_color(0, 0, 0);
1920 		} else {
1921 			if (textColor == NULL)
1922 				color = make_color(0, 0, 0);
1923 
1924 			glowColor = make_color(255, 255, 255);
1925 		}
1926 
1927 		// drawing occurs on the desktop
1928 		if (fCachedWorkspace != current_workspace()) {
1929 			int8 indice = 0;
1930 			int32 mask;
1931 			bool tmpOutline;
1932 			while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces",
1933 					indice, &mask) == B_OK
1934 				&& fBackgroundInfo.FindBool("be:bgndimginfoerasetext",
1935 					indice, &tmpOutline) == B_OK) {
1936 
1937 				if (((1 << current_workspace()) & mask) != 0) {
1938 					fCachedOutline = tmpOutline;
1939 					fCachedWorkspace = current_workspace();
1940 					break;
1941 				}
1942 				indice++;
1943 			}
1944 		}
1945 
1946 		if (fCachedOutline) {
1947 			BFont font;
1948 			view->GetFont(&font);
1949 
1950 			view->SetDrawingMode(B_OP_ALPHA);
1951 			view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
1952 			// Draw glow or outline
1953 			if (glowColor.Brightness() > 128) {
1954 				font.SetFalseBoldWidth(2.0);
1955 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
1956 
1957 				glowColor.alpha = 30;
1958 				view->SetHighColor(glowColor);
1959 				view->DrawString(label, where);
1960 
1961 				font.SetFalseBoldWidth(1.0);
1962 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
1963 
1964 				glowColor.alpha = 65;
1965 				view->SetHighColor(glowColor);
1966 				view->DrawString(label, where);
1967 
1968 				font.SetFalseBoldWidth(0.0);
1969 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
1970 			} else {
1971 				font.SetFalseBoldWidth(1.0);
1972 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
1973 
1974 				glowColor.alpha = 30;
1975 				view->SetHighColor(glowColor);
1976 				view->DrawString(label, where);
1977 
1978 				font.SetFalseBoldWidth(0.0);
1979 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
1980 
1981 				glowColor.alpha = 200;
1982 				view->SetHighColor(glowColor);
1983 				view->DrawString(label, BPoint(where.x + 1, where.y + 1));
1984 			}
1985 		}
1986 	}
1987 
1988 	view->SetHighColor(color);
1989 	view->SetDrawingMode(B_OP_OVER);
1990 	view->DrawString(label, where);
1991 	view->SetDrawingMode(oldMode);
1992 }
1993 
1994 
1995 void
1996 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon,
1997 	BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags,
1998 	const BAlignment& alignment, const rgb_color* textColor)
1999 {
2000 	if (!rect.Intersects(updateRect))
2001 		return;
2002 
2003 	if (label == NULL && icon == NULL)
2004 		return;
2005 
2006 	if (label == NULL) {
2007 		// icon only
2008 		BRect alignedRect = BLayoutUtils::AlignInFrame(rect,
2009 			icon->Bounds().Size(), alignment);
2010 		drawing_mode oldMode = view->DrawingMode();
2011 		view->SetDrawingMode(B_OP_OVER);
2012 		view->DrawBitmap(icon, alignedRect.LeftTop());
2013 		view->SetDrawingMode(oldMode);
2014 		return;
2015 	}
2016 
2017 	// label, possibly with icon
2018 	float availableWidth = rect.Width() + 1;
2019 	float width = 0;
2020 	float textOffset = 0;
2021 	float height = 0;
2022 
2023 	if (icon != NULL) {
2024 		width = icon->Bounds().Width() + DefaultLabelSpacing() + 1;
2025 		height = icon->Bounds().Height() + 1;
2026 		textOffset = width;
2027 		availableWidth -= textOffset;
2028 	}
2029 
2030 	// truncate the label if necessary and get the width and height
2031 	BString truncatedLabel(label);
2032 
2033 	BFont font;
2034 	view->GetFont(&font);
2035 
2036 	font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth);
2037 	width += ceilf(font.StringWidth(truncatedLabel.String()));
2038 
2039 	font_height fontHeight;
2040 	font.GetHeight(&fontHeight);
2041 	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
2042 	height = std::max(height, textHeight);
2043 
2044 	// handle alignment
2045 	BRect alignedRect(BLayoutUtils::AlignOnRect(rect,
2046 		BSize(width - 1, height - 1), alignment));
2047 
2048 	if (icon != NULL) {
2049 		BPoint location(alignedRect.LeftTop());
2050 		if (icon->Bounds().Height() + 1 < height)
2051 			location.y += ceilf((height - icon->Bounds().Height() - 1) / 2);
2052 
2053 		drawing_mode oldMode = view->DrawingMode();
2054 		view->SetDrawingMode(B_OP_OVER);
2055 		view->DrawBitmap(icon, location);
2056 		view->SetDrawingMode(oldMode);
2057 	}
2058 
2059 	BPoint location(alignedRect.left + textOffset,
2060 		alignedRect.top + ceilf(fontHeight.ascent));
2061 	if (textHeight < height)
2062 		location.y += ceilf((height - textHeight) / 2);
2063 
2064 	DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor);
2065 }
2066 
2067 
2068 void
2069 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left,
2070 	float& _top, float& _right, float& _bottom)
2071 {
2072 	// All frames have the same inset on each side.
2073 	float inset = 0;
2074 
2075 	switch (frameType) {
2076 		case B_BUTTON_FRAME:
2077 			inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2;
2078 			break;
2079 		case B_GROUP_FRAME:
2080 		case B_MENU_FIELD_FRAME:
2081 			inset = 3;
2082 			break;
2083 		case B_SCROLL_VIEW_FRAME:
2084 		case B_TEXT_CONTROL_FRAME:
2085 			inset = 2;
2086 			break;
2087 	}
2088 
2089 	_left = inset;
2090 	_top = inset;
2091 	_right = inset;
2092 	_bottom = inset;
2093 }
2094 
2095 
2096 void
2097 HaikuControlLook::GetBackgroundInsets(background_type backgroundType,
2098 	uint32 flags, float& _left, float& _top, float& _right, float& _bottom)
2099 {
2100 	// Most backgrounds have the same inset on each side.
2101 	float inset = 0;
2102 
2103 	switch (backgroundType) {
2104 		case B_BUTTON_BACKGROUND:
2105 		case B_MENU_BACKGROUND:
2106 		case B_MENU_BAR_BACKGROUND:
2107 		case B_MENU_FIELD_BACKGROUND:
2108 		case B_MENU_ITEM_BACKGROUND:
2109 			inset = 1;
2110 			break;
2111 		case B_BUTTON_WITH_POP_UP_BACKGROUND:
2112 			_left = 1;
2113 			_top = 1;
2114 			_right = 1 + kButtonPopUpIndicatorWidth;
2115 			_bottom = 1;
2116 			return;
2117 		case B_HORIZONTAL_SCROLL_BAR_BACKGROUND:
2118 			_left = 2;
2119 			_top = 0;
2120 			_right = 1;
2121 			_bottom = 0;
2122 			return;
2123 		case B_VERTICAL_SCROLL_BAR_BACKGROUND:
2124 			_left = 0;
2125 			_top = 2;
2126 			_right = 0;
2127 			_bottom = 1;
2128 			return;
2129 	}
2130 
2131 	_left = inset;
2132 	_top = inset;
2133 	_right = inset;
2134 	_bottom = inset;
2135 }
2136 
2137 
2138 void
2139 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2140 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2141 	uint32 borders, orientation orientation)
2142 {
2143 	_DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
2144 		base, true, flags, borders, orientation);
2145 }
2146 
2147 
2148 void
2149 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2150 	const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
2151 	uint32 borders, orientation orientation)
2152 {
2153 	_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
2154 		radius, base, true, flags, borders, orientation);
2155 }
2156 
2157 
2158 void
2159 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2160 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2161 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2162 	uint32 flags, uint32 borders, orientation orientation)
2163 {
2164 	_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
2165 		rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
2166 		borders, orientation);
2167 }
2168 
2169 
2170 // #pragma mark -
2171 
2172 
2173 void
2174 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect,
2175 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2176 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2177 	const rgb_color& background, float contrast, float brightness,
2178 	uint32 flags, uint32 borders)
2179 {
2180 	if (!rect.IsValid())
2181 		return;
2182 
2183 	// save the clipping constraints of the view
2184 	view->PushState();
2185 
2186 	// set clipping constraints to updateRect
2187 	BRegion clipping(updateRect);
2188 	view->ConstrainClippingRegion(&clipping);
2189 
2190 	// If the button is flat and neither activated nor otherwise highlighted
2191 	// (mouse hovering or focussed), draw it flat.
2192 	if ((flags & B_FLAT) != 0
2193 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2194 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2195 			|| (flags & B_DISABLED) != 0)) {
2196 		_DrawFrame(view, rect, background, background, background,
2197 			background, borders);
2198 		_DrawFrame(view, rect, background, background, background,
2199 			background, borders);
2200 		view->PopState();
2201 		return;
2202 	}
2203 
2204 	// outer edge colors
2205 	rgb_color edgeLightColor;
2206 	rgb_color edgeShadowColor;
2207 
2208 	// default button frame color
2209 	rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR);
2210 	rgb_color cornerBgColor;
2211 
2212 	if ((flags & B_DISABLED) != 0) {
2213 		defaultIndicatorColor = disable_color(defaultIndicatorColor,
2214 			background);
2215 	}
2216 
2217 	drawing_mode oldMode = view->DrawingMode();
2218 
2219 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2220 		cornerBgColor = defaultIndicatorColor;
2221 		edgeLightColor = _EdgeLightColor(defaultIndicatorColor,
2222 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2223 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2224 		edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor,
2225 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2226 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2227 
2228 		// draw default button indicator
2229 		// Allow a 1-pixel border of the background to come through.
2230 		rect.InsetBy(1, 1);
2231 
2232 		view->SetHighColor(defaultIndicatorColor);
2233 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2234 		rect.InsetBy(1, 1);
2235 
2236 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2237 		rect.InsetBy(1, 1);
2238 	} else {
2239 		cornerBgColor = background;
2240 		if ((flags & B_BLEND_FRAME) != 0) {
2241 			// set the background color to transparent for the case
2242 			// that we are on the desktop
2243 			cornerBgColor.alpha = 0;
2244 			view->SetDrawingMode(B_OP_ALPHA);
2245 		}
2246 
2247 		edgeLightColor = _EdgeLightColor(background,
2248 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2249 			brightness * 1.0, flags);
2250 		edgeShadowColor = _EdgeShadowColor(background,
2251 			contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0,
2252 			brightness * 1.0, flags);
2253 	}
2254 
2255 	// frame colors
2256 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
2257 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
2258 
2259 	// rounded corners
2260 
2261 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2262 		&& leftTopRadius > 0) {
2263 		// draw left top rounded corner
2264 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2265 			floorf(rect.left + leftTopRadius),
2266 			floorf(rect.top + leftTopRadius));
2267 		clipping.Exclude(leftTopCorner);
2268 		_DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect,
2269 			cornerBgColor, edgeShadowColor, frameLightColor);
2270 	}
2271 
2272 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2273 		&& rightTopRadius > 0) {
2274 		// draw right top rounded corner
2275 		BRect rightTopCorner(floorf(rect.right - rightTopRadius),
2276 			floorf(rect.top), floorf(rect.right),
2277 			floorf(rect.top + rightTopRadius));
2278 		clipping.Exclude(rightTopCorner);
2279 		_DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect,
2280 			cornerBgColor, edgeShadowColor, edgeLightColor,
2281 			frameLightColor, frameShadowColor);
2282 	}
2283 
2284 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2285 		&& leftBottomRadius > 0) {
2286 		// draw left bottom rounded corner
2287 		BRect leftBottomCorner(floorf(rect.left),
2288 			floorf(rect.bottom - leftBottomRadius),
2289 			floorf(rect.left + leftBottomRadius), floorf(rect.bottom));
2290 		clipping.Exclude(leftBottomCorner);
2291 		_DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect,
2292 			cornerBgColor, edgeShadowColor, edgeLightColor,
2293 			frameLightColor, frameShadowColor);
2294 	}
2295 
2296 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2297 		&& rightBottomRadius > 0) {
2298 		// draw right bottom rounded corner
2299 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius),
2300 			floorf(rect.bottom - rightBottomRadius), floorf(rect.right),
2301 			floorf(rect.bottom));
2302 		clipping.Exclude(rightBottomCorner);
2303 		_DrawRoundCornerFrameRightBottom(view, rightBottomCorner,
2304 			updateRect, cornerBgColor, edgeLightColor, frameShadowColor);
2305 	}
2306 
2307 	// clip out the corners
2308 	view->ConstrainClippingRegion(&clipping);
2309 
2310 	// draw outer edge
2311 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2312 		_DrawOuterResessedFrame(view, rect, defaultIndicatorColor,
2313 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2314 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9),
2315 			flags, borders);
2316 	} else {
2317 		_DrawOuterResessedFrame(view, rect, background,
2318 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2319 			brightness * 1.0, flags, borders);
2320 	}
2321 
2322 	view->SetDrawingMode(oldMode);
2323 
2324 	// draw frame
2325 	if ((flags & B_BLEND_FRAME) != 0) {
2326 		drawing_mode oldDrawingMode = view->DrawingMode();
2327 		view->SetDrawingMode(B_OP_ALPHA);
2328 
2329 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2330 			frameShadowColor, frameShadowColor, borders);
2331 
2332 		view->SetDrawingMode(oldDrawingMode);
2333 	} else {
2334 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2335 			frameShadowColor, frameShadowColor, borders);
2336 	}
2337 
2338 	// restore the clipping constraints of the view
2339 	view->PopState();
2340 }
2341 
2342 
2343 void
2344 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
2345 	const rgb_color& base, float contrast, float brightness, uint32 flags,
2346 	uint32 borders)
2347 {
2348 	rgb_color edgeLightColor = _EdgeLightColor(base, contrast,
2349 		brightness, flags);
2350 	rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast,
2351 		brightness, flags);
2352 
2353 	if ((flags & B_BLEND_FRAME) != 0) {
2354 		// assumes the background has already been painted
2355 		drawing_mode oldDrawingMode = view->DrawingMode();
2356 		view->SetDrawingMode(B_OP_ALPHA);
2357 
2358 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2359 			edgeLightColor, edgeLightColor, borders);
2360 
2361 		view->SetDrawingMode(oldDrawingMode);
2362 	} else {
2363 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2364 			edgeLightColor, edgeLightColor, borders);
2365 	}
2366 }
2367 
2368 
2369 void
2370 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2371 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2372 	uint32 borders)
2373 {
2374 	view->BeginLineArray(4);
2375 
2376 	if (borders & B_LEFT_BORDER) {
2377 		view->AddLine(
2378 			BPoint(rect.left, rect.bottom),
2379 			BPoint(rect.left, rect.top), left);
2380 		rect.left++;
2381 	}
2382 	if (borders & B_TOP_BORDER) {
2383 		view->AddLine(
2384 			BPoint(rect.left, rect.top),
2385 			BPoint(rect.right, rect.top), top);
2386 		rect.top++;
2387 	}
2388 	if (borders & B_RIGHT_BORDER) {
2389 		view->AddLine(
2390 			BPoint(rect.right, rect.top),
2391 			BPoint(rect.right, rect.bottom), right);
2392 		rect.right--;
2393 	}
2394 	if (borders & B_BOTTOM_BORDER) {
2395 		view->AddLine(
2396 			BPoint(rect.left, rect.bottom),
2397 			BPoint(rect.right, rect.bottom), bottom);
2398 		rect.bottom--;
2399 	}
2400 
2401 	view->EndLineArray();
2402 }
2403 
2404 
2405 void
2406 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2407 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2408 	const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders)
2409 {
2410 	view->BeginLineArray(6);
2411 
2412 	if (borders & B_TOP_BORDER) {
2413 		if (borders & B_RIGHT_BORDER) {
2414 			view->AddLine(
2415 				BPoint(rect.left, rect.top),
2416 				BPoint(rect.right - 1, rect.top), top);
2417 			view->AddLine(
2418 				BPoint(rect.right, rect.top),
2419 				BPoint(rect.right, rect.top), rightTop);
2420 		} else {
2421 			view->AddLine(
2422 				BPoint(rect.left, rect.top),
2423 				BPoint(rect.right, rect.top), top);
2424 		}
2425 		rect.top++;
2426 	}
2427 
2428 	if (borders & B_LEFT_BORDER) {
2429 		view->AddLine(
2430 			BPoint(rect.left, rect.top),
2431 			BPoint(rect.left, rect.bottom - 1), left);
2432 		view->AddLine(
2433 			BPoint(rect.left, rect.bottom),
2434 			BPoint(rect.left, rect.bottom), leftBottom);
2435 		rect.left++;
2436 	}
2437 
2438 	if (borders & B_BOTTOM_BORDER) {
2439 		view->AddLine(
2440 			BPoint(rect.left, rect.bottom),
2441 			BPoint(rect.right, rect.bottom), bottom);
2442 		rect.bottom--;
2443 	}
2444 
2445 	if (borders & B_RIGHT_BORDER) {
2446 		view->AddLine(
2447 			BPoint(rect.right, rect.bottom),
2448 			BPoint(rect.right, rect.top), right);
2449 		rect.right--;
2450 	}
2451 
2452 	view->EndLineArray();
2453 }
2454 
2455 
2456 void
2457 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect,
2458 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2459 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2460 	bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
2461 {
2462 	if (!rect.IsValid())
2463 		return;
2464 
2465 	// save the clipping constraints of the view
2466 	view->PushState();
2467 
2468 	// set clipping constraints to updateRect
2469 	BRegion clipping(updateRect);
2470 	view->ConstrainClippingRegion(&clipping);
2471 
2472 	// If the button is flat and neither activated nor otherwise highlighted
2473 	// (mouse hovering or focussed), draw it flat.
2474 	if ((flags & B_FLAT) != 0
2475 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2476 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2477 			|| (flags & B_DISABLED) != 0)) {
2478 		_DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator,
2479 			flags, borders, orientation);
2480 	} else {
2481 		_DrawNonFlatButtonBackground(view, rect, updateRect, clipping,
2482 			leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius,
2483 			base, popupIndicator, flags, borders, orientation);
2484 	}
2485 
2486 	// restore the clipping constraints of the view
2487 	view->PopState();
2488 }
2489 
2490 
2491 void
2492 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect,
2493 	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
2494 	uint32 flags, uint32 borders, orientation orientation)
2495 {
2496 	_DrawFrame(view, rect, base, base, base, base, borders);
2497 		// Not an actual frame, but the method insets our rect as needed.
2498 
2499 	view->SetHighColor(base);
2500 	view->FillRect(rect);
2501 
2502 	if (popupIndicator) {
2503 		BRect indicatorRect(rect);
2504 		rect.right -= kButtonPopUpIndicatorWidth;
2505 		indicatorRect.left = rect.right + 3;
2506 			// 2 pixels for the separator
2507 
2508 		view->SetHighColor(base);
2509 		view->FillRect(indicatorRect);
2510 
2511 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2512 	}
2513 }
2514 
2515 
2516 void
2517 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect,
2518 	const BRect& updateRect, BRegion& clipping, float leftTopRadius,
2519 	float rightTopRadius, float leftBottomRadius, float rightBottomRadius,
2520 	const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders,
2521 	orientation orientation)
2522 {
2523 	// inner bevel colors
2524 	rgb_color bevelLightColor  = _BevelLightColor(base, flags);
2525 	rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
2526 
2527 	// button background color
2528 	rgb_color buttonBgColor;
2529 	if ((flags & B_DISABLED) != 0)
2530 		buttonBgColor = tint_color(base, 0.7);
2531 	else
2532 		buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT);
2533 
2534 	// surface top gradient
2535 	BGradientLinear fillGradient;
2536 	_MakeButtonGradient(fillGradient, rect, base, flags, orientation);
2537 
2538 	// rounded corners
2539 
2540 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2541 		&& leftTopRadius > 0) {
2542 		// draw left top rounded corner
2543 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2544 			floorf(rect.left + leftTopRadius - 2.0),
2545 			floorf(rect.top + leftTopRadius - 2.0));
2546 		clipping.Exclude(leftTopCorner);
2547 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
2548 			bevelLightColor, fillGradient);
2549 	}
2550 
2551 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2552 		&& rightTopRadius > 0) {
2553 		// draw right top rounded corner
2554 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
2555 			floorf(rect.top), floorf(rect.right),
2556 			floorf(rect.top + rightTopRadius - 2.0));
2557 		clipping.Exclude(rightTopCorner);
2558 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner,
2559 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2560 	}
2561 
2562 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2563 		&& leftBottomRadius > 0) {
2564 		// draw left bottom rounded corner
2565 		BRect leftBottomCorner(floorf(rect.left),
2566 			floorf(rect.bottom - leftBottomRadius + 2.0),
2567 			floorf(rect.left + leftBottomRadius - 2.0),
2568 			floorf(rect.bottom));
2569 		clipping.Exclude(leftBottomCorner);
2570 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
2571 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2572 	}
2573 
2574 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2575 		&& rightBottomRadius > 0) {
2576 		// draw right bottom rounded corner
2577 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
2578 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
2579 			floorf(rect.bottom));
2580 		clipping.Exclude(rightBottomCorner);
2581 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
2582 			updateRect, bevelShadowColor, fillGradient);
2583 	}
2584 
2585 	// clip out the corners
2586 	view->ConstrainClippingRegion(&clipping);
2587 
2588 	// draw inner bevel
2589 
2590 	if ((flags & B_ACTIVATED) != 0) {
2591 		view->BeginLineArray(4);
2592 
2593 		// shadow along left/top borders
2594 		if (borders & B_LEFT_BORDER) {
2595 			view->AddLine(BPoint(rect.left, rect.top),
2596 				BPoint(rect.left, rect.bottom), bevelLightColor);
2597 			rect.left++;
2598 		}
2599 		if (borders & B_TOP_BORDER) {
2600 			view->AddLine(BPoint(rect.left, rect.top),
2601 				BPoint(rect.right, rect.top), bevelLightColor);
2602 			rect.top++;
2603 		}
2604 
2605 		// softer shadow along left/top borders
2606 		if (borders & B_LEFT_BORDER) {
2607 			view->AddLine(BPoint(rect.left, rect.top),
2608 				BPoint(rect.left, rect.bottom), bevelShadowColor);
2609 			rect.left++;
2610 		}
2611 		if (borders & B_TOP_BORDER) {
2612 			view->AddLine(BPoint(rect.left, rect.top),
2613 				BPoint(rect.right, rect.top), bevelShadowColor);
2614 			rect.top++;
2615 		}
2616 
2617 		view->EndLineArray();
2618 	} else {
2619 		_DrawFrame(view, rect,
2620 			bevelLightColor, bevelLightColor,
2621 			bevelShadowColor, bevelShadowColor,
2622 			buttonBgColor, buttonBgColor, borders);
2623 	}
2624 
2625 	if (popupIndicator) {
2626 		BRect indicatorRect(rect);
2627 		rect.right -= kButtonPopUpIndicatorWidth;
2628 		indicatorRect.left = rect.right + 3;
2629 			// 2 pixels for the separator
2630 
2631 		// Even when depressed we want the pop-up indicator background and
2632 		// separator to cover the area up to the top.
2633 		if ((flags & B_ACTIVATED) != 0)
2634 			indicatorRect.top--;
2635 
2636 		// draw the separator
2637 		rgb_color separatorBaseColor = base;
2638 		if ((flags & B_ACTIVATED) != 0)
2639 			separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
2640 
2641 		rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor,
2642 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2643 		rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor,
2644 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2645 
2646 		view->BeginLineArray(2);
2647 
2648 		view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top),
2649 			BPoint(indicatorRect.left - 2, indicatorRect.bottom),
2650 			separatorShadowColor);
2651 		view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top),
2652 			BPoint(indicatorRect.left - 1, indicatorRect.bottom),
2653 			separatorLightColor);
2654 
2655 		view->EndLineArray();
2656 
2657 		// draw background and pop-up marker
2658 		_DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect,
2659 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0);
2660 
2661 		if ((flags & B_ACTIVATED) != 0)
2662 			indicatorRect.top++;
2663 
2664 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2665 	}
2666 
2667 	// fill in the background
2668 	view->FillRect(rect, fillGradient);
2669 }
2670 
2671 
2672 void
2673 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
2674 	const rgb_color& base, uint32 flags)
2675 {
2676 	BPoint center(roundf((rect.left + rect.right) / 2.0),
2677 		roundf((rect.top + rect.bottom) / 2.0));
2678 	BPoint triangle[3];
2679 	triangle[0] = center + BPoint(-2.5, -0.5);
2680 	triangle[1] = center + BPoint(2.5, -0.5);
2681 	triangle[2] = center + BPoint(0.0, 2.0);
2682 
2683 	uint32 viewFlags = view->Flags();
2684 	view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
2685 
2686 	rgb_color markColor;
2687 	if ((flags & B_DISABLED) != 0)
2688 		markColor = tint_color(base, 1.35);
2689 	else
2690 		markColor = tint_color(base, 1.65);
2691 
2692 	view->SetHighColor(markColor);
2693 	view->FillTriangle(triangle[0], triangle[1], triangle[2]);
2694 
2695 	view->SetFlags(viewFlags);
2696 }
2697 
2698 
2699 void
2700 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
2701 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2702 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2703 	bool popupIndicator, uint32 flags)
2704 {
2705 	if (!rect.IsValid() || !rect.Intersects(updateRect))
2706 		return;
2707 
2708 	if (popupIndicator) {
2709 		BRect leftRect(rect);
2710 		leftRect.right -= 10;
2711 
2712 		BRect rightRect(rect);
2713 		rightRect.left = rightRect.right - 9;
2714 
2715 		_DrawMenuFieldBackgroundInside(view, leftRect, updateRect,
2716 			leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags,
2717 			B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
2718 
2719 		_DrawMenuFieldBackgroundInside(view, rightRect, updateRect,
2720 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags,
2721 			B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
2722 
2723 		_DrawPopUpMarker(view, rightRect, base, flags);
2724 
2725 		// draw a line on the left of the popup frame
2726 		rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
2727 		view->SetHighColor(bevelShadowColor);
2728 		BPoint leftTopCorner(floorf(rightRect.left - 1.0),
2729 			floorf(rightRect.top - 1.0));
2730 		BPoint leftBottomCorner(floorf(rightRect.left - 1.0),
2731 			floorf(rightRect.bottom + 1.0));
2732 		view->StrokeLine(leftTopCorner, leftBottomCorner);
2733 
2734 		rect = leftRect;
2735 	} else {
2736 		_DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius,
2737 			rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags);
2738 	}
2739 }
2740 
2741 
2742 void
2743 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
2744 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2745 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2746 	uint32 flags, uint32 borders)
2747 {
2748 	if (!rect.IsValid() || !rect.Intersects(updateRect))
2749 		return;
2750 
2751 	// save the clipping constraints of the view
2752 	view->PushState();
2753 
2754 	// set clipping constraints to updateRect
2755 	BRegion clipping(updateRect);
2756 	view->ConstrainClippingRegion(&clipping);
2757 
2758 	// frame colors
2759 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
2760 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
2761 
2762 	// indicator background color
2763 	rgb_color indicatorBase;
2764 	if ((borders & B_LEFT_BORDER) != 0)
2765 		indicatorBase = base;
2766 	else {
2767 		if ((flags & B_DISABLED) != 0)
2768 			indicatorBase = tint_color(base, 1.05);
2769 		else
2770 			indicatorBase = tint_color(base, 1.12);
2771 	}
2772 
2773 	// bevel colors
2774 	rgb_color cornerColor = tint_color(indicatorBase, 0.85);
2775 	rgb_color bevelColor1 = tint_color(indicatorBase, 0.3);
2776 	rgb_color bevelColor2 = tint_color(indicatorBase, 0.5);
2777 	rgb_color bevelColor3 = tint_color(indicatorBase, 1.03);
2778 
2779 	if ((flags & B_DISABLED) != 0) {
2780 		cornerColor = tint_color(indicatorBase, 0.8);
2781 		bevelColor1 = tint_color(indicatorBase, 0.7);
2782 		bevelColor2 = tint_color(indicatorBase, 0.8);
2783 		bevelColor3 = tint_color(indicatorBase, 1.01);
2784 	} else {
2785 		cornerColor = tint_color(indicatorBase, 0.85);
2786 		bevelColor1 = tint_color(indicatorBase, 0.3);
2787 		bevelColor2 = tint_color(indicatorBase, 0.5);
2788 		bevelColor3 = tint_color(indicatorBase, 1.03);
2789 	}
2790 
2791 	// surface top gradient
2792 	BGradientLinear fillGradient;
2793 	_MakeButtonGradient(fillGradient, rect, indicatorBase, flags);
2794 
2795 	// rounded corners
2796 
2797 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2798 		&& leftTopRadius > 0) {
2799 		// draw left top rounded corner
2800 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2801 			floorf(rect.left + leftTopRadius - 2.0),
2802 			floorf(rect.top + leftTopRadius - 2.0));
2803 		clipping.Exclude(leftTopCorner);
2804 
2805 		BRegion cornerClipping(leftTopCorner);
2806 		view->ConstrainClippingRegion(&cornerClipping);
2807 
2808 		BRect ellipseRect(leftTopCorner);
2809 		ellipseRect.InsetBy(-1.0, -1.0);
2810 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
2811 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2812 
2813 		// draw the frame (again)
2814 		view->SetHighColor(frameLightColor);
2815 		view->FillEllipse(ellipseRect);
2816 
2817 		// draw the bevel and background
2818 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
2819 			bevelColor1, fillGradient);
2820 	}
2821 
2822 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2823 		&& rightTopRadius > 0) {
2824 		// draw right top rounded corner
2825 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
2826 			floorf(rect.top), floorf(rect.right),
2827 			floorf(rect.top + rightTopRadius - 2.0));
2828 		clipping.Exclude(rightTopCorner);
2829 
2830 		BRegion cornerClipping(rightTopCorner);
2831 		view->ConstrainClippingRegion(&cornerClipping);
2832 
2833 		BRect ellipseRect(rightTopCorner);
2834 		ellipseRect.InsetBy(-1.0, -1.0);
2835 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
2836 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2837 
2838 		// draw the frame (again)
2839 		if (frameLightColor == frameShadowColor) {
2840 			view->SetHighColor(frameLightColor);
2841 			view->FillEllipse(ellipseRect);
2842 		} else {
2843 			BGradientLinear gradient;
2844 			gradient.AddColor(frameLightColor, 0);
2845 			gradient.AddColor(frameShadowColor, 255);
2846 			gradient.SetStart(rightTopCorner.LeftTop());
2847 			gradient.SetEnd(rightTopCorner.RightBottom());
2848 			view->FillEllipse(ellipseRect, gradient);
2849 		}
2850 
2851 		// draw the bevel and background
2852 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect,
2853 			bevelColor1, bevelColor3, fillGradient);
2854 	}
2855 
2856 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2857 		&& leftBottomRadius > 0) {
2858 		// draw left bottom rounded corner
2859 		BRect leftBottomCorner(floorf(rect.left),
2860 			floorf(rect.bottom - leftBottomRadius + 2.0),
2861 			floorf(rect.left + leftBottomRadius - 2.0),
2862 			floorf(rect.bottom));
2863 		clipping.Exclude(leftBottomCorner);
2864 
2865 		BRegion cornerClipping(leftBottomCorner);
2866 		view->ConstrainClippingRegion(&cornerClipping);
2867 
2868 		BRect ellipseRect(leftBottomCorner);
2869 		ellipseRect.InsetBy(-1.0, -1.0);
2870 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
2871 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
2872 
2873 		// draw the frame (again)
2874 		if (frameLightColor == frameShadowColor) {
2875 			view->SetHighColor(frameLightColor);
2876 			view->FillEllipse(ellipseRect);
2877 		} else {
2878 			BGradientLinear gradient;
2879 			gradient.AddColor(frameLightColor, 0);
2880 			gradient.AddColor(frameShadowColor, 255);
2881 			gradient.SetStart(leftBottomCorner.LeftTop());
2882 			gradient.SetEnd(leftBottomCorner.RightBottom());
2883 			view->FillEllipse(ellipseRect, gradient);
2884 		}
2885 
2886 		// draw the bevel and background
2887 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
2888 			updateRect, bevelColor2, bevelColor3, fillGradient);
2889 	}
2890 
2891 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2892 		&& rightBottomRadius > 0) {
2893 		// draw right bottom rounded corner
2894 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
2895 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
2896 			floorf(rect.bottom));
2897 		clipping.Exclude(rightBottomCorner);
2898 
2899 		BRegion cornerClipping(rightBottomCorner);
2900 		view->ConstrainClippingRegion(&cornerClipping);
2901 
2902 		BRect ellipseRect(rightBottomCorner);
2903 		ellipseRect.InsetBy(-1.0, -1.0);
2904 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
2905 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
2906 
2907 		// draw the frame (again)
2908 		view->SetHighColor(frameShadowColor);
2909 		view->FillEllipse(ellipseRect);
2910 
2911 		// draw the bevel and background
2912 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
2913 			updateRect, bevelColor3, fillGradient);
2914 	}
2915 
2916 	// clip out the corners
2917 	view->ConstrainClippingRegion(&clipping);
2918 
2919 	// draw the bevel
2920 	_DrawFrame(view, rect,
2921 		bevelColor2, bevelColor1,
2922 		bevelColor3, bevelColor3,
2923 		cornerColor, cornerColor,
2924 		borders);
2925 
2926 	// fill in the background
2927 	view->FillRect(rect, fillGradient);
2928 
2929 	// restore the clipping constraints of the view
2930 	view->PopState();
2931 }
2932 
2933 
2934 void
2935 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect,
2936 	const BRect& updateRect, const rgb_color& background,
2937 	const rgb_color& edgeColor, const rgb_color& frameColor,
2938 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
2939 {
2940 	_DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect,
2941 		background, edgeColor, frameColor);
2942 	_DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect,
2943 		bevelColor, fillGradient);
2944 }
2945 
2946 
2947 void
2948 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect,
2949 	const BRect& updateRect, const rgb_color& background,
2950 	const rgb_color& edgeColor, const rgb_color& frameColor)
2951 {
2952 	// constrain clipping region to corner
2953 	BRegion clipping(cornerRect);
2954 	view->ConstrainClippingRegion(&clipping);
2955 
2956 	// background
2957 	view->SetHighColor(background);
2958 	view->FillRect(cornerRect);
2959 
2960 	// outer edge
2961 	BRect ellipseRect(cornerRect);
2962 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
2963 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2964 
2965 	view->SetHighColor(edgeColor);
2966 	view->FillEllipse(ellipseRect);
2967 
2968 	// frame
2969 	ellipseRect.InsetBy(1, 1);
2970 	cornerRect.left++;
2971 	cornerRect.top++;
2972 	view->SetHighColor(frameColor);
2973 	view->FillEllipse(ellipseRect);
2974 
2975 	// prepare for bevel
2976 	cornerRect.left++;
2977 	cornerRect.top++;
2978 }
2979 
2980 
2981 void
2982 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect,
2983 	const BRect& updateRect, const rgb_color& bevelColor,
2984 	const BGradientLinear& fillGradient)
2985 {
2986 	// constrain clipping region to corner
2987 	BRegion clipping(cornerRect);
2988 	view->ConstrainClippingRegion(&clipping);
2989 
2990 	BRect ellipseRect(cornerRect);
2991 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
2992 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2993 
2994 	// bevel
2995 	view->SetHighColor(bevelColor);
2996 	view->FillEllipse(ellipseRect);
2997 
2998 	// gradient
2999 	ellipseRect.InsetBy(1, 1);
3000 	view->FillEllipse(ellipseRect, fillGradient);
3001 }
3002 
3003 
3004 void
3005 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect,
3006 	const BRect& updateRect, const rgb_color& background,
3007 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3008 	const rgb_color& frameTopColor, const rgb_color& frameRightColor,
3009 	const rgb_color& bevelTopColor, const rgb_color& bevelRightColor,
3010 	const BGradientLinear& fillGradient)
3011 {
3012 	_DrawRoundCornerFrameRightTop(view, cornerRect, updateRect,
3013 		background, edgeTopColor, edgeRightColor, frameTopColor,
3014 		frameRightColor);
3015 	_DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect,
3016 		bevelTopColor, bevelRightColor, fillGradient);
3017 }
3018 
3019 
3020 void
3021 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect,
3022 	const BRect& updateRect, const rgb_color& background,
3023 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3024 	const rgb_color& frameTopColor, const rgb_color& frameRightColor)
3025 {
3026 	// constrain clipping region to corner
3027 	BRegion clipping(cornerRect);
3028 	view->ConstrainClippingRegion(&clipping);
3029 
3030 	// background
3031 	view->SetHighColor(background);
3032 	view->FillRect(cornerRect);
3033 
3034 	// outer edge
3035 	BRect ellipseRect(cornerRect);
3036 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3037 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3038 
3039 	BGradientLinear gradient;
3040 	gradient.AddColor(edgeTopColor, 0);
3041 	gradient.AddColor(edgeRightColor, 255);
3042 	gradient.SetStart(cornerRect.LeftTop());
3043 	gradient.SetEnd(cornerRect.RightBottom());
3044 	view->FillEllipse(ellipseRect, gradient);
3045 
3046 	// frame
3047 	ellipseRect.InsetBy(1, 1);
3048 	cornerRect.right--;
3049 	cornerRect.top++;
3050 	if (frameTopColor == frameRightColor) {
3051 		view->SetHighColor(frameTopColor);
3052 		view->FillEllipse(ellipseRect);
3053 	} else {
3054 		gradient.SetColor(0, frameTopColor);
3055 		gradient.SetColor(1, frameRightColor);
3056 		gradient.SetStart(cornerRect.LeftTop());
3057 		gradient.SetEnd(cornerRect.RightBottom());
3058 		view->FillEllipse(ellipseRect, gradient);
3059 	}
3060 
3061 	// prepare for bevel
3062 	cornerRect.right--;
3063 	cornerRect.top++;
3064 }
3065 
3066 
3067 void
3068 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect,
3069 	const BRect& updateRect, const rgb_color& bevelTopColor,
3070 	const rgb_color& bevelRightColor, const BGradientLinear& fillGradient)
3071 {
3072 	// constrain clipping region to corner
3073 	BRegion clipping(cornerRect);
3074 	view->ConstrainClippingRegion(&clipping);
3075 
3076 	BRect ellipseRect(cornerRect);
3077 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3078 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3079 
3080 	// bevel
3081 	BGradientLinear gradient;
3082 	gradient.AddColor(bevelTopColor, 0);
3083 	gradient.AddColor(bevelRightColor, 255);
3084 	gradient.SetStart(cornerRect.LeftTop());
3085 	gradient.SetEnd(cornerRect.RightBottom());
3086 	view->FillEllipse(ellipseRect, gradient);
3087 
3088 	// gradient
3089 	ellipseRect.InsetBy(1, 1);
3090 	view->FillEllipse(ellipseRect, fillGradient);
3091 }
3092 
3093 
3094 void
3095 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect,
3096 	const BRect& updateRect, const rgb_color& background,
3097 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3098 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor,
3099 	const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor,
3100 	const BGradientLinear& fillGradient)
3101 {
3102 	_DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect,
3103 		background, edgeLeftColor, edgeBottomColor, frameLeftColor,
3104 		frameBottomColor);
3105 	_DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect,
3106 		bevelLeftColor, bevelBottomColor, fillGradient);
3107 }
3108 
3109 
3110 void
3111 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect,
3112 	const BRect& updateRect, const rgb_color& background,
3113 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3114 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor)
3115 {
3116 	// constrain clipping region to corner
3117 	BRegion clipping(cornerRect);
3118 	view->ConstrainClippingRegion(&clipping);
3119 
3120 	// background
3121 	view->SetHighColor(background);
3122 	view->FillRect(cornerRect);
3123 
3124 	// outer edge
3125 	BRect ellipseRect(cornerRect);
3126 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3127 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3128 
3129 	BGradientLinear gradient;
3130 	gradient.AddColor(edgeLeftColor, 0);
3131 	gradient.AddColor(edgeBottomColor, 255);
3132 	gradient.SetStart(cornerRect.LeftTop());
3133 	gradient.SetEnd(cornerRect.RightBottom());
3134 	view->FillEllipse(ellipseRect, gradient);
3135 
3136 	// frame
3137 	ellipseRect.InsetBy(1, 1);
3138 	cornerRect.left++;
3139 	cornerRect.bottom--;
3140 	if (frameLeftColor == frameBottomColor) {
3141 		view->SetHighColor(frameLeftColor);
3142 		view->FillEllipse(ellipseRect);
3143 	} else {
3144 		gradient.SetColor(0, frameLeftColor);
3145 		gradient.SetColor(1, frameBottomColor);
3146 		gradient.SetStart(cornerRect.LeftTop());
3147 		gradient.SetEnd(cornerRect.RightBottom());
3148 		view->FillEllipse(ellipseRect, gradient);
3149 	}
3150 
3151 	// prepare for bevel
3152 	cornerRect.left++;
3153 	cornerRect.bottom--;
3154 }
3155 
3156 
3157 void
3158 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect,
3159 	const BRect& updateRect, const rgb_color& bevelLeftColor,
3160 	const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient)
3161 {
3162 	// constrain clipping region to corner
3163 	BRegion clipping(cornerRect);
3164 	view->ConstrainClippingRegion(&clipping);
3165 
3166 	BRect ellipseRect(cornerRect);
3167 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3168 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3169 
3170 	// bevel
3171 	BGradientLinear gradient;
3172 	gradient.AddColor(bevelLeftColor, 0);
3173 	gradient.AddColor(bevelBottomColor, 255);
3174 	gradient.SetStart(cornerRect.LeftTop());
3175 	gradient.SetEnd(cornerRect.RightBottom());
3176 	view->FillEllipse(ellipseRect, gradient);
3177 
3178 	// gradient
3179 	ellipseRect.InsetBy(1, 1);
3180 	view->FillEllipse(ellipseRect, fillGradient);
3181 }
3182 
3183 
3184 void
3185 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect,
3186 	const BRect& updateRect, const rgb_color& background,
3187 	const rgb_color& edgeColor, const rgb_color& frameColor,
3188 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3189 {
3190 	_DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect,
3191 		background, edgeColor, frameColor);
3192 	_DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect,
3193 		bevelColor, fillGradient);
3194 }
3195 
3196 
3197 void
3198 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect,
3199 	const BRect& updateRect, const rgb_color& background,
3200 	const rgb_color& edgeColor, const rgb_color& frameColor)
3201 {
3202 	// constrain clipping region to corner
3203 	BRegion clipping(cornerRect);
3204 	view->ConstrainClippingRegion(&clipping);
3205 
3206 	// background
3207 	view->SetHighColor(background);
3208 	view->FillRect(cornerRect);
3209 
3210 	// outer edge
3211 	BRect ellipseRect(cornerRect);
3212 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3213 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3214 
3215 	view->SetHighColor(edgeColor);
3216 	view->FillEllipse(ellipseRect);
3217 
3218 	// frame
3219 	ellipseRect.InsetBy(1, 1);
3220 	cornerRect.right--;
3221 	cornerRect.bottom--;
3222 	view->SetHighColor(frameColor);
3223 	view->FillEllipse(ellipseRect);
3224 
3225 	// prepare for bevel
3226 	cornerRect.right--;
3227 	cornerRect.bottom--;
3228 }
3229 
3230 
3231 void
3232 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view,
3233 	BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor,
3234 	const BGradientLinear& fillGradient)
3235 {
3236 	// constrain clipping region to corner
3237 	BRegion clipping(cornerRect);
3238 	view->ConstrainClippingRegion(&clipping);
3239 
3240 	BRect ellipseRect(cornerRect);
3241 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3242 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3243 
3244 	// bevel
3245 	view->SetHighColor(bevelColor);
3246 	view->FillEllipse(ellipseRect);
3247 
3248 	// gradient
3249 	ellipseRect.InsetBy(1, 1);
3250 	view->FillEllipse(ellipseRect, fillGradient);
3251 }
3252 
3253 
3254 void
3255 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect,
3256 	const BRect& updateRect,
3257 	const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor,
3258 	const rgb_color& frameLightColor, const rgb_color& frameShadowColor,
3259 	const rgb_color& fillLightColor, const rgb_color& fillShadowColor,
3260 	float leftInset, float topInset, float rightInset, float bottomInset,
3261 	orientation orientation)
3262 {
3263 	if (!rect.IsValid() || !rect.Intersects(updateRect))
3264 		return;
3265 
3266 	BGradientLinear gradient;
3267 	gradient.AddColor(edgeShadowColor, 0);
3268 	gradient.AddColor(edgeLightColor, 255);
3269 	gradient.SetStart(rect.LeftTop());
3270 	if (orientation == B_HORIZONTAL)
3271 		gradient.SetEnd(rect.LeftBottom());
3272 	else
3273 		gradient.SetEnd(rect.RightTop());
3274 
3275 	view->FillEllipse(rect, gradient);
3276 
3277 	rect.left += leftInset;
3278 	rect.top += topInset;
3279 	rect.right += rightInset;
3280 	rect.bottom += bottomInset;
3281 
3282 	gradient.MakeEmpty();
3283 	gradient.AddColor(frameShadowColor, 0);
3284 	gradient.AddColor(frameLightColor, 255);
3285 	gradient.SetStart(rect.LeftTop());
3286 	if (orientation == B_HORIZONTAL)
3287 		gradient.SetEnd(rect.LeftBottom());
3288 	else
3289 		gradient.SetEnd(rect.RightTop());
3290 
3291 	view->FillEllipse(rect, gradient);
3292 
3293 	rect.left += leftInset;
3294 	rect.top += topInset;
3295 	rect.right += rightInset;
3296 	rect.bottom += bottomInset;
3297 
3298 	gradient.MakeEmpty();
3299 	gradient.AddColor(fillShadowColor, 0);
3300 	gradient.AddColor(fillLightColor, 255);
3301 	gradient.SetStart(rect.LeftTop());
3302 	if (orientation == B_HORIZONTAL)
3303 		gradient.SetEnd(rect.LeftBottom());
3304 	else
3305 		gradient.SetEnd(rect.RightTop());
3306 
3307 	view->FillEllipse(rect, gradient);
3308 }
3309 
3310 
3311 rgb_color
3312 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast,
3313 	float brightness, uint32 flags)
3314 {
3315 	rgb_color edgeLightColor;
3316 
3317 	if ((flags & B_BLEND_FRAME) != 0) {
3318 		uint8 alpha = uint8(20 * contrast);
3319 		uint8 white = uint8(255 * brightness);
3320 
3321 		edgeLightColor = (rgb_color){ white, white, white, alpha };
3322 	} else {
3323 		// colors
3324 		float tintLight = kEdgeBevelLightTint;
3325 
3326 		if (contrast == 0.0)
3327 			tintLight = B_NO_TINT;
3328 		else if (contrast != 1.0)
3329 			tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast;
3330 
3331 		edgeLightColor = tint_color(base, tintLight);
3332 
3333 		if (brightness < 1.0) {
3334 			edgeLightColor.red = uint8(edgeLightColor.red * brightness);
3335 			edgeLightColor.green = uint8(edgeLightColor.green * brightness);
3336 			edgeLightColor.blue = uint8(edgeLightColor.blue * brightness);
3337 		}
3338 	}
3339 
3340 	return edgeLightColor;
3341 }
3342 
3343 
3344 rgb_color
3345 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast,
3346 	float brightness, uint32 flags)
3347 {
3348 	rgb_color edgeShadowColor;
3349 
3350 	if ((flags & B_BLEND_FRAME) != 0) {
3351 		uint8 alpha = uint8(20 * contrast);
3352 		edgeShadowColor = (rgb_color){ 0, 0, 0, alpha };
3353 	} else {
3354 		float tintShadow = kEdgeBevelShadowTint;
3355 
3356 		if (contrast == 0.0)
3357 			tintShadow = B_NO_TINT;
3358 		else if (contrast != 1.0)
3359 			tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast;
3360 
3361 		edgeShadowColor = tint_color(base, tintShadow);
3362 
3363 		if (brightness < 1.0) {
3364 			edgeShadowColor.red = uint8(edgeShadowColor.red * brightness);
3365 			edgeShadowColor.green = uint8(edgeShadowColor.green * brightness);
3366 			edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness);
3367 		}
3368 	}
3369 
3370 	return edgeShadowColor;
3371 }
3372 
3373 
3374 rgb_color
3375 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags)
3376 {
3377 	if ((flags & B_FOCUSED) != 0)
3378 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3379 
3380 	if ((flags & B_ACTIVATED) != 0)
3381 		return _FrameShadowColor(base, flags & ~B_ACTIVATED);
3382 
3383 	rgb_color frameLightColor;
3384 
3385 	if ((flags & B_DISABLED) != 0) {
3386 		// TODO: B_BLEND_FRAME
3387 		frameLightColor = tint_color(base, 1.145);
3388 
3389 		if ((flags & B_DEFAULT_BUTTON) != 0)
3390 			frameLightColor = tint_color(frameLightColor, 1.14);
3391 	} else {
3392 		if ((flags & B_BLEND_FRAME) != 0)
3393 			frameLightColor = (rgb_color){ 0, 0, 0, 75 };
3394 		else
3395 			frameLightColor = tint_color(base, 1.33);
3396 
3397 		if ((flags & B_DEFAULT_BUTTON) != 0)
3398 			frameLightColor = tint_color(frameLightColor, 1.35);
3399 	}
3400 
3401 	return frameLightColor;
3402 }
3403 
3404 
3405 rgb_color
3406 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags)
3407 {
3408 	if ((flags & B_FOCUSED) != 0)
3409 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3410 
3411 	if ((flags & B_ACTIVATED) != 0)
3412 		return _FrameLightColor(base, flags & ~B_ACTIVATED);
3413 
3414 	rgb_color frameShadowColor;
3415 
3416 	if ((flags & B_DISABLED) != 0) {
3417 		// TODO: B_BLEND_FRAME
3418 		frameShadowColor = tint_color(base, 1.24);
3419 
3420 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3421 			frameShadowColor = tint_color(base, 1.145);
3422 			frameShadowColor = tint_color(frameShadowColor, 1.12);
3423 		}
3424 	} else {
3425 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3426 			if ((flags & B_BLEND_FRAME) != 0)
3427 				frameShadowColor = (rgb_color){ 0, 0, 0, 75 };
3428 			else
3429 				frameShadowColor = tint_color(base, 1.33);
3430 
3431 			frameShadowColor = tint_color(frameShadowColor, 1.5);
3432 		} else {
3433 			if ((flags & B_BLEND_FRAME) != 0)
3434 				frameShadowColor = (rgb_color){ 0, 0, 0, 95 };
3435 			else
3436 				frameShadowColor = tint_color(base, 1.47);
3437 		}
3438 	}
3439 
3440 	return frameShadowColor;
3441 }
3442 
3443 
3444 rgb_color
3445 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags)
3446 {
3447 	rgb_color bevelLightColor = tint_color(base, 0.2);
3448 
3449 	if ((flags & B_DISABLED) != 0)
3450 		bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT);
3451 
3452 	if ((flags & B_ACTIVATED) != 0)
3453 		bevelLightColor = tint_color(base, B_DARKEN_1_TINT);
3454 
3455 	return bevelLightColor;
3456 }
3457 
3458 
3459 rgb_color
3460 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags)
3461 {
3462 	rgb_color bevelShadowColor = tint_color(base, 1.08);
3463 
3464 	if ((flags & B_DISABLED) != 0)
3465 		bevelShadowColor = base;
3466 
3467 	if ((flags & B_ACTIVATED) != 0)
3468 		bevelShadowColor = tint_color(base, B_DARKEN_1_TINT);
3469 
3470 	return bevelShadowColor;
3471 }
3472 
3473 
3474 void
3475 HaikuControlLook::_FillGradient(BView* view, const BRect& rect,
3476 	const rgb_color& base, float topTint, float bottomTint,
3477 	orientation orientation)
3478 {
3479 	BGradientLinear gradient;
3480 	_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3481 	view->FillRect(rect, gradient);
3482 }
3483 
3484 
3485 void
3486 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect,
3487 	const rgb_color& base, float topTint, float middle1Tint,
3488 	float middle2Tint, float bottomTint, orientation orientation)
3489 {
3490 	BGradientLinear gradient;
3491 	_MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint,
3492 		middle2Tint, bottomTint, orientation);
3493 	view->FillRect(rect, gradient);
3494 }
3495 
3496 
3497 void
3498 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
3499 	const rgb_color& base, float topTint, float bottomTint,
3500 	orientation orientation) const
3501 {
3502 	gradient.AddColor(tint_color(base, topTint), 0);
3503 	gradient.AddColor(tint_color(base, bottomTint), 255);
3504 	gradient.SetStart(rect.LeftTop());
3505 	if (orientation == B_HORIZONTAL)
3506 		gradient.SetEnd(rect.LeftBottom());
3507 	else
3508 		gradient.SetEnd(rect.RightTop());
3509 }
3510 
3511 
3512 void
3513 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
3514 	const rgb_color& base, float topTint, float middle1Tint,
3515 	float middle2Tint, float bottomTint,
3516 	orientation orientation) const
3517 {
3518 	gradient.AddColor(tint_color(base, topTint), 0);
3519 	gradient.AddColor(tint_color(base, middle1Tint), 132);
3520 	gradient.AddColor(tint_color(base, middle2Tint), 136);
3521 	gradient.AddColor(tint_color(base, bottomTint), 255);
3522 	gradient.SetStart(rect.LeftTop());
3523 	if (orientation == B_HORIZONTAL)
3524 		gradient.SetEnd(rect.LeftBottom());
3525 	else
3526 		gradient.SetEnd(rect.RightTop());
3527 }
3528 
3529 
3530 void
3531 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect,
3532 	const rgb_color& base, uint32 flags, orientation orientation) const
3533 {
3534 	float topTint = 0.49;
3535 	float middleTint1 = 0.62;
3536 	float middleTint2 = 0.76;
3537 	float bottomTint = 0.90;
3538 
3539 	if ((flags & B_ACTIVATED) != 0) {
3540 		topTint = 1.11;
3541 		bottomTint = 1.08;
3542 	}
3543 
3544 	if ((flags & B_DISABLED) != 0) {
3545 		topTint = (topTint + B_NO_TINT) / 2;
3546 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
3547 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
3548 		bottomTint = (bottomTint + B_NO_TINT) / 2;
3549 	} else if ((flags & B_HOVER) != 0) {
3550 		topTint *= kHoverTintFactor;
3551 		middleTint1 *= kHoverTintFactor;
3552 		middleTint2 *= kHoverTintFactor;
3553 		bottomTint *= kHoverTintFactor;
3554 	}
3555 
3556 	if ((flags & B_ACTIVATED) != 0) {
3557 		_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3558 	} else {
3559 		_MakeGlossyGradient(gradient, rect, base, topTint, middleTint1,
3560 			middleTint2, bottomTint, orientation);
3561 	}
3562 }
3563 
3564 
3565 
3566 bool
3567 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
3568 	rgb_color& color, uint32 flags) const
3569 {
3570 	if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) {
3571 		// no mark to be drawn at all
3572 		return false;
3573 	}
3574 
3575 	color = ui_color(B_CONTROL_MARK_COLOR);
3576 
3577 	float mix = 1.0;
3578 
3579 	if ((flags & B_DISABLED) != 0) {
3580 		// activated, but disabled
3581 		mix = 0.4;
3582 	} else if ((flags & B_CLICKED) != 0) {
3583 		if ((flags & B_ACTIVATED) != 0) {
3584 			// losing activation
3585 			mix = 0.7;
3586 		} else {
3587 			// becoming activated (or losing partial activation)
3588 			mix = 0.3;
3589 		}
3590 	} else if ((flags & B_PARTIALLY_ACTIVATED) != 0) {
3591 		// partially activated
3592 		mix = 0.5;
3593 	} else {
3594 		// simply activated
3595 	}
3596 
3597 	color.red = uint8(color.red * mix + base.red * (1.0 - mix));
3598 	color.green = uint8(color.green * mix + base.green * (1.0 - mix));
3599 	color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix));
3600 
3601 	return true;
3602 }
3603 
3604 
3605 } // namespace BPrivate
3606