xref: /haiku/src/kits/interface/HaikuControlLook.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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
2201 		&& window->Feel() == kDesktopWindowFeel
2202 		&& window->Look() == kDesktopWindowLook
2203 		&& view->Parent()
2204 		&& view->Parent()->Parent() == NULL
2205 		&& (flags & B_IGNORE_OUTLINE) == 0;
2206 
2207 	rgb_color low;
2208 	rgb_color color;
2209 	rgb_color glowColor;
2210 
2211 	if (textColor != NULL)
2212 		glowColor = *textColor;
2213 	else if ((flags & B_IS_CONTROL) != 0)
2214 		glowColor = ui_color(B_CONTROL_TEXT_COLOR);
2215 	else
2216 		glowColor = ui_color(B_PANEL_TEXT_COLOR);
2217 
2218 	color = glowColor;
2219 
2220 	if (isDesktop)
2221 		low = view->Parent()->ViewColor();
2222 	else
2223 		low = base;
2224 
2225 	if ((flags & B_DISABLED) != 0) {
2226 		color.red = (uint8)(((int32)low.red + color.red + 1) / 2);
2227 		color.green = (uint8)(((int32)low.green + color.green + 1) / 2);
2228 		color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2);
2229 	}
2230 
2231 	drawing_mode oldMode = view->DrawingMode();
2232 
2233 	if (isDesktop) {
2234 		// enforce proper use of desktop label colors
2235 		if (low.Brightness() < 100) {
2236 			if (textColor == NULL)
2237 				color = make_color(255, 255, 255);
2238 
2239 			glowColor = make_color(0, 0, 0);
2240 		} else {
2241 			if (textColor == NULL)
2242 				color = make_color(0, 0, 0);
2243 
2244 			glowColor = make_color(255, 255, 255);
2245 		}
2246 
2247 		// drawing occurs on the desktop
2248 		if (fCachedWorkspace != current_workspace()) {
2249 			int8 indice = 0;
2250 			int32 mask;
2251 			bool tmpOutline;
2252 			while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces",
2253 					indice, &mask) == B_OK
2254 				&& fBackgroundInfo.FindBool("be:bgndimginfoerasetext",
2255 					indice, &tmpOutline) == B_OK) {
2256 
2257 				if (((1 << current_workspace()) & mask) != 0) {
2258 					fCachedOutline = tmpOutline;
2259 					fCachedWorkspace = current_workspace();
2260 					break;
2261 				}
2262 				indice++;
2263 			}
2264 		}
2265 
2266 		if (fCachedOutline) {
2267 			BFont font;
2268 			view->GetFont(&font);
2269 
2270 			view->SetDrawingMode(B_OP_ALPHA);
2271 			view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
2272 			// Draw glow or outline
2273 			if (glowColor.Brightness() > 128) {
2274 				font.SetFalseBoldWidth(2.0);
2275 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2276 
2277 				glowColor.alpha = 30;
2278 				view->SetHighColor(glowColor);
2279 				view->DrawString(label, where);
2280 
2281 				font.SetFalseBoldWidth(1.0);
2282 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2283 
2284 				glowColor.alpha = 65;
2285 				view->SetHighColor(glowColor);
2286 				view->DrawString(label, where);
2287 
2288 				font.SetFalseBoldWidth(0.0);
2289 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2290 			} else {
2291 				font.SetFalseBoldWidth(1.0);
2292 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2293 
2294 				glowColor.alpha = 30;
2295 				view->SetHighColor(glowColor);
2296 				view->DrawString(label, where);
2297 
2298 				font.SetFalseBoldWidth(0.0);
2299 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2300 
2301 				glowColor.alpha = 200;
2302 				view->SetHighColor(glowColor);
2303 				view->DrawString(label, BPoint(where.x + 1, where.y + 1));
2304 			}
2305 		}
2306 	}
2307 
2308 	view->SetHighColor(color);
2309 	view->SetDrawingMode(B_OP_OVER);
2310 	view->DrawString(label, where);
2311 	view->SetDrawingMode(oldMode);
2312 }
2313 
2314 
2315 void
2316 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon,
2317 	BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags,
2318 	const BAlignment& alignment, const rgb_color* textColor)
2319 {
2320 	if (!ShouldDraw(view, rect, updateRect))
2321 		return;
2322 
2323 	if (label == NULL && icon == NULL)
2324 		return;
2325 
2326 	if (label == NULL) {
2327 		// icon only
2328 		BRect alignedRect = BLayoutUtils::AlignInFrame(rect,
2329 			icon->Bounds().Size(), alignment);
2330 		drawing_mode oldMode = view->DrawingMode();
2331 		view->SetDrawingMode(B_OP_OVER);
2332 		view->DrawBitmap(icon, alignedRect.LeftTop());
2333 		view->SetDrawingMode(oldMode);
2334 		return;
2335 	}
2336 
2337 	// label, possibly with icon
2338 	float availableWidth = rect.Width() + 1;
2339 	float width = 0;
2340 	float textOffset = 0;
2341 	float height = 0;
2342 
2343 	if (icon != NULL) {
2344 		width = icon->Bounds().Width() + DefaultLabelSpacing() + 1;
2345 		height = icon->Bounds().Height() + 1;
2346 		textOffset = width;
2347 		availableWidth -= textOffset;
2348 	}
2349 
2350 	// truncate the label if necessary and get the width and height
2351 	BString truncatedLabel(label);
2352 
2353 	BFont font;
2354 	view->GetFont(&font);
2355 
2356 	font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth);
2357 	width += ceilf(font.StringWidth(truncatedLabel.String()));
2358 
2359 	font_height fontHeight;
2360 	font.GetHeight(&fontHeight);
2361 	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
2362 	height = std::max(height, textHeight);
2363 
2364 	// handle alignment
2365 	BRect alignedRect(BLayoutUtils::AlignOnRect(rect,
2366 		BSize(width - 1, height - 1), alignment));
2367 
2368 	if (icon != NULL) {
2369 		BPoint location(alignedRect.LeftTop());
2370 		if (icon->Bounds().Height() + 1 < height)
2371 			location.y += ceilf((height - icon->Bounds().Height() - 1) / 2);
2372 
2373 		drawing_mode oldMode = view->DrawingMode();
2374 		view->SetDrawingMode(B_OP_OVER);
2375 		view->DrawBitmap(icon, location);
2376 		view->SetDrawingMode(oldMode);
2377 	}
2378 
2379 	BPoint location(alignedRect.left + textOffset,
2380 		alignedRect.top + ceilf(fontHeight.ascent));
2381 	if (textHeight < height)
2382 		location.y += ceilf((height - textHeight) / 2);
2383 
2384 	DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor);
2385 }
2386 
2387 
2388 void
2389 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left,
2390 	float& _top, float& _right, float& _bottom)
2391 {
2392 	// All frames have the same inset on each side.
2393 	float inset = 0;
2394 
2395 	switch (frameType) {
2396 		case B_BUTTON_FRAME:
2397 			inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2;
2398 			break;
2399 		case B_GROUP_FRAME:
2400 		case B_MENU_FIELD_FRAME:
2401 			inset = 3;
2402 			break;
2403 		case B_SCROLL_VIEW_FRAME:
2404 		case B_TEXT_CONTROL_FRAME:
2405 			inset = 2;
2406 			break;
2407 	}
2408 
2409 	inset = ceilf(inset * (be_plain_font->Size() / 12.0f));
2410 
2411 	_left = inset;
2412 	_top = inset;
2413 	_right = inset;
2414 	_bottom = inset;
2415 }
2416 
2417 
2418 void
2419 HaikuControlLook::GetBackgroundInsets(background_type backgroundType,
2420 	uint32 flags, float& _left, float& _top, float& _right, float& _bottom)
2421 {
2422 	// Most backgrounds have the same inset on each side.
2423 	float inset = 0;
2424 
2425 	switch (backgroundType) {
2426 		case B_BUTTON_BACKGROUND:
2427 		case B_MENU_BACKGROUND:
2428 		case B_MENU_BAR_BACKGROUND:
2429 		case B_MENU_FIELD_BACKGROUND:
2430 		case B_MENU_ITEM_BACKGROUND:
2431 			inset = 1;
2432 			break;
2433 		case B_BUTTON_WITH_POP_UP_BACKGROUND:
2434 			_left = 1;
2435 			_top = 1;
2436 			_right = 1 + ComposeSpacing(kButtonPopUpIndicatorWidth);
2437 			_bottom = 1;
2438 			return;
2439 		case B_HORIZONTAL_SCROLL_BAR_BACKGROUND:
2440 			_left = 2;
2441 			_top = 0;
2442 			_right = 1;
2443 			_bottom = 0;
2444 			return;
2445 		case B_VERTICAL_SCROLL_BAR_BACKGROUND:
2446 			_left = 0;
2447 			_top = 2;
2448 			_right = 0;
2449 			_bottom = 1;
2450 			return;
2451 	}
2452 
2453 	_left = inset;
2454 	_top = inset;
2455 	_right = inset;
2456 	_bottom = inset;
2457 }
2458 
2459 
2460 void
2461 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2462 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2463 	uint32 borders, orientation orientation)
2464 {
2465 	_DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
2466 		base, true, flags, borders, orientation);
2467 }
2468 
2469 
2470 void
2471 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2472 	const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
2473 	uint32 borders, orientation orientation)
2474 {
2475 	_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
2476 		radius, base, true, flags, borders, orientation);
2477 }
2478 
2479 
2480 void
2481 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2482 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2483 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2484 	uint32 flags, uint32 borders, orientation orientation)
2485 {
2486 	_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
2487 		rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
2488 		borders, orientation);
2489 }
2490 
2491 
2492 // #pragma mark -
2493 
2494 
2495 void
2496 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect,
2497 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2498 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2499 	const rgb_color& background, float contrast, float brightness,
2500 	uint32 flags, uint32 borders)
2501 {
2502 	if (!rect.IsValid())
2503 		return;
2504 
2505 	// save the clipping constraints of the view
2506 	view->PushState();
2507 
2508 	// set clipping constraints to rect
2509 	view->ClipToRect(rect);
2510 
2511 	// If the button is flat and neither activated nor otherwise highlighted
2512 	// (mouse hovering or focussed), draw it flat.
2513 	if ((flags & B_FLAT) != 0
2514 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2515 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2516 			|| (flags & B_DISABLED) != 0)) {
2517 		_DrawFrame(view, rect, background, background, background,
2518 			background, borders);
2519 		_DrawFrame(view, rect, background, background, background,
2520 			background, borders);
2521 		view->PopState();
2522 		return;
2523 	}
2524 
2525 	// outer edge colors
2526 	rgb_color edgeLightColor;
2527 	rgb_color edgeShadowColor;
2528 
2529 	// default button frame color
2530 	rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR);
2531 	rgb_color cornerBgColor;
2532 
2533 	if ((flags & B_DISABLED) != 0) {
2534 		defaultIndicatorColor = disable_color(defaultIndicatorColor,
2535 			background);
2536 	}
2537 
2538 	drawing_mode oldMode = view->DrawingMode();
2539 
2540 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2541 		cornerBgColor = defaultIndicatorColor;
2542 		edgeLightColor = _EdgeLightColor(defaultIndicatorColor,
2543 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2544 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2545 		edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor,
2546 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2547 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2548 
2549 		// draw default button indicator
2550 		// Allow a 1-pixel border of the background to come through.
2551 		rect.InsetBy(1, 1);
2552 
2553 		view->SetHighColor(defaultIndicatorColor);
2554 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2555 		rect.InsetBy(1, 1);
2556 
2557 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2558 		rect.InsetBy(1, 1);
2559 	} else {
2560 		cornerBgColor = background;
2561 		if ((flags & B_BLEND_FRAME) != 0) {
2562 			// set the background color to transparent for the case
2563 			// that we are on the desktop
2564 			cornerBgColor.alpha = 0;
2565 			view->SetDrawingMode(B_OP_ALPHA);
2566 		}
2567 
2568 		edgeLightColor = _EdgeLightColor(background,
2569 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2570 			brightness * 1.0, flags);
2571 		edgeShadowColor = _EdgeShadowColor(background,
2572 			contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0,
2573 			brightness * 1.0, flags);
2574 	}
2575 
2576 	// frame colors
2577 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
2578 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
2579 
2580 	// rounded corners
2581 
2582 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2583 		&& leftTopRadius > 0) {
2584 		// draw left top rounded corner
2585 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2586 			floorf(rect.left + leftTopRadius),
2587 			floorf(rect.top + leftTopRadius));
2588 		BRect cornerRect(leftTopCorner);
2589 		_DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect,
2590 			cornerBgColor, edgeShadowColor, frameLightColor);
2591 		view->ClipToInverseRect(cornerRect);
2592 	}
2593 
2594 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2595 		&& rightTopRadius > 0) {
2596 		// draw right top rounded corner
2597 		BRect rightTopCorner(floorf(rect.right - rightTopRadius),
2598 			floorf(rect.top), floorf(rect.right),
2599 			floorf(rect.top + rightTopRadius));
2600 		BRect cornerRect(rightTopCorner);
2601 		_DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect,
2602 			cornerBgColor, edgeShadowColor, edgeLightColor,
2603 			frameLightColor, frameShadowColor);
2604 		view->ClipToInverseRect(cornerRect);
2605 	}
2606 
2607 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2608 		&& leftBottomRadius > 0) {
2609 		// draw left bottom rounded corner
2610 		BRect leftBottomCorner(floorf(rect.left),
2611 			floorf(rect.bottom - leftBottomRadius),
2612 			floorf(rect.left + leftBottomRadius), floorf(rect.bottom));
2613 		BRect cornerRect(leftBottomCorner);
2614 		_DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect,
2615 			cornerBgColor, edgeShadowColor, edgeLightColor,
2616 			frameLightColor, frameShadowColor);
2617 		view->ClipToInverseRect(cornerRect);
2618 	}
2619 
2620 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2621 		&& rightBottomRadius > 0) {
2622 		// draw right bottom rounded corner
2623 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius),
2624 			floorf(rect.bottom - rightBottomRadius), floorf(rect.right),
2625 			floorf(rect.bottom));
2626 		BRect cornerRect(rightBottomCorner);
2627 		_DrawRoundCornerFrameRightBottom(view, rightBottomCorner,
2628 			updateRect, cornerBgColor, edgeLightColor, frameShadowColor);
2629 		view->ClipToInverseRect(cornerRect);
2630 	}
2631 
2632 	// draw outer edge
2633 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2634 		_DrawOuterResessedFrame(view, rect, defaultIndicatorColor,
2635 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2636 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9),
2637 			flags, borders);
2638 	} else {
2639 		_DrawOuterResessedFrame(view, rect, background,
2640 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2641 			brightness * 1.0, flags, borders);
2642 	}
2643 
2644 	view->SetDrawingMode(oldMode);
2645 
2646 	// draw frame
2647 	if ((flags & B_BLEND_FRAME) != 0) {
2648 		drawing_mode oldDrawingMode = view->DrawingMode();
2649 		view->SetDrawingMode(B_OP_ALPHA);
2650 
2651 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2652 			frameShadowColor, frameShadowColor, borders);
2653 
2654 		view->SetDrawingMode(oldDrawingMode);
2655 	} else {
2656 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2657 			frameShadowColor, frameShadowColor, borders);
2658 	}
2659 
2660 	// restore the clipping constraints of the view
2661 	view->PopState();
2662 }
2663 
2664 
2665 void
2666 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
2667 	const rgb_color& base, float contrast, float brightness, uint32 flags,
2668 	uint32 borders)
2669 {
2670 	rgb_color edgeLightColor = _EdgeLightColor(base, contrast,
2671 		brightness, flags);
2672 	rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast,
2673 		brightness, flags);
2674 
2675 	if ((flags & B_BLEND_FRAME) != 0) {
2676 		// assumes the background has already been painted
2677 		drawing_mode oldDrawingMode = view->DrawingMode();
2678 		view->SetDrawingMode(B_OP_ALPHA);
2679 
2680 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2681 			edgeLightColor, edgeLightColor, borders);
2682 
2683 		view->SetDrawingMode(oldDrawingMode);
2684 	} else {
2685 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2686 			edgeLightColor, edgeLightColor, borders);
2687 	}
2688 }
2689 
2690 
2691 void
2692 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2693 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2694 	uint32 borders)
2695 {
2696 	view->BeginLineArray(4);
2697 
2698 	if (borders & B_LEFT_BORDER) {
2699 		view->AddLine(
2700 			BPoint(rect.left, rect.bottom),
2701 			BPoint(rect.left, rect.top), left);
2702 		rect.left++;
2703 	}
2704 	if (borders & B_TOP_BORDER) {
2705 		view->AddLine(
2706 			BPoint(rect.left, rect.top),
2707 			BPoint(rect.right, rect.top), top);
2708 		rect.top++;
2709 	}
2710 	if (borders & B_RIGHT_BORDER) {
2711 		view->AddLine(
2712 			BPoint(rect.right, rect.top),
2713 			BPoint(rect.right, rect.bottom), right);
2714 		rect.right--;
2715 	}
2716 	if (borders & B_BOTTOM_BORDER) {
2717 		view->AddLine(
2718 			BPoint(rect.left, rect.bottom),
2719 			BPoint(rect.right, rect.bottom), bottom);
2720 		rect.bottom--;
2721 	}
2722 
2723 	view->EndLineArray();
2724 }
2725 
2726 
2727 void
2728 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2729 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2730 	const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders)
2731 {
2732 	view->BeginLineArray(6);
2733 
2734 	if (borders & B_TOP_BORDER) {
2735 		if (borders & B_RIGHT_BORDER) {
2736 			view->AddLine(
2737 				BPoint(rect.left, rect.top),
2738 				BPoint(rect.right - 1, rect.top), top);
2739 			view->AddLine(
2740 				BPoint(rect.right, rect.top),
2741 				BPoint(rect.right, rect.top), rightTop);
2742 		} else {
2743 			view->AddLine(
2744 				BPoint(rect.left, rect.top),
2745 				BPoint(rect.right, rect.top), top);
2746 		}
2747 		rect.top++;
2748 	}
2749 
2750 	if (borders & B_LEFT_BORDER) {
2751 		view->AddLine(
2752 			BPoint(rect.left, rect.top),
2753 			BPoint(rect.left, rect.bottom - 1), left);
2754 		view->AddLine(
2755 			BPoint(rect.left, rect.bottom),
2756 			BPoint(rect.left, rect.bottom), leftBottom);
2757 		rect.left++;
2758 	}
2759 
2760 	if (borders & B_BOTTOM_BORDER) {
2761 		view->AddLine(
2762 			BPoint(rect.left, rect.bottom),
2763 			BPoint(rect.right, rect.bottom), bottom);
2764 		rect.bottom--;
2765 	}
2766 
2767 	if (borders & B_RIGHT_BORDER) {
2768 		view->AddLine(
2769 			BPoint(rect.right, rect.bottom),
2770 			BPoint(rect.right, rect.top), right);
2771 		rect.right--;
2772 	}
2773 
2774 	view->EndLineArray();
2775 }
2776 
2777 
2778 void
2779 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect,
2780 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2781 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2782 	bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
2783 {
2784 	if (!rect.IsValid())
2785 		return;
2786 
2787 	// save the clipping constraints of the view
2788 	view->PushState();
2789 
2790 	// set clipping constraints to rect
2791 	view->ClipToRect(rect);
2792 
2793 	// If the button is flat and neither activated nor otherwise highlighted
2794 	// (mouse hovering or focussed), draw it flat.
2795 	if ((flags & B_FLAT) != 0
2796 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2797 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2798 			|| (flags & B_DISABLED) != 0)) {
2799 		_DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator,
2800 			flags, borders, orientation);
2801 	} else {
2802 		BRegion clipping(rect);
2803 		_DrawNonFlatButtonBackground(view, rect, updateRect, clipping,
2804 			leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius,
2805 			base, popupIndicator, flags, borders, orientation);
2806 	}
2807 
2808 	// restore the clipping constraints of the view
2809 	view->PopState();
2810 }
2811 
2812 
2813 void
2814 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect,
2815 	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
2816 	uint32 flags, uint32 borders, orientation orientation)
2817 {
2818 	_DrawFrame(view, rect, base, base, base, base, borders);
2819 		// Not an actual frame, but the method insets our rect as needed.
2820 
2821 	view->SetHighColor(base);
2822 	view->FillRect(rect);
2823 
2824 	if (popupIndicator) {
2825 		BRect indicatorRect(rect);
2826 		rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth);
2827 		indicatorRect.left = rect.right + 3;
2828 			// 2 pixels for the separator
2829 
2830 		view->SetHighColor(base);
2831 		view->FillRect(indicatorRect);
2832 
2833 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2834 	}
2835 }
2836 
2837 
2838 void
2839 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect,
2840 	const BRect& updateRect, BRegion& clipping, float leftTopRadius,
2841 	float rightTopRadius, float leftBottomRadius, float rightBottomRadius,
2842 	const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders,
2843 	orientation orientation)
2844 {
2845 	// inner bevel colors
2846 	rgb_color bevelLightColor  = _BevelLightColor(base, flags);
2847 	rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
2848 
2849 	// button background color
2850 	rgb_color buttonBgColor;
2851 	if ((flags & B_DISABLED) != 0)
2852 		buttonBgColor = tint_color(base, 0.7);
2853 	else
2854 		buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT);
2855 
2856 	// surface top gradient
2857 	BGradientLinear fillGradient;
2858 	_MakeButtonGradient(fillGradient, rect, base, flags, orientation);
2859 
2860 	// rounded corners
2861 
2862 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2863 		&& leftTopRadius > 0) {
2864 		// draw left top rounded corner
2865 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2866 			floorf(rect.left + leftTopRadius - 2.0),
2867 			floorf(rect.top + leftTopRadius - 2.0));
2868 		clipping.Exclude(leftTopCorner);
2869 		BRect cornerRect(leftTopCorner);
2870 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
2871 			bevelLightColor, fillGradient);
2872 		view->ClipToInverseRect(cornerRect);
2873 	}
2874 
2875 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2876 		&& rightTopRadius > 0) {
2877 		// draw right top rounded corner
2878 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
2879 			floorf(rect.top), floorf(rect.right),
2880 			floorf(rect.top + rightTopRadius - 2.0));
2881 		clipping.Exclude(rightTopCorner);
2882 		BRect cornerRect(rightTopCorner);
2883 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner,
2884 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2885 		view->ClipToInverseRect(cornerRect);
2886 	}
2887 
2888 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2889 		&& leftBottomRadius > 0) {
2890 		// draw left bottom rounded corner
2891 		BRect leftBottomCorner(floorf(rect.left),
2892 			floorf(rect.bottom - leftBottomRadius + 2.0),
2893 			floorf(rect.left + leftBottomRadius - 2.0),
2894 			floorf(rect.bottom));
2895 		clipping.Exclude(leftBottomCorner);
2896 		BRect cornerRect(leftBottomCorner);
2897 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
2898 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2899 		view->ClipToInverseRect(cornerRect);
2900 	}
2901 
2902 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2903 		&& rightBottomRadius > 0) {
2904 		// draw right bottom rounded corner
2905 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
2906 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
2907 			floorf(rect.bottom));
2908 		clipping.Exclude(rightBottomCorner);
2909 		BRect cornerRect(rightBottomCorner);
2910 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
2911 			updateRect, bevelShadowColor, fillGradient);
2912 		view->ClipToInverseRect(cornerRect);
2913 	}
2914 
2915 	// draw inner bevel
2916 
2917 	if ((flags & B_ACTIVATED) != 0) {
2918 		view->BeginLineArray(4);
2919 
2920 		// shadow along left/top borders
2921 		if (borders & B_LEFT_BORDER) {
2922 			view->AddLine(BPoint(rect.left, rect.top),
2923 				BPoint(rect.left, rect.bottom), bevelLightColor);
2924 			rect.left++;
2925 		}
2926 		if (borders & B_TOP_BORDER) {
2927 			view->AddLine(BPoint(rect.left, rect.top),
2928 				BPoint(rect.right, rect.top), bevelLightColor);
2929 			rect.top++;
2930 		}
2931 
2932 		// softer shadow along left/top borders
2933 		if (borders & B_LEFT_BORDER) {
2934 			view->AddLine(BPoint(rect.left, rect.top),
2935 				BPoint(rect.left, rect.bottom), bevelShadowColor);
2936 			rect.left++;
2937 		}
2938 		if (borders & B_TOP_BORDER) {
2939 			view->AddLine(BPoint(rect.left, rect.top),
2940 				BPoint(rect.right, rect.top), bevelShadowColor);
2941 			rect.top++;
2942 		}
2943 
2944 		view->EndLineArray();
2945 	} else {
2946 		_DrawFrame(view, rect,
2947 			bevelLightColor, bevelLightColor,
2948 			bevelShadowColor, bevelShadowColor,
2949 			buttonBgColor, buttonBgColor, borders);
2950 	}
2951 
2952 	if (popupIndicator) {
2953 		BRect indicatorRect(rect);
2954 		rect.right -= ComposeSpacing(kButtonPopUpIndicatorWidth);
2955 		indicatorRect.left = rect.right + 3;
2956 			// 2 pixels for the separator
2957 
2958 		// Even when depressed we want the pop-up indicator background and
2959 		// separator to cover the area up to the top.
2960 		if ((flags & B_ACTIVATED) != 0)
2961 			indicatorRect.top--;
2962 
2963 		// draw the separator
2964 		rgb_color separatorBaseColor = base;
2965 		if ((flags & B_ACTIVATED) != 0)
2966 			separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
2967 
2968 		rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor,
2969 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2970 		rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor,
2971 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2972 
2973 		view->BeginLineArray(2);
2974 
2975 		view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top),
2976 			BPoint(indicatorRect.left - 2, indicatorRect.bottom),
2977 			separatorShadowColor);
2978 		view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top),
2979 			BPoint(indicatorRect.left - 1, indicatorRect.bottom),
2980 			separatorLightColor);
2981 
2982 		view->EndLineArray();
2983 
2984 		// draw background and pop-up marker
2985 		_DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect,
2986 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0);
2987 
2988 		if ((flags & B_ACTIVATED) != 0)
2989 			indicatorRect.top++;
2990 
2991 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2992 	}
2993 
2994 	// fill in the background
2995 	view->FillRect(rect, fillGradient);
2996 }
2997 
2998 
2999 void
3000 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
3001 	const rgb_color& base, uint32 flags)
3002 {
3003 	BPoint center(roundf((rect.left + rect.right) / 2.0),
3004 		roundf((rect.top + rect.bottom) / 2.0));
3005 	const float metric = roundf(rect.Width() * 3.125f) / 10.0f,
3006 		offset = ceilf((metric * 0.2f) * 10.0f) / 10.0f;
3007 	BPoint triangle[3];
3008 	triangle[0] = center + BPoint(-metric, -offset);
3009 	triangle[1] = center + BPoint(metric, -offset);
3010 	triangle[2] = center + BPoint(0.0, metric * 0.8f);
3011 
3012 	const uint32 viewFlags = view->Flags();
3013 	view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
3014 
3015 	rgb_color markColor;
3016 	if ((flags & B_DISABLED) != 0)
3017 		markColor = tint_color(base, 1.35);
3018 	else
3019 		markColor = tint_color(base, 1.65);
3020 
3021 	view->SetHighColor(markColor);
3022 	view->FillTriangle(triangle[0], triangle[1], triangle[2]);
3023 
3024 	view->SetFlags(viewFlags);
3025 }
3026 
3027 
3028 void
3029 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
3030 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3031 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3032 	bool popupIndicator, uint32 flags)
3033 {
3034 	if (!ShouldDraw(view, rect, updateRect))
3035 		return;
3036 
3037 	if (popupIndicator) {
3038 		const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth);
3039 		const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f);
3040 
3041 		BRect leftRect(rect);
3042 		leftRect.right -= indicatorWidth - spacing;
3043 
3044 		BRect rightRect(rect);
3045 		rightRect.left = rightRect.right - (indicatorWidth - spacing * 2);
3046 
3047 		_DrawMenuFieldBackgroundInside(view, leftRect, updateRect,
3048 			leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags,
3049 			B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
3050 
3051 		_DrawMenuFieldBackgroundInside(view, rightRect, updateRect,
3052 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags,
3053 			B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
3054 
3055 		_DrawPopUpMarker(view, rightRect, base, flags);
3056 
3057 		// draw a line on the left of the popup frame
3058 		rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
3059 		view->SetHighColor(bevelShadowColor);
3060 		BPoint leftTopCorner(floorf(rightRect.left - spacing),
3061 			floorf(rightRect.top - spacing));
3062 		BPoint leftBottomCorner(floorf(rightRect.left - spacing),
3063 			floorf(rightRect.bottom + spacing));
3064 		for (float i = 0; i < spacing; i++) {
3065 			view->StrokeLine(leftTopCorner + BPoint(i, 0),
3066 				leftBottomCorner + BPoint(i, 0));
3067 		}
3068 
3069 		rect = leftRect;
3070 	} else {
3071 		_DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius,
3072 			rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags);
3073 	}
3074 }
3075 
3076 
3077 void
3078 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
3079 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3080 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3081 	uint32 flags, uint32 borders)
3082 {
3083 	if (!ShouldDraw(view, rect, updateRect))
3084 		return;
3085 
3086 	// save the clipping constraints of the view
3087 	view->PushState();
3088 
3089 	// set clipping constraints to rect
3090 	view->ClipToRect(rect);
3091 
3092 	// frame colors
3093 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
3094 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
3095 
3096 	// indicator background color
3097 	rgb_color indicatorBase;
3098 	if ((borders & B_LEFT_BORDER) != 0)
3099 		indicatorBase = base;
3100 	else {
3101 		if ((flags & B_DISABLED) != 0)
3102 			indicatorBase = tint_color(base, 1.05);
3103 		else
3104 			indicatorBase = tint_color(base, 1.12);
3105 	}
3106 
3107 	// bevel colors
3108 	rgb_color cornerColor = tint_color(indicatorBase, 0.85);
3109 	rgb_color bevelColor1 = tint_color(indicatorBase, 0.3);
3110 	rgb_color bevelColor2 = tint_color(indicatorBase, 0.5);
3111 	rgb_color bevelColor3 = tint_color(indicatorBase, 1.03);
3112 
3113 	if ((flags & B_DISABLED) != 0) {
3114 		cornerColor = tint_color(indicatorBase, 0.8);
3115 		bevelColor1 = tint_color(indicatorBase, 0.7);
3116 		bevelColor2 = tint_color(indicatorBase, 0.8);
3117 		bevelColor3 = tint_color(indicatorBase, 1.01);
3118 	} else {
3119 		cornerColor = tint_color(indicatorBase, 0.85);
3120 		bevelColor1 = tint_color(indicatorBase, 0.3);
3121 		bevelColor2 = tint_color(indicatorBase, 0.5);
3122 		bevelColor3 = tint_color(indicatorBase, 1.03);
3123 	}
3124 
3125 	// surface top gradient
3126 	BGradientLinear fillGradient;
3127 	_MakeButtonGradient(fillGradient, rect, indicatorBase, flags);
3128 
3129 	// rounded corners
3130 
3131 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
3132 		&& leftTopRadius > 0) {
3133 		// draw left top rounded corner
3134 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
3135 			floorf(rect.left + leftTopRadius - 2.0),
3136 			floorf(rect.top + leftTopRadius - 2.0));
3137 		BRect cornerRect(leftTopCorner);
3138 
3139 		view->PushState();
3140 		view->ClipToRect(cornerRect);
3141 
3142 		BRect ellipseRect(leftTopCorner);
3143 		ellipseRect.InsetBy(-1.0, -1.0);
3144 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3145 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3146 
3147 		// draw the frame (again)
3148 		view->SetHighColor(frameLightColor);
3149 		view->FillEllipse(ellipseRect);
3150 
3151 		// draw the bevel and background
3152 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
3153 			bevelColor1, fillGradient);
3154 
3155 		view->PopState();
3156 		view->ClipToInverseRect(cornerRect);
3157 	}
3158 
3159 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
3160 		&& rightTopRadius > 0) {
3161 		// draw right top rounded corner
3162 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
3163 			floorf(rect.top), floorf(rect.right),
3164 			floorf(rect.top + rightTopRadius - 2.0));
3165 		BRect cornerRect(rightTopCorner);
3166 
3167 		view->PushState();
3168 		view->ClipToRect(cornerRect);
3169 
3170 		BRect ellipseRect(rightTopCorner);
3171 		ellipseRect.InsetBy(-1.0, -1.0);
3172 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3173 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3174 
3175 		// draw the frame (again)
3176 		if (frameLightColor == frameShadowColor) {
3177 			view->SetHighColor(frameLightColor);
3178 			view->FillEllipse(ellipseRect);
3179 		} else {
3180 			BGradientLinear gradient;
3181 			gradient.AddColor(frameLightColor, 0);
3182 			gradient.AddColor(frameShadowColor, 255);
3183 			gradient.SetStart(rightTopCorner.LeftTop());
3184 			gradient.SetEnd(rightTopCorner.RightBottom());
3185 			view->FillEllipse(ellipseRect, gradient);
3186 		}
3187 
3188 		// draw the bevel and background
3189 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect,
3190 			bevelColor1, bevelColor3, fillGradient);
3191 
3192 		view->PopState();
3193 		view->ClipToInverseRect(cornerRect);
3194 	}
3195 
3196 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3197 		&& leftBottomRadius > 0) {
3198 		// draw left bottom rounded corner
3199 		BRect leftBottomCorner(floorf(rect.left),
3200 			floorf(rect.bottom - leftBottomRadius + 2.0),
3201 			floorf(rect.left + leftBottomRadius - 2.0),
3202 			floorf(rect.bottom));
3203 		BRect cornerRect(leftBottomCorner);
3204 
3205 		view->PushState();
3206 		view->ClipToRect(cornerRect);
3207 
3208 		BRect ellipseRect(leftBottomCorner);
3209 		ellipseRect.InsetBy(-1.0, -1.0);
3210 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3211 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3212 
3213 		// draw the frame (again)
3214 		if (frameLightColor == frameShadowColor) {
3215 			view->SetHighColor(frameLightColor);
3216 			view->FillEllipse(ellipseRect);
3217 		} else {
3218 			BGradientLinear gradient;
3219 			gradient.AddColor(frameLightColor, 0);
3220 			gradient.AddColor(frameShadowColor, 255);
3221 			gradient.SetStart(leftBottomCorner.LeftTop());
3222 			gradient.SetEnd(leftBottomCorner.RightBottom());
3223 			view->FillEllipse(ellipseRect, gradient);
3224 		}
3225 
3226 		// draw the bevel and background
3227 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
3228 			updateRect, bevelColor2, bevelColor3, fillGradient);
3229 
3230 		view->PopState();
3231 		view->ClipToInverseRect(cornerRect);
3232 	}
3233 
3234 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3235 		&& rightBottomRadius > 0) {
3236 		// draw right bottom rounded corner
3237 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
3238 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
3239 			floorf(rect.bottom));
3240 		BRect cornerRect(rightBottomCorner);
3241 
3242 		view->PushState();
3243 		view->ClipToRect(cornerRect);
3244 
3245 		BRect ellipseRect(rightBottomCorner);
3246 		ellipseRect.InsetBy(-1.0, -1.0);
3247 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3248 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3249 
3250 		// draw the frame (again)
3251 		view->SetHighColor(frameShadowColor);
3252 		view->FillEllipse(ellipseRect);
3253 
3254 		// draw the bevel and background
3255 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
3256 			updateRect, bevelColor3, fillGradient);
3257 
3258 		view->PopState();
3259 		view->ClipToInverseRect(cornerRect);
3260 	}
3261 
3262 	// draw the bevel
3263 	_DrawFrame(view, rect,
3264 		bevelColor2, bevelColor1,
3265 		bevelColor3, bevelColor3,
3266 		cornerColor, cornerColor,
3267 		borders);
3268 
3269 	// fill in the background
3270 	view->FillRect(rect, fillGradient);
3271 
3272 	// restore the clipping constraints of the view
3273 	view->PopState();
3274 }
3275 
3276 
3277 void
3278 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect,
3279 	const BRect& updateRect, const rgb_color& background,
3280 	const rgb_color& edgeColor, const rgb_color& frameColor,
3281 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3282 {
3283 	_DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect,
3284 		background, edgeColor, frameColor);
3285 	_DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect,
3286 		bevelColor, fillGradient);
3287 }
3288 
3289 
3290 void
3291 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect,
3292 	const BRect& updateRect, const rgb_color& background,
3293 	const rgb_color& edgeColor, const rgb_color& frameColor)
3294 {
3295 	view->PushState();
3296 
3297 	// constrain clipping region to corner
3298 	view->ClipToRect(cornerRect);
3299 
3300 	// background
3301 	view->SetHighColor(background);
3302 	view->FillRect(cornerRect);
3303 
3304 	// outer edge
3305 	BRect ellipseRect(cornerRect);
3306 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3307 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3308 
3309 	view->SetHighColor(edgeColor);
3310 	view->FillEllipse(ellipseRect);
3311 
3312 	// frame
3313 	ellipseRect.InsetBy(1, 1);
3314 	cornerRect.left++;
3315 	cornerRect.top++;
3316 	view->SetHighColor(frameColor);
3317 	view->FillEllipse(ellipseRect);
3318 
3319 	// prepare for bevel
3320 	cornerRect.left++;
3321 	cornerRect.top++;
3322 
3323 	view->PopState();
3324 }
3325 
3326 
3327 void
3328 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect,
3329 	const BRect& updateRect, const rgb_color& bevelColor,
3330 	const BGradientLinear& fillGradient)
3331 {
3332 	view->PushState();
3333 
3334 	// constrain clipping region to corner
3335 	view->ClipToRect(cornerRect);
3336 
3337 	BRect ellipseRect(cornerRect);
3338 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3339 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3340 
3341 	// bevel
3342 	view->SetHighColor(bevelColor);
3343 	view->FillEllipse(ellipseRect);
3344 
3345 	// gradient
3346 	ellipseRect.InsetBy(1, 1);
3347 	view->FillEllipse(ellipseRect, fillGradient);
3348 
3349 	view->PopState();
3350 }
3351 
3352 
3353 void
3354 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect,
3355 	const BRect& updateRect, const rgb_color& background,
3356 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3357 	const rgb_color& frameTopColor, const rgb_color& frameRightColor,
3358 	const rgb_color& bevelTopColor, const rgb_color& bevelRightColor,
3359 	const BGradientLinear& fillGradient)
3360 {
3361 	_DrawRoundCornerFrameRightTop(view, cornerRect, updateRect,
3362 		background, edgeTopColor, edgeRightColor, frameTopColor,
3363 		frameRightColor);
3364 	_DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect,
3365 		bevelTopColor, bevelRightColor, fillGradient);
3366 }
3367 
3368 
3369 void
3370 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect,
3371 	const BRect& updateRect, const rgb_color& background,
3372 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3373 	const rgb_color& frameTopColor, const rgb_color& frameRightColor)
3374 {
3375 	view->PushState();
3376 
3377 	// constrain clipping region to corner
3378 	view->ClipToRect(cornerRect);
3379 
3380 	// background
3381 	view->SetHighColor(background);
3382 	view->FillRect(cornerRect);
3383 
3384 	// outer edge
3385 	BRect ellipseRect(cornerRect);
3386 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3387 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3388 
3389 	BGradientLinear gradient;
3390 	gradient.AddColor(edgeTopColor, 0);
3391 	gradient.AddColor(edgeRightColor, 255);
3392 	gradient.SetStart(cornerRect.LeftTop());
3393 	gradient.SetEnd(cornerRect.RightBottom());
3394 	view->FillEllipse(ellipseRect, gradient);
3395 
3396 	// frame
3397 	ellipseRect.InsetBy(1, 1);
3398 	cornerRect.right--;
3399 	cornerRect.top++;
3400 	if (frameTopColor == frameRightColor) {
3401 		view->SetHighColor(frameTopColor);
3402 		view->FillEllipse(ellipseRect);
3403 	} else {
3404 		gradient.SetColor(0, frameTopColor);
3405 		gradient.SetColor(1, frameRightColor);
3406 		gradient.SetStart(cornerRect.LeftTop());
3407 		gradient.SetEnd(cornerRect.RightBottom());
3408 		view->FillEllipse(ellipseRect, gradient);
3409 	}
3410 
3411 	// prepare for bevel
3412 	cornerRect.right--;
3413 	cornerRect.top++;
3414 
3415 	view->PopState();
3416 }
3417 
3418 
3419 void
3420 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect,
3421 	const BRect& updateRect, const rgb_color& bevelTopColor,
3422 	const rgb_color& bevelRightColor, const BGradientLinear& fillGradient)
3423 {
3424 	view->PushState();
3425 
3426 	// constrain clipping region to corner
3427 	view->ClipToRect(cornerRect);
3428 
3429 	BRect ellipseRect(cornerRect);
3430 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3431 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3432 
3433 	// bevel
3434 	BGradientLinear gradient;
3435 	gradient.AddColor(bevelTopColor, 0);
3436 	gradient.AddColor(bevelRightColor, 255);
3437 	gradient.SetStart(cornerRect.LeftTop());
3438 	gradient.SetEnd(cornerRect.RightBottom());
3439 	view->FillEllipse(ellipseRect, gradient);
3440 
3441 	// gradient
3442 	ellipseRect.InsetBy(1, 1);
3443 	view->FillEllipse(ellipseRect, fillGradient);
3444 
3445 	view->PopState();
3446 }
3447 
3448 
3449 void
3450 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect,
3451 	const BRect& updateRect, const rgb_color& background,
3452 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3453 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor,
3454 	const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor,
3455 	const BGradientLinear& fillGradient)
3456 {
3457 	_DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect,
3458 		background, edgeLeftColor, edgeBottomColor, frameLeftColor,
3459 		frameBottomColor);
3460 	_DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect,
3461 		bevelLeftColor, bevelBottomColor, fillGradient);
3462 }
3463 
3464 
3465 void
3466 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect,
3467 	const BRect& updateRect, const rgb_color& background,
3468 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3469 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor)
3470 {
3471 	view->PushState();
3472 
3473 	// constrain clipping region to corner
3474 	view->ClipToRect(cornerRect);
3475 
3476 	// background
3477 	view->SetHighColor(background);
3478 	view->FillRect(cornerRect);
3479 
3480 	// outer edge
3481 	BRect ellipseRect(cornerRect);
3482 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3483 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3484 
3485 	BGradientLinear gradient;
3486 	gradient.AddColor(edgeLeftColor, 0);
3487 	gradient.AddColor(edgeBottomColor, 255);
3488 	gradient.SetStart(cornerRect.LeftTop());
3489 	gradient.SetEnd(cornerRect.RightBottom());
3490 	view->FillEllipse(ellipseRect, gradient);
3491 
3492 	// frame
3493 	ellipseRect.InsetBy(1, 1);
3494 	cornerRect.left++;
3495 	cornerRect.bottom--;
3496 	if (frameLeftColor == frameBottomColor) {
3497 		view->SetHighColor(frameLeftColor);
3498 		view->FillEllipse(ellipseRect);
3499 	} else {
3500 		gradient.SetColor(0, frameLeftColor);
3501 		gradient.SetColor(1, frameBottomColor);
3502 		gradient.SetStart(cornerRect.LeftTop());
3503 		gradient.SetEnd(cornerRect.RightBottom());
3504 		view->FillEllipse(ellipseRect, gradient);
3505 	}
3506 
3507 	// prepare for bevel
3508 	cornerRect.left++;
3509 	cornerRect.bottom--;
3510 
3511 	view->PopState();
3512 }
3513 
3514 
3515 void
3516 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect,
3517 	const BRect& updateRect, const rgb_color& bevelLeftColor,
3518 	const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient)
3519 {
3520 	view->PushState();
3521 
3522 	// constrain clipping region to corner
3523 	view->ClipToRect(cornerRect);
3524 
3525 	BRect ellipseRect(cornerRect);
3526 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3527 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3528 
3529 	// bevel
3530 	BGradientLinear gradient;
3531 	gradient.AddColor(bevelLeftColor, 0);
3532 	gradient.AddColor(bevelBottomColor, 255);
3533 	gradient.SetStart(cornerRect.LeftTop());
3534 	gradient.SetEnd(cornerRect.RightBottom());
3535 	view->FillEllipse(ellipseRect, gradient);
3536 
3537 	// gradient
3538 	ellipseRect.InsetBy(1, 1);
3539 	view->FillEllipse(ellipseRect, fillGradient);
3540 
3541 	view->PopState();
3542 }
3543 
3544 
3545 void
3546 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect,
3547 	const BRect& updateRect, const rgb_color& background,
3548 	const rgb_color& edgeColor, const rgb_color& frameColor,
3549 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3550 {
3551 	_DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect,
3552 		background, edgeColor, frameColor);
3553 	_DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect,
3554 		bevelColor, fillGradient);
3555 }
3556 
3557 
3558 void
3559 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect,
3560 	const BRect& updateRect, const rgb_color& background,
3561 	const rgb_color& edgeColor, const rgb_color& frameColor)
3562 {
3563 	view->PushState();
3564 
3565 	// constrain clipping region to corner
3566 	view->ClipToRect(cornerRect);
3567 
3568 	// background
3569 	view->SetHighColor(background);
3570 	view->FillRect(cornerRect);
3571 
3572 	// outer edge
3573 	BRect ellipseRect(cornerRect);
3574 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3575 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3576 
3577 	view->SetHighColor(edgeColor);
3578 	view->FillEllipse(ellipseRect);
3579 
3580 	// frame
3581 	ellipseRect.InsetBy(1, 1);
3582 	cornerRect.right--;
3583 	cornerRect.bottom--;
3584 	view->SetHighColor(frameColor);
3585 	view->FillEllipse(ellipseRect);
3586 
3587 	// prepare for bevel
3588 	cornerRect.right--;
3589 	cornerRect.bottom--;
3590 
3591 	view->PopState();
3592 }
3593 
3594 
3595 void
3596 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view,
3597 	BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor,
3598 	const BGradientLinear& fillGradient)
3599 {
3600 	view->PushState();
3601 
3602 	// constrain clipping region to corner
3603 	view->ClipToRect(cornerRect);
3604 
3605 	BRect ellipseRect(cornerRect);
3606 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3607 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3608 
3609 	// bevel
3610 	view->SetHighColor(bevelColor);
3611 	view->FillEllipse(ellipseRect);
3612 
3613 	// gradient
3614 	ellipseRect.InsetBy(1, 1);
3615 	view->FillEllipse(ellipseRect, fillGradient);
3616 
3617 	view->PopState();
3618 }
3619 
3620 
3621 void
3622 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect,
3623 	const BRect& updateRect,
3624 	const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor,
3625 	const rgb_color& frameLightColor, const rgb_color& frameShadowColor,
3626 	const rgb_color& fillLightColor, const rgb_color& fillShadowColor,
3627 	float leftInset, float topInset, float rightInset, float bottomInset,
3628 	orientation orientation)
3629 {
3630 	if (!ShouldDraw(view, rect, updateRect))
3631 		return;
3632 
3633 	BGradientLinear gradient;
3634 	gradient.AddColor(edgeShadowColor, 0);
3635 	gradient.AddColor(edgeLightColor, 255);
3636 	gradient.SetStart(rect.LeftTop());
3637 	if (orientation == B_HORIZONTAL)
3638 		gradient.SetEnd(rect.LeftBottom());
3639 	else
3640 		gradient.SetEnd(rect.RightTop());
3641 
3642 	view->FillEllipse(rect, gradient);
3643 
3644 	rect.left += leftInset;
3645 	rect.top += topInset;
3646 	rect.right += rightInset;
3647 	rect.bottom += bottomInset;
3648 
3649 	gradient.MakeEmpty();
3650 	gradient.AddColor(frameShadowColor, 0);
3651 	gradient.AddColor(frameLightColor, 255);
3652 	gradient.SetStart(rect.LeftTop());
3653 	if (orientation == B_HORIZONTAL)
3654 		gradient.SetEnd(rect.LeftBottom());
3655 	else
3656 		gradient.SetEnd(rect.RightTop());
3657 
3658 	view->FillEllipse(rect, gradient);
3659 
3660 	rect.left += leftInset;
3661 	rect.top += topInset;
3662 	rect.right += rightInset;
3663 	rect.bottom += bottomInset;
3664 
3665 	gradient.MakeEmpty();
3666 	gradient.AddColor(fillShadowColor, 0);
3667 	gradient.AddColor(fillLightColor, 255);
3668 	gradient.SetStart(rect.LeftTop());
3669 	if (orientation == B_HORIZONTAL)
3670 		gradient.SetEnd(rect.LeftBottom());
3671 	else
3672 		gradient.SetEnd(rect.RightTop());
3673 
3674 	view->FillEllipse(rect, gradient);
3675 }
3676 
3677 
3678 rgb_color
3679 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast,
3680 	float brightness, uint32 flags)
3681 {
3682 	rgb_color edgeLightColor;
3683 
3684 	if ((flags & B_BLEND_FRAME) != 0) {
3685 		uint8 alpha = uint8(20 * contrast);
3686 		uint8 white = uint8(255 * brightness);
3687 
3688 		edgeLightColor = (rgb_color){ white, white, white, alpha };
3689 	} else {
3690 		// colors
3691 		float tintLight = kEdgeBevelLightTint;
3692 
3693 		if (contrast == 0.0)
3694 			tintLight = B_NO_TINT;
3695 		else if (contrast != 1.0)
3696 			tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast;
3697 
3698 		edgeLightColor = tint_color(base, tintLight);
3699 
3700 		if (brightness < 1.0) {
3701 			edgeLightColor.red = uint8(edgeLightColor.red * brightness);
3702 			edgeLightColor.green = uint8(edgeLightColor.green * brightness);
3703 			edgeLightColor.blue = uint8(edgeLightColor.blue * brightness);
3704 		}
3705 	}
3706 
3707 	return edgeLightColor;
3708 }
3709 
3710 
3711 rgb_color
3712 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast,
3713 	float brightness, uint32 flags)
3714 {
3715 	rgb_color edgeShadowColor;
3716 
3717 	if ((flags & B_BLEND_FRAME) != 0) {
3718 		uint8 alpha = uint8(20 * contrast);
3719 		edgeShadowColor = (rgb_color){ 0, 0, 0, alpha };
3720 	} else {
3721 		float tintShadow = kEdgeBevelShadowTint;
3722 
3723 		if (contrast == 0.0)
3724 			tintShadow = B_NO_TINT;
3725 		else if (contrast != 1.0)
3726 			tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast;
3727 
3728 		edgeShadowColor = tint_color(base, tintShadow);
3729 
3730 		if (brightness < 1.0) {
3731 			edgeShadowColor.red = uint8(edgeShadowColor.red * brightness);
3732 			edgeShadowColor.green = uint8(edgeShadowColor.green * brightness);
3733 			edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness);
3734 		}
3735 	}
3736 
3737 	return edgeShadowColor;
3738 }
3739 
3740 
3741 rgb_color
3742 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags)
3743 {
3744 	if ((flags & B_FOCUSED) != 0)
3745 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3746 
3747 	if ((flags & B_ACTIVATED) != 0)
3748 		return _FrameShadowColor(base, flags & ~B_ACTIVATED);
3749 
3750 	rgb_color frameLightColor;
3751 
3752 	if ((flags & B_DISABLED) != 0) {
3753 		// TODO: B_BLEND_FRAME
3754 		frameLightColor = tint_color(base, 1.145);
3755 
3756 		if ((flags & B_DEFAULT_BUTTON) != 0)
3757 			frameLightColor = tint_color(frameLightColor, 1.14);
3758 	} else {
3759 		if ((flags & B_BLEND_FRAME) != 0)
3760 			frameLightColor = (rgb_color){ 0, 0, 0, 75 };
3761 		else
3762 			frameLightColor = tint_color(base, 1.33);
3763 
3764 		if ((flags & B_DEFAULT_BUTTON) != 0)
3765 			frameLightColor = tint_color(frameLightColor, 1.35);
3766 	}
3767 
3768 	return frameLightColor;
3769 }
3770 
3771 
3772 rgb_color
3773 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags)
3774 {
3775 	if ((flags & B_FOCUSED) != 0)
3776 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3777 
3778 	if ((flags & B_ACTIVATED) != 0)
3779 		return _FrameLightColor(base, flags & ~B_ACTIVATED);
3780 
3781 	rgb_color frameShadowColor;
3782 
3783 	if ((flags & B_DISABLED) != 0) {
3784 		// TODO: B_BLEND_FRAME
3785 		frameShadowColor = tint_color(base, 1.24);
3786 
3787 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3788 			frameShadowColor = tint_color(base, 1.145);
3789 			frameShadowColor = tint_color(frameShadowColor, 1.12);
3790 		}
3791 	} else {
3792 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3793 			if ((flags & B_BLEND_FRAME) != 0)
3794 				frameShadowColor = (rgb_color){ 0, 0, 0, 75 };
3795 			else
3796 				frameShadowColor = tint_color(base, 1.33);
3797 
3798 			frameShadowColor = tint_color(frameShadowColor, 1.5);
3799 		} else {
3800 			if ((flags & B_BLEND_FRAME) != 0)
3801 				frameShadowColor = (rgb_color){ 0, 0, 0, 95 };
3802 			else
3803 				frameShadowColor = tint_color(base, 1.47);
3804 		}
3805 	}
3806 
3807 	return frameShadowColor;
3808 }
3809 
3810 
3811 rgb_color
3812 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags)
3813 {
3814 	rgb_color bevelLightColor = tint_color(base, 0.2);
3815 
3816 	if ((flags & B_DISABLED) != 0)
3817 		bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT);
3818 
3819 	if ((flags & B_ACTIVATED) != 0)
3820 		bevelLightColor = tint_color(base, B_DARKEN_1_TINT);
3821 
3822 	return bevelLightColor;
3823 }
3824 
3825 
3826 rgb_color
3827 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags)
3828 {
3829 	rgb_color bevelShadowColor = tint_color(base, 1.08);
3830 
3831 	if ((flags & B_DISABLED) != 0)
3832 		bevelShadowColor = base;
3833 
3834 	if ((flags & B_ACTIVATED) != 0)
3835 		bevelShadowColor = tint_color(base, B_DARKEN_1_TINT);
3836 
3837 	return bevelShadowColor;
3838 }
3839 
3840 
3841 void
3842 HaikuControlLook::_FillGradient(BView* view, const BRect& rect,
3843 	const rgb_color& base, float topTint, float bottomTint,
3844 	orientation orientation)
3845 {
3846 	BGradientLinear gradient;
3847 	_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3848 	view->FillRect(rect, gradient);
3849 }
3850 
3851 
3852 void
3853 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect,
3854 	const rgb_color& base, float topTint, float middle1Tint,
3855 	float middle2Tint, float bottomTint, orientation orientation)
3856 {
3857 	BGradientLinear gradient;
3858 	_MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint,
3859 		middle2Tint, bottomTint, orientation);
3860 	view->FillRect(rect, gradient);
3861 }
3862 
3863 
3864 void
3865 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
3866 	const rgb_color& base, float topTint, float bottomTint,
3867 	orientation orientation) const
3868 {
3869 	gradient.AddColor(tint_color(base, topTint), 0);
3870 	gradient.AddColor(tint_color(base, bottomTint), 255);
3871 	gradient.SetStart(rect.LeftTop());
3872 	if (orientation == B_HORIZONTAL)
3873 		gradient.SetEnd(rect.LeftBottom());
3874 	else
3875 		gradient.SetEnd(rect.RightTop());
3876 }
3877 
3878 
3879 void
3880 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
3881 	const rgb_color& base, float topTint, float middle1Tint,
3882 	float middle2Tint, float bottomTint,
3883 	orientation orientation) const
3884 {
3885 	gradient.AddColor(tint_color(base, topTint), 0);
3886 	gradient.AddColor(tint_color(base, middle1Tint), 132);
3887 	gradient.AddColor(tint_color(base, middle2Tint), 136);
3888 	gradient.AddColor(tint_color(base, bottomTint), 255);
3889 	gradient.SetStart(rect.LeftTop());
3890 	if (orientation == B_HORIZONTAL)
3891 		gradient.SetEnd(rect.LeftBottom());
3892 	else
3893 		gradient.SetEnd(rect.RightTop());
3894 }
3895 
3896 
3897 void
3898 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect,
3899 	const rgb_color& base, uint32 flags, orientation orientation) const
3900 {
3901 	float topTint = 0.49;
3902 	float middleTint1 = 0.62;
3903 	float middleTint2 = 0.76;
3904 	float bottomTint = 0.90;
3905 
3906 	if ((flags & B_ACTIVATED) != 0) {
3907 		topTint = 1.11;
3908 		bottomTint = 1.08;
3909 	}
3910 
3911 	if ((flags & B_DISABLED) != 0) {
3912 		topTint = (topTint + B_NO_TINT) / 2;
3913 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
3914 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
3915 		bottomTint = (bottomTint + B_NO_TINT) / 2;
3916 	} else if ((flags & B_HOVER) != 0) {
3917 		topTint *= kHoverTintFactor;
3918 		middleTint1 *= kHoverTintFactor;
3919 		middleTint2 *= kHoverTintFactor;
3920 		bottomTint *= kHoverTintFactor;
3921 	}
3922 
3923 	if ((flags & B_ACTIVATED) != 0) {
3924 		_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3925 	} else {
3926 		_MakeGlossyGradient(gradient, rect, base, topTint, middleTint1,
3927 			middleTint2, bottomTint, orientation);
3928 	}
3929 }
3930 
3931 
3932 bool
3933 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
3934 	rgb_color& color, uint32 flags) const
3935 {
3936 	if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) {
3937 		// no mark to be drawn at all
3938 		return false;
3939 	}
3940 
3941 	color = ui_color(B_CONTROL_MARK_COLOR);
3942 
3943 	float mix = 1.0;
3944 
3945 	if ((flags & B_DISABLED) != 0) {
3946 		// activated, but disabled
3947 		mix = 0.4;
3948 	} else if ((flags & B_CLICKED) != 0) {
3949 		if ((flags & B_ACTIVATED) != 0) {
3950 			// losing activation
3951 			mix = 0.7;
3952 		} else {
3953 			// becoming activated (or losing partial activation)
3954 			mix = 0.3;
3955 		}
3956 	} else if ((flags & B_PARTIALLY_ACTIVATED) != 0) {
3957 		// partially activated
3958 		mix = 0.5;
3959 	} else {
3960 		// simply activated
3961 	}
3962 
3963 	color.red = uint8(color.red * mix + base.red * (1.0 - mix));
3964 	color.green = uint8(color.green * mix + base.green * (1.0 - mix));
3965 	color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix));
3966 
3967 	return true;
3968 }
3969 
3970 } // namespace BPrivate
3971