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