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