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