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