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