xref: /haiku/src/kits/interface/ControlLook.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
3  * Distributed under the terms of the MIT License.
4  */
5 #include <ControlLook.h>
6 
7 #include <stdio.h>
8 
9 #include <Control.h>
10 #include <GradientLinear.h>
11 #include <Region.h>
12 #include <Shape.h>
13 #include <String.h>
14 #include <View.h>
15 
16 namespace BPrivate {
17 
18 static const float kEdgeBevelLightTint = 0.59;
19 static const float kEdgeBevelShadowTint = 1.0735;
20 
21 
22 BControlLook::BControlLook()
23 {
24 }
25 
26 
27 BControlLook::~BControlLook()
28 {
29 }
30 
31 
32 BAlignment
33 BControlLook::DefaultLabelAlignment() const
34 {
35 	return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER);
36 }
37 
38 
39 float
40 BControlLook::DefaultLabelSpacing() const
41 {
42 	return ceilf(be_plain_font->Size() / 2.0);
43 }
44 
45 
46 float
47 BControlLook::DefaultItemSpacing() const
48 {
49 	return ceilf(be_plain_font->Size() * 0.85);
50 }
51 
52 
53 uint32
54 BControlLook::Flags(BControl* control) const
55 {
56 	uint32 flags = 0;
57 
58 	if (!control->IsEnabled())
59 		flags |= B_DISABLED;
60 
61 	if (control->IsFocus())
62 		flags |= B_FOCUSED;
63 
64 	if (control->Value() == B_CONTROL_ON)
65 		flags |= B_ACTIVATED;
66 
67 	return flags;
68 }
69 
70 
71 // #pragma mark -
72 
73 
74 void
75 BControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
76 	const rgb_color& base, const rgb_color& background, uint32 flags,
77 	uint32 borders)
78 {
79 	_DrawButtonFrame(view, rect, updateRect, base, background, 1.0, 1.0, flags,
80 		borders);
81 }
82 
83 
84 void
85 BControlLook::DrawButtonBackground(BView* view, BRect& rect,
86 	const BRect& updateRect, const rgb_color& base, uint32 flags,
87 	uint32 borders, enum orientation orientation)
88 {
89 	if (!rect.IsValid() || !updateRect.Intersects(rect))
90 		return;
91 
92 	// the surface edges
93 
94 	// colors
95 	rgb_color buttonBgColor = tint_color(base, B_LIGHTEN_1_TINT);
96 	rgb_color maxLightColor;
97 
98 	rgb_color bevelColor1;
99 	rgb_color bevelColor2;
100 
101 	if ((flags & B_DISABLED) == 0) {
102 		maxLightColor = tint_color(base, 0.2);
103 		bevelColor1 = tint_color(base, 1.08);
104 		bevelColor2 = base;
105 	} else {
106 		maxLightColor = tint_color(base, 0.7);
107 		bevelColor1 = base;
108 		bevelColor2 = buttonBgColor;
109 		buttonBgColor = maxLightColor;
110 	}
111 
112 	if (flags & B_ACTIVATED) {
113 		view->BeginLineArray(4);
114 
115 		bevelColor1 = tint_color(bevelColor1, B_DARKEN_1_TINT);
116 		bevelColor2 = tint_color(bevelColor2, B_DARKEN_1_TINT);
117 
118 		// shadow along left/top borders
119 		if (borders & B_LEFT_BORDER) {
120 			view->AddLine(BPoint(rect.left, rect.top),
121 				BPoint(rect.left, rect.bottom), bevelColor1);
122 			rect.left++;
123 		}
124 		if (borders & B_TOP_BORDER) {
125 			view->AddLine(BPoint(rect.left, rect.top),
126 				BPoint(rect.right, rect.top), bevelColor1);
127 			rect.top++;
128 		}
129 
130 		// softer shadow along left/top borders
131 		if (borders & B_LEFT_BORDER) {
132 			view->AddLine(BPoint(rect.left, rect.top),
133 				BPoint(rect.left, rect.bottom), bevelColor2);
134 			rect.left++;
135 		}
136 		if (borders & B_TOP_BORDER) {
137 			view->AddLine(BPoint(rect.left, rect.top),
138 				BPoint(rect.right, rect.top), bevelColor2);
139 			rect.top++;
140 		}
141 
142 		view->EndLineArray();
143 	} else {
144 		_DrawFrame(view, rect,
145 			maxLightColor, maxLightColor,
146 			bevelColor1, bevelColor1,
147 			buttonBgColor, buttonBgColor, borders);
148 	}
149 
150 	// the actual surface top
151 
152 	float topTint = 0.49;
153 	float middleTint1 = 0.62;
154 	float middleTint2 = 0.76;
155 	float bottomTint = 0.90;
156 
157 	if (flags & B_ACTIVATED) {
158 		topTint = 1.11;
159 		bottomTint = 1.08;
160 	}
161 
162 	if (flags & B_DISABLED) {
163 		topTint = (topTint + B_NO_TINT) / 2;
164 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
165 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
166 		bottomTint = (bottomTint + B_NO_TINT) / 2;
167 	} else if (flags & B_HOVER) {
168 		static const float kHoverTintFactor = 0.85;
169 		topTint *= kHoverTintFactor;
170 		middleTint1 *= kHoverTintFactor;
171 		middleTint2 *= kHoverTintFactor;
172 		bottomTint *= kHoverTintFactor;
173 	}
174 
175 	if (flags & B_ACTIVATED) {
176 		_FillGradient(view, rect, base, topTint, bottomTint, orientation);
177 	} else {
178 		_FillGlossyGradient(view, rect, base, topTint, middleTint1,
179 			middleTint2, bottomTint, orientation);
180 	}
181 }
182 
183 
184 void
185 BControlLook::DrawMenuBarBackground(BView* view, BRect& rect,
186 	const BRect& updateRect, const rgb_color& base, uint32 flags,
187 	uint32 borders)
188 {
189 	if (!rect.IsValid() || !updateRect.Intersects(rect))
190 		return;
191 
192 	// the surface edges
193 
194 	// colors
195 	float topTint;
196 	float bottomTint;
197 
198 	if (flags & B_ACTIVATED) {
199 		rgb_color bevelColor1 = tint_color(base, 1.40);
200 		rgb_color bevelColor2 = tint_color(base, 1.25);
201 
202 		topTint = 1.25;
203 		bottomTint = 1.20;
204 
205 		_DrawFrame(view, rect,
206 			bevelColor1, bevelColor1,
207 			bevelColor2, bevelColor2,
208 			borders & B_TOP_BORDER);
209 	} else {
210 		rgb_color cornerColor = tint_color(base, 0.9);
211 		rgb_color bevelColorTop = tint_color(base, 0.5);
212 		rgb_color bevelColorLeft = tint_color(base, 0.7);
213 		rgb_color bevelColorRightBottom = tint_color(base, 1.08);
214 
215 		topTint = 0.69;
216 		bottomTint = 1.03;
217 
218 		_DrawFrame(view, rect,
219 			bevelColorLeft, bevelColorTop,
220 			bevelColorRightBottom, bevelColorRightBottom,
221 			cornerColor, cornerColor,
222 			borders);
223 	}
224 
225 	// the actual surface top
226 
227 	_FillGradient(view, rect, base, topTint, bottomTint);
228 }
229 
230 
231 void
232 BControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
233 	const BRect& updateRect, const rgb_color& base,
234 	const rgb_color& background, uint32 flags, uint32 borders)
235 {
236 	_DrawButtonFrame(view, rect, updateRect, base, background, 0.6, 1.0, flags,
237 		borders);
238 }
239 
240 
241 void
242 BControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
243 	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
244 	uint32 flags)
245 {
246 	if (popupIndicator) {
247 		BRect leftRect(rect);
248 		leftRect.right -= 10;
249 
250 		BRect rightRect(rect);
251 		rightRect.left = rightRect.right - 9;
252 
253 		DrawMenuFieldBackground(view, leftRect, updateRect, base, flags,
254 			B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
255 
256 		rgb_color indicatorBase;
257 		rgb_color markColor;
258 		if (flags & B_DISABLED) {
259 			indicatorBase = tint_color(base, 1.05);
260 			markColor = tint_color(base, 1.35);
261 		} else {
262 			indicatorBase = tint_color(base, 1.12);
263 			markColor = tint_color(base, 1.65);
264 		}
265 
266 		DrawMenuFieldBackground(view, rightRect, updateRect, indicatorBase,
267 			flags, B_RIGHT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
268 
269 		// popup marker
270 		BPoint center(roundf((rightRect.left + rightRect.right) / 2.0),
271 					  roundf((rightRect.top + rightRect.bottom) / 2.0));
272 		BPoint triangle[3];
273 		triangle[0] = center + BPoint(-2.5, -0.5);
274 		triangle[1] = center + BPoint(2.5, -0.5);
275 		triangle[2] = center + BPoint(0.0, 2.0);
276 
277 		uint32 viewFlags = view->Flags();
278 		view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
279 
280 		view->SetHighColor(markColor);
281 		view->FillTriangle(triangle[0], triangle[1], triangle[2]);
282 
283 		view->SetFlags(viewFlags);
284 
285 		rect = leftRect;
286 	} else {
287 		DrawMenuFieldBackground(view, rect, updateRect, base, flags);
288 	}
289 }
290 
291 void
292 BControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
293 	const BRect& updateRect, const rgb_color& base, uint32 flags,
294 	uint32 borders)
295 {
296 	if (!rect.IsValid() || !updateRect.Intersects(rect))
297 		return;
298 
299 	// the surface edges
300 
301 	// colors
302 	rgb_color cornerColor = tint_color(base, 0.85);
303 	rgb_color bevelColor1 = tint_color(base, 0.3);
304 	rgb_color bevelColor2 = tint_color(base, 0.5);
305 	rgb_color bevelColor3 = tint_color(base, 1.03);
306 
307 	if (flags & B_DISABLED) {
308 		cornerColor = tint_color(base, 0.8);
309 		bevelColor1 = tint_color(base, 0.7);
310 		bevelColor2 = tint_color(base, 0.8);
311 		bevelColor3 = tint_color(base, 1.01);
312 	} else {
313 		cornerColor = tint_color(base, 0.85);
314 		bevelColor1 = tint_color(base, 0.3);
315 		bevelColor2 = tint_color(base, 0.5);
316 		bevelColor3 = tint_color(base, 1.03);
317 	}
318 
319 	_DrawFrame(view, rect,
320 		bevelColor2, bevelColor1,
321 		bevelColor3, bevelColor3,
322 		cornerColor, cornerColor,
323 		borders);
324 
325 	// the actual surface top
326 
327 	float topTint = 0.49;
328 	float middleTint1 = 0.62;
329 	float middleTint2 = 0.76;
330 	float bottomTint = 0.90;
331 
332 	if (flags & B_DISABLED) {
333 		topTint = (topTint + B_NO_TINT) / 2;
334 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
335 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
336 		bottomTint = (bottomTint + B_NO_TINT) / 2;
337 	} else if (flags & B_HOVER) {
338 		static const float kHoverTintFactor = 0.85;
339 		topTint *= kHoverTintFactor;
340 		middleTint1 *= kHoverTintFactor;
341 		middleTint2 *= kHoverTintFactor;
342 		bottomTint *= kHoverTintFactor;
343 	}
344 
345 	_FillGlossyGradient(view, rect, base, topTint, middleTint1,
346 		middleTint2, bottomTint);
347 }
348 
349 void
350 BControlLook::DrawMenuBackground(BView* view, BRect& rect,
351 	const BRect& updateRect, const rgb_color& base, uint32 flags,
352 	uint32 borders)
353 {
354 	if (!rect.IsValid() || !updateRect.Intersects(rect))
355 		return;
356 
357 	// the surface edges
358 
359 	rgb_color bevelLightColor;
360 	rgb_color bevelShadowColor;
361 	rgb_color background = tint_color(base, 0.75);
362 
363 	if (flags & B_DISABLED) {
364 		bevelLightColor = tint_color(background, 0.80);
365 		bevelShadowColor = tint_color(background, 1.07);
366 	} else {
367 		bevelLightColor = tint_color(background, 0.6);
368 		bevelShadowColor = tint_color(background, 1.12);
369 	}
370 
371 	_DrawFrame(view, rect,
372 		bevelLightColor, bevelLightColor,
373 		bevelShadowColor, bevelShadowColor,
374 		borders);
375 
376 	// the actual surface top
377 
378 	view->SetHighColor(background);
379 	view->FillRect(rect);
380 }
381 
382 
383 void
384 BControlLook::DrawMenuItemBackground(BView* view, BRect& rect,
385 	const BRect& updateRect, const rgb_color& base, uint32 flags,
386 	uint32 borders)
387 {
388 	if (!rect.IsValid() || !updateRect.Intersects(rect))
389 		return;
390 
391 	// the surface edges
392 
393 	float topTint;
394 	float bottomTint;
395 	rgb_color selectedColor = base;
396 
397 	if (flags & B_ACTIVATED) {
398 		topTint = 0.9;
399 		bottomTint = 1.05;
400 		selectedColor = tint_color(base, 1.26);
401 	} else if (flags & B_DISABLED) {
402 		topTint = 0.80;
403 		bottomTint = 1.07;
404 	} else {
405 		topTint = 0.6;
406 		bottomTint = 1.12;
407 	}
408 
409 	rgb_color bevelLightColor = tint_color(selectedColor, topTint);
410 	rgb_color bevelShadowColor = tint_color(selectedColor, bottomTint);
411 
412 	_DrawFrame(view, rect,
413 		bevelLightColor, bevelLightColor,
414 		bevelShadowColor, bevelShadowColor,
415 		borders);
416 
417 	// the actual surface top
418 
419 	view->SetLowColor(selectedColor);
420 //	_FillGradient(view, rect, selectedColor, topTint, bottomTint);
421 	_FillGradient(view, rect, selectedColor, bottomTint, topTint);
422 }
423 
424 
425 void
426 BControlLook::DrawStatusBar(BView* view, BRect& rect, const BRect& updateRect,
427 	const rgb_color& base, const rgb_color& barColor, float progressPosition)
428 {
429 	if (!rect.Intersects(updateRect))
430 		return;
431 
432 	_DrawOuterResessedFrame(view, rect, base, 0.6);
433 
434 	// colors
435 	rgb_color dark1BorderColor = tint_color(base, 1.3);
436 	rgb_color dark2BorderColor = tint_color(base, 1.2);
437 	rgb_color dark1FilledBorderColor = tint_color(barColor, 1.20);
438 	rgb_color dark2FilledBorderColor = tint_color(barColor, 1.45);
439 
440 	BRect filledRect(rect);
441 	filledRect.right = progressPosition - 1;
442 
443 	BRect nonfilledRect(rect);
444 	nonfilledRect.left = progressPosition;
445 
446 	bool filledSurface = filledRect.Width() > 0;
447 	bool nonfilledSurface = nonfilledRect.Width() > 0;
448 
449 	if (filledSurface) {
450 		_DrawFrame(view, filledRect,
451 			dark1FilledBorderColor, dark1FilledBorderColor,
452 			dark2FilledBorderColor, dark2FilledBorderColor);
453 
454 		_FillGlossyGradient(view, filledRect, barColor, 0.55, 0.68, 0.76, 0.90);
455 	}
456 
457 	if (nonfilledSurface) {
458 		_DrawFrame(view, nonfilledRect, dark1BorderColor, dark1BorderColor,
459 			dark2BorderColor, dark2BorderColor,
460 			B_TOP_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER);
461 
462 		if (nonfilledRect.left < nonfilledRect.right) {
463 			// shadow from fill bar, or left border
464 			rgb_color leftBorder = dark1BorderColor;
465 			if (filledSurface)
466 				leftBorder = tint_color(base, 0.50);
467 			view->SetHighColor(leftBorder);
468 			view->StrokeLine(nonfilledRect.LeftTop(),
469 				nonfilledRect.LeftBottom());
470 			nonfilledRect.left++;
471 		}
472 
473 		_FillGradient(view, nonfilledRect, base, 0.25, 0.06);
474 	}
475 }
476 
477 
478 void
479 BControlLook::DrawCheckBox(BView* view, BRect& rect, const BRect& updateRect,
480 	const rgb_color& base, uint32 flags)
481 {
482 	if (!rect.Intersects(updateRect))
483 		return;
484 
485 	rgb_color dark1BorderColor;
486 	rgb_color dark2BorderColor;
487 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
488 
489 	if (flags & B_DISABLED) {
490 		_DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags);
491 
492 		dark1BorderColor = tint_color(base, 1.15);
493 		dark2BorderColor = tint_color(base, 1.15);
494 	} else if (flags & B_CLICKED) {
495 		dark1BorderColor = tint_color(base, 1.50);
496 		dark2BorderColor = tint_color(base, 1.48);
497 
498 		_DrawFrame(view, rect,
499 			dark1BorderColor, dark1BorderColor,
500 			dark2BorderColor, dark2BorderColor);
501 
502 		dark2BorderColor = dark1BorderColor;
503 	} else {
504 		_DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags);
505 
506 		dark1BorderColor = tint_color(base, 1.40);
507 		dark2BorderColor = tint_color(base, 1.38);
508 	}
509 
510 	if (flags & B_FOCUSED) {
511 		dark1BorderColor = navigationColor;
512 		dark2BorderColor = navigationColor;
513 	}
514 
515 	_DrawFrame(view, rect,
516 		dark1BorderColor, dark1BorderColor,
517 		dark2BorderColor, dark2BorderColor);
518 
519 	if (flags & B_DISABLED) {
520 		_FillGradient(view, rect, base, 0.4, 0.2);
521 	} else {
522 		_FillGradient(view, rect, base, 0.15, 0.0);
523 	}
524 
525 	rgb_color markColor;
526 	if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) {
527 		view->SetHighColor(markColor);
528 
529 		rect.InsetBy(2, 2);
530 		view->SetPenSize(max_c(1.0, ceilf(rect.Width() / 3.5)));
531 		view->SetDrawingMode(B_OP_OVER);
532 
533 		view->StrokeLine(rect.LeftTop(), rect.RightBottom());
534 		view->StrokeLine(rect.LeftBottom(), rect.RightTop());
535 	}
536 }
537 
538 
539 void
540 BControlLook::DrawRadioButton(BView* view, BRect& rect, const BRect& updateRect,
541 	const rgb_color& base, uint32 flags)
542 {
543 	if (!rect.Intersects(updateRect))
544 		return;
545 
546 	rgb_color borderColor;
547 	rgb_color bevelLight;
548 	rgb_color bevelShadow;
549 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
550 
551 	if (flags & B_DISABLED) {
552 		borderColor = tint_color(base, 1.15);
553 		bevelLight = base;
554 		bevelShadow = base;
555 	} else if (flags & B_CLICKED) {
556 		borderColor = tint_color(base, 1.50);
557 		bevelLight = borderColor;
558 		bevelShadow = borderColor;
559 	} else {
560 		borderColor = tint_color(base, 1.45);
561 		bevelLight = tint_color(base, 0.55);
562 		bevelShadow = tint_color(base, 1.11);
563 	}
564 
565 	if (flags & B_FOCUSED) {
566 		borderColor = navigationColor;
567 	}
568 
569 	BGradientLinear bevelGradient;
570 	bevelGradient.AddColor(bevelShadow, 0);
571 	bevelGradient.AddColor(bevelLight, 255);
572 	bevelGradient.SetStart(rect.LeftTop());
573 	bevelGradient.SetEnd(rect.RightBottom());
574 
575 	view->FillEllipse(rect, bevelGradient);
576 	rect.InsetBy(1, 1);
577 
578 	bevelGradient.MakeEmpty();
579 	bevelGradient.AddColor(borderColor, 0);
580 	bevelGradient.AddColor(tint_color(borderColor, 0.8), 255);
581 	view->FillEllipse(rect, bevelGradient);
582 	rect.InsetBy(1, 1);
583 
584 	float topTint;
585 	float bottomTint;
586 	if (flags & B_DISABLED) {
587 		topTint = 0.4;
588 		bottomTint = 0.2;
589 	} else {
590 		topTint = 0.15;
591 		bottomTint = 0.0;
592 	}
593 
594 	BGradientLinear gradient;
595 	_MakeGradient(gradient, rect, base, topTint, bottomTint);
596 	view->FillEllipse(rect, gradient);
597 
598 	rgb_color markColor;
599 	if (_RadioButtonAndCheckBoxMarkColor(base, markColor, flags)) {
600 		view->SetHighColor(markColor);
601 		rect.InsetBy(3, 3);
602 		view->FillEllipse(rect);
603 	}
604 }
605 
606 
607 void
608 BControlLook::DrawScrollBarBackground(BView* view, BRect& rect1, BRect& rect2,
609 	const BRect& updateRect, const rgb_color& base, uint32 flags,
610 	enum orientation orientation)
611 {
612 	DrawScrollBarBackground(view, rect1, updateRect, base, flags, orientation);
613 	DrawScrollBarBackground(view, rect2, updateRect, base, flags, orientation);
614 }
615 
616 void
617 BControlLook::DrawScrollBarBackground(BView* view, BRect& rect,
618 	const BRect& updateRect, const rgb_color& base, uint32 flags,
619 	enum orientation orientation)
620 {
621 	if (!rect.IsValid() || !rect.Intersects(updateRect))
622 		return;
623 
624 	float gradient1Tint;
625 	float gradient2Tint;
626 	float darkEdge1Tint;
627 	float darkEdge2Tint;
628 	float shadowTint;
629 
630 	if (flags & B_DISABLED) {
631 		gradient1Tint = 0.9;
632 		gradient2Tint = 0.8;
633 		darkEdge1Tint = B_DARKEN_2_TINT;
634 		darkEdge2Tint = B_DARKEN_2_TINT;
635 		shadowTint = gradient1Tint;
636 	} else {
637 		gradient1Tint = 1.10;
638 		gradient2Tint = 1.05;
639 		darkEdge1Tint = B_DARKEN_3_TINT;
640 		darkEdge2Tint = B_DARKEN_2_TINT;
641 		shadowTint = gradient1Tint;
642 	}
643 
644 	rgb_color darkEdge1 = tint_color(base, darkEdge1Tint);
645 	rgb_color darkEdge2 = tint_color(base, darkEdge2Tint);
646 	rgb_color shadow = tint_color(base, shadowTint);
647 
648 	if (orientation == B_HORIZONTAL) {
649 		// dark vertical line on left edge
650 		if (rect.Width() > 0) {
651 			view->SetHighColor(darkEdge1);
652 			view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
653 			rect.left++;
654 		}
655 		// dark vertical line on right edge
656 		if (rect.Width() >= 0) {
657 			view->SetHighColor(darkEdge2);
658 			view->StrokeLine(rect.RightTop(), rect.RightBottom());
659 			rect.right--;
660 		}
661 		// vertical shadow line after left edge
662 		if (rect.Width() >= 0) {
663 			view->SetHighColor(shadow);
664 			view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
665 			rect.left++;
666 		}
667 		// fill
668 		if (rect.Width() >= 0) {
669 			_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
670 				orientation);
671 		}
672 	} else {
673 		// dark vertical line on top edge
674 		if (rect.Height() > 0) {
675 			view->SetHighColor(darkEdge1);
676 			view->StrokeLine(rect.LeftTop(), rect.RightTop());
677 			rect.top++;
678 		}
679 		// dark vertical line on bottom edge
680 		if (rect.Height() >= 0) {
681 			view->SetHighColor(darkEdge2);
682 			view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
683 			rect.bottom--;
684 		}
685 		// horizontal shadow line after top edge
686 		if (rect.Height() >= 0) {
687 			view->SetHighColor(shadow);
688 			view->StrokeLine(rect.LeftTop(), rect.RightTop());
689 			rect.top++;
690 		}
691 		// fill
692 		if (rect.Height() >= 0) {
693 			_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
694 				orientation);
695 		}
696 	}
697 }
698 
699 
700 void
701 BControlLook::DrawScrollViewFrame(BView* view, BRect& rect,
702 	const BRect& updateRect, BRect verticalScrollBarFrame,
703 	BRect horizontalScrollBarFrame, const rgb_color& base,
704 	border_style border, uint32 flags, uint32 _borders)
705 {
706 	// calculate scroll corner rect before messing with the "rect"
707 	BRect scrollCornerFillRect(rect.right, rect.bottom,
708 		rect.right, rect.bottom);
709 	if (horizontalScrollBarFrame.IsValid())
710 		scrollCornerFillRect.left = horizontalScrollBarFrame.right + 1;
711 	if (verticalScrollBarFrame.IsValid())
712 		scrollCornerFillRect.top = verticalScrollBarFrame.bottom + 1;
713 
714 	if (border == B_NO_BORDER) {
715 		if (scrollCornerFillRect.IsValid()) {
716 			view->SetHighColor(base);
717 			view->FillRect(scrollCornerFillRect);
718 		}
719 		return;
720 	}
721 
722 	bool excludeScrollCorner = border == B_FANCY_BORDER
723 		&& horizontalScrollBarFrame.IsValid()
724 		&& verticalScrollBarFrame.IsValid();
725 
726 	uint32 borders = _borders;
727 	if (excludeScrollCorner) {
728 		rect.bottom = horizontalScrollBarFrame.top;
729 		rect.right = verticalScrollBarFrame.left;
730 		borders &= ~(B_RIGHT_BORDER | B_BOTTOM_BORDER);
731 	}
732 
733 	rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT);
734 
735 	if (border == B_FANCY_BORDER)
736 		_DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
737 
738 	if (flags & B_FOCUSED) {
739 		rgb_color focusColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
740 		_DrawFrame(view, rect, focusColor, focusColor, focusColor, focusColor,
741 			borders);
742 	} else {
743 		_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
744 			scrollbarFrameColor, scrollbarFrameColor, borders);
745 	}
746 
747 	if (excludeScrollCorner) {
748 		horizontalScrollBarFrame.InsetBy(-1, -1);
749 		// do not overdraw the top edge
750 		horizontalScrollBarFrame.top += 2;
751 		borders = _borders;
752 		borders &= ~B_TOP_BORDER;
753 		_DrawOuterResessedFrame(view, horizontalScrollBarFrame, base,
754 			1.0, 1.0, flags, borders);
755 		_DrawFrame(view, horizontalScrollBarFrame, scrollbarFrameColor,
756 			scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
757 			borders);
758 
759 
760 		verticalScrollBarFrame.InsetBy(-1, -1);
761 		// do not overdraw the left edge
762 		verticalScrollBarFrame.left += 2;
763 		borders = _borders;
764 		borders &= ~B_LEFT_BORDER;
765 		_DrawOuterResessedFrame(view, verticalScrollBarFrame, base,
766 			1.0, 1.0, flags, borders);
767 		_DrawFrame(view, verticalScrollBarFrame, scrollbarFrameColor,
768 			scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
769 			borders);
770 
771 		// exclude recessed frame
772 		scrollCornerFillRect.top++;
773 		scrollCornerFillRect.left++;
774 	}
775 
776 	if (scrollCornerFillRect.IsValid()) {
777 		view->SetHighColor(base);
778 		view->FillRect(scrollCornerFillRect);
779 	}
780 }
781 
782 
783 void
784 BControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect,
785 	const rgb_color& base, uint32 direction, uint32 flags, float tint)
786 {
787 	BPoint tri1, tri2, tri3;
788 	float hInset = rect.Width() / 3;
789 	float vInset = rect.Height() / 3;
790 	rect.InsetBy(hInset, vInset);
791 
792 	switch (direction) {
793 		case B_LEFT_ARROW:
794 			tri1.Set(rect.right, rect.top);
795 			tri2.Set(rect.right - rect.Width() / 1.33,
796 				(rect.top + rect.bottom + 1) /2 );
797 			tri3.Set(rect.right, rect.bottom + 1);
798 			break;
799 		case B_RIGHT_ARROW:
800 			tri1.Set(rect.left, rect.bottom + 1);
801 			tri2.Set(rect.left + rect.Width() / 1.33,
802 				(rect.top + rect.bottom + 1) / 2);
803 			tri3.Set(rect.left, rect.top);
804 			break;
805 		case B_UP_ARROW:
806 			tri1.Set(rect.left, rect.bottom);
807 			tri2.Set((rect.left + rect.right + 1) / 2,
808 				rect.bottom - rect.Height() / 1.33);
809 			tri3.Set(rect.right + 1, rect.bottom);
810 			break;
811 		case B_DOWN_ARROW:
812 		default:
813 			tri1.Set(rect.left, rect.top);
814 			tri2.Set((rect.left + rect.right + 1) / 2,
815 				rect.top + rect.Height() / 1.33);
816 			tri3.Set(rect.right + 1, rect.top);
817 			break;
818 	}
819 	// offset triangle if down
820 	if (flags & B_ACTIVATED)
821 		view->MovePenTo(BPoint(1, 1));
822 	else
823 		view->MovePenTo(BPoint(0, 0));
824 
825 	BShape arrowShape;
826 	arrowShape.MoveTo(tri1);
827 	arrowShape.LineTo(tri2);
828 	arrowShape.LineTo(tri3);
829 
830 	if (flags & B_DISABLED)
831 		tint = (tint + B_NO_TINT + B_NO_TINT) / 3;
832 
833 	view->SetHighColor(tint_color(base, tint));
834 
835 	float penSize = view->PenSize();
836 	drawing_mode mode = view->DrawingMode();
837 
838 	view->SetPenSize(ceilf(hInset / 2.0));
839 	view->SetDrawingMode(B_OP_OVER);
840 	view->StrokeShape(&arrowShape);
841 
842 	view->SetPenSize(penSize);
843 	view->SetDrawingMode(mode);
844 }
845 
846 
847 rgb_color
848 BControlLook::SliderBarColor(const rgb_color& base)
849 {
850 	return tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_1_TINT);
851 }
852 
853 
854 void
855 BControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
856 	const rgb_color& base, rgb_color leftFillColor, rgb_color rightFillColor,
857 	float sliderScale, uint32 flags, enum orientation orientation)
858 {
859 	if (!rect.IsValid() || !rect.Intersects(updateRect))
860 		return;
861 
862 	// separate the bar in two sides
863 	float sliderPosition;
864 	BRect leftBarSide = rect;
865 	BRect rightBarSide = rect;
866 
867 	if (orientation == B_HORIZONTAL) {
868 		sliderPosition = floorf(rect.left + 2 + (rect.Width() - 2)
869 			* sliderScale);
870 		leftBarSide.right = sliderPosition - 1;
871 		rightBarSide.left = sliderPosition;
872 	} else {
873 		sliderPosition = floorf(rect.top + 2 + (rect.Height() - 2)
874 			* sliderScale);
875 		leftBarSide.bottom = sliderPosition - 1;
876 		rightBarSide.top = sliderPosition;
877 	}
878 
879 	// fill the background for the corners, exclude the middle bar for now
880 	BRegion region(rect);
881 	region.Exclude(rightBarSide);
882 	view->ConstrainClippingRegion(&region);
883 
884 	view->PushState();
885 
886 	DrawSliderBar(view, rect, updateRect, base, leftFillColor, flags,
887 		orientation);
888 
889 	view->PopState();
890 
891 	region.Set(rect);
892 	region.Exclude(leftBarSide);
893 	view->ConstrainClippingRegion(&region);
894 
895 	view->PushState();
896 
897 	DrawSliderBar(view, rect, updateRect, base, rightFillColor, flags,
898 		orientation);
899 
900 	view->PopState();
901 
902 	view->ConstrainClippingRegion(NULL);
903 }
904 
905 
906 void
907 BControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
908 	const rgb_color& base, rgb_color fillColor, uint32 flags,
909 	enum orientation orientation)
910 {
911 	if (!rect.IsValid() || !rect.Intersects(updateRect))
912 		return;
913 
914 	// separate the rect into corners
915 	BRect leftCorner(rect);
916 	BRect rightCorner(rect);
917 	BRect barRect(rect);
918 
919 	if (orientation == B_HORIZONTAL) {
920 		leftCorner.right = leftCorner.left + leftCorner.Height();
921 		rightCorner.left = rightCorner.right - rightCorner.Height();
922 		barRect.left += ceilf(barRect.Height() / 2);
923 		barRect.right -= ceilf(barRect.Height() / 2);
924 	} else {
925 		leftCorner.bottom = leftCorner.top + leftCorner.Width();
926 		rightCorner.top = rightCorner.bottom - rightCorner.Width();
927 		barRect.top += ceilf(barRect.Width() / 2);
928 		barRect.bottom -= ceilf(barRect.Width() / 2);
929 	}
930 
931 	// fill the background for the corners, exclude the middle bar for now
932 	BRegion region(rect);
933 	region.Exclude(barRect);
934 	view->ConstrainClippingRegion(&region);
935 
936 	view->SetHighColor(base);
937 	view->FillRect(rect);
938 
939 	// figure out the tints to be used
940 	float edgeLightTint;
941 	float edgeShadowTint;
942 	float frameLightTint;
943 	float frameShadowTint;
944 	float fillLightTint;
945 	float fillShadowTint;
946 
947 	if (flags & B_DISABLED) {
948 		edgeLightTint = 1.0;
949 		edgeShadowTint = 1.0;
950 		frameLightTint = 1.20;
951 		frameShadowTint = 1.25;
952 		fillLightTint = 0.9;
953 		fillShadowTint = 1.05;
954 
955 		fillColor.red = uint8(fillColor.red * 0.4 + base.red * 0.6);
956 		fillColor.green = uint8(fillColor.green * 0.4 + base.green * 0.6);
957 		fillColor.blue = uint8(fillColor.blue * 0.4 + base.blue * 0.6);
958 	} else {
959 		edgeLightTint = 0.65;
960 		edgeShadowTint = 1.07;
961 		frameLightTint = 1.40;
962 		frameShadowTint = 1.50;
963 		fillLightTint = 0.8;
964 		fillShadowTint = 1.1;
965 	}
966 
967 	rgb_color edgeLightColor = tint_color(base, edgeLightTint);
968 	rgb_color edgeShadowColor = tint_color(base, edgeShadowTint);
969 	rgb_color frameLightColor = tint_color(fillColor, frameLightTint);
970 	rgb_color frameShadowColor = tint_color(fillColor, frameShadowTint);
971 	rgb_color fillLightColor = tint_color(fillColor, fillLightTint);
972 	rgb_color fillShadowColor = tint_color(fillColor, fillShadowTint);
973 
974 	if (orientation == B_HORIZONTAL) {
975 		_DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
976 			edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
977 			fillShadowColor, 1.0, 1.0, 0.0, -1.0, orientation);
978 
979 		_DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
980 			edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
981 			fillShadowColor, 0.0, 1.0, -1.0, -1.0, orientation);
982 	} else {
983 		_DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
984 			edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
985 			fillShadowColor, 1.0, 1.0, -1.0, 0.0, orientation);
986 
987 		_DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
988 			edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
989 			fillShadowColor, 1.0, 0.0, -1.0, -1.0, orientation);
990 	}
991 
992 	view->ConstrainClippingRegion(NULL);
993 
994 	view->BeginLineArray(4);
995 	if (orientation == B_HORIZONTAL) {
996 		view->AddLine(barRect.LeftTop(), barRect.RightTop(), edgeShadowColor);
997 		view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
998 			edgeLightColor);
999 		barRect.InsetBy(0, 1);
1000 		view->AddLine(barRect.LeftTop(), barRect.RightTop(), frameShadowColor);
1001 		view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
1002 			frameLightColor);
1003 		barRect.InsetBy(0, 1);
1004 	} else {
1005 		view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), edgeShadowColor);
1006 		view->AddLine(barRect.RightTop(), barRect.RightBottom(),
1007 			edgeLightColor);
1008 		barRect.InsetBy(1, 0);
1009 		view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), frameShadowColor);
1010 		view->AddLine(barRect.RightTop(), barRect.RightBottom(),
1011 			frameLightColor);
1012 		barRect.InsetBy(1, 0);
1013 	}
1014 	view->EndLineArray();
1015 
1016 	_FillGradient(view, barRect, fillColor, fillShadowTint, fillLightTint,
1017 		orientation);
1018 }
1019 
1020 
1021 void
1022 BControlLook::DrawSliderThumb(BView* view, BRect& rect, const BRect& updateRect,
1023 	const rgb_color& base, uint32 flags, enum orientation orientation)
1024 {
1025 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1026 		return;
1027 
1028 	// figure out frame color
1029 	rgb_color frameLightColor;
1030 	rgb_color frameShadowColor;
1031 	rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
1032 
1033 	if (flags & B_FOCUSED) {
1034 		// focused
1035 		frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1036 		frameShadowColor = frameLightColor;
1037 	} else {
1038 		// figure out the tints to be used
1039 		float frameLightTint;
1040 		float frameShadowTint;
1041 
1042 		if (flags & B_DISABLED) {
1043 			frameLightTint = 1.30;
1044 			frameShadowTint = 1.35;
1045 			shadowColor.alpha = 30;
1046 		} else {
1047 			frameLightTint = 1.6;
1048 			frameShadowTint = 1.65;
1049 		}
1050 
1051 		frameLightColor = tint_color(base, frameLightTint);
1052 		frameShadowColor = tint_color(base, frameShadowTint);
1053 	}
1054 
1055 	BRect originalRect(rect);
1056 	rect.right--;
1057 	rect.bottom--;
1058 
1059 	_DrawFrame(view, rect, frameLightColor, frameLightColor,
1060 		frameShadowColor, frameShadowColor);
1061 
1062 	flags &= ~B_ACTIVATED;
1063 	DrawButtonBackground(view, rect, updateRect, base, flags);
1064 
1065 	// thumb shadow
1066 	view->SetDrawingMode(B_OP_ALPHA);
1067 	view->SetHighColor(shadowColor);
1068 	originalRect.left++;
1069 	originalRect.top++;
1070 	view->StrokeLine(originalRect.LeftBottom(), originalRect.RightBottom());
1071 	originalRect.bottom--;
1072 	view->StrokeLine(originalRect.RightTop(), originalRect.RightBottom());
1073 
1074 	// thumb edge
1075 	if (orientation == B_HORIZONTAL) {
1076 		rect.InsetBy(0, floorf(rect.Height() / 4));
1077 		rect.left = floorf((rect.left + rect.right) / 2);
1078 		rect.right = rect.left + 1;
1079 		shadowColor = tint_color(base, B_DARKEN_2_TINT);
1080 		shadowColor.alpha = 128;
1081 		view->SetHighColor(shadowColor);
1082 		view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
1083 		rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT);
1084 		lightColor.alpha = 128;
1085 		view->SetHighColor(lightColor);
1086 		view->StrokeLine(rect.RightTop(), rect.RightBottom());
1087 	} else {
1088 		rect.InsetBy(floorf(rect.Width() / 4), 0);
1089 		rect.top = floorf((rect.top + rect.bottom) / 2);
1090 		rect.bottom = rect.top + 1;
1091 		shadowColor = tint_color(base, B_DARKEN_2_TINT);
1092 		shadowColor.alpha = 128;
1093 		view->SetHighColor(shadowColor);
1094 		view->StrokeLine(rect.LeftTop(), rect.RightTop());
1095 		rgb_color lightColor = tint_color(base, B_LIGHTEN_2_TINT);
1096 		lightColor.alpha = 128;
1097 		view->SetHighColor(lightColor);
1098 		view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
1099 	}
1100 
1101 	view->SetDrawingMode(B_OP_COPY);
1102 }
1103 
1104 
1105 void
1106 BControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1107 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1108 	enum orientation orientation)
1109 {
1110 	DrawSliderTriangle(view, rect, updateRect, base, base, flags, orientation);
1111 }
1112 
1113 
1114 void
1115 BControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1116 	const BRect& updateRect, const rgb_color& base, const rgb_color& fill,
1117 	uint32 flags, enum orientation orientation)
1118 {
1119 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1120 		return;
1121 
1122 	// figure out frame color
1123 	rgb_color frameLightColor;
1124 	rgb_color frameShadowColor;
1125 	rgb_color shadowColor = (rgb_color){ 0, 0, 0, 60 };
1126 
1127 	float topTint = 0.49;
1128 	float middleTint1 = 0.62;
1129 	float middleTint2 = 0.76;
1130 	float bottomTint = 0.90;
1131 
1132 	if (flags & B_DISABLED) {
1133 		topTint = (topTint + B_NO_TINT) / 2;
1134 		middleTint1 = (middleTint1 + B_NO_TINT) / 2;
1135 		middleTint2 = (middleTint2 + B_NO_TINT) / 2;
1136 		bottomTint = (bottomTint + B_NO_TINT) / 2;
1137 	} else if (flags & B_HOVER) {
1138 		static const float kHoverTintFactor = 0.85;
1139 		topTint *= kHoverTintFactor;
1140 		middleTint1 *= kHoverTintFactor;
1141 		middleTint2 *= kHoverTintFactor;
1142 		bottomTint *= kHoverTintFactor;
1143 	}
1144 
1145 	if (flags & B_FOCUSED) {
1146 		// focused
1147 		frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1148 		frameShadowColor = frameLightColor;
1149 	} else {
1150 		// figure out the tints to be used
1151 		float frameLightTint;
1152 		float frameShadowTint;
1153 
1154 		if (flags & B_DISABLED) {
1155 			frameLightTint = 1.30;
1156 			frameShadowTint = 1.35;
1157 			shadowColor.alpha = 30;
1158 		} else {
1159 			frameLightTint = 1.6;
1160 			frameShadowTint = 1.65;
1161 		}
1162 
1163 		frameLightColor = tint_color(base, frameLightTint);
1164 		frameShadowColor = tint_color(base, frameShadowTint);
1165 	}
1166 
1167 	// make room for the shadow
1168 	rect.right--;
1169 	rect.bottom--;
1170 
1171 	uint32 viewFlags = view->Flags();
1172 	view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
1173 	view->SetLineMode(B_ROUND_CAP, B_ROUND_JOIN);
1174 
1175 	float center = (rect.left + rect.right) / 2;
1176 
1177 	BShape shape;
1178 	shape.MoveTo(BPoint(rect.left + 0.5, rect.bottom + 0.5));
1179 	shape.LineTo(BPoint(rect.right + 0.5, rect.bottom + 0.5));
1180 	shape.LineTo(BPoint(rect.right + 0.5, rect.bottom - 1 + 0.5));
1181 	shape.LineTo(BPoint(center + 0.5, rect.top + 0.5));
1182 	shape.LineTo(BPoint(rect.left + 0.5, rect.bottom - 1 + 0.5));
1183 	shape.Close();
1184 
1185 	view->MovePenTo(BPoint(1, 1));
1186 
1187 	view->SetDrawingMode(B_OP_ALPHA);
1188 	view->SetHighColor(shadowColor);
1189 	view->StrokeShape(&shape);
1190 
1191 	view->MovePenTo(B_ORIGIN);
1192 
1193 	view->SetDrawingMode(B_OP_COPY);
1194 	view->SetHighColor(frameLightColor);
1195 	view->StrokeShape(&shape);
1196 
1197 	rect.InsetBy(1, 1);
1198 	shape.Clear();
1199 	shape.MoveTo(BPoint(rect.left, rect.bottom + 1));
1200 	shape.LineTo(BPoint(rect.right + 1, rect.bottom + 1));
1201 	shape.LineTo(BPoint(center + 0.5, rect.top));
1202 	shape.Close();
1203 
1204 	BGradientLinear gradient;
1205 	if (flags & B_DISABLED) {
1206 		_MakeGradient(gradient, rect, fill, topTint, bottomTint);
1207 	} else {
1208 		_MakeGlossyGradient(gradient, rect, fill, topTint, middleTint1,
1209 			middleTint2, bottomTint);
1210 	}
1211 
1212 	view->FillShape(&shape, gradient);
1213 
1214 	view->SetFlags(viewFlags);
1215 }
1216 
1217 
1218 void
1219 BControlLook::DrawSliderHashMarks(BView* view, BRect& rect,
1220 	const BRect& updateRect, const rgb_color& base, int32 count,
1221 	hash_mark_location location, uint32 flags, enum orientation orientation)
1222 {
1223 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1224 		return;
1225 
1226 	rgb_color lightColor;
1227 	rgb_color darkColor;
1228 
1229 	if (flags & B_DISABLED) {
1230 		lightColor = tint_color(base, 0.9);
1231 		darkColor = tint_color(base, 1.07);
1232 	} else {
1233 		lightColor = tint_color(base, 0.8);
1234 		darkColor = tint_color(base, 1.14);
1235 	}
1236 
1237 	int32 hashMarkCount = max_c(count, 2);
1238 		// draw at least two hashmarks at min/max if
1239 		// fHashMarks != B_HASH_MARKS_NONE
1240 	float factor;
1241 	float startPos;
1242 	if (orientation == B_HORIZONTAL) {
1243 		factor = (rect.Width() - 2) / (hashMarkCount - 1);
1244 		startPos = rect.left + 1;
1245 	} else {
1246 		factor = (rect.Height() - 2) / (hashMarkCount - 1);
1247 		startPos = rect.top + 1;
1248 	}
1249 
1250 	if (location & B_HASH_MARKS_TOP) {
1251 		view->BeginLineArray(hashMarkCount * 2);
1252 
1253 		if (orientation == B_HORIZONTAL) {
1254 			float pos = startPos;
1255 			for (int32 i = 0; i < hashMarkCount; i++) {
1256 				view->AddLine(BPoint(pos, rect.top),
1257 							  BPoint(pos, rect.top + 4), darkColor);
1258 				view->AddLine(BPoint(pos + 1, rect.top),
1259 							  BPoint(pos + 1, rect.top + 4), lightColor);
1260 
1261 				pos += factor;
1262 			}
1263 		} else {
1264 			float pos = startPos;
1265 			for (int32 i = 0; i < hashMarkCount; i++) {
1266 				view->AddLine(BPoint(rect.left, pos),
1267 							  BPoint(rect.left + 4, pos), darkColor);
1268 				view->AddLine(BPoint(rect.left, pos + 1),
1269 							  BPoint(rect.left + 4, pos + 1), lightColor);
1270 
1271 				pos += factor;
1272 			}
1273 		}
1274 
1275 		view->EndLineArray();
1276 	}
1277 
1278 	if (location & B_HASH_MARKS_BOTTOM) {
1279 
1280 		view->BeginLineArray(hashMarkCount * 2);
1281 
1282 		if (orientation == B_HORIZONTAL) {
1283 			float pos = startPos;
1284 			for (int32 i = 0; i < hashMarkCount; i++) {
1285 				view->AddLine(BPoint(pos, rect.bottom - 4),
1286 							  BPoint(pos, rect.bottom), darkColor);
1287 				view->AddLine(BPoint(pos + 1, rect.bottom - 4),
1288 							  BPoint(pos + 1, rect.bottom), lightColor);
1289 
1290 				pos += factor;
1291 			}
1292 		} else {
1293 			float pos = startPos;
1294 			for (int32 i = 0; i < hashMarkCount; i++) {
1295 				view->AddLine(BPoint(rect.right - 4, pos),
1296 							  BPoint(rect.right, pos), darkColor);
1297 				view->AddLine(BPoint(rect.right - 4, pos + 1),
1298 							  BPoint(rect.right, pos + 1), lightColor);
1299 
1300 				pos += factor;
1301 			}
1302 		}
1303 
1304 		view->EndLineArray();
1305 	}
1306 }
1307 
1308 
1309 void
1310 BControlLook::DrawActiveTab(BView* view, BRect& rect, const BRect& updateRect,
1311 	const rgb_color& base, uint32 flags, uint32 borders)
1312 {
1313 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1314 		return;
1315 
1316 	rgb_color edgeShadowColor;
1317 	rgb_color edgeLightColor;
1318 	rgb_color frameShadowColor;
1319 	rgb_color frameLightColor;
1320 	rgb_color bevelShadowColor;
1321 	rgb_color bevelLightColor;
1322 	BGradientLinear fillGradient;
1323 	fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3));
1324 	fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3));
1325 
1326 	if (flags & B_DISABLED) {
1327 		edgeShadowColor = base;
1328 		edgeLightColor = base;
1329 		frameShadowColor = tint_color(base, 1.30);
1330 		frameLightColor = tint_color(base, 1.25);
1331 		bevelShadowColor = tint_color(base, 1.07);
1332 		bevelLightColor = tint_color(base, 0.8);
1333 		fillGradient.AddColor(tint_color(base, 0.85), 0);
1334 		fillGradient.AddColor(base, 255);
1335 	} else {
1336 		edgeShadowColor = tint_color(base, 1.03);
1337 		edgeLightColor = tint_color(base, 0.80);
1338 		frameShadowColor = tint_color(base, 1.30);
1339 		frameLightColor = tint_color(base, 1.30);
1340 		bevelShadowColor = tint_color(base, 1.07);
1341 		bevelLightColor = tint_color(base, 0.6);
1342 		fillGradient.AddColor(tint_color(base, 0.75), 0);
1343 		fillGradient.AddColor(tint_color(base, 1.03), 255);
1344 	}
1345 
1346 	static const float kRoundCornerRadius = 4;
1347 
1348 	// left/top corner
1349 	BRect cornerRect(rect);
1350 	cornerRect.right = cornerRect.left + kRoundCornerRadius;
1351 	cornerRect.bottom = cornerRect.top + kRoundCornerRadius;
1352 
1353 	BRegion clipping(rect);
1354 	clipping.Exclude(cornerRect);
1355 
1356 	_DrawRoundCornerLeftTop(view, cornerRect, updateRect, base, edgeShadowColor,
1357 		frameLightColor, bevelLightColor, fillGradient);
1358 
1359 	// left/top corner
1360 	cornerRect.right = rect.right;
1361 	cornerRect.left = cornerRect.right - kRoundCornerRadius;
1362 
1363 	clipping.Exclude(cornerRect);
1364 
1365 	_DrawRoundCornerRightTop(view, cornerRect, updateRect, base, edgeShadowColor,
1366 		edgeLightColor, frameLightColor, frameShadowColor, bevelLightColor,
1367 		bevelShadowColor, fillGradient);
1368 
1369 	// rest of frame and fill
1370 	view->ConstrainClippingRegion(&clipping);
1371 
1372 	_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
1373 		edgeLightColor,
1374 		borders & (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER));
1375 	if ((borders & B_LEFT_BORDER) == 0)
1376 		rect.left++;
1377 	if ((borders & B_RIGHT_BORDER) == 0)
1378 		rect.right--;
1379 
1380 	_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
1381 		frameShadowColor, B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER);
1382 
1383 	_DrawFrame(view, rect, bevelLightColor, bevelLightColor, bevelShadowColor,
1384 		bevelShadowColor);
1385 
1386 	view->FillRect(rect, fillGradient);
1387 
1388 	view->ConstrainClippingRegion(NULL);
1389 }
1390 
1391 
1392 void
1393 BControlLook::DrawInactiveTab(BView* view, BRect& rect, const BRect& updateRect,
1394 	const rgb_color& base, uint32 flags, uint32 borders)
1395 {
1396 	if (!rect.IsValid() || !rect.Intersects(updateRect))
1397 		return;
1398 
1399 	rgb_color edgeShadowColor;
1400 	rgb_color edgeLightColor;
1401 	rgb_color frameShadowColor;
1402 	rgb_color frameLightColor;
1403 	rgb_color bevelShadowColor;
1404 	rgb_color bevelLightColor;
1405 	BGradientLinear fillGradient;
1406 	fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3));
1407 	fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3));
1408 
1409 	if (flags & B_DISABLED) {
1410 		edgeShadowColor = base;
1411 		edgeLightColor = base;
1412 		frameShadowColor = tint_color(base, 1.30);
1413 		frameLightColor = tint_color(base, 1.25);
1414 		bevelShadowColor = tint_color(base, 1.07);
1415 		bevelLightColor = tint_color(base, 0.8);
1416 		fillGradient.AddColor(tint_color(base, 0.85), 0);
1417 		fillGradient.AddColor(base, 255);
1418 	} else {
1419 		edgeShadowColor = tint_color(base, 1.03);
1420 		edgeLightColor = tint_color(base, 0.80);
1421 		frameShadowColor = tint_color(base, 1.30);
1422 		frameLightColor = tint_color(base, 1.30);
1423 		bevelShadowColor = tint_color(base, 1.17);
1424 		bevelLightColor = tint_color(base, 1.10);
1425 		fillGradient.AddColor(tint_color(base, 1.12), 0);
1426 		fillGradient.AddColor(tint_color(base, 1.08), 255);
1427 	}
1428 
1429 	// active tabs stand out at the top, but this is an inactive tab
1430 	view->SetHighColor(base);
1431 	view->FillRect(BRect(rect.left, rect.top, rect.right, rect.top + 4));
1432 	rect.top += 4;
1433 
1434 	// frame and fill
1435 	_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
1436 		edgeLightColor,
1437 		borders & (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER));
1438 
1439 	_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
1440 		frameShadowColor,
1441 		borders & (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER));
1442 
1443 	if (rect.IsValid()) {
1444 		_DrawFrame(view, rect, bevelShadowColor, bevelShadowColor,
1445 			bevelLightColor, bevelLightColor, B_LEFT_BORDER & ~borders);
1446 	} else {
1447 		if ((B_LEFT_BORDER & ~borders) != 0)
1448 			rect.left++;
1449 	}
1450 
1451 	view->FillRect(rect, fillGradient);
1452 }
1453 
1454 
1455 void
1456 BControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect,
1457 	const rgb_color& base, enum orientation orientation, uint32 flags,
1458 	uint32 borders)
1459 {
1460 	rgb_color background;
1461 	if ((flags & (B_CLICKED | B_ACTIVATED)) != 0)
1462 		background = tint_color(base, B_DARKEN_1_TINT);
1463 	else
1464 		background = base;
1465 
1466 	rgb_color light = tint_color(background, 0.6);
1467 	rgb_color shadow = tint_color(background, 1.21);
1468 
1469 	// frame
1470 	if (borders != 0 && rect.Width() > 3 && rect.Height() > 3)
1471 		DrawRaisedBorder(view, rect, updateRect, background, flags, borders);
1472 
1473 	// dots and rest of background
1474 	if (orientation == B_HORIZONTAL) {
1475 		if (rect.Width() > 2) {
1476 			// background on left/right
1477 			BRegion region(rect);
1478 			rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5);
1479 			rect.right = rect.left + 1;
1480 			region.Exclude(rect);
1481 			view->SetHighColor(background);
1482 			view->FillRegion(&region);
1483 		}
1484 
1485 		BPoint dot = rect.LeftTop();
1486 		BPoint stop = rect.LeftBottom();
1487 		int32 num = 1;
1488 		while (dot.y <= stop.y) {
1489 			rgb_color col1;
1490 			rgb_color col2;
1491 			switch (num) {
1492 				case 1:
1493 					col1 = background;
1494 					col2 = background;
1495 					break;
1496 				case 2:
1497 					col1 = shadow;
1498 					col2 = background;
1499 					break;
1500 				case 3:
1501 				default:
1502 					col1 = background;
1503 					col2 = light;
1504 					num = 0;
1505 					break;
1506 			}
1507 			view->SetHighColor(col1);
1508 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1509 			view->SetHighColor(col2);
1510 			dot.x++;
1511 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1512 			dot.x -= 1.0;
1513 			// next pixel
1514 			num++;
1515 			dot.y++;
1516 		}
1517 	} else {
1518 		if (rect.Height() > 2) {
1519 			// background on left/right
1520 			BRegion region(rect);
1521 			rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5);
1522 			rect.bottom = rect.top + 1;
1523 			region.Exclude(rect);
1524 			view->SetHighColor(background);
1525 			view->FillRegion(&region);
1526 		}
1527 
1528 		BPoint dot = rect.LeftTop();
1529 		BPoint stop = rect.RightTop();
1530 		int32 num = 1;
1531 		while (dot.x <= stop.x) {
1532 			rgb_color col1;
1533 			rgb_color col2;
1534 			switch (num) {
1535 				case 1:
1536 					col1 = background;
1537 					col2 = background;
1538 					break;
1539 				case 2:
1540 					col1 = shadow;
1541 					col2 = background;
1542 					break;
1543 				case 3:
1544 				default:
1545 					col1 = background;
1546 					col2 = light;
1547 					num = 0;
1548 					break;
1549 			}
1550 			view->SetHighColor(col1);
1551 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1552 			view->SetHighColor(col2);
1553 			dot.y++;
1554 			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1555 			dot.y -= 1.0;
1556 			// next pixel
1557 			num++;
1558 			dot.x++;
1559 		}
1560 	}
1561 }
1562 
1563 
1564 // #pragma mark -
1565 
1566 
1567 void
1568 BControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect,
1569 	const rgb_color& base, border_style border, uint32 flags, uint32 borders)
1570 {
1571 	if (border == B_NO_BORDER)
1572 		return;
1573 
1574 	rgb_color scrollbarFrameColor = tint_color(base, B_DARKEN_2_TINT);
1575 	if (flags & B_FOCUSED)
1576 		scrollbarFrameColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1577 
1578 	if (border == B_FANCY_BORDER)
1579 		_DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
1580 
1581 	_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
1582 		scrollbarFrameColor, scrollbarFrameColor, borders);
1583 }
1584 
1585 
1586 void
1587 BControlLook::DrawRaisedBorder(BView* view, BRect& rect,
1588 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1589 	uint32 borders)
1590 {
1591 	rgb_color lightColor;
1592 	rgb_color shadowColor;
1593 
1594 	if (flags & B_DISABLED) {
1595 		lightColor = base;
1596 		shadowColor = base;
1597 	} else {
1598 		lightColor = tint_color(base, 0.85);
1599 		shadowColor = tint_color(base, 1.07);
1600 	}
1601 
1602 	_DrawFrame(view, rect, lightColor, lightColor, shadowColor, shadowColor,
1603 		borders);
1604 }
1605 
1606 
1607 void
1608 BControlLook::DrawTextControlBorder(BView* view, BRect& rect,
1609 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1610 	uint32 borders)
1611 {
1612 	if (!rect.Intersects(updateRect))
1613 		return;
1614 
1615 	rgb_color dark1BorderColor;
1616 	rgb_color dark2BorderColor;
1617 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1618 
1619 	if (flags & B_DISABLED) {
1620 		_DrawOuterResessedFrame(view, rect, base, 0.0, 1.0, flags, borders);
1621 
1622 		if (flags & B_BLEND_FRAME)
1623 			dark1BorderColor = (rgb_color){ 0, 0, 0, 40 };
1624 		else
1625 			dark1BorderColor = tint_color(base, 1.15);
1626 		dark2BorderColor = dark1BorderColor;
1627 	} else if (flags & B_CLICKED) {
1628 		dark1BorderColor = tint_color(base, 1.50);
1629 		dark2BorderColor = tint_color(base, 1.49);
1630 
1631 		// BCheckBox uses this to indicate the clicked state...
1632 		_DrawFrame(view, rect,
1633 			dark1BorderColor, dark1BorderColor,
1634 			dark2BorderColor, dark2BorderColor);
1635 
1636 		dark2BorderColor = dark1BorderColor;
1637 	} else {
1638 		_DrawOuterResessedFrame(view, rect, base, 0.6, 1.0, flags, borders);
1639 
1640 		if (flags & B_BLEND_FRAME) {
1641 			dark1BorderColor = (rgb_color){ 0, 0, 0, 102 };
1642 			dark2BorderColor = (rgb_color){ 0, 0, 0, 97 };
1643 		} else {
1644 			dark1BorderColor = tint_color(base, 1.40);
1645 			dark2BorderColor = tint_color(base, 1.38);
1646 		}
1647 	}
1648 
1649 	if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED)) {
1650 		dark1BorderColor = navigationColor;
1651 		dark2BorderColor = navigationColor;
1652 	}
1653 
1654 	if (flags & B_BLEND_FRAME) {
1655 		drawing_mode oldMode = view->DrawingMode();
1656 		view->SetDrawingMode(B_OP_ALPHA);
1657 
1658 		_DrawFrame(view, rect,
1659 			dark1BorderColor, dark1BorderColor,
1660 			dark2BorderColor, dark2BorderColor, borders);
1661 
1662 		view->SetDrawingMode(oldMode);
1663 	} else {
1664 		_DrawFrame(view, rect,
1665 			dark1BorderColor, dark1BorderColor,
1666 			dark2BorderColor, dark2BorderColor, borders);
1667 	}
1668 }
1669 
1670 
1671 void
1672 BControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
1673 	const rgb_color& base, uint32 borders)
1674 {
1675 	rgb_color frameColor = tint_color(base, 1.30);
1676 	rgb_color bevelLight = tint_color(base, 0.8);
1677 	rgb_color bevelShadow = tint_color(base, 1.03);
1678 
1679 	_DrawFrame(view, rect, bevelShadow, bevelShadow, bevelLight, bevelLight,
1680 		borders);
1681 
1682 	_DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor,
1683 		borders);
1684 
1685 	_DrawFrame(view, rect, bevelLight, bevelLight, bevelShadow, bevelShadow,
1686 		borders);
1687 }
1688 
1689 
1690 void
1691 BControlLook::DrawLabel(BView* view, const char* label, BRect rect,
1692 	const BRect& updateRect, const rgb_color& base, uint32 flags)
1693 {
1694 	DrawLabel(view, label, rect, updateRect, base, flags,
1695 		DefaultLabelAlignment());
1696 }
1697 
1698 
1699 void
1700 BControlLook::DrawLabel(BView* view, const char* label, BRect rect,
1701 	const BRect& updateRect, const rgb_color& base, uint32 flags,
1702 	const BAlignment& alignment)
1703 {
1704 	if (!rect.Intersects(updateRect))
1705 		return;
1706 
1707 	// setup the text color
1708 	rgb_color color;
1709 	if (base.red + base.green + base.blue > 128 * 3)
1710 		color = tint_color(base, B_DARKEN_MAX_TINT);
1711 	else
1712 		color = tint_color(base, B_LIGHTEN_MAX_TINT);
1713 
1714 	if (flags & B_DISABLED) {
1715 		color.red = (uint8)(((int32)base.red + color.red + 1) / 2);
1716 		color.green = (uint8)(((int32)base.green + color.green + 1) / 2);
1717 		color.blue = (uint8)(((int32)base.blue + color.blue + 1) / 2);
1718 	}
1719 
1720 	view->SetHighColor(color);
1721 	view->SetDrawingMode(B_OP_OVER);
1722 
1723 	// truncate the label if necessary and get the width and height
1724 	BString truncatedLabel(label);
1725 
1726 	BFont font;
1727 	view->GetFont(&font);
1728 
1729 	float width = rect.Width();
1730 	font.TruncateString(&truncatedLabel, B_TRUNCATE_END, width);
1731 	width = font.StringWidth(truncatedLabel.String());
1732 
1733 	font_height fontHeight;
1734 	font.GetHeight(&fontHeight);
1735 	float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
1736 
1737 	// handle alignment
1738 	BPoint location;
1739 
1740 	switch (alignment.horizontal) {
1741 	default:
1742 		case B_ALIGN_LEFT:
1743 			location.x = rect.left;
1744 			break;
1745 		case B_ALIGN_RIGHT:
1746 			location.x = rect.right - width;
1747 			break;
1748 		case B_ALIGN_CENTER:
1749 			location.x = (rect.left + rect.right - width) / 2.0f;
1750 			break;
1751 	}
1752 
1753 	switch (alignment.vertical) {
1754 		case B_ALIGN_TOP:
1755 			location.y = rect.top + ceilf(fontHeight.ascent);
1756 			break;
1757 		default:
1758 		case B_ALIGN_MIDDLE:
1759 			location.y = floorf((rect.top + rect.bottom - height) / 2.0f + 0.5f)
1760 				+ ceilf(fontHeight.ascent);
1761 			break;
1762 		case B_ALIGN_BOTTOM:
1763 			location.y = rect.bottom - ceilf(fontHeight.descent);
1764 			break;
1765 	}
1766 
1767 	view->DrawString(truncatedLabel.String(), location);
1768 }
1769 
1770 
1771 // #pragma mark -
1772 
1773 
1774 void
1775 BControlLook::_DrawButtonFrame(BView* view, BRect& rect,
1776 	const BRect& updateRect, const rgb_color& base, const rgb_color& background,
1777 	float contrast, float brightness, uint32 flags, uint32 borders)
1778 {
1779 	// colors
1780 	rgb_color dark1BorderColor;
1781 	rgb_color dark2BorderColor;
1782 
1783 	if ((flags & B_DISABLED) == 0) {
1784 		if (flags & B_BLEND_FRAME) {
1785 			dark1BorderColor = (rgb_color){ 0, 0, 0, 75 };
1786 			dark2BorderColor = (rgb_color){ 0, 0, 0, 95 };
1787 		} else {
1788 			dark1BorderColor = tint_color(base, 1.33);
1789 			dark2BorderColor = tint_color(base, 1.45);
1790 		}
1791 
1792 		if (flags & B_DEFAULT_BUTTON) {
1793 			// TODO: B_BLEND_FRAME
1794 			dark2BorderColor = tint_color(dark1BorderColor, 1.5);
1795 			dark1BorderColor = tint_color(dark1BorderColor, 1.35);
1796 		}
1797 	} else {
1798 		// TODO: B_BLEND_FRAME
1799 		dark1BorderColor = tint_color(base, 1.147);
1800 		dark2BorderColor = tint_color(base, 1.24);
1801 
1802 		if (flags & B_DEFAULT_BUTTON) {
1803 			dark1BorderColor = tint_color(dark1BorderColor, 1.14);
1804 			dark2BorderColor = tint_color(dark1BorderColor, 1.12);
1805 		}
1806 	}
1807 
1808 	if (flags & B_ACTIVATED) {
1809 		rgb_color temp = dark2BorderColor;
1810 		dark2BorderColor = dark1BorderColor;
1811 		dark1BorderColor = temp;
1812 	}
1813 
1814 	// indicate focus by changing main button border
1815 	if (flags & B_FOCUSED) {
1816 		dark1BorderColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
1817 		dark2BorderColor = dark1BorderColor;
1818 	}
1819 
1820 	if (flags & B_DEFAULT_BUTTON) {
1821 		// TODO: B_BLEND_FRAME
1822 		float focusTint = 1.2;
1823 		if (flags & B_DISABLED)
1824 			focusTint = (B_NO_TINT + focusTint) / 2;
1825 
1826 		rgb_color focusColor = tint_color(base, focusTint);
1827 		view->SetHighColor(base);
1828 
1829 		view->StrokeRect(rect);
1830 		rect.InsetBy(1.0, 1.0);
1831 
1832 		view->SetHighColor(focusColor);
1833 		view->StrokeRect(rect);
1834 		rect.InsetBy(1.0, 1.0);
1835 		view->StrokeRect(rect);
1836 		rect.InsetBy(1.0, 1.0);
1837 
1838 		// bevel around external border
1839 		_DrawOuterResessedFrame(view, rect, focusColor,
1840 			contrast * (((flags & B_DISABLED) ? 0.3 : 0.8)),
1841 			brightness * (((flags & B_DISABLED) ? 1.0 : 0.9)),
1842 			flags, borders);
1843 	} else {
1844 		// bevel around external border
1845 		_DrawOuterResessedFrame(view, rect, background,
1846 			contrast * ((flags & B_DISABLED) ? 0.0 : 1.0), brightness * 1.0,
1847 			flags, borders);
1848 	}
1849 
1850 	if (flags & B_BLEND_FRAME) {
1851 		drawing_mode oldDrawingMode = view->DrawingMode();
1852 		view->SetDrawingMode(B_OP_ALPHA);
1853 
1854 		_DrawFrame(view, rect, dark1BorderColor, dark1BorderColor,
1855 			dark2BorderColor, dark2BorderColor, borders);
1856 
1857 		view->SetDrawingMode(oldDrawingMode);
1858 	} else {
1859 		_DrawFrame(view, rect, dark1BorderColor, dark1BorderColor,
1860 			dark2BorderColor, dark2BorderColor, borders);
1861 	}
1862 }
1863 
1864 
1865 void
1866 BControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
1867 	const rgb_color& base, float contrast, float brightness, uint32 flags,
1868 	uint32 borders)
1869 {
1870 	if (flags & B_BLEND_FRAME) {
1871 		// assumes the background has already been painted
1872 		drawing_mode oldDrawingMode = view->DrawingMode();
1873 		view->SetDrawingMode(B_OP_ALPHA);
1874 
1875 		uint8 alpha = uint8(20 * contrast);
1876 		uint32 white = uint8(255 * brightness);
1877 
1878 		rgb_color borderBevelShadow = (rgb_color){ 0, 0, 0, alpha };
1879 		rgb_color borderBevelLight = (rgb_color){ white, white, white, alpha };
1880 
1881 		_DrawFrame(view, rect, borderBevelShadow, borderBevelShadow,
1882 			borderBevelLight, borderBevelLight, borders);
1883 
1884 		view->SetDrawingMode(oldDrawingMode);
1885 	} else {
1886 		// colors
1887 		float tintLight = kEdgeBevelLightTint;
1888 		float tintShadow = kEdgeBevelShadowTint;
1889 
1890 		if (contrast == 0.0) {
1891 			tintLight = B_NO_TINT;
1892 			tintShadow = B_NO_TINT;
1893 		} else if (contrast != 1.0) {
1894 			tintLight = B_NO_TINT + (tintLight - B_NO_TINT) * contrast;
1895 			tintShadow = B_NO_TINT + (tintShadow - B_NO_TINT) * contrast;
1896 		}
1897 
1898 		rgb_color borderBevelShadow = tint_color(base, tintShadow);
1899 		rgb_color borderBevelLight = tint_color(base, tintLight);
1900 
1901 		if (brightness < 1.0) {
1902 			borderBevelShadow.red = uint8(borderBevelShadow.red * brightness);
1903 			borderBevelShadow.green = uint8(borderBevelShadow.green * brightness);
1904 			borderBevelShadow.blue = uint8(borderBevelShadow.blue * brightness);
1905 			borderBevelLight.red = uint8(borderBevelLight.red * brightness);
1906 			borderBevelLight.green = uint8(borderBevelLight.green * brightness);
1907 			borderBevelLight.blue = uint8(borderBevelLight.blue * brightness);
1908 		}
1909 
1910 		_DrawFrame(view, rect, borderBevelShadow, borderBevelShadow,
1911 			borderBevelLight, borderBevelLight, borders);
1912 	}
1913 }
1914 
1915 
1916 void
1917 BControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
1918 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
1919 	uint32 borders)
1920 {
1921 	view->BeginLineArray(4);
1922 
1923 	if (borders & B_LEFT_BORDER) {
1924 		view->AddLine(
1925 			BPoint(rect.left, rect.bottom),
1926 			BPoint(rect.left, rect.top), left);
1927 		rect.left++;
1928 	}
1929 	if (borders & B_TOP_BORDER) {
1930 		view->AddLine(
1931 			BPoint(rect.left, rect.top),
1932 			BPoint(rect.right, rect.top), top);
1933 		rect.top++;
1934 	}
1935 	if (borders & B_RIGHT_BORDER) {
1936 		view->AddLine(
1937 			BPoint(rect.right, rect.top),
1938 			BPoint(rect.right, rect.bottom), right);
1939 		rect.right--;
1940 	}
1941 	if (borders & B_BOTTOM_BORDER) {
1942 		view->AddLine(
1943 			BPoint(rect.left, rect.bottom),
1944 			BPoint(rect.right, rect.bottom), bottom);
1945 		rect.bottom--;
1946 	}
1947 
1948 	view->EndLineArray();
1949 }
1950 
1951 
1952 void
1953 BControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
1954 	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
1955 	const rgb_color& rightTop, const rgb_color& leftBottom, uint32 borders)
1956 {
1957 	view->BeginLineArray(6);
1958 
1959 	if (borders & B_TOP_BORDER) {
1960 		if (borders & B_RIGHT_BORDER) {
1961 			view->AddLine(
1962 				BPoint(rect.left, rect.top),
1963 				BPoint(rect.right - 1, rect.top), top);
1964 			view->AddLine(
1965 				BPoint(rect.right, rect.top),
1966 				BPoint(rect.right, rect.top), rightTop);
1967 		} else {
1968 			view->AddLine(
1969 				BPoint(rect.left, rect.top),
1970 				BPoint(rect.right, rect.top), top);
1971 		}
1972 		rect.top++;
1973 	}
1974 
1975 	if (borders & B_LEFT_BORDER) {
1976 		view->AddLine(
1977 			BPoint(rect.left, rect.top),
1978 			BPoint(rect.left, rect.bottom - 1), left);
1979 		view->AddLine(
1980 			BPoint(rect.left, rect.bottom),
1981 			BPoint(rect.left, rect.bottom), leftBottom);
1982 		rect.left++;
1983 	}
1984 
1985 	if (borders & B_BOTTOM_BORDER) {
1986 		view->AddLine(
1987 			BPoint(rect.left, rect.bottom),
1988 			BPoint(rect.right, rect.bottom), bottom);
1989 		rect.bottom--;
1990 	}
1991 
1992 	if (borders & B_RIGHT_BORDER) {
1993 		view->AddLine(
1994 			BPoint(rect.right, rect.bottom),
1995 			BPoint(rect.right, rect.top), right);
1996 		rect.right--;
1997 	}
1998 
1999 	view->EndLineArray();
2000 }
2001 
2002 
2003 //void
2004 //BControlLook::_DrawShadowFrame(BView* view, BRect& rect, const rgb_color& base,
2005 //	uint32 borders)
2006 //{
2007 //	view->BeginLineArray(4);
2008 //
2009 //	bevelColor1 = tint_color(base, 1.2);
2010 //	bevelColor2 = tint_color(base, 1.1);
2011 //
2012 //	// shadow along left/top borders
2013 //	if (rect.Height() > 0 && borders & B_LEFT_BORDER) {
2014 //		view->AddLine(BPoint(rect.left, rect.top),
2015 //			BPoint(rect.left, rect.bottom), bevelColor1);
2016 //		rect.left++;
2017 //	}
2018 //	if (rect.Width() > 0 && borders & B_TOP_BORDER) {
2019 //		view->AddLine(BPoint(rect.left, rect.top),
2020 //			BPoint(rect.right, rect.top), bevelColor1);
2021 //		rect.top++;
2022 //	}
2023 //
2024 //	// softer shadow along left/top borders
2025 //	if (rect.Height() > 0 && borders & B_LEFT_BORDER) {
2026 //		view->AddLine(BPoint(rect.left, rect.top),
2027 //			BPoint(rect.left, rect.bottom), bevelColor2);
2028 //		rect.left++;
2029 //	}
2030 //	if (rect.Width() > 0 && borders & B_TOP_BORDER) {
2031 //		view->AddLine(BPoint(rect.left, rect.top),
2032 //			BPoint(rect.right, rect.top), bevelColor2);
2033 //		rect.top++;
2034 //	}
2035 //
2036 //	view->EndLineArray();
2037 //}
2038 
2039 
2040 void
2041 BControlLook::_FillGradient(BView* view, const BRect& rect,
2042 	const rgb_color& base, float topTint, float bottomTint,
2043 	enum orientation orientation)
2044 {
2045 	BGradientLinear gradient;
2046 	_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
2047 	view->FillRect(rect, gradient);
2048 }
2049 
2050 
2051 void
2052 BControlLook::_FillGlossyGradient(BView* view, const BRect& rect,
2053 	const rgb_color& base, float topTint, float middle1Tint,
2054 	float middle2Tint, float bottomTint, enum orientation orientation)
2055 {
2056 	BGradientLinear gradient;
2057 	_MakeGlossyGradient(gradient, rect, base, topTint, middle1Tint,
2058 		middle2Tint, bottomTint, orientation);
2059 	view->FillRect(rect, gradient);
2060 }
2061 
2062 
2063 void
2064 BControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
2065 	const rgb_color& base, float topTint, float bottomTint,
2066 	enum orientation orientation) const
2067 {
2068 	gradient.AddColor(tint_color(base, topTint), 0);
2069 	gradient.AddColor(tint_color(base, bottomTint), 255);
2070 	gradient.SetStart(rect.LeftTop());
2071 	if (orientation == B_HORIZONTAL)
2072 		gradient.SetEnd(rect.LeftBottom());
2073 	else
2074 		gradient.SetEnd(rect.RightTop());
2075 }
2076 
2077 
2078 void
2079 BControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
2080 	const rgb_color& base, float topTint, float middle1Tint,
2081 	float middle2Tint, float bottomTint,
2082 	enum orientation orientation) const
2083 {
2084 	gradient.AddColor(tint_color(base, topTint), 0);
2085 	gradient.AddColor(tint_color(base, middle1Tint), 132);
2086 	gradient.AddColor(tint_color(base, middle2Tint), 136);
2087 	gradient.AddColor(tint_color(base, bottomTint), 255);
2088 	gradient.SetStart(rect.LeftTop());
2089 	if (orientation == B_HORIZONTAL)
2090 		gradient.SetEnd(rect.LeftBottom());
2091 	else
2092 		gradient.SetEnd(rect.RightTop());
2093 }
2094 
2095 
2096 bool
2097 BControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
2098 	rgb_color& color, uint32 flags) const
2099 {
2100 	if ((flags & (B_ACTIVATED | B_CLICKED)) == 0) {
2101 		// no mark to be drawn at all
2102 		return false;
2103 	}
2104 
2105 	// TODO: Get from UI settings
2106 	color.red = 27;
2107 	color.green = 82;
2108 	color.blue = 140;
2109 
2110 	float mix = 1.0;
2111 
2112 	if (flags & B_DISABLED) {
2113 		// activated, but disabled
2114 		mix = 0.4;
2115 	} else if (flags & B_CLICKED) {
2116 		if (flags & B_ACTIVATED) {
2117 			// loosing activation
2118 			mix = 0.7;
2119 		} else {
2120 			// becoming activated
2121 			mix = 0.3;
2122 		}
2123 	} else {
2124 		// simply activated
2125 	}
2126 
2127 	color.red = uint8(color.red * mix + base.red * (1.0 - mix));
2128 	color.green = uint8(color.green * mix + base.green * (1.0 - mix));
2129 	color.blue = uint8(color.blue * mix + base.blue * (1.0 - mix));
2130 
2131 	return true;
2132 }
2133 
2134 
2135 void
2136 BControlLook::_DrawRoundBarCorner(BView* view, BRect& rect,
2137 	const BRect& updateRect,
2138 	const rgb_color& edgeLightColor, const rgb_color& edgeShadowColor,
2139 	const rgb_color& frameLightColor, const rgb_color& frameShadowColor,
2140 	const rgb_color& fillLightColor, const rgb_color& fillShadowColor,
2141 	float leftInset, float topInset, float rightInset, float bottomInset,
2142 	enum orientation orientation)
2143 {
2144 	if (!rect.IsValid() || !rect.Intersects(updateRect))
2145 		return;
2146 
2147 	BGradientLinear gradient;
2148 	gradient.AddColor(edgeShadowColor, 0);
2149 	gradient.AddColor(edgeLightColor, 255);
2150 	gradient.SetStart(rect.LeftTop());
2151 	if (orientation == B_HORIZONTAL)
2152 		gradient.SetEnd(rect.LeftBottom());
2153 	else
2154 		gradient.SetEnd(rect.RightTop());
2155 
2156 	view->FillEllipse(rect, gradient);
2157 
2158 	rect.left += leftInset;
2159 	rect.top += topInset;
2160 	rect.right += rightInset;
2161 	rect.bottom += bottomInset;
2162 
2163 	gradient.MakeEmpty();
2164 	gradient.AddColor(frameShadowColor, 0);
2165 	gradient.AddColor(frameLightColor, 255);
2166 	gradient.SetStart(rect.LeftTop());
2167 	if (orientation == B_HORIZONTAL)
2168 		gradient.SetEnd(rect.LeftBottom());
2169 	else
2170 		gradient.SetEnd(rect.RightTop());
2171 
2172 	view->FillEllipse(rect, gradient);
2173 
2174 	rect.left += leftInset;
2175 	rect.top += topInset;
2176 	rect.right += rightInset;
2177 	rect.bottom += bottomInset;
2178 
2179 	gradient.MakeEmpty();
2180 	gradient.AddColor(fillShadowColor, 0);
2181 	gradient.AddColor(fillLightColor, 255);
2182 	gradient.SetStart(rect.LeftTop());
2183 	if (orientation == B_HORIZONTAL)
2184 		gradient.SetEnd(rect.LeftBottom());
2185 	else
2186 		gradient.SetEnd(rect.RightTop());
2187 
2188 	view->FillEllipse(rect, gradient);
2189 }
2190 
2191 
2192 void
2193 BControlLook::_DrawRoundCornerLeftTop(BView* view, BRect& rect,
2194 	const BRect& updateRect, const rgb_color& base, const rgb_color& edgeColor,
2195 	const rgb_color& frameColor, const rgb_color& bevelColor,
2196 	const BGradientLinear& fillGradient)
2197 {
2198 	if (!rect.IsValid() || !rect.Intersects(updateRect))
2199 		return;
2200 
2201 	BRegion clipping(rect);
2202 	view->ConstrainClippingRegion(&clipping);
2203 
2204 	// background
2205 	view->SetHighColor(base);
2206 	view->FillRect(rect);
2207 
2208 	// outer edge
2209 	BRect ellipseRect(rect);
2210 	ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
2211 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2212 
2213 	view->SetHighColor(edgeColor);
2214 	view->FillEllipse(ellipseRect);
2215 
2216 	// frame
2217 	ellipseRect.InsetBy(1, 1);
2218 	view->SetHighColor(frameColor);
2219 	view->FillEllipse(ellipseRect);
2220 
2221 	// bevel
2222 	ellipseRect.InsetBy(1, 1);
2223 	view->SetHighColor(bevelColor);
2224 	view->FillEllipse(ellipseRect);
2225 
2226 	// fill
2227 	ellipseRect.InsetBy(1, 1);
2228 	view->FillEllipse(ellipseRect, fillGradient);
2229 
2230 	view->ConstrainClippingRegion(NULL);
2231 }
2232 
2233 void
2234 BControlLook::_DrawRoundCornerRightTop(BView* view, BRect& rect,
2235 	const BRect& updateRect, const rgb_color& base,
2236 	const rgb_color& edgeTopColor, const rgb_color& edgeRightColor,
2237 	const rgb_color& frameTopColor, const rgb_color& frameRightColor,
2238 	const rgb_color& bevelTopColor, const rgb_color& bevelRightColor,
2239 	const BGradientLinear& fillGradient)
2240 {
2241 	if (!rect.IsValid() || !rect.Intersects(updateRect))
2242 		return;
2243 
2244 	BRegion clipping(rect);
2245 	view->ConstrainClippingRegion(&clipping);
2246 
2247 	// background
2248 	view->SetHighColor(base);
2249 	view->FillRect(rect);
2250 
2251 	// outer edge
2252 	BRect ellipseRect(rect);
2253 	ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
2254 	ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
2255 
2256 	BGradientLinear gradient;
2257 	gradient.AddColor(edgeTopColor, 0);
2258 	gradient.AddColor(edgeRightColor, 255);
2259 	gradient.SetStart(rect.LeftTop());
2260 	gradient.SetEnd(rect.RightBottom());
2261 	view->FillEllipse(ellipseRect, gradient);
2262 
2263 	// frame
2264 	ellipseRect.InsetBy(1, 1);
2265 	rect.right--;
2266 	rect.top++;
2267 	if (frameTopColor == frameRightColor) {
2268 		view->SetHighColor(frameTopColor);
2269 		view->FillEllipse(ellipseRect);
2270 	} else {
2271 		gradient.SetColor(0, frameTopColor);
2272 		gradient.SetColor(1, frameRightColor);
2273 		gradient.SetStart(rect.LeftTop());
2274 		gradient.SetEnd(rect.RightBottom());
2275 		view->FillEllipse(ellipseRect, gradient);
2276 	}
2277 
2278 	// bevel
2279 	ellipseRect.InsetBy(1, 1);
2280 	rect.right--;
2281 	rect.top++;
2282 	gradient.SetColor(0, bevelTopColor);
2283 	gradient.SetColor(1, bevelRightColor);
2284 	gradient.SetStart(rect.LeftTop());
2285 	gradient.SetEnd(rect.RightBottom());
2286 	view->FillEllipse(ellipseRect, gradient);
2287 
2288 	// fill
2289 	ellipseRect.InsetBy(1, 1);
2290 	view->FillEllipse(ellipseRect, fillGradient);
2291 
2292 	view->ConstrainClippingRegion(NULL);
2293 }
2294 
2295 
2296 // NOTE: May come from a add-on in the future. Initialized in
2297 // InterfaceDefs.cpp
2298 BControlLook* be_control_look = NULL;
2299 
2300 } // namespace BPrivate
2301