xref: /haiku/src/kits/interface/HaikuControlLook.cpp (revision 6011ce6c7495e4e707bd33b12a7e22d66c710aad)
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 float kButtonPopUpIndicatorWidth = 11;
36 
37 
38 HaikuControlLook::HaikuControlLook()
39 	:
40 	fCachedOutline(false)
41 {
42 }
43 
44 
45 HaikuControlLook::~HaikuControlLook()
46 {
47 }
48 
49 
50 BAlignment
51 HaikuControlLook::DefaultLabelAlignment() const
52 {
53 	return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER);
54 }
55 
56 
57 float
58 HaikuControlLook::DefaultLabelSpacing() const
59 {
60 	return ceilf(be_plain_font->Size() / 2.0);
61 }
62 
63 
64 float
65 HaikuControlLook::DefaultItemSpacing() const
66 {
67 	return ceilf(be_plain_font->Size() * 0.85);
68 }
69 
70 
71 uint32
72 HaikuControlLook::Flags(BControl* control) const
73 {
74 	uint32 flags = B_IS_CONTROL;
75 
76 	if (!control->IsEnabled())
77 		flags |= B_DISABLED;
78 
79 	if (control->IsFocus() && control->Window() != NULL
80 		&& control->Window()->IsActive()) {
81 		flags |= B_FOCUSED;
82 	}
83 
84 	switch (control->Value()) {
85 		case B_CONTROL_ON:
86 			flags |= B_ACTIVATED;
87 			break;
88 		case B_CONTROL_PARTIALLY_ON:
89 			flags |= B_PARTIALLY_ACTIVATED;
90 			break;
91 	}
92 
93 	if (control->Parent() != NULL
94 		&& (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) {
95 		// In this constellation, assume we want to render the control
96 		// against the already existing view contents of the parent view.
97 		flags |= B_BLEND_FRAME;
98 	}
99 
100 	return flags;
101 }
102 
103 
104 // #pragma mark -
105 
106 
107 void
108 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
109 	const rgb_color& base, const rgb_color& background, uint32 flags,
110 	uint32 borders)
111 {
112 	_DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base,
113 		background, 1.0, 1.0, flags, borders);
114 }
115 
116 
117 void
118 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
119 	float radius, const rgb_color& base, const rgb_color& background, uint32 flags,
120 	uint32 borders)
121 {
122 	_DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius,
123 		base, background, 1.0, 1.0, flags, borders);
124 }
125 
126 
127 void
128 HaikuControlLook::DrawButtonFrame(BView* view, BRect& rect,
129 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
130 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
131 	const rgb_color& background, uint32 flags,
132 	uint32 borders)
133 {
134 	_DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius,
135 		leftBottomRadius, rightBottomRadius, base, background,
136 		1.0, 1.0, flags, borders);
137 }
138 
139 
140 void
141 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
142 	const BRect& updateRect, const rgb_color& base, uint32 flags,
143 	uint32 borders, orientation orientation)
144 {
145 	_DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
146 		base, false, flags, borders, orientation);
147 }
148 
149 
150 void
151 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
152 	const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
153 	uint32 borders, orientation orientation)
154 {
155 	_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
156 		radius, base, false, flags, borders, orientation);
157 }
158 
159 
160 void
161 HaikuControlLook::DrawButtonBackground(BView* view, BRect& rect,
162 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
163 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
164 	uint32 flags, uint32 borders, orientation orientation)
165 {
166 	_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
167 		rightTopRadius, leftBottomRadius, rightBottomRadius, base, false, flags,
168 		borders, orientation);
169 }
170 
171 
172 void
173 HaikuControlLook::DrawMenuBarBackground(BView* view, BRect& rect,
174 	const BRect& updateRect, const rgb_color& base, uint32 flags,
175 	uint32 borders)
176 {
177 	if (!rect.IsValid() || !rect.Intersects(updateRect))
178 		return;
179 
180 	// the surface edges
181 
182 	// colors
183 	float topTint;
184 	float bottomTint;
185 
186 	if ((flags & B_ACTIVATED) != 0) {
187 		rgb_color bevelColor1 = tint_color(base, 1.40);
188 		rgb_color bevelColor2 = tint_color(base, 1.25);
189 
190 		topTint = 1.25;
191 		bottomTint = 1.20;
192 
193 		_DrawFrame(view, rect,
194 			bevelColor1, bevelColor1,
195 			bevelColor2, bevelColor2,
196 			borders & B_TOP_BORDER);
197 	} else {
198 		rgb_color cornerColor = tint_color(base, 0.9);
199 		rgb_color bevelColorTop = tint_color(base, 0.5);
200 		rgb_color bevelColorLeft = tint_color(base, 0.7);
201 		rgb_color bevelColorRightBottom = tint_color(base, 1.08);
202 
203 		topTint = 0.69;
204 		bottomTint = 1.03;
205 
206 		_DrawFrame(view, rect,
207 			bevelColorLeft, bevelColorTop,
208 			bevelColorRightBottom, bevelColorRightBottom,
209 			cornerColor, cornerColor,
210 			borders);
211 	}
212 
213 	// draw surface top
214 	_FillGradient(view, rect, base, topTint, bottomTint);
215 }
216 
217 
218 void
219 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
220 	const BRect& updateRect, const rgb_color& base,
221 	const rgb_color& background, uint32 flags, uint32 borders)
222 {
223 	_DrawButtonFrame(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f, base,
224 		background, 0.6, 1.0, flags, borders);
225 }
226 
227 
228 void
229 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
230 	const BRect& updateRect, float radius, const rgb_color& base,
231 	const rgb_color& background, uint32 flags, uint32 borders)
232 {
233 	_DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius,
234 		base, background, 0.6, 1.0, flags, borders);
235 }
236 
237 
238 void
239 HaikuControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
240 	const BRect& updateRect, float leftTopRadius,
241 	float rightTopRadius, float leftBottomRadius,
242 	float rightBottomRadius, const rgb_color& base,
243 	const rgb_color& background, uint32 flags, uint32 borders)
244 {
245 	_DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius,
246 		leftBottomRadius, rightBottomRadius, base, background, 0.6, 1.0,
247 		flags, borders);
248 }
249 
250 
251 void
252 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
253 	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
254 	uint32 flags)
255 {
256 	_DrawMenuFieldBackgroundOutside(view, rect, updateRect,
257 		0.0f, 0.0f, 0.0f, 0.0f, base, popupIndicator, flags);
258 }
259 
260 
261 void
262 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
263 	const BRect& updateRect, const rgb_color& base, uint32 flags,
264 	uint32 borders)
265 {
266 	_DrawMenuFieldBackgroundInside(view, rect, updateRect,
267 		0.0f, 0.0f, 0.0f, 0.0f, base, flags, borders);
268 }
269 
270 
271 void
272 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
273 	const BRect& updateRect, float radius, const rgb_color& base,
274 	bool popupIndicator, uint32 flags)
275 {
276 	_DrawMenuFieldBackgroundOutside(view, rect, updateRect, radius, radius,
277 		radius, radius, base, popupIndicator, flags);
278 }
279 
280 
281 void
282 HaikuControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
283 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
284 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
285 	bool popupIndicator, uint32 flags)
286 {
287 	_DrawMenuFieldBackgroundOutside(view, rect, updateRect, leftTopRadius,
288 		rightTopRadius, leftBottomRadius, rightBottomRadius, base,
289 		popupIndicator, flags);
290 }
291 
292 
293 void
294 HaikuControlLook::DrawMenuBackground(BView* view, BRect& rect,
295 	const BRect& updateRect, const rgb_color& base, uint32 flags,
296 	uint32 borders)
297 {
298 	if (!rect.IsValid() || !rect.Intersects(updateRect))
299 		return;
300 
301 	// 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 	switch (side) {
1878 		default:
1879 		case B_TOP_BORDER:
1880 			rect.top += 4;
1881 			background.bottom = rect.top;
1882 			break;
1883 
1884 		case B_BOTTOM_BORDER:
1885 			rect.bottom -= 4;
1886 			background.top = rect.bottom;
1887 			break;
1888 
1889 		case B_LEFT_BORDER:
1890 			rect.left += 4;
1891 			background.right = rect.left;
1892 			break;
1893 
1894 		case B_RIGHT_BORDER:
1895 			rect.right -= 4;
1896 			background.left = rect.right;
1897 			break;
1898 	}
1899 
1900 	// active tabs stand out at the top, but this is an inactive tab
1901 	view->SetHighColor(base);
1902 	view->FillRect(background);
1903 
1904 	// frame and fill
1905 	_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
1906 		edgeLightColor, borders);
1907 
1908 	_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
1909 		frameShadowColor, borders);
1910 
1911 	if ((side == B_TOP_BORDER || side == B_BOTTOM_BORDER)
1912 		&& (borders & B_LEFT_BORDER) != 0) {
1913 		if (rect.IsValid()) {
1914 			_DrawFrame(view, rect, bevelShadowColor, bevelShadowColor,
1915 				bevelLightColor, bevelLightColor, B_LEFT_BORDER & ~borders);
1916 		} else if ((B_LEFT_BORDER & ~borders) != 0)
1917 			rect.left++;
1918 	} else if ((side == B_LEFT_BORDER || side == B_RIGHT_BORDER)
1919 		&& (borders & B_TOP_BORDER) != 0) {
1920 		if (rect.IsValid()) {
1921 			_DrawFrame(view, rect, bevelShadowColor, bevelShadowColor,
1922 				bevelLightColor, bevelLightColor, B_TOP_BORDER & ~borders);
1923 		} else if ((B_TOP_BORDER & ~borders) != 0)
1924 			rect.top++;
1925 	}
1926 
1927 	view->FillRect(rect, fillGradient);
1928 }
1929 
1930 
1931 void
1932 HaikuControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect,
1933 	const rgb_color& base, orientation orientation, uint32 flags,
1934 	uint32 borders)
1935 {
1936 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1937 		return;
1938 
1939 	rgb_color background;
1940 	if ((flags & (B_CLICKED | B_ACTIVATED)) != 0)
1941 		background = tint_color(base, B_DARKEN_1_TINT);
1942 	else
1943 		background = base;
1944 
1945 	rgb_color light = tint_color(background, 0.6);
1946 	rgb_color shadow = tint_color(background, 1.21);
1947 
1948 	// frame
1949 	if (borders != 0 && rect.Width() > 3 && rect.Height() > 3)
1950 		DrawRaisedBorder(view, rect, updateRect, background, flags, borders);
1951 
1952 	// dots and rest of background
1953 	if (orientation == B_HORIZONTAL) {
1954 		if (rect.Width() > 2) {
1955 			// background on left/right
1956 			BRegion region(rect);
1957 			rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5);
1958 			rect.right = rect.left + 1;
1959 			region.Exclude(rect);
1960 			view->SetHighColor(background);
1961 			view->FillRegion(&region);
1962 		}
1963 
1964 		BPoint dot = rect.LeftTop();
1965 		BPoint stop = rect.LeftBottom();
1966 		int32 num = 1;
1967 		while (dot.y <= stop.y) {
1968 			rgb_color col1;
1969 			rgb_color col2;
1970 			switch (num) {
1971 				case 1:
1972 					col1 = background;
1973 					col2 = background;
1974 					break;
1975 				case 2:
1976 					col1 = shadow;
1977 					col2 = background;
1978 					break;
1979 				case 3:
1980 				default:
1981 					col1 = background;
1982 					col2 = light;
1983 					num = 0;
1984 					break;
1985 			}
1986 			view->SetHighColor(col1);
1987 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1988 			view->SetHighColor(col2);
1989 			dot.x++;
1990 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1991 			dot.x -= 1.0;
1992 			// next pixel
1993 			num++;
1994 			dot.y++;
1995 		}
1996 	} else {
1997 		if (rect.Height() > 2) {
1998 			// background on left/right
1999 			BRegion region(rect);
2000 			rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5);
2001 			rect.bottom = rect.top + 1;
2002 			region.Exclude(rect);
2003 			view->SetHighColor(background);
2004 			view->FillRegion(&region);
2005 		}
2006 
2007 		BPoint dot = rect.LeftTop();
2008 		BPoint stop = rect.RightTop();
2009 		int32 num = 1;
2010 		while (dot.x <= stop.x) {
2011 			rgb_color col1;
2012 			rgb_color col2;
2013 			switch (num) {
2014 				case 1:
2015 					col1 = background;
2016 					col2 = background;
2017 					break;
2018 				case 2:
2019 					col1 = shadow;
2020 					col2 = background;
2021 					break;
2022 				case 3:
2023 				default:
2024 					col1 = background;
2025 					col2 = light;
2026 					num = 0;
2027 					break;
2028 			}
2029 			view->SetHighColor(col1);
2030 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
2031 			view->SetHighColor(col2);
2032 			dot.y++;
2033 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
2034 			dot.y -= 1.0;
2035 			// next pixel
2036 			num++;
2037 			dot.x++;
2038 		}
2039 	}
2040 }
2041 
2042 
2043 // #pragma mark -
2044 
2045 
2046 void
2047 HaikuControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect,
2048 	const rgb_color& base, border_style borderStyle, uint32 flags,
2049 	uint32 borders)
2050 {
2051 	if (borderStyle == B_NO_BORDER)
2052 		return;
2053 
2054 	rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT);
2055 	if (base.red + base.green + base.blue <= 128 * 3) {
2056 		scrollbarFrameColor = tint_color(base, B_LIGHTEN_1_TINT);
2057 	}
2058 
2059 	if ((flags & B_FOCUSED) != 0)
2060 		scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
2061 
2062 	if (borderStyle == B_FANCY_BORDER)
2063 		_DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
2064 
2065 	_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
2066 		scrollbarFrameColor, scrollbarFrameColor, borders);
2067 }
2068 
2069 
2070 void
2071 HaikuControlLook::DrawRaisedBorder(BView* view, BRect& rect,
2072 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2073 	uint32 borders)
2074 {
2075 	rgb_color lightColor;
2076 	rgb_color shadowColor;
2077 
2078 	if ((flags & B_DISABLED) != 0) {
2079 		lightColor = base;
2080 		shadowColor = base;
2081 	} else {
2082 		lightColor = tint_color(base, 0.85);
2083 		shadowColor = tint_color(base, 1.07);
2084 	}
2085 
2086 	_DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor,
2087 		borders);
2088 }
2089 
2090 
2091 void
2092 HaikuControlLook::DrawTextControlBorder(BView* view, BRect& rect,
2093 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2094 	uint32 borders)
2095 {
2096 	if (!rect.Intersects(updateRect))
2097 		return;
2098 
2099 	rgb_color dark1BorderColor;
2100 	rgb_color dark2BorderColor;
2101 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
2102 	rgb_color invalidColor = ui_color(B_FAILURE_COLOR);
2103 
2104 	if ((flags & B_DISABLED) != 0) {
2105 		_DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders);
2106 
2107 		if ((flags & B_BLEND_FRAME) != 0)
2108 			dark1BorderColor = (rgb_color){ 0, 0, 0, 40 };
2109 		else
2110 			dark1BorderColor = tint_color(base, 1.15);
2111 		dark2BorderColor = dark1BorderColor;
2112 	} else if ((flags & B_CLICKED) != 0) {
2113 		dark1BorderColor = tint_color(base, 1.50);
2114 		dark2BorderColor = tint_color(base, 1.49);
2115 
2116 		// BCheckBox uses this to indicate the clicked state...
2117 		_DrawFrame(view, rect,
2118 			dark1BorderColor, dark1BorderColor,
2119 			dark2BorderColor, dark2BorderColor);
2120 
2121 		dark2BorderColor = dark1BorderColor;
2122 	} else {
2123 		_DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders);
2124 
2125 		if ((flags & B_BLEND_FRAME) != 0) {
2126 			dark1BorderColor = (rgb_color){ 0, 0, 0, 102 };
2127 			dark2BorderColor = (rgb_color){ 0, 0, 0, 97 };
2128 		} else {
2129 			dark1BorderColor = tint_color(base, 1.40);
2130 			dark2BorderColor = tint_color(base, 1.38);
2131 		}
2132 	}
2133 
2134 	if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) {
2135 		dark1BorderColor = navigationColor;
2136 		dark2BorderColor = navigationColor;
2137 	}
2138 
2139 	if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0) {
2140 		dark1BorderColor = invalidColor;
2141 		dark2BorderColor = invalidColor;
2142 	}
2143 
2144 	if ((flags & B_BLEND_FRAME) != 0) {
2145 		drawing_mode oldMode = view->DrawingMode();
2146 		view->SetDrawingMode(B_OP_ALPHA);
2147 
2148 		_DrawFrame(view, rect,
2149 			dark1BorderColor, dark1BorderColor,
2150 			dark2BorderColor, dark2BorderColor, borders);
2151 
2152 		view->SetDrawingMode(oldMode);
2153 	} else {
2154 		_DrawFrame(view, rect,
2155 			dark1BorderColor, dark1BorderColor,
2156 			dark2BorderColor, dark2BorderColor, borders);
2157 	}
2158 }
2159 
2160 
2161 void
2162 HaikuControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
2163 	const rgb_color& base, uint32 borders)
2164 {
2165 	rgb_color frameColor = tint_color(base, 1.30);
2166 	rgb_color bevelLight = tint_color(base, 0.8);
2167 	rgb_color bevelShadow = tint_color(base, 1.03);
2168 
2169 	_DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight,
2170 		borders);
2171 
2172 	_DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor,
2173 		borders);
2174 
2175 	_DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow,
2176 		borders);
2177 }
2178 
2179 
2180 void
2181 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2182 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2183 	const rgb_color* textColor)
2184 {
2185 	DrawLabel(view, label, NULL, rect, updateRect, base, flags,
2186 		DefaultLabelAlignment(), textColor);
2187 }
2188 
2189 
2190 void
2191 HaikuControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2192 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2193 	const BAlignment& alignment, const rgb_color* textColor)
2194 {
2195 	DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment,
2196 		textColor);
2197 }
2198 
2199 
2200 void
2201 HaikuControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base,
2202 	uint32 flags, const BPoint& where, const rgb_color* textColor)
2203 {
2204 	// setup the text color
2205 
2206 	BWindow* window = view->Window();
2207 	bool isDesktop = window
2208 		&& window->Feel() == kDesktopWindowFeel
2209 		&& window->Look() == kDesktopWindowLook
2210 		&& view->Parent()
2211 		&& view->Parent()->Parent() == NULL
2212 		&& (flags & B_IGNORE_OUTLINE) == 0;
2213 
2214 	rgb_color low;
2215 	rgb_color color;
2216 	rgb_color glowColor;
2217 
2218 	if (textColor != NULL)
2219 		glowColor = *textColor;
2220 	else if ((flags & B_IS_CONTROL) != 0)
2221 		glowColor = ui_color(B_CONTROL_TEXT_COLOR);
2222 	else
2223 		glowColor = ui_color(B_PANEL_TEXT_COLOR);
2224 
2225 	color = glowColor;
2226 
2227 	if (isDesktop)
2228 		low = view->Parent()->ViewColor();
2229 	else
2230 		low = base;
2231 
2232 	if ((flags & B_DISABLED) != 0) {
2233 		color.red = (uint8)(((int32)low.red + color.red + 1) / 2);
2234 		color.green = (uint8)(((int32)low.green + color.green + 1) / 2);
2235 		color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2);
2236 	}
2237 
2238 	drawing_mode oldMode = view->DrawingMode();
2239 
2240 	if (isDesktop) {
2241 		// enforce proper use of desktop label colors
2242 		if (low.Brightness() < 100) {
2243 			if (textColor == NULL)
2244 				color = make_color(255, 255, 255);
2245 
2246 			glowColor = make_color(0, 0, 0);
2247 		} else {
2248 			if (textColor == NULL)
2249 				color = make_color(0, 0, 0);
2250 
2251 			glowColor = make_color(255, 255, 255);
2252 		}
2253 
2254 		// drawing occurs on the desktop
2255 		if (fCachedWorkspace != current_workspace()) {
2256 			int8 indice = 0;
2257 			int32 mask;
2258 			bool tmpOutline;
2259 			while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces",
2260 					indice, &mask) == B_OK
2261 				&& fBackgroundInfo.FindBool("be:bgndimginfoerasetext",
2262 					indice, &tmpOutline) == B_OK) {
2263 
2264 				if (((1 << current_workspace()) & mask) != 0) {
2265 					fCachedOutline = tmpOutline;
2266 					fCachedWorkspace = current_workspace();
2267 					break;
2268 				}
2269 				indice++;
2270 			}
2271 		}
2272 
2273 		if (fCachedOutline) {
2274 			BFont font;
2275 			view->GetFont(&font);
2276 
2277 			view->SetDrawingMode(B_OP_ALPHA);
2278 			view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
2279 			// Draw glow or outline
2280 			if (glowColor.Brightness() > 128) {
2281 				font.SetFalseBoldWidth(2.0);
2282 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2283 
2284 				glowColor.alpha = 30;
2285 				view->SetHighColor(glowColor);
2286 				view->DrawString(label, where);
2287 
2288 				font.SetFalseBoldWidth(1.0);
2289 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2290 
2291 				glowColor.alpha = 65;
2292 				view->SetHighColor(glowColor);
2293 				view->DrawString(label, where);
2294 
2295 				font.SetFalseBoldWidth(0.0);
2296 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2297 			} else {
2298 				font.SetFalseBoldWidth(1.0);
2299 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2300 
2301 				glowColor.alpha = 30;
2302 				view->SetHighColor(glowColor);
2303 				view->DrawString(label, where);
2304 
2305 				font.SetFalseBoldWidth(0.0);
2306 				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2307 
2308 				glowColor.alpha = 200;
2309 				view->SetHighColor(glowColor);
2310 				view->DrawString(label, BPoint(where.x + 1, where.y + 1));
2311 			}
2312 		}
2313 	}
2314 
2315 	view->SetHighColor(color);
2316 	view->SetDrawingMode(B_OP_OVER);
2317 	view->DrawString(label, where);
2318 	view->SetDrawingMode(oldMode);
2319 }
2320 
2321 
2322 void
2323 HaikuControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon,
2324 	BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags,
2325 	const BAlignment& alignment, const rgb_color* textColor)
2326 {
2327 	if (!rect.Intersects(updateRect))
2328 		return;
2329 
2330 	if (label == NULL && icon == NULL)
2331 		return;
2332 
2333 	if (label == NULL) {
2334 		// icon only
2335 		BRect alignedRect = BLayoutUtils::AlignInFrame(rect,
2336 			icon->Bounds().Size(), alignment);
2337 		drawing_mode oldMode = view->DrawingMode();
2338 		view->SetDrawingMode(B_OP_OVER);
2339 		view->DrawBitmap(icon, alignedRect.LeftTop());
2340 		view->SetDrawingMode(oldMode);
2341 		return;
2342 	}
2343 
2344 	// label, possibly with icon
2345 	float availableWidth = rect.Width() + 1;
2346 	float width = 0;
2347 	float textOffset = 0;
2348 	float height = 0;
2349 
2350 	if (icon != NULL) {
2351 		width = icon->Bounds().Width() + DefaultLabelSpacing() + 1;
2352 		height = icon->Bounds().Height() + 1;
2353 		textOffset = width;
2354 		availableWidth -= textOffset;
2355 	}
2356 
2357 	// truncate the label if necessary and get the width and height
2358 	BString truncatedLabel(label);
2359 
2360 	BFont font;
2361 	view->GetFont(&font);
2362 
2363 	font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth);
2364 	width += ceilf(font.StringWidth(truncatedLabel.String()));
2365 
2366 	font_height fontHeight;
2367 	font.GetHeight(&fontHeight);
2368 	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
2369 	height = std::max(height, textHeight);
2370 
2371 	// handle alignment
2372 	BRect alignedRect(BLayoutUtils::AlignOnRect(rect,
2373 		BSize(width - 1, height - 1), alignment));
2374 
2375 	if (icon != NULL) {
2376 		BPoint location(alignedRect.LeftTop());
2377 		if (icon->Bounds().Height() + 1 < height)
2378 			location.y += ceilf((height - icon->Bounds().Height() - 1) / 2);
2379 
2380 		drawing_mode oldMode = view->DrawingMode();
2381 		view->SetDrawingMode(B_OP_OVER);
2382 		view->DrawBitmap(icon, location);
2383 		view->SetDrawingMode(oldMode);
2384 	}
2385 
2386 	BPoint location(alignedRect.left + textOffset,
2387 		alignedRect.top + ceilf(fontHeight.ascent));
2388 	if (textHeight < height)
2389 		location.y += ceilf((height - textHeight) / 2);
2390 
2391 	DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor);
2392 }
2393 
2394 
2395 void
2396 HaikuControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left,
2397 	float& _top, float& _right, float& _bottom)
2398 {
2399 	// All frames have the same inset on each side.
2400 	float inset = 0;
2401 
2402 	switch (frameType) {
2403 		case B_BUTTON_FRAME:
2404 			inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2;
2405 			break;
2406 		case B_GROUP_FRAME:
2407 		case B_MENU_FIELD_FRAME:
2408 			inset = 3;
2409 			break;
2410 		case B_SCROLL_VIEW_FRAME:
2411 		case B_TEXT_CONTROL_FRAME:
2412 			inset = 2;
2413 			break;
2414 	}
2415 
2416 	inset = ceilf(inset * (be_plain_font->Size() / 12.0f));
2417 
2418 	_left = inset;
2419 	_top = inset;
2420 	_right = inset;
2421 	_bottom = inset;
2422 }
2423 
2424 
2425 void
2426 HaikuControlLook::GetBackgroundInsets(background_type backgroundType,
2427 	uint32 flags, float& _left, float& _top, float& _right, float& _bottom)
2428 {
2429 	// Most backgrounds have the same inset on each side.
2430 	float inset = 0;
2431 
2432 	switch (backgroundType) {
2433 		case B_BUTTON_BACKGROUND:
2434 		case B_MENU_BACKGROUND:
2435 		case B_MENU_BAR_BACKGROUND:
2436 		case B_MENU_FIELD_BACKGROUND:
2437 		case B_MENU_ITEM_BACKGROUND:
2438 			inset = 1;
2439 			break;
2440 		case B_BUTTON_WITH_POP_UP_BACKGROUND:
2441 			_left = 1;
2442 			_top = 1;
2443 			_right = 1 + kButtonPopUpIndicatorWidth;
2444 			_bottom = 1;
2445 			return;
2446 		case B_HORIZONTAL_SCROLL_BAR_BACKGROUND:
2447 			_left = 2;
2448 			_top = 0;
2449 			_right = 1;
2450 			_bottom = 0;
2451 			return;
2452 		case B_VERTICAL_SCROLL_BAR_BACKGROUND:
2453 			_left = 0;
2454 			_top = 2;
2455 			_right = 0;
2456 			_bottom = 1;
2457 			return;
2458 	}
2459 
2460 	_left = inset;
2461 	_top = inset;
2462 	_right = inset;
2463 	_bottom = inset;
2464 }
2465 
2466 
2467 void
2468 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2469 	const BRect& updateRect, const rgb_color& base, uint32 flags,
2470 	uint32 borders, orientation orientation)
2471 {
2472 	_DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
2473 		base, true, flags, borders, orientation);
2474 }
2475 
2476 
2477 void
2478 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2479 	const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
2480 	uint32 borders, orientation orientation)
2481 {
2482 	_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
2483 		radius, base, true, flags, borders, orientation);
2484 }
2485 
2486 
2487 void
2488 HaikuControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2489 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2490 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2491 	uint32 flags, uint32 borders, orientation orientation)
2492 {
2493 	_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
2494 		rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
2495 		borders, orientation);
2496 }
2497 
2498 
2499 // #pragma mark -
2500 
2501 
2502 void
2503 HaikuControlLook::_DrawButtonFrame(BView* view, BRect& rect,
2504 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2505 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2506 	const rgb_color& background, float contrast, float brightness,
2507 	uint32 flags, uint32 borders)
2508 {
2509 	if (!rect.IsValid())
2510 		return;
2511 
2512 	// save the clipping constraints of the view
2513 	view->PushState();
2514 
2515 	// set clipping constraints to updateRect
2516 	BRegion clipping(updateRect);
2517 	view->ConstrainClippingRegion(&clipping);
2518 
2519 	// If the button is flat and neither activated nor otherwise highlighted
2520 	// (mouse hovering or focussed), draw it flat.
2521 	if ((flags & B_FLAT) != 0
2522 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2523 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2524 			|| (flags & B_DISABLED) != 0)) {
2525 		_DrawFrame(view, rect, background, background, background,
2526 			background, borders);
2527 		_DrawFrame(view, rect, background, background, background,
2528 			background, borders);
2529 		view->PopState();
2530 		return;
2531 	}
2532 
2533 	// outer edge colors
2534 	rgb_color edgeLightColor;
2535 	rgb_color edgeShadowColor;
2536 
2537 	// default button frame color
2538 	rgb_color defaultIndicatorColor = ui_color(B_CONTROL_BORDER_COLOR);
2539 	rgb_color cornerBgColor;
2540 
2541 	if ((flags & B_DISABLED) != 0) {
2542 		defaultIndicatorColor = disable_color(defaultIndicatorColor,
2543 			background);
2544 	}
2545 
2546 	drawing_mode oldMode = view->DrawingMode();
2547 
2548 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2549 		cornerBgColor = defaultIndicatorColor;
2550 		edgeLightColor = _EdgeLightColor(defaultIndicatorColor,
2551 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2552 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2553 		edgeShadowColor = _EdgeShadowColor(defaultIndicatorColor,
2554 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2555 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9), flags);
2556 
2557 		// draw default button indicator
2558 		// Allow a 1-pixel border of the background to come through.
2559 		rect.InsetBy(1, 1);
2560 
2561 		view->SetHighColor(defaultIndicatorColor);
2562 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2563 		rect.InsetBy(1, 1);
2564 
2565 		view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
2566 		rect.InsetBy(1, 1);
2567 	} else {
2568 		cornerBgColor = background;
2569 		if ((flags & B_BLEND_FRAME) != 0) {
2570 			// set the background color to transparent for the case
2571 			// that we are on the desktop
2572 			cornerBgColor.alpha = 0;
2573 			view->SetDrawingMode(B_OP_ALPHA);
2574 		}
2575 
2576 		edgeLightColor = _EdgeLightColor(background,
2577 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2578 			brightness * 1.0, flags);
2579 		edgeShadowColor = _EdgeShadowColor(background,
2580 			contrast * (flags & B_DISABLED) != 0 ? 0.0 : 1.0,
2581 			brightness * 1.0, flags);
2582 	}
2583 
2584 	// frame colors
2585 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
2586 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
2587 
2588 	// rounded corners
2589 
2590 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2591 		&& leftTopRadius > 0) {
2592 		// draw left top rounded corner
2593 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2594 			floorf(rect.left + leftTopRadius),
2595 			floorf(rect.top + leftTopRadius));
2596 		clipping.Exclude(leftTopCorner);
2597 		_DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect,
2598 			cornerBgColor, edgeShadowColor, frameLightColor);
2599 	}
2600 
2601 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2602 		&& rightTopRadius > 0) {
2603 		// draw right top rounded corner
2604 		BRect rightTopCorner(floorf(rect.right - rightTopRadius),
2605 			floorf(rect.top), floorf(rect.right),
2606 			floorf(rect.top + rightTopRadius));
2607 		clipping.Exclude(rightTopCorner);
2608 		_DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect,
2609 			cornerBgColor, edgeShadowColor, edgeLightColor,
2610 			frameLightColor, frameShadowColor);
2611 	}
2612 
2613 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2614 		&& leftBottomRadius > 0) {
2615 		// draw left bottom rounded corner
2616 		BRect leftBottomCorner(floorf(rect.left),
2617 			floorf(rect.bottom - leftBottomRadius),
2618 			floorf(rect.left + leftBottomRadius), floorf(rect.bottom));
2619 		clipping.Exclude(leftBottomCorner);
2620 		_DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect,
2621 			cornerBgColor, edgeShadowColor, edgeLightColor,
2622 			frameLightColor, frameShadowColor);
2623 	}
2624 
2625 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2626 		&& rightBottomRadius > 0) {
2627 		// draw right bottom rounded corner
2628 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius),
2629 			floorf(rect.bottom - rightBottomRadius), floorf(rect.right),
2630 			floorf(rect.bottom));
2631 		clipping.Exclude(rightBottomCorner);
2632 		_DrawRoundCornerFrameRightBottom(view, rightBottomCorner,
2633 			updateRect, cornerBgColor, edgeLightColor, frameShadowColor);
2634 	}
2635 
2636 	// clip out the corners
2637 	view->ConstrainClippingRegion(&clipping);
2638 
2639 	// draw outer edge
2640 	if ((flags & B_DEFAULT_BUTTON) != 0) {
2641 		_DrawOuterResessedFrame(view, rect, defaultIndicatorColor,
2642 			contrast * ((flags & B_DISABLED) != 0 ? 0.3 : 0.8),
2643 			brightness * ((flags & B_DISABLED) != 0 ? 1.0 : 0.9),
2644 			flags, borders);
2645 	} else {
2646 		_DrawOuterResessedFrame(view, rect, background,
2647 			contrast * ((flags & B_DISABLED) != 0 ? 0.0 : 1.0),
2648 			brightness * 1.0, flags, borders);
2649 	}
2650 
2651 	view->SetDrawingMode(oldMode);
2652 
2653 	// draw frame
2654 	if ((flags & B_BLEND_FRAME) != 0) {
2655 		drawing_mode oldDrawingMode = view->DrawingMode();
2656 		view->SetDrawingMode(B_OP_ALPHA);
2657 
2658 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2659 			frameShadowColor, frameShadowColor, borders);
2660 
2661 		view->SetDrawingMode(oldDrawingMode);
2662 	} else {
2663 		_DrawFrame(view, rect, frameLightColor, frameLightColor,
2664 			frameShadowColor, frameShadowColor, borders);
2665 	}
2666 
2667 	// restore the clipping constraints of the view
2668 	view->PopState();
2669 }
2670 
2671 
2672 void
2673 HaikuControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
2674 	const rgb_color& base, float contrast, float brightness, uint32 flags,
2675 	uint32 borders)
2676 {
2677 	rgb_color edgeLightColor = _EdgeLightColor(base, contrast,
2678 		brightness, flags);
2679 	rgb_color edgeShadowColor = _EdgeShadowColor(base, contrast,
2680 		brightness, flags);
2681 
2682 	if ((flags & B_BLEND_FRAME) != 0) {
2683 		// assumes the background has already been painted
2684 		drawing_mode oldDrawingMode = view->DrawingMode();
2685 		view->SetDrawingMode(B_OP_ALPHA);
2686 
2687 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2688 			edgeLightColor, edgeLightColor, borders);
2689 
2690 		view->SetDrawingMode(oldDrawingMode);
2691 	} else {
2692 		_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor,
2693 			edgeLightColor, edgeLightColor, borders);
2694 	}
2695 }
2696 
2697 
2698 void
2699 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2700 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2701 	uint32 borders)
2702 {
2703 	view->BeginLineArray(4);
2704 
2705 	if (borders & B_LEFT_BORDER) {
2706 		view->AddLine(
2707 			BPoint(rect.left, rect.bottom),
2708 			BPoint(rect.left, rect.top), left);
2709 		rect.left++;
2710 	}
2711 	if (borders & B_TOP_BORDER) {
2712 		view->AddLine(
2713 			BPoint(rect.left, rect.top),
2714 			BPoint(rect.right, rect.top), top);
2715 		rect.top++;
2716 	}
2717 	if (borders & B_RIGHT_BORDER) {
2718 		view->AddLine(
2719 			BPoint(rect.right, rect.top),
2720 			BPoint(rect.right, rect.bottom), right);
2721 		rect.right--;
2722 	}
2723 	if (borders & B_BOTTOM_BORDER) {
2724 		view->AddLine(
2725 			BPoint(rect.left, rect.bottom),
2726 			BPoint(rect.right, rect.bottom), bottom);
2727 		rect.bottom--;
2728 	}
2729 
2730 	view->EndLineArray();
2731 }
2732 
2733 
2734 void
2735 HaikuControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
2736 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
2737 	const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders)
2738 {
2739 	view->BeginLineArray(6);
2740 
2741 	if (borders & B_TOP_BORDER) {
2742 		if (borders & B_RIGHT_BORDER) {
2743 			view->AddLine(
2744 				BPoint(rect.left, rect.top),
2745 				BPoint(rect.right - 1, rect.top), top);
2746 			view->AddLine(
2747 				BPoint(rect.right, rect.top),
2748 				BPoint(rect.right, rect.top), rightTop);
2749 		} else {
2750 			view->AddLine(
2751 				BPoint(rect.left, rect.top),
2752 				BPoint(rect.right, rect.top), top);
2753 		}
2754 		rect.top++;
2755 	}
2756 
2757 	if (borders & B_LEFT_BORDER) {
2758 		view->AddLine(
2759 			BPoint(rect.left, rect.top),
2760 			BPoint(rect.left, rect.bottom - 1), left);
2761 		view->AddLine(
2762 			BPoint(rect.left, rect.bottom),
2763 			BPoint(rect.left, rect.bottom), leftBottom);
2764 		rect.left++;
2765 	}
2766 
2767 	if (borders & B_BOTTOM_BORDER) {
2768 		view->AddLine(
2769 			BPoint(rect.left, rect.bottom),
2770 			BPoint(rect.right, rect.bottom), bottom);
2771 		rect.bottom--;
2772 	}
2773 
2774 	if (borders & B_RIGHT_BORDER) {
2775 		view->AddLine(
2776 			BPoint(rect.right, rect.bottom),
2777 			BPoint(rect.right, rect.top), right);
2778 		rect.right--;
2779 	}
2780 
2781 	view->EndLineArray();
2782 }
2783 
2784 
2785 void
2786 HaikuControlLook::_DrawButtonBackground(BView* view, BRect& rect,
2787 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2788 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2789 	bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
2790 {
2791 	if (!rect.IsValid())
2792 		return;
2793 
2794 	// save the clipping constraints of the view
2795 	view->PushState();
2796 
2797 	// set clipping constraints to updateRect
2798 	BRegion clipping(updateRect);
2799 	view->ConstrainClippingRegion(&clipping);
2800 
2801 	// If the button is flat and neither activated nor otherwise highlighted
2802 	// (mouse hovering or focussed), draw it flat.
2803 	if ((flags & B_FLAT) != 0
2804 		&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
2805 		&& ((flags & (B_HOVER | B_FOCUSED)) == 0
2806 			|| (flags & B_DISABLED) != 0)) {
2807 		_DrawFlatButtonBackground(view, rect, updateRect, base, popupIndicator,
2808 			flags, borders, orientation);
2809 	} else {
2810 		_DrawNonFlatButtonBackground(view, rect, updateRect, clipping,
2811 			leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius,
2812 			base, popupIndicator, flags, borders, orientation);
2813 	}
2814 
2815 	// restore the clipping constraints of the view
2816 	view->PopState();
2817 }
2818 
2819 
2820 void
2821 HaikuControlLook::_DrawFlatButtonBackground(BView* view, BRect& rect,
2822 	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
2823 	uint32 flags, uint32 borders, orientation orientation)
2824 {
2825 	_DrawFrame(view, rect, base, base, base, base, borders);
2826 		// Not an actual frame, but the method insets our rect as needed.
2827 
2828 	view->SetHighColor(base);
2829 	view->FillRect(rect);
2830 
2831 	if (popupIndicator) {
2832 		BRect indicatorRect(rect);
2833 		rect.right -= kButtonPopUpIndicatorWidth;
2834 		indicatorRect.left = rect.right + 3;
2835 			// 2 pixels for the separator
2836 
2837 		view->SetHighColor(base);
2838 		view->FillRect(indicatorRect);
2839 
2840 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2841 	}
2842 }
2843 
2844 
2845 void
2846 HaikuControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect,
2847 	const BRect& updateRect, BRegion& clipping, float leftTopRadius,
2848 	float rightTopRadius, float leftBottomRadius, float rightBottomRadius,
2849 	const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders,
2850 	orientation orientation)
2851 {
2852 	// inner bevel colors
2853 	rgb_color bevelLightColor  = _BevelLightColor(base, flags);
2854 	rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
2855 
2856 	// button background color
2857 	rgb_color buttonBgColor;
2858 	if ((flags & B_DISABLED) != 0)
2859 		buttonBgColor = tint_color(base, 0.7);
2860 	else
2861 		buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT);
2862 
2863 	// surface top gradient
2864 	BGradientLinear fillGradient;
2865 	_MakeButtonGradient(fillGradient, rect, base, flags, orientation);
2866 
2867 	// rounded corners
2868 
2869 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
2870 		&& leftTopRadius > 0) {
2871 		// draw left top rounded corner
2872 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
2873 			floorf(rect.left + leftTopRadius - 2.0),
2874 			floorf(rect.top + leftTopRadius - 2.0));
2875 		clipping.Exclude(leftTopCorner);
2876 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
2877 			bevelLightColor, fillGradient);
2878 	}
2879 
2880 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
2881 		&& rightTopRadius > 0) {
2882 		// draw right top rounded corner
2883 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
2884 			floorf(rect.top), floorf(rect.right),
2885 			floorf(rect.top + rightTopRadius - 2.0));
2886 		clipping.Exclude(rightTopCorner);
2887 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner,
2888 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2889 	}
2890 
2891 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2892 		&& leftBottomRadius > 0) {
2893 		// draw left bottom rounded corner
2894 		BRect leftBottomCorner(floorf(rect.left),
2895 			floorf(rect.bottom - leftBottomRadius + 2.0),
2896 			floorf(rect.left + leftBottomRadius - 2.0),
2897 			floorf(rect.bottom));
2898 		clipping.Exclude(leftBottomCorner);
2899 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
2900 			updateRect, bevelLightColor, bevelShadowColor, fillGradient);
2901 	}
2902 
2903 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
2904 		&& rightBottomRadius > 0) {
2905 		// draw right bottom rounded corner
2906 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
2907 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
2908 			floorf(rect.bottom));
2909 		clipping.Exclude(rightBottomCorner);
2910 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
2911 			updateRect, bevelShadowColor, fillGradient);
2912 	}
2913 
2914 	// clip out the corners
2915 	view->ConstrainClippingRegion(&clipping);
2916 
2917 	// draw inner bevel
2918 
2919 	if ((flags & B_ACTIVATED) != 0) {
2920 		view->BeginLineArray(4);
2921 
2922 		// shadow along left/top borders
2923 		if (borders & B_LEFT_BORDER) {
2924 			view->AddLine(BPoint(rect.left, rect.top),
2925 				BPoint(rect.left, rect.bottom), bevelLightColor);
2926 			rect.left++;
2927 		}
2928 		if (borders & B_TOP_BORDER) {
2929 			view->AddLine(BPoint(rect.left, rect.top),
2930 				BPoint(rect.right, rect.top), bevelLightColor);
2931 			rect.top++;
2932 		}
2933 
2934 		// softer shadow along left/top borders
2935 		if (borders & B_LEFT_BORDER) {
2936 			view->AddLine(BPoint(rect.left, rect.top),
2937 				BPoint(rect.left, rect.bottom), bevelShadowColor);
2938 			rect.left++;
2939 		}
2940 		if (borders & B_TOP_BORDER) {
2941 			view->AddLine(BPoint(rect.left, rect.top),
2942 				BPoint(rect.right, rect.top), bevelShadowColor);
2943 			rect.top++;
2944 		}
2945 
2946 		view->EndLineArray();
2947 	} else {
2948 		_DrawFrame(view, rect,
2949 			bevelLightColor, bevelLightColor,
2950 			bevelShadowColor, bevelShadowColor,
2951 			buttonBgColor, buttonBgColor, borders);
2952 	}
2953 
2954 	if (popupIndicator) {
2955 		BRect indicatorRect(rect);
2956 		rect.right -= kButtonPopUpIndicatorWidth;
2957 		indicatorRect.left = rect.right + 3;
2958 			// 2 pixels for the separator
2959 
2960 		// Even when depressed we want the pop-up indicator background and
2961 		// separator to cover the area up to the top.
2962 		if ((flags & B_ACTIVATED) != 0)
2963 			indicatorRect.top--;
2964 
2965 		// draw the separator
2966 		rgb_color separatorBaseColor = base;
2967 		if ((flags & B_ACTIVATED) != 0)
2968 			separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
2969 
2970 		rgb_color separatorLightColor = _EdgeLightColor(separatorBaseColor,
2971 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2972 		rgb_color separatorShadowColor = _EdgeShadowColor(separatorBaseColor,
2973 			(flags & B_DISABLED) != 0 ? 0.7 : 1.0, 1.0, flags);
2974 
2975 		view->BeginLineArray(2);
2976 
2977 		view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top),
2978 			BPoint(indicatorRect.left - 2, indicatorRect.bottom),
2979 			separatorShadowColor);
2980 		view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top),
2981 			BPoint(indicatorRect.left - 1, indicatorRect.bottom),
2982 			separatorLightColor);
2983 
2984 		view->EndLineArray();
2985 
2986 		// draw background and pop-up marker
2987 		_DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect,
2988 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags, 0);
2989 
2990 		if ((flags & B_ACTIVATED) != 0)
2991 			indicatorRect.top++;
2992 
2993 		_DrawPopUpMarker(view, indicatorRect, base, flags);
2994 	}
2995 
2996 	// fill in the background
2997 	view->FillRect(rect, fillGradient);
2998 }
2999 
3000 
3001 void
3002 HaikuControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
3003 	const rgb_color& base, uint32 flags)
3004 {
3005 	BPoint center(roundf((rect.left + rect.right) / 2.0),
3006 		roundf((rect.top + rect.bottom) / 2.0));
3007 	BPoint triangle[3];
3008 	triangle[0] = center + BPoint(-2.5, -0.5);
3009 	triangle[1] = center + BPoint(2.5, -0.5);
3010 	triangle[2] = center + BPoint(0.0, 2.0);
3011 
3012 	uint32 viewFlags = view->Flags();
3013 	view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
3014 
3015 	rgb_color markColor;
3016 	if ((flags & B_DISABLED) != 0)
3017 		markColor = tint_color(base, 1.35);
3018 	else
3019 		markColor = tint_color(base, 1.65);
3020 
3021 	view->SetHighColor(markColor);
3022 	view->FillTriangle(triangle[0], triangle[1], triangle[2]);
3023 
3024 	view->SetFlags(viewFlags);
3025 }
3026 
3027 
3028 void
3029 HaikuControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
3030 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3031 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3032 	bool popupIndicator, uint32 flags)
3033 {
3034 	if (!rect.IsValid() || !rect.Intersects(updateRect))
3035 		return;
3036 
3037 	if (popupIndicator) {
3038 		BRect leftRect(rect);
3039 		leftRect.right -= 10;
3040 
3041 		BRect rightRect(rect);
3042 		rightRect.left = rightRect.right - 9;
3043 
3044 		_DrawMenuFieldBackgroundInside(view, leftRect, updateRect,
3045 			leftTopRadius, 0.0f, leftBottomRadius, 0.0f, base, flags,
3046 			B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
3047 
3048 		_DrawMenuFieldBackgroundInside(view, rightRect, updateRect,
3049 			0.0f, rightTopRadius, 0.0f, rightBottomRadius, base, flags,
3050 			B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
3051 
3052 		_DrawPopUpMarker(view, rightRect, base, flags);
3053 
3054 		// draw a line on the left of the popup frame
3055 		rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
3056 		view->SetHighColor(bevelShadowColor);
3057 		BPoint leftTopCorner(floorf(rightRect.left - 1.0),
3058 			floorf(rightRect.top - 1.0));
3059 		BPoint leftBottomCorner(floorf(rightRect.left - 1.0),
3060 			floorf(rightRect.bottom + 1.0));
3061 		view->StrokeLine(leftTopCorner, leftBottomCorner);
3062 
3063 		rect = leftRect;
3064 	} else {
3065 		_DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius,
3066 			rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags);
3067 	}
3068 }
3069 
3070 
3071 void
3072 HaikuControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
3073 	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
3074 	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
3075 	uint32 flags, uint32 borders)
3076 {
3077 	if (!rect.IsValid() || !rect.Intersects(updateRect))
3078 		return;
3079 
3080 	// save the clipping constraints of the view
3081 	view->PushState();
3082 
3083 	// set clipping constraints to updateRect
3084 	BRegion clipping(updateRect);
3085 	view->ConstrainClippingRegion(&clipping);
3086 
3087 	// frame colors
3088 	rgb_color frameLightColor  = _FrameLightColor(base, flags);
3089 	rgb_color frameShadowColor = _FrameShadowColor(base, flags);
3090 
3091 	// indicator background color
3092 	rgb_color indicatorBase;
3093 	if ((borders & B_LEFT_BORDER) != 0)
3094 		indicatorBase = base;
3095 	else {
3096 		if ((flags & B_DISABLED) != 0)
3097 			indicatorBase = tint_color(base, 1.05);
3098 		else
3099 			indicatorBase = tint_color(base, 1.12);
3100 	}
3101 
3102 	// bevel colors
3103 	rgb_color cornerColor = tint_color(indicatorBase, 0.85);
3104 	rgb_color bevelColor1 = tint_color(indicatorBase, 0.3);
3105 	rgb_color bevelColor2 = tint_color(indicatorBase, 0.5);
3106 	rgb_color bevelColor3 = tint_color(indicatorBase, 1.03);
3107 
3108 	if ((flags & B_DISABLED) != 0) {
3109 		cornerColor = tint_color(indicatorBase, 0.8);
3110 		bevelColor1 = tint_color(indicatorBase, 0.7);
3111 		bevelColor2 = tint_color(indicatorBase, 0.8);
3112 		bevelColor3 = tint_color(indicatorBase, 1.01);
3113 	} else {
3114 		cornerColor = tint_color(indicatorBase, 0.85);
3115 		bevelColor1 = tint_color(indicatorBase, 0.3);
3116 		bevelColor2 = tint_color(indicatorBase, 0.5);
3117 		bevelColor3 = tint_color(indicatorBase, 1.03);
3118 	}
3119 
3120 	// surface top gradient
3121 	BGradientLinear fillGradient;
3122 	_MakeButtonGradient(fillGradient, rect, indicatorBase, flags);
3123 
3124 	// rounded corners
3125 
3126 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
3127 		&& leftTopRadius > 0) {
3128 		// draw left top rounded corner
3129 		BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
3130 			floorf(rect.left + leftTopRadius - 2.0),
3131 			floorf(rect.top + leftTopRadius - 2.0));
3132 		clipping.Exclude(leftTopCorner);
3133 
3134 		BRegion cornerClipping(leftTopCorner);
3135 		view->ConstrainClippingRegion(&cornerClipping);
3136 
3137 		BRect ellipseRect(leftTopCorner);
3138 		ellipseRect.InsetBy(-1.0, -1.0);
3139 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3140 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3141 
3142 		// draw the frame (again)
3143 		view->SetHighColor(frameLightColor);
3144 		view->FillEllipse(ellipseRect);
3145 
3146 		// draw the bevel and background
3147 		_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
3148 			bevelColor1, fillGradient);
3149 	}
3150 
3151 	if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
3152 		&& rightTopRadius > 0) {
3153 		// draw right top rounded corner
3154 		BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
3155 			floorf(rect.top), floorf(rect.right),
3156 			floorf(rect.top + rightTopRadius - 2.0));
3157 		clipping.Exclude(rightTopCorner);
3158 
3159 		BRegion cornerClipping(rightTopCorner);
3160 		view->ConstrainClippingRegion(&cornerClipping);
3161 
3162 		BRect ellipseRect(rightTopCorner);
3163 		ellipseRect.InsetBy(-1.0, -1.0);
3164 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3165 		ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3166 
3167 		// draw the frame (again)
3168 		if (frameLightColor == frameShadowColor) {
3169 			view->SetHighColor(frameLightColor);
3170 			view->FillEllipse(ellipseRect);
3171 		} else {
3172 			BGradientLinear gradient;
3173 			gradient.AddColor(frameLightColor, 0);
3174 			gradient.AddColor(frameShadowColor, 255);
3175 			gradient.SetStart(rightTopCorner.LeftTop());
3176 			gradient.SetEnd(rightTopCorner.RightBottom());
3177 			view->FillEllipse(ellipseRect, gradient);
3178 		}
3179 
3180 		// draw the bevel and background
3181 		_DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect,
3182 			bevelColor1, bevelColor3, fillGradient);
3183 	}
3184 
3185 	if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3186 		&& leftBottomRadius > 0) {
3187 		// draw left bottom rounded corner
3188 		BRect leftBottomCorner(floorf(rect.left),
3189 			floorf(rect.bottom - leftBottomRadius + 2.0),
3190 			floorf(rect.left + leftBottomRadius - 2.0),
3191 			floorf(rect.bottom));
3192 		clipping.Exclude(leftBottomCorner);
3193 
3194 		BRegion cornerClipping(leftBottomCorner);
3195 		view->ConstrainClippingRegion(&cornerClipping);
3196 
3197 		BRect ellipseRect(leftBottomCorner);
3198 		ellipseRect.InsetBy(-1.0, -1.0);
3199 		ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3200 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3201 
3202 		// draw the frame (again)
3203 		if (frameLightColor == frameShadowColor) {
3204 			view->SetHighColor(frameLightColor);
3205 			view->FillEllipse(ellipseRect);
3206 		} else {
3207 			BGradientLinear gradient;
3208 			gradient.AddColor(frameLightColor, 0);
3209 			gradient.AddColor(frameShadowColor, 255);
3210 			gradient.SetStart(leftBottomCorner.LeftTop());
3211 			gradient.SetEnd(leftBottomCorner.RightBottom());
3212 			view->FillEllipse(ellipseRect, gradient);
3213 		}
3214 
3215 		// draw the bevel and background
3216 		_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
3217 			updateRect, bevelColor2, bevelColor3, fillGradient);
3218 	}
3219 
3220 	if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
3221 		&& rightBottomRadius > 0) {
3222 		// draw right bottom rounded corner
3223 		BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
3224 			floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
3225 			floorf(rect.bottom));
3226 		clipping.Exclude(rightBottomCorner);
3227 
3228 		BRegion cornerClipping(rightBottomCorner);
3229 		view->ConstrainClippingRegion(&cornerClipping);
3230 
3231 		BRect ellipseRect(rightBottomCorner);
3232 		ellipseRect.InsetBy(-1.0, -1.0);
3233 		ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3234 		ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3235 
3236 		// draw the frame (again)
3237 		view->SetHighColor(frameShadowColor);
3238 		view->FillEllipse(ellipseRect);
3239 
3240 		// draw the bevel and background
3241 		_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
3242 			updateRect, bevelColor3, fillGradient);
3243 	}
3244 
3245 	// clip out the corners
3246 	view->ConstrainClippingRegion(&clipping);
3247 
3248 	// draw the bevel
3249 	_DrawFrame(view, rect,
3250 		bevelColor2, bevelColor1,
3251 		bevelColor3, bevelColor3,
3252 		cornerColor, cornerColor,
3253 		borders);
3254 
3255 	// fill in the background
3256 	view->FillRect(rect, fillGradient);
3257 
3258 	// restore the clipping constraints of the view
3259 	view->PopState();
3260 }
3261 
3262 
3263 void
3264 HaikuControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& cornerRect,
3265 	const BRect& updateRect, const rgb_color& background,
3266 	const rgb_color& edgeColor, const rgb_color& frameColor,
3267 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3268 {
3269 	_DrawRoundCornerFrameLeftTop(view, cornerRect, updateRect,
3270 		background, edgeColor, frameColor);
3271 	_DrawRoundCornerBackgroundLeftTop(view, cornerRect, updateRect,
3272 		bevelColor, fillGradient);
3273 }
3274 
3275 
3276 void
3277 HaikuControlLook::_DrawRoundCornerFrameLeftTop(BView* view, BRect& cornerRect,
3278 	const BRect& updateRect, const rgb_color& background,
3279 	const rgb_color& edgeColor, const rgb_color& frameColor)
3280 {
3281 	// constrain clipping region to corner
3282 	BRegion clipping(cornerRect);
3283 	view->ConstrainClippingRegion(&clipping);
3284 
3285 	// background
3286 	view->SetHighColor(background);
3287 	view->FillRect(cornerRect);
3288 
3289 	// outer edge
3290 	BRect ellipseRect(cornerRect);
3291 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3292 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3293 
3294 	view->SetHighColor(edgeColor);
3295 	view->FillEllipse(ellipseRect);
3296 
3297 	// frame
3298 	ellipseRect.InsetBy(1, 1);
3299 	cornerRect.left++;
3300 	cornerRect.top++;
3301 	view->SetHighColor(frameColor);
3302 	view->FillEllipse(ellipseRect);
3303 
3304 	// prepare for bevel
3305 	cornerRect.left++;
3306 	cornerRect.top++;
3307 }
3308 
3309 
3310 void
3311 HaikuControlLook::_DrawRoundCornerBackgroundLeftTop(BView* view, BRect& cornerRect,
3312 	const BRect& updateRect, const rgb_color& bevelColor,
3313 	const BGradientLinear& fillGradient)
3314 {
3315 	// constrain clipping region to corner
3316 	BRegion clipping(cornerRect);
3317 	view->ConstrainClippingRegion(&clipping);
3318 
3319 	BRect ellipseRect(cornerRect);
3320 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3321 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3322 
3323 	// bevel
3324 	view->SetHighColor(bevelColor);
3325 	view->FillEllipse(ellipseRect);
3326 
3327 	// gradient
3328 	ellipseRect.InsetBy(1, 1);
3329 	view->FillEllipse(ellipseRect, fillGradient);
3330 }
3331 
3332 
3333 void
3334 HaikuControlLook::_DrawRoundCornerRightTop(BView* view, BRect& cornerRect,
3335 	const BRect& updateRect, const rgb_color& background,
3336 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3337 	const rgb_color& frameTopColor, const rgb_color& frameRightColor,
3338 	const rgb_color& bevelTopColor, const rgb_color& bevelRightColor,
3339 	const BGradientLinear& fillGradient)
3340 {
3341 	_DrawRoundCornerFrameRightTop(view, cornerRect, updateRect,
3342 		background, edgeTopColor, edgeRightColor, frameTopColor,
3343 		frameRightColor);
3344 	_DrawRoundCornerBackgroundRightTop(view, cornerRect, updateRect,
3345 		bevelTopColor, bevelRightColor, fillGradient);
3346 }
3347 
3348 
3349 void
3350 HaikuControlLook::_DrawRoundCornerFrameRightTop(BView* view, BRect& cornerRect,
3351 	const BRect& updateRect, const rgb_color& background,
3352 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
3353 	const rgb_color& frameTopColor, const rgb_color& frameRightColor)
3354 {
3355 	// constrain clipping region to corner
3356 	BRegion clipping(cornerRect);
3357 	view->ConstrainClippingRegion(&clipping);
3358 
3359 	// background
3360 	view->SetHighColor(background);
3361 	view->FillRect(cornerRect);
3362 
3363 	// outer edge
3364 	BRect ellipseRect(cornerRect);
3365 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3366 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3367 
3368 	BGradientLinear gradient;
3369 	gradient.AddColor(edgeTopColor, 0);
3370 	gradient.AddColor(edgeRightColor, 255);
3371 	gradient.SetStart(cornerRect.LeftTop());
3372 	gradient.SetEnd(cornerRect.RightBottom());
3373 	view->FillEllipse(ellipseRect, gradient);
3374 
3375 	// frame
3376 	ellipseRect.InsetBy(1, 1);
3377 	cornerRect.right--;
3378 	cornerRect.top++;
3379 	if (frameTopColor == frameRightColor) {
3380 		view->SetHighColor(frameTopColor);
3381 		view->FillEllipse(ellipseRect);
3382 	} else {
3383 		gradient.SetColor(0, frameTopColor);
3384 		gradient.SetColor(1, frameRightColor);
3385 		gradient.SetStart(cornerRect.LeftTop());
3386 		gradient.SetEnd(cornerRect.RightBottom());
3387 		view->FillEllipse(ellipseRect, gradient);
3388 	}
3389 
3390 	// prepare for bevel
3391 	cornerRect.right--;
3392 	cornerRect.top++;
3393 }
3394 
3395 
3396 void
3397 HaikuControlLook::_DrawRoundCornerBackgroundRightTop(BView* view, BRect& cornerRect,
3398 	const BRect& updateRect, const rgb_color& bevelTopColor,
3399 	const rgb_color& bevelRightColor, const BGradientLinear& fillGradient)
3400 {
3401 	// constrain clipping region to corner
3402 	BRegion clipping(cornerRect);
3403 	view->ConstrainClippingRegion(&clipping);
3404 
3405 	BRect ellipseRect(cornerRect);
3406 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3407 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
3408 
3409 	// bevel
3410 	BGradientLinear gradient;
3411 	gradient.AddColor(bevelTopColor, 0);
3412 	gradient.AddColor(bevelRightColor, 255);
3413 	gradient.SetStart(cornerRect.LeftTop());
3414 	gradient.SetEnd(cornerRect.RightBottom());
3415 	view->FillEllipse(ellipseRect, gradient);
3416 
3417 	// gradient
3418 	ellipseRect.InsetBy(1, 1);
3419 	view->FillEllipse(ellipseRect, fillGradient);
3420 }
3421 
3422 
3423 void
3424 HaikuControlLook::_DrawRoundCornerLeftBottom(BView* view, BRect& cornerRect,
3425 	const BRect& updateRect, const rgb_color& background,
3426 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3427 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor,
3428 	const rgb_color& bevelLeftColor, const rgb_color& bevelBottomColor,
3429 	const BGradientLinear& fillGradient)
3430 {
3431 	_DrawRoundCornerFrameLeftBottom(view, cornerRect, updateRect,
3432 		background, edgeLeftColor, edgeBottomColor, frameLeftColor,
3433 		frameBottomColor);
3434 	_DrawRoundCornerBackgroundLeftBottom(view, cornerRect, updateRect,
3435 		bevelLeftColor, bevelBottomColor, fillGradient);
3436 }
3437 
3438 
3439 void
3440 HaikuControlLook::_DrawRoundCornerFrameLeftBottom(BView* view, BRect& cornerRect,
3441 	const BRect& updateRect, const rgb_color& background,
3442 	const rgb_color& edgeLeftColor, const rgb_color& edgeBottomColor,
3443 	const rgb_color& frameLeftColor, const rgb_color& frameBottomColor)
3444 {
3445 	// constrain clipping region to corner
3446 	BRegion clipping(cornerRect);
3447 	view->ConstrainClippingRegion(&clipping);
3448 
3449 	// background
3450 	view->SetHighColor(background);
3451 	view->FillRect(cornerRect);
3452 
3453 	// outer edge
3454 	BRect ellipseRect(cornerRect);
3455 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3456 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3457 
3458 	BGradientLinear gradient;
3459 	gradient.AddColor(edgeLeftColor, 0);
3460 	gradient.AddColor(edgeBottomColor, 255);
3461 	gradient.SetStart(cornerRect.LeftTop());
3462 	gradient.SetEnd(cornerRect.RightBottom());
3463 	view->FillEllipse(ellipseRect, gradient);
3464 
3465 	// frame
3466 	ellipseRect.InsetBy(1, 1);
3467 	cornerRect.left++;
3468 	cornerRect.bottom--;
3469 	if (frameLeftColor == frameBottomColor) {
3470 		view->SetHighColor(frameLeftColor);
3471 		view->FillEllipse(ellipseRect);
3472 	} else {
3473 		gradient.SetColor(0, frameLeftColor);
3474 		gradient.SetColor(1, frameBottomColor);
3475 		gradient.SetStart(cornerRect.LeftTop());
3476 		gradient.SetEnd(cornerRect.RightBottom());
3477 		view->FillEllipse(ellipseRect, gradient);
3478 	}
3479 
3480 	// prepare for bevel
3481 	cornerRect.left++;
3482 	cornerRect.bottom--;
3483 }
3484 
3485 
3486 void
3487 HaikuControlLook::_DrawRoundCornerBackgroundLeftBottom(BView* view, BRect& cornerRect,
3488 	const BRect& updateRect, const rgb_color& bevelLeftColor,
3489 	const rgb_color& bevelBottomColor, const BGradientLinear& fillGradient)
3490 {
3491 	// constrain clipping region to corner
3492 	BRegion clipping(cornerRect);
3493 	view->ConstrainClippingRegion(&clipping);
3494 
3495 	BRect ellipseRect(cornerRect);
3496 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
3497 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3498 
3499 	// bevel
3500 	BGradientLinear gradient;
3501 	gradient.AddColor(bevelLeftColor, 0);
3502 	gradient.AddColor(bevelBottomColor, 255);
3503 	gradient.SetStart(cornerRect.LeftTop());
3504 	gradient.SetEnd(cornerRect.RightBottom());
3505 	view->FillEllipse(ellipseRect, gradient);
3506 
3507 	// gradient
3508 	ellipseRect.InsetBy(1, 1);
3509 	view->FillEllipse(ellipseRect, fillGradient);
3510 }
3511 
3512 
3513 void
3514 HaikuControlLook::_DrawRoundCornerRightBottom(BView* view, BRect& cornerRect,
3515 	const BRect& updateRect, const rgb_color& background,
3516 	const rgb_color& edgeColor, const rgb_color& frameColor,
3517 	const rgb_color& bevelColor, const BGradientLinear& fillGradient)
3518 {
3519 	_DrawRoundCornerFrameRightBottom(view, cornerRect, updateRect,
3520 		background, edgeColor, frameColor);
3521 	_DrawRoundCornerBackgroundRightBottom(view, cornerRect, updateRect,
3522 		bevelColor, fillGradient);
3523 }
3524 
3525 
3526 void
3527 HaikuControlLook::_DrawRoundCornerFrameRightBottom(BView* view, BRect& cornerRect,
3528 	const BRect& updateRect, const rgb_color& background,
3529 	const rgb_color& edgeColor, const rgb_color& frameColor)
3530 {
3531 	// constrain clipping region to corner
3532 	BRegion clipping(cornerRect);
3533 	view->ConstrainClippingRegion(&clipping);
3534 
3535 	// background
3536 	view->SetHighColor(background);
3537 	view->FillRect(cornerRect);
3538 
3539 	// outer edge
3540 	BRect ellipseRect(cornerRect);
3541 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3542 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3543 
3544 	view->SetHighColor(edgeColor);
3545 	view->FillEllipse(ellipseRect);
3546 
3547 	// frame
3548 	ellipseRect.InsetBy(1, 1);
3549 	cornerRect.right--;
3550 	cornerRect.bottom--;
3551 	view->SetHighColor(frameColor);
3552 	view->FillEllipse(ellipseRect);
3553 
3554 	// prepare for bevel
3555 	cornerRect.right--;
3556 	cornerRect.bottom--;
3557 }
3558 
3559 
3560 void
3561 HaikuControlLook::_DrawRoundCornerBackgroundRightBottom(BView* view,
3562 	BRect& cornerRect, const BRect& updateRect, const rgb_color& bevelColor,
3563 	const BGradientLinear& fillGradient)
3564 {
3565 	// constrain clipping region to corner
3566 	BRegion clipping(cornerRect);
3567 	view->ConstrainClippingRegion(&clipping);
3568 
3569 	BRect ellipseRect(cornerRect);
3570 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
3571 	ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
3572 
3573 	// bevel
3574 	view->SetHighColor(bevelColor);
3575 	view->FillEllipse(ellipseRect);
3576 
3577 	// gradient
3578 	ellipseRect.InsetBy(1, 1);
3579 	view->FillEllipse(ellipseRect, fillGradient);
3580 }
3581 
3582 
3583 void
3584 HaikuControlLook::_DrawRoundBarCorner(BView* view, BRect& rect,
3585 	const BRect& updateRect,
3586 	const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor,
3587 	const rgb_color& frameLightColor, const rgb_color& frameShadowColor,
3588 	const rgb_color& fillLightColor, const rgb_color& fillShadowColor,
3589 	float leftInset, float topInset, float rightInset, float bottomInset,
3590 	orientation orientation)
3591 {
3592 	if (!rect.IsValid() || !rect.Intersects(updateRect))
3593 		return;
3594 
3595 	BGradientLinear gradient;
3596 	gradient.AddColor(edgeShadowColor, 0);
3597 	gradient.AddColor(edgeLightColor, 255);
3598 	gradient.SetStart(rect.LeftTop());
3599 	if (orientation == B_HORIZONTAL)
3600 		gradient.SetEnd(rect.LeftBottom());
3601 	else
3602 		gradient.SetEnd(rect.RightTop());
3603 
3604 	view->FillEllipse(rect, gradient);
3605 
3606 	rect.left += leftInset;
3607 	rect.top += topInset;
3608 	rect.right += rightInset;
3609 	rect.bottom += bottomInset;
3610 
3611 	gradient.MakeEmpty();
3612 	gradient.AddColor(frameShadowColor, 0);
3613 	gradient.AddColor(frameLightColor, 255);
3614 	gradient.SetStart(rect.LeftTop());
3615 	if (orientation == B_HORIZONTAL)
3616 		gradient.SetEnd(rect.LeftBottom());
3617 	else
3618 		gradient.SetEnd(rect.RightTop());
3619 
3620 	view->FillEllipse(rect, gradient);
3621 
3622 	rect.left += leftInset;
3623 	rect.top += topInset;
3624 	rect.right += rightInset;
3625 	rect.bottom += bottomInset;
3626 
3627 	gradient.MakeEmpty();
3628 	gradient.AddColor(fillShadowColor, 0);
3629 	gradient.AddColor(fillLightColor, 255);
3630 	gradient.SetStart(rect.LeftTop());
3631 	if (orientation == B_HORIZONTAL)
3632 		gradient.SetEnd(rect.LeftBottom());
3633 	else
3634 		gradient.SetEnd(rect.RightTop());
3635 
3636 	view->FillEllipse(rect, gradient);
3637 }
3638 
3639 
3640 rgb_color
3641 HaikuControlLook::_EdgeLightColor(const rgb_color& base, float contrast,
3642 	float brightness, uint32 flags)
3643 {
3644 	rgb_color edgeLightColor;
3645 
3646 	if ((flags & B_BLEND_FRAME) != 0) {
3647 		uint8 alpha = uint8(20 * contrast);
3648 		uint8 white = uint8(255 * brightness);
3649 
3650 		edgeLightColor = (rgb_color){ white, white, white, alpha };
3651 	} else {
3652 		// colors
3653 		float tintLight = kEdgeBevelLightTint;
3654 
3655 		if (contrast == 0.0)
3656 			tintLight = B_NO_TINT;
3657 		else if (contrast != 1.0)
3658 			tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast;
3659 
3660 		edgeLightColor = tint_color(base, tintLight);
3661 
3662 		if (brightness < 1.0) {
3663 			edgeLightColor.red = uint8(edgeLightColor.red * brightness);
3664 			edgeLightColor.green = uint8(edgeLightColor.green * brightness);
3665 			edgeLightColor.blue = uint8(edgeLightColor.blue * brightness);
3666 		}
3667 	}
3668 
3669 	return edgeLightColor;
3670 }
3671 
3672 
3673 rgb_color
3674 HaikuControlLook::_EdgeShadowColor(const rgb_color& base, float contrast,
3675 	float brightness, uint32 flags)
3676 {
3677 	rgb_color edgeShadowColor;
3678 
3679 	if ((flags & B_BLEND_FRAME) != 0) {
3680 		uint8 alpha = uint8(20 * contrast);
3681 		edgeShadowColor = (rgb_color){ 0, 0, 0, alpha };
3682 	} else {
3683 		float tintShadow = kEdgeBevelShadowTint;
3684 
3685 		if (contrast == 0.0)
3686 			tintShadow = B_NO_TINT;
3687 		else if (contrast != 1.0)
3688 			tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast;
3689 
3690 		edgeShadowColor = tint_color(base, tintShadow);
3691 
3692 		if (brightness < 1.0) {
3693 			edgeShadowColor.red = uint8(edgeShadowColor.red * brightness);
3694 			edgeShadowColor.green = uint8(edgeShadowColor.green * brightness);
3695 			edgeShadowColor.blue = uint8(edgeShadowColor.blue * brightness);
3696 		}
3697 	}
3698 
3699 	return edgeShadowColor;
3700 }
3701 
3702 
3703 rgb_color
3704 HaikuControlLook::_FrameLightColor(const rgb_color& base, uint32 flags)
3705 {
3706 	if ((flags & B_FOCUSED) != 0)
3707 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3708 
3709 	if ((flags & B_ACTIVATED) != 0)
3710 		return _FrameShadowColor(base, flags & ~B_ACTIVATED);
3711 
3712 	rgb_color frameLightColor;
3713 
3714 	if ((flags & B_DISABLED) != 0) {
3715 		// TODO: B_BLEND_FRAME
3716 		frameLightColor = tint_color(base, 1.145);
3717 
3718 		if ((flags & B_DEFAULT_BUTTON) != 0)
3719 			frameLightColor = tint_color(frameLightColor, 1.14);
3720 	} else {
3721 		if ((flags & B_BLEND_FRAME) != 0)
3722 			frameLightColor = (rgb_color){ 0, 0, 0, 75 };
3723 		else
3724 			frameLightColor = tint_color(base, 1.33);
3725 
3726 		if ((flags & B_DEFAULT_BUTTON) != 0)
3727 			frameLightColor = tint_color(frameLightColor, 1.35);
3728 	}
3729 
3730 	return frameLightColor;
3731 }
3732 
3733 
3734 rgb_color
3735 HaikuControlLook::_FrameShadowColor(const rgb_color& base, uint32 flags)
3736 {
3737 	if ((flags & B_FOCUSED) != 0)
3738 		return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
3739 
3740 	if ((flags & B_ACTIVATED) != 0)
3741 		return _FrameLightColor(base, flags & ~B_ACTIVATED);
3742 
3743 	rgb_color frameShadowColor;
3744 
3745 	if ((flags & B_DISABLED) != 0) {
3746 		// TODO: B_BLEND_FRAME
3747 		frameShadowColor = tint_color(base, 1.24);
3748 
3749 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3750 			frameShadowColor = tint_color(base, 1.145);
3751 			frameShadowColor = tint_color(frameShadowColor, 1.12);
3752 		}
3753 	} else {
3754 		if ((flags & B_DEFAULT_BUTTON) != 0) {
3755 			if ((flags & B_BLEND_FRAME) != 0)
3756 				frameShadowColor = (rgb_color){ 0, 0, 0, 75 };
3757 			else
3758 				frameShadowColor = tint_color(base, 1.33);
3759 
3760 			frameShadowColor = tint_color(frameShadowColor, 1.5);
3761 		} else {
3762 			if ((flags & B_BLEND_FRAME) != 0)
3763 				frameShadowColor = (rgb_color){ 0, 0, 0, 95 };
3764 			else
3765 				frameShadowColor = tint_color(base, 1.47);
3766 		}
3767 	}
3768 
3769 	return frameShadowColor;
3770 }
3771 
3772 
3773 rgb_color
3774 HaikuControlLook::_BevelLightColor(const rgb_color& base, uint32 flags)
3775 {
3776 	rgb_color bevelLightColor = tint_color(base, 0.2);
3777 
3778 	if ((flags & B_DISABLED) != 0)
3779 		bevelLightColor = tint_color(base, B_LIGHTEN_1_TINT);
3780 
3781 	if ((flags & B_ACTIVATED) != 0)
3782 		bevelLightColor = tint_color(base, B_DARKEN_1_TINT);
3783 
3784 	return bevelLightColor;
3785 }
3786 
3787 
3788 rgb_color
3789 HaikuControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags)
3790 {
3791 	rgb_color bevelShadowColor = tint_color(base, 1.08);
3792 
3793 	if ((flags & B_DISABLED) != 0)
3794 		bevelShadowColor = base;
3795 
3796 	if ((flags & B_ACTIVATED) != 0)
3797 		bevelShadowColor = tint_color(base, B_DARKEN_1_TINT);
3798 
3799 	return bevelShadowColor;
3800 }
3801 
3802 
3803 void
3804 HaikuControlLook::_FillGradient(BView* view, const BRect& rect,
3805 	const rgb_color& base, float topTint, float bottomTint,
3806 	orientation orientation)
3807 {
3808 	BGradientLinear gradient;
3809 	_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3810 	view->FillRect(rect, gradient);
3811 }
3812 
3813 
3814 void
3815 HaikuControlLook::_FillGlossyGradient(BView* view, const BRect& rect,
3816 	const rgb_color& base, float topTint, float middle1Tint,
3817 	float middle2Tint, float bottomTint, orientation orientation)
3818 {
3819 	BGradientLinear gradient;
3820 	_MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint,
3821 		middle2Tint, bottomTint, orientation);
3822 	view->FillRect(rect, gradient);
3823 }
3824 
3825 
3826 void
3827 HaikuControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
3828 	const rgb_color& base, float topTint, float bottomTint,
3829 	orientation orientation) const
3830 {
3831 	gradient.AddColor(tint_color(base, topTint), 0);
3832 	gradient.AddColor(tint_color(base, bottomTint), 255);
3833 	gradient.SetStart(rect.LeftTop());
3834 	if (orientation == B_HORIZONTAL)
3835 		gradient.SetEnd(rect.LeftBottom());
3836 	else
3837 		gradient.SetEnd(rect.RightTop());
3838 }
3839 
3840 
3841 void
3842 HaikuControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
3843 	const rgb_color& base, float topTint, float middle1Tint,
3844 	float middle2Tint, float bottomTint,
3845 	orientation orientation) const
3846 {
3847 	gradient.AddColor(tint_color(base, topTint), 0);
3848 	gradient.AddColor(tint_color(base, middle1Tint), 132);
3849 	gradient.AddColor(tint_color(base, middle2Tint), 136);
3850 	gradient.AddColor(tint_color(base, bottomTint), 255);
3851 	gradient.SetStart(rect.LeftTop());
3852 	if (orientation == B_HORIZONTAL)
3853 		gradient.SetEnd(rect.LeftBottom());
3854 	else
3855 		gradient.SetEnd(rect.RightTop());
3856 }
3857 
3858 
3859 void
3860 HaikuControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect,
3861 	const rgb_color& base, uint32 flags, orientation orientation) const
3862 {
3863 	float topTint = 0.49;
3864 	float middleTint1 = 0.62;
3865 	float middleTint2 = 0.76;
3866 	float bottomTint = 0.90;
3867 
3868 	if ((flags & B_ACTIVATED) != 0) {
3869 		topTint = 1.11;
3870 		bottomTint = 1.08;
3871 	}
3872 
3873 	if ((flags & B_DISABLED) != 0) {
3874 		topTint = (topTint + B_NO_TINT) / 2;
3875 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
3876 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
3877 		bottomTint = (bottomTint + B_NO_TINT) / 2;
3878 	} else if ((flags & B_HOVER) != 0) {
3879 		topTint *= kHoverTintFactor;
3880 		middleTint1 *= kHoverTintFactor;
3881 		middleTint2 *= kHoverTintFactor;
3882 		bottomTint *= kHoverTintFactor;
3883 	}
3884 
3885 	if ((flags & B_ACTIVATED) != 0) {
3886 		_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
3887 	} else {
3888 		_MakeGlossyGradient(gradient, rect, base, topTint, middleTint1,
3889 			middleTint2, bottomTint, orientation);
3890 	}
3891 }
3892 
3893 
3894 bool
3895 HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
3896 	rgb_color& color, uint32 flags) const
3897 {
3898 	if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) {
3899 		// no mark to be drawn at all
3900 		return false;
3901 	}
3902 
3903 	color = ui_color(B_CONTROL_MARK_COLOR);
3904 
3905 	float mix = 1.0;
3906 
3907 	if ((flags & B_DISABLED) != 0) {
3908 		// activated, but disabled
3909 		mix = 0.4;
3910 	} else if ((flags & B_CLICKED) != 0) {
3911 		if ((flags & B_ACTIVATED) != 0) {
3912 			// losing activation
3913 			mix = 0.7;
3914 		} else {
3915 			// becoming activated (or losing partial activation)
3916 			mix = 0.3;
3917 		}
3918 	} else if ((flags & B_PARTIALLY_ACTIVATED) != 0) {
3919 		// partially activated
3920 		mix = 0.5;
3921 	} else {
3922 		// simply activated
3923 	}
3924 
3925 	color.red = uint8(color.red * mix + base.red * (1.0 - mix));
3926 	color.green = uint8(color.green * mix + base.green * (1.0 - mix));
3927 	color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix));
3928 
3929 	return true;
3930 }
3931 
3932 } // namespace BPrivate
3933