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