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