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