1/*
2 * Copyright 2003-2023 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 *		DarkWyrm, bpmagic@columbus.rr.com
8 *		Marc Flerackers, mflerackers@androme.be
9 *		Fran��ois Revol, revol@free.fr
10 *		John Scipione, jscipione@gmail.com
11 *		Clemens Zeidler, haiku@clemens-zeidler.de
12 */
13
14
15/*! BControlLook resembling BeOS R5 */
16
17
18#include "BeControlLook.h"
19
20#include <algorithm>
21
22#include <Alignment.h>
23#include <Bitmap.h>
24#include <Button.h>
25#include <Control.h>
26#include <LayoutUtils.h>
27#include <Region.h>
28#include <Shape.h>
29#include <String.h>
30#include <TabView.h>
31#include <View.h>
32#include <Window.h>
33#include <WindowPrivate.h>
34
35//#define DEBUG_CONTROL_LOOK
36#ifdef DEBUG_CONTROL_LOOK
37#  define STRACE(x) printf x
38#else
39#  define STRACE(x) ;
40#endif
41
42
43namespace BPrivate {
44
45static const float kButtonPopUpIndicatorWidth = 11;
46
47
48BeControlLook::BeControlLook(image_id id)
49	:
50	fCachedOutline(false)
51{
52}
53
54
55BeControlLook::~BeControlLook()
56{
57}
58
59
60BAlignment
61BeControlLook::DefaultLabelAlignment() const
62{
63	return BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER);
64}
65
66
67float
68BeControlLook::DefaultLabelSpacing() const
69{
70	return ceilf(be_plain_font->Size() / 2.0);
71}
72
73
74float
75BeControlLook::DefaultItemSpacing() const
76{
77	return ceilf(be_plain_font->Size() * 0.85);
78}
79
80
81uint32
82BeControlLook::Flags(BControl* control) const
83{
84	uint32 flags = B_IS_CONTROL;
85
86	if (!control->IsEnabled())
87		flags |= B_DISABLED;
88
89	if (control->IsFocus() && control->Window() != NULL
90		&& control->Window()->IsActive()) {
91		flags |= B_FOCUSED;
92	}
93
94	switch (control->Value()) {
95		case B_CONTROL_ON:
96			flags |= B_ACTIVATED;
97			break;
98		case B_CONTROL_PARTIALLY_ON:
99			flags |= B_PARTIALLY_ACTIVATED;
100			break;
101	}
102
103	if (control->Parent() != NULL
104		&& (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) {
105		// In this constellation, assume we want to render the control
106		// against the already existing view contents of the parent view.
107		flags |= B_BLEND_FRAME;
108	}
109
110	return flags;
111}
112
113
114void
115BeControlLook::DrawButtonFrame(BView* view, BRect& rect,
116	const BRect& updateRect, const rgb_color& base,
117	const rgb_color& background, uint32 flags, uint32 borders)
118{
119	_DrawButtonFrame(view, rect, updateRect, 0, 0, 0, 0, base,
120		background, 1.0, 1.0, flags, borders);
121}
122
123
124void
125BeControlLook::DrawButtonFrame(BView* view, BRect& rect,
126	const BRect& updateRect, float, const rgb_color& base,
127	const rgb_color& background, uint32 flags, uint32 borders)
128{
129	_DrawButtonFrame(view, rect, updateRect, 0, 0, 0, 0, base,
130		background, 1.0, 1.0, flags, borders);
131}
132
133
134void
135BeControlLook::DrawButtonFrame(BView* view, BRect& rect,
136	const BRect& updateRect, float, float, float, float, const rgb_color& base,
137	const rgb_color& background, uint32 flags, uint32 borders)
138{
139	_DrawButtonFrame(view, rect, updateRect, 0, 0, 0, 0, base,
140		background, 1.0, 1.0, flags, borders);
141}
142
143
144void
145BeControlLook::DrawButtonBackground(BView* view, BRect& rect,
146	const BRect& updateRect, const rgb_color& base, uint32 flags,
147	uint32 borders, orientation orientation)
148{
149	_DrawButtonBackground(view, rect, updateRect, 0, 0, 0, 0,
150		base, false, flags, borders, orientation);
151}
152
153
154void
155BeControlLook::DrawButtonBackground(BView* view, BRect& rect,
156	const BRect& updateRect, float, const rgb_color& base, uint32 flags,
157	uint32 borders, orientation orientation)
158{
159	_DrawButtonBackground(view, rect, updateRect, 0, 0, 0, 0,
160		base, false, flags, borders, orientation);
161}
162
163
164void
165BeControlLook::DrawButtonBackground(BView* view, BRect& rect,
166	const BRect& updateRect, float, float, float, float, const rgb_color& base,
167	uint32 flags, uint32 borders, orientation orientation)
168{
169	_DrawButtonBackground(view, rect, updateRect, 0, 0, 0, 0,
170		base, false, flags, borders, orientation);
171}
172
173
174void
175BeControlLook::DrawCheckBox(BView* view, BRect& rect, const BRect& updateRect,
176	const rgb_color& base, uint32 flags)
177{
178	if (!rect.Intersects(updateRect))
179		return;
180
181	bool isEnabled = (flags & B_DISABLED) == 0;
182	bool isActivated = (flags & B_ACTIVATED) != 0;
183	bool isFocused = (flags & B_FOCUSED) != 0;
184	bool isClicked = (flags & B_CLICKED) != 0;
185
186	rgb_color lighten1 = tint_color(base, B_LIGHTEN_1_TINT);
187	rgb_color lightenMax = tint_color(base, B_LIGHTEN_MAX_TINT);
188	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
189	rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT);
190	rgb_color darken3 = tint_color(base, B_DARKEN_3_TINT);
191	rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT);
192
193	view->SetLowColor(base);
194
195	if (isEnabled) {
196		// Filling
197		view->SetHighColor(lightenMax);
198		view->FillRect(rect);
199
200		// Box
201		if (isClicked) {
202			view->SetHighColor(darken3);
203			view->StrokeRect(rect);
204
205			rect.InsetBy(1, 1);
206
207			view->BeginLineArray(6);
208
209			view->AddLine(BPoint(rect.left, rect.bottom),
210				BPoint(rect.left, rect.top), darken2);
211			view->AddLine(BPoint(rect.left, rect.top),
212				BPoint(rect.right, rect.top), darken2);
213			view->AddLine(BPoint(rect.left, rect.bottom),
214				BPoint(rect.right, rect.bottom), darken4);
215			view->AddLine(BPoint(rect.right, rect.bottom),
216				BPoint(rect.right, rect.top), darken4);
217
218			view->EndLineArray();
219		} else {
220			view->BeginLineArray(6);
221
222			view->AddLine(BPoint(rect.left, rect.bottom),
223				BPoint(rect.left, rect.top), darken1);
224			view->AddLine(BPoint(rect.left, rect.top),
225				BPoint(rect.right, rect.top), darken1);
226
227			rect.InsetBy(1, 1);
228			view->AddLine(BPoint(rect.left, rect.bottom),
229				BPoint(rect.left, rect.top), darken4);
230			view->AddLine(BPoint(rect.left, rect.top),
231				BPoint(rect.right, rect.top), darken4);
232			view->AddLine(BPoint(rect.left + 1, rect.bottom),
233				BPoint(rect.right, rect.bottom), base);
234			view->AddLine(BPoint(rect.right, rect.bottom),
235				BPoint(rect.right, rect.top + 1), base);
236
237			view->EndLineArray();
238		}
239
240		// Focus
241		if (isFocused) {
242			view->SetDrawingMode(B_OP_OVER);
243			view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
244			view->StrokeRect(rect);
245			view->SetDrawingMode(B_OP_COPY);
246		}
247	} else {
248		// Filling
249		view->SetHighColor(lighten1);
250		view->FillRect(rect);
251
252		// Box
253		view->BeginLineArray(6);
254
255		view->AddLine(BPoint(rect.left, rect.bottom),
256				BPoint(rect.left, rect.top), base);
257		view->AddLine(BPoint(rect.left, rect.top),
258				BPoint(rect.right, rect.top), base);
259
260		rect.InsetBy(1, 1);
261		view->AddLine(BPoint(rect.left, rect.bottom),
262				BPoint(rect.left, rect.top), darken2);
263		view->AddLine(BPoint(rect.left, rect.top),
264				BPoint(rect.right, rect.top), darken2);
265		view->AddLine(BPoint(rect.left + 1, rect.bottom),
266				BPoint(rect.right, rect.bottom), darken1);
267		view->AddLine(BPoint(rect.right, rect.bottom),
268				BPoint(rect.right, rect.top + 1), darken1);
269
270		view->EndLineArray();
271	}
272
273	// Checkmark
274	if (isActivated) {
275		rect.InsetBy(4, 4);
276
277		float penSize = std::max(1, 2);
278		if (penSize > 1 && fmodf(penSize, 2) == 0) {
279			// Tweak ends to "include" the pixel at the index,
280			// we need to do this in order to produce results like R5,
281			// where coordinates were inclusive
282			rect.right++;
283			rect.bottom++;
284		}
285
286		view->SetPenSize(penSize);
287		view->SetDrawingMode(B_OP_OVER);
288		if (isEnabled)
289			view->SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
290		else {
291			view->SetHighColor(tint_color(ui_color(B_CONTROL_MARK_COLOR),
292				B_DISABLED_MARK_TINT));
293		}
294		view->StrokeLine(rect.LeftTop(), rect.RightBottom());
295		view->StrokeLine(rect.LeftBottom(), rect.RightTop());
296	}
297}
298
299
300void
301BeControlLook::DrawRadioButton(BView* view, BRect& rect,
302	const BRect& updateRect, const rgb_color& base, uint32 flags)
303{
304	if (!ShouldDraw(view, rect, updateRect))
305		return;
306
307	bool isEnabled = (flags & B_DISABLED) == 0;
308	bool isActivated = (flags & B_ACTIVATED) != 0;
309	bool isFocused = (flags & B_FOCUSED) != 0;
310
311	// colors
312	rgb_color bg = ui_color(B_PANEL_BACKGROUND_COLOR);
313	rgb_color lightenmax;
314	rgb_color lighten1;
315	rgb_color darken1;
316	rgb_color darken2;
317	rgb_color darken3;
318
319	rgb_color markColor = ui_color(B_CONTROL_MARK_COLOR);
320	rgb_color knob;
321	rgb_color knobDark;
322	rgb_color knobLight;
323
324	if (isEnabled) {
325		lightenmax	= tint_color(bg, B_LIGHTEN_MAX_TINT);
326		lighten1	= tint_color(bg, B_LIGHTEN_1_TINT);
327		darken1		= tint_color(bg, B_DARKEN_1_TINT);
328		darken2		= tint_color(bg, B_DARKEN_2_TINT);
329		darken3		= tint_color(bg, B_DARKEN_3_TINT);
330
331		knob		= markColor;
332		knobDark	= tint_color(markColor, B_DARKEN_3_TINT);
333		knobLight	= tint_color(markColor, 0.15);
334	} else {
335		lightenmax	= tint_color(bg, B_LIGHTEN_2_TINT);
336		lighten1	= bg;
337		darken1		= bg;
338		darken2		= tint_color(bg, B_DARKEN_1_TINT);
339		darken3		= tint_color(bg, B_DARKEN_2_TINT);
340
341		knob		= tint_color(markColor, B_LIGHTEN_2_TINT);
342		knobDark	= tint_color(markColor, B_LIGHTEN_1_TINT);
343		knobLight	= tint_color(markColor,
344			(B_LIGHTEN_2_TINT + B_LIGHTEN_MAX_TINT) / 2.0);
345	}
346
347	rect.InsetBy(2, 2);
348
349	view->SetLowColor(bg);
350
351	// dot
352	if (isActivated) {
353		// full
354		view->SetHighColor(knobDark);
355		view->FillEllipse(rect);
356
357		view->SetHighColor(knob);
358		view->FillEllipse(BRect(rect.left + 2, rect.top + 2, rect.right - 3,
359			rect.bottom - 3));
360
361		view->SetHighColor(knobLight);
362		view->FillEllipse(BRect(rect.left + 3, rect.top + 3, rect.right - 5,
363			rect.bottom - 5));
364	} else {
365		// empty
366		view->SetHighColor(lightenmax);
367		view->FillEllipse(rect);
368	}
369
370	rect.InsetBy(-1, -1);
371
372	// outer circle
373	if (isFocused) {
374		// indicating "about to change value"
375		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
376		view->SetPenSize(2);
377		view->SetDrawingMode(B_OP_OVER);
378		view->StrokeEllipse(rect.InsetByCopy(1, 1));
379		view->SetDrawingMode(B_OP_COPY);
380		view->SetPenSize(1);
381	} else {
382		view->SetHighColor(darken1);
383		view->StrokeArc(rect, 45.0, 180.0);
384		view->SetHighColor(lightenmax);
385		view->StrokeArc(rect, 45.0, -180.0);
386	}
387
388	// inner circle
389	view->SetHighColor(darken3);
390	view->StrokeArc(rect, 45.0, 180.0);
391	view->SetHighColor(bg);
392	view->StrokeArc(rect, 45.0, -180.0);
393
394	// for faster font rendering, we restore B_OP_COPY
395	view->SetDrawingMode(B_OP_COPY);
396}
397
398
399void
400BeControlLook::DrawScrollBarBorder(BView* view, BRect rect,
401	const BRect& updateRect, const rgb_color& base, uint32 flags,
402	orientation orientation)
403{
404	if (!ShouldDraw(view, rect, updateRect))
405		return;
406
407	view->PushState();
408
409	view->ClipToRect(rect);
410
411	bool isEnabled = (flags & B_DISABLED) == 0;
412	bool isFocused = (flags & B_FOCUSED) != 0;
413
414	if (isEnabled && isFocused)
415		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
416	else
417		view->SetHighColor(tint_color(base, B_DARKEN_2_TINT));
418
419	view->StrokeRect(rect);
420
421	view->PopState();
422}
423
424
425void
426BeControlLook::DrawScrollBarButton(BView* view, BRect rect,
427	const BRect& updateRect, const rgb_color& base, uint32 flags,
428	int32 direction, orientation orientation, bool down)
429{
430	view->PushState();
431
432	bool isEnabled = (flags & B_DISABLED) == 0;
433
434	// border = 152, shine = 144/255, shadow = 208/184/192
435	rgb_color shine = down ? tint_color(base, 1.333)
436		: tint_color(base, B_LIGHTEN_MAX_TINT);
437	rgb_color shadow;
438	if (isEnabled && down)
439		shadow = tint_color(base, 1.037);
440	else if (isEnabled)
441		shadow = tint_color(base, B_DARKEN_1_TINT);
442	else
443		shadow = tint_color(base, 1.111);
444
445	view->BeginLineArray(4);
446	view->AddLine(rect.LeftTop(), rect.LeftBottom() - BPoint(0, 1), shine);
447	view->AddLine(rect.LeftTop(), rect.RightTop() - BPoint(1, 0), shine);
448	view->AddLine(rect.RightTop(), rect.RightBottom() - BPoint(0, 1), shadow);
449	view->AddLine(rect.LeftBottom(), rect.RightBottom(), shadow);
450	view->EndLineArray();
451
452	rgb_color bg;
453	if (isEnabled) {
454		// bg = 176/216
455		bg = down ? tint_color(base, 1.185) : base;
456	} else {
457		// bg = 240
458		rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
459		lighten2.red++; lighten2.green++; lighten2.blue++;
460			// lighten2 = 239, 240 = 239 + 1
461		bg = lighten2;
462	}
463	view->SetHighColor(bg);
464	rect.InsetBy(1, 1);
465	view->FillRect(rect);
466
467	// draw button triangle
468	// don't use DrawArrowShape because we use that to draw arrows differently
469	// in menus and outline list view
470
471	rect.InsetBy(1, 1);
472	rect.OffsetBy(-3, -3);
473
474	BPoint tri1, tri2, tri3;
475	BPoint off1, off2, off3;
476	BRect r(rect.left, rect.top, rect.left + 14, rect.top + 14);
477	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
478	rgb_color light, dark, arrow, arrow2;
479
480	switch(direction) {
481		case B_LEFT_ARROW:
482			tri1.Set(r.left + 3, floorf((r.top + r.bottom) / 2));
483			tri2.Set(r.right - 4, r.top + 4);
484			tri3.Set(r.right - 4, r.bottom - 4);
485			break;
486
487		default:
488		case B_RIGHT_ARROW:
489			tri1.Set(r.left + 4, r.bottom - 4);
490			tri2.Set(r.left + 4, r.top + 4);
491			tri3.Set(r.right - 3, floorf((r.top + r.bottom) / 2));
492			break;
493
494		case B_UP_ARROW:
495			tri1.Set(r.left + 4, r.bottom - 4);
496			tri2.Set(floorf((r.left + r.right) / 2), r.top + 3);
497			tri3.Set(r.right - 4, r.bottom - 4);
498			break;
499
500		case B_DOWN_ARROW:
501			tri1.Set(r.left + 4, r.top + 4);
502			tri2.Set(r.right - 4, r.top + 4);
503			tri3.Set(floorf((r.left + r.right) / 2), r.bottom - 3);
504			break;
505	}
506
507	r.InsetBy(1, 1);
508
509	float tint = B_NO_TINT;
510	if (!isEnabled)
511		tint = (tint + B_NO_TINT + B_NO_TINT) / 3;
512
513	view->SetHighColor(tint_color(base, tint));
514	view->MovePenTo(B_ORIGIN);
515	view->SetDrawingMode(B_OP_OVER);
516
517	view->SetHighColor(tint_color(base, tint));
518
519	if (isEnabled) {
520		arrow2 = light = tint_color(base, B_DARKEN_2_TINT);
521		dark = tint_color(base, B_DARKEN_3_TINT);
522		arrow = tint_color(base, B_DARKEN_MAX_TINT);
523	} else
524		arrow = arrow2 = light = dark = tint_color(base, B_DARKEN_1_TINT);
525
526	// white triangle offset by 1px
527	off1.Set(tri1.x + 1, tri1.y + 1);
528	off2.Set(tri2.x + 1, tri2.y + 1);
529	off3.Set(tri3.x + 1, tri3.y + 1);
530
531	// draw white triangle
532	view->BeginLineArray(3);
533	view->AddLine(off2, off3, lightenmax);
534	view->AddLine(off1, off3, lightenmax);
535	view->AddLine(off1, off2, lightenmax);
536	view->EndLineArray();
537
538	// draw triangle on top
539	view->BeginLineArray(3);
540	view->AddLine(tri2, tri3, dark);
541	view->AddLine(tri1, tri3, dark);
542	view->AddLine(tri1, tri2, arrow2);
543	view->EndLineArray();
544
545	view->PopState();
546}
547
548
549void
550BeControlLook::DrawScrollBarBackground(BView* view, BRect& rect1, BRect& rect2,
551	const BRect& updateRect, const rgb_color& base, uint32 flags,
552	orientation orientation)
553{
554	_DrawScrollBarBackgroundFirst(view, rect1, updateRect, base, flags,
555		orientation);
556	_DrawScrollBarBackgroundSecond(view, rect2, updateRect, base, flags,
557		orientation);
558}
559
560
561void
562BeControlLook::DrawScrollBarBackground(BView* view, BRect& rect,
563	const BRect& updateRect, const rgb_color& base, uint32 flags,
564	orientation orientation)
565{
566	_DrawScrollBarBackgroundFirst(view, rect, updateRect, base, flags,
567		orientation);
568}
569
570
571void
572BeControlLook::DrawScrollBarThumb(BView* view, BRect& rect,
573	const BRect& updateRect, const rgb_color& base, uint32 flags,
574	orientation orientation, uint32 knobStyle)
575{
576	if (!ShouldDraw(view, rect, updateRect))
577		return;
578
579	view->PushState();
580
581	view->ClipToRect(rect);
582
583	bool isEnabled = (flags & B_DISABLED) == 0;
584
585	BRect orig(rect);
586
587	// shine = 255
588	rgb_color shine = tint_color(base, B_LIGHTEN_MAX_TINT);
589	rgb_color bg;
590	if (isEnabled) {
591		// bg = 216
592		bg = base;
593	} else {
594		// bg = 240
595		rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
596		lighten2.red++; lighten2.green++; lighten2.blue++;
597			// lighten2 = 239, 240 = 239 + 1
598		bg = lighten2;
599	}
600
601	// draw thumb over background
602	view->SetDrawingMode(B_OP_OVER);
603
604	view->BeginLineArray(2);
605	if (orientation == B_VERTICAL) {
606		// shine
607		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shine);
608		rect.left++;
609		view->AddLine(rect.LeftTop(), rect.RightTop(), shine);
610		rect.top++;
611	} else {
612		// shine
613		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shine);
614		rect.left++;
615		view->AddLine(rect.LeftTop(), rect.RightTop(), shine);
616		rect.top++;
617	}
618	view->EndLineArray();
619
620	// fill bg
621	view->SetHighColor(bg);
622	view->FillRect(rect);
623
624	// undraw right top or left bottom point
625	view->BeginLineArray(1);
626	if (orientation == B_VERTICAL) {
627		rect.right--;
628		view->AddLine(rect.RightTop(), rect.RightTop(), base);
629	} else {
630		rect.bottom--;
631		view->AddLine(rect.LeftBottom(), rect.LeftBottom(), base);
632	}
633	view->EndLineArray();
634
635	// restore rect
636	rect = orig;
637
638	// knobs
639
640	if (knobStyle != B_KNOB_NONE) {
641		float hcenter = rect.left + rect.Width() / 2;
642		float vmiddle = rect.top + rect.Height() / 2;
643		rgb_color knobDark = tint_color(base, B_DARKEN_1_TINT);
644		rgb_color knobLight = tint_color(base, B_LIGHTEN_MAX_TINT);
645
646		if (knobStyle == B_KNOB_DOTS) {
647			// center/middle dot
648			_DrawScrollBarKnobDot(view, hcenter, vmiddle, knobDark, knobLight,
649				orientation);
650			if (orientation == B_HORIZONTAL) {
651				float spacer = rect.Height();
652				// left dot
653				if (rect.left + 7 < hcenter - spacer) {
654					_DrawScrollBarKnobDot(view, hcenter - 7, vmiddle, knobDark,
655						knobLight, orientation);
656				}
657				// right dot
658				if (rect.right - 7 > hcenter + spacer) {
659					_DrawScrollBarKnobDot(view, hcenter + 7, vmiddle, knobDark,
660						knobLight, orientation);
661				}
662			} else {
663				float spacer = rect.Width();
664				// top dot
665				if (rect.top + 7 < vmiddle - spacer) {
666					_DrawScrollBarKnobDot(view, hcenter, vmiddle - 7, knobDark,
667						knobLight, orientation);
668				}
669				// bottom dot
670				if (rect.bottom - 7 > vmiddle + spacer) {
671					_DrawScrollBarKnobDot(view, hcenter, vmiddle + 7, knobDark,
672						knobLight, orientation);
673				}
674			}
675		} else if (knobStyle == B_KNOB_LINES) {
676			// center/middle line
677			_DrawScrollBarKnobLine(view, hcenter, vmiddle, knobDark, knobLight,
678				orientation);
679			if (orientation == B_HORIZONTAL) {
680				float spacer = rect.Height();
681				// left line
682				if (rect.left + 4 < hcenter - spacer) {
683					_DrawScrollBarKnobLine(view, hcenter - 4, vmiddle, knobDark,
684						knobLight, orientation);
685				}
686				// right line
687				if (rect.right - 4 > hcenter + spacer) {
688					_DrawScrollBarKnobLine(view, hcenter + 4, vmiddle, knobDark,
689						knobLight, orientation);
690				}
691			} else {
692				float spacer = rect.Width();
693				// top line
694				if (rect.top + 4 < vmiddle - spacer) {
695					_DrawScrollBarKnobLine(view, hcenter, vmiddle - 4, knobDark,
696						knobLight, orientation);
697				}
698				// bottom line
699				if (rect.bottom - 5 > vmiddle + spacer) {
700					_DrawScrollBarKnobLine(view, hcenter, vmiddle + 4, knobDark,
701						knobLight, orientation);
702				}
703			}
704		}
705	}
706
707	view->PopState();
708}
709
710
711
712void
713BeControlLook::DrawScrollViewFrame(BView* view, BRect& rect,
714	const BRect& updateRect, BRect verticalScrollBarFrame,
715	BRect horizontalScrollBarFrame, const rgb_color& base,
716	border_style borderStyle, uint32 flags, uint32 _borders)
717{
718	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
719	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
720
721	view->BeginLineArray(4);
722	view->AddLine(rect.LeftBottom(), rect.LeftTop(), darken1);
723	view->AddLine(rect.LeftTop(), rect.RightTop(), darken1);
724	view->AddLine(rect.RightTop(), rect.RightBottom(), lightenmax);
725	view->AddLine(rect.RightBottom(), rect.LeftBottom(), lightenmax);
726	view->EndLineArray();
727
728	rect.InsetBy(1, 1);
729
730	bool isEnabled = (flags & B_DISABLED) == 0;
731	bool isFocused = (flags & B_FOCUSED) != 0;
732
733	if (isEnabled && isFocused)
734		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
735	else
736		view->SetHighColor(tint_color(base, B_DARKEN_2_TINT));
737
738	view->StrokeRect(rect);
739}
740
741
742void
743BeControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect,
744	const rgb_color& base, uint32 direction, uint32 flags, float tint)
745{
746	if (!ShouldDraw(view, rect, updateRect))
747		return;
748
749	view->PushState();
750
751	rgb_color fill = tint_color(base, 1.074); // 200
752	rgb_color stroke = tint_color(base, 1.629); // 80
753
754	switch(direction) {
755		case B_LEFT_ARROW:
756			view->SetHighColor(fill);
757			view->FillTriangle(rect.LeftTop() + BPoint(4, 6),
758				rect.LeftTop() + BPoint(8, 2),
759				rect.LeftTop() + BPoint(8, 10));
760			view->SetHighColor(stroke);
761			view->StrokeTriangle(rect.LeftTop() + BPoint(4, 6),
762				rect.LeftTop() + BPoint(8, 2),
763				rect.LeftTop() + BPoint(8, 10));
764			break;
765
766		default:
767		case B_RIGHT_ARROW:
768			view->SetHighColor(fill);
769			view->FillTriangle(rect.LeftTop() + BPoint(4, 2),
770				rect.LeftTop() + BPoint(4, 10),
771				rect.LeftTop() + BPoint(8, 6));
772			view->SetHighColor(stroke);
773			view->StrokeTriangle(rect.LeftTop() + BPoint(4, 2),
774				rect.LeftTop() + BPoint(4, 10),
775				rect.LeftTop() + BPoint(8, 6));
776			break;
777
778		case B_UP_ARROW:
779			view->SetHighColor(fill);
780			view->FillTriangle(rect.LeftTop() + BPoint(6, 4),
781				rect.LeftTop() + BPoint(2, 8),
782				rect.LeftTop() + BPoint(10, 8));
783			view->SetHighColor(stroke);
784			view->StrokeTriangle(rect.LeftTop() + BPoint(6, 4),
785				rect.LeftTop() + BPoint(2, 8),
786				rect.LeftTop() + BPoint(10, 8));
787			break;
788
789		case B_DOWN_ARROW:
790			view->SetHighColor(fill);
791			view->FillTriangle(rect.LeftTop() + BPoint(2, 4),
792				rect.LeftTop() + BPoint(10, 4),
793				rect.LeftTop() + BPoint(6, 8));
794			view->SetHighColor(stroke);
795			view->StrokeTriangle(rect.LeftTop() + BPoint(2, 4),
796				rect.LeftTop() + BPoint(10, 4),
797				rect.LeftTop() + BPoint(6, 8));
798			break;
799	}
800
801	view->PopState();
802}
803
804
805void
806BeControlLook::DrawMenuBarBackground(BView* view, BRect& rect,
807	const BRect& updateRect, const rgb_color& base, uint32 flags,
808	uint32 borders)
809{
810	if (!ShouldDraw(view, rect, updateRect))
811		return;
812
813	view->PushState();
814
815	// restore the background color in case a menu item was selected
816	view->SetHighColor(base);
817	view->FillRect(rect);
818
819	rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
820	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
821
822	view->BeginLineArray(3);
823	view->AddLine(rect.LeftTop(), rect.RightTop(), lighten2);
824	// left bottom pixel is base color
825	view->AddLine(rect.LeftTop(), rect.LeftBottom() - BPoint(0, 1),
826		lighten2);
827	view->AddLine(rect.LeftBottom() + BPoint(1, 0), rect.RightBottom(),
828		darken1);
829	view->EndLineArray();
830
831	view->PopState();
832}
833
834
835void
836BeControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
837	const BRect& updateRect, const rgb_color& base,
838	const rgb_color& background, uint32 flags, uint32 borders)
839{
840	// BeControlLook does not support rounded corners and it never will
841	DrawMenuFieldFrame(view, rect, updateRect, 0, base, background, flags,
842		borders);
843}
844
845
846void
847BeControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
848	const BRect& updateRect, float, const rgb_color& base,
849	const rgb_color& background, uint32 flags, uint32 borders)
850{
851	// BeControlLook does not support rounded corners and it never will
852	DrawMenuFieldFrame(view, rect, updateRect, 0, 0, 0, 0, base,
853		background, flags, borders);
854}
855
856
857void
858BeControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
859	const BRect& updateRect, float, float, float, float, const rgb_color& base,
860	const rgb_color& background, uint32 flags, uint32 borders)
861{
862	if (!ShouldDraw(view, rect, updateRect))
863		return;
864
865	bool isEnabled = (flags & B_DISABLED) == 0;
866	bool isFocused = (flags & B_FOCUSED) != 0;
867
868	// inset the frame by 2 and draw the outer border
869	rect.InsetBy(2, 2);
870
871	rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT);
872
873	// draw left and top side and top right corner
874	view->BeginLineArray(3);
875	view->AddLine(BPoint(rect.left - 1, rect.top - 1),
876		BPoint(rect.left - 1, rect.bottom - 1), darken2);
877	view->AddLine(BPoint(rect.left - 1, rect.top - 1),
878		BPoint(rect.right - 1, rect.top - 1), darken2);
879	view->AddLine(BPoint(rect.right, rect.top - 1),
880		BPoint(rect.right, rect.top - 1), darken2);
881	view->EndLineArray();
882
883	if (isEnabled && isFocused) {
884		// draw the focus ring on top of the frame
885		// Note that this is an intentional deviation from BeOS R5
886		// which draws the frame around the outside of the frame
887		// but that doesn't look as good.
888		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
889		view->StrokeRect(rect.InsetByCopy(-1, -1));
890	}
891}
892
893
894void
895BeControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
896	const BRect& updateRect, const rgb_color& base, bool popupIndicator,
897	uint32 flags)
898{
899	_DrawMenuFieldBackgroundOutside(view, rect, updateRect,
900		0, 0, 0, 0, base, popupIndicator, flags);
901}
902
903
904void
905BeControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
906	const BRect& updateRect, const rgb_color& base, uint32 flags,
907	uint32 borders)
908{
909	_DrawMenuFieldBackgroundInside(view, rect, updateRect,
910		0, 0, 0, 0, base, flags, borders);
911}
912
913
914void
915BeControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
916	const BRect& updateRect, float, const rgb_color& base,
917	bool popupIndicator, uint32 flags)
918{
919	_DrawMenuFieldBackgroundOutside(view, rect, updateRect, 0, 0,
920		0, 0, base, popupIndicator, flags);
921}
922
923
924void
925BeControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
926	const BRect& updateRect, float, float, float, float, const rgb_color& base,
927	bool popupIndicator, uint32 flags)
928{
929	_DrawMenuFieldBackgroundOutside(view, rect, updateRect, 0, 0,
930		0, 0, base, popupIndicator, flags);
931}
932
933
934void
935BeControlLook::DrawMenuBackground(BView* view, BRect& rect,
936	const BRect& updateRect, const rgb_color& base, uint32 flags,
937	uint32 borders)
938{
939	if (!ShouldDraw(view, rect, updateRect))
940		return;
941
942	view->PushState();
943
944	view->SetHighColor(base);
945	view->FillRect(rect);
946
947	view->PopState();
948}
949
950
951void
952BeControlLook::DrawMenuItemBackground(BView* view, BRect& rect,
953	const BRect& updateRect, const rgb_color& base, uint32 flags,
954	uint32 borders)
955{
956	if (!ShouldDraw(view, rect, updateRect))
957		return;
958
959	view->PushState();
960
961	view->SetHighColor(base);
962	view->FillRect(rect);
963
964	view->PopState();
965}
966
967
968void
969BeControlLook::DrawStatusBar(BView* view, BRect& rect, const BRect& updateRect,
970	const rgb_color& base, const rgb_color& barColor, float progressPosition)
971{
972	if (!ShouldDraw(view, rect, updateRect))
973		return;
974
975	view->PushState();
976
977	// draw background
978	view->SetHighColor(base);
979	view->FillRect(rect);
980
981	// draw frame around bar
982	DrawTextControlBorder(view, rect, updateRect, tint_color(base, B_DARKEN_1_TINT));
983
984	// filled and nonfilled rects
985	BRect filledRect(rect);
986	filledRect.right = progressPosition - 1;
987	BRect nonfilledRect(rect);
988	nonfilledRect.left = progressPosition;
989
990	bool drawFilled = filledRect.Width() > 0;
991	bool drawNonfilled = nonfilledRect.Width() > 0;
992
993	// filled
994	if (drawFilled) {
995		rgb_color light = tint_color(barColor, 0.6);
996		rgb_color dark = tint_color(barColor, 1.4);
997		_DrawFrame(view, filledRect, light, light, dark, dark);
998
999		view->SetHighColor(barColor);
1000		view->FillRect(filledRect);
1001	}
1002
1003	// nonfilled
1004	if (drawNonfilled) {
1005		view->SetHighColor(ui_color(B_CONTROL_BACKGROUND_COLOR));
1006		view->FillRect(nonfilledRect);
1007	}
1008
1009	view->PopState();
1010}
1011
1012
1013rgb_color
1014BeControlLook::SliderBarColor(const rgb_color& base)
1015{
1016	return tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_1_TINT);
1017}
1018
1019
1020void
1021BeControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
1022	const rgb_color& base, rgb_color leftFillColor, rgb_color rightFillColor,
1023	float sliderScale, uint32 flags, orientation orientation)
1024{
1025	if (!ShouldDraw(view, rect, updateRect))
1026		return;
1027
1028	// separate the bar in two sides
1029	float sliderPosition;
1030	BRect leftBarSide = rect;
1031	BRect rightBarSide = rect;
1032
1033	if (orientation == B_HORIZONTAL) {
1034		sliderPosition = floorf(rect.left + 2 + (rect.Width() - 2)
1035			* sliderScale);
1036		leftBarSide.right = sliderPosition - 1;
1037		rightBarSide.left = sliderPosition;
1038	} else {
1039		// NOTE: position is reverse of coords
1040		sliderPosition = floorf(rect.top + 2 + (rect.Height() - 2)
1041			* (1.0 - sliderScale));
1042		leftBarSide.top = sliderPosition;
1043		rightBarSide.bottom = sliderPosition - 1;
1044	}
1045
1046	view->PushState();
1047	view->ClipToRect(leftBarSide);
1048
1049	DrawSliderBar(view, rect, updateRect, base, leftFillColor, flags,
1050		orientation);
1051	view->PopState();
1052
1053	view->PushState();
1054	view->ClipToRect(rightBarSide);
1055
1056	DrawSliderBar(view, rect, updateRect, base, rightFillColor, flags,
1057		orientation);
1058	view->PopState();
1059}
1060
1061
1062void
1063BeControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
1064	const rgb_color& base, rgb_color fillColor, uint32 flags,
1065	orientation orientation)
1066{
1067	if (!ShouldDraw(view, rect, updateRect))
1068		return;
1069
1070	view->SetHighColor(fillColor);
1071	view->FillRect(rect);
1072
1073	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
1074	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT);
1075	rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT);
1076	rgb_color darkenmax = tint_color(base, B_DARKEN_MAX_TINT);
1077
1078	view->BeginLineArray(9);
1079
1080	view->AddLine(BPoint(rect.left, rect.top),
1081		BPoint(rect.left + 1, rect.top), darken1);
1082	view->AddLine(BPoint(rect.left, rect.bottom),
1083		BPoint(rect.left + 1, rect.bottom), darken1);
1084	view->AddLine(BPoint(rect.right - 1, rect.top),
1085		BPoint(rect.right, rect.top), darken1);
1086
1087	view->AddLine(BPoint(rect.left + 1, rect.top),
1088		BPoint(rect.right - 1, rect.top), darken2);
1089	view->AddLine(BPoint(rect.left, rect.bottom - 1),
1090		BPoint(rect.left, rect.top + 1), darken2);
1091
1092	view->AddLine(BPoint(rect.left + 1, rect.bottom),
1093		BPoint(rect.right, rect.bottom), lightenmax);
1094	view->AddLine(BPoint(rect.right, rect.top + 1),
1095		BPoint(rect.right, rect.bottom), lightenmax);
1096
1097	rect.InsetBy(1, 1);
1098
1099	view->AddLine(BPoint(rect.left, rect.top),
1100		BPoint(rect.left, rect.bottom), darkenmax);
1101	view->AddLine(BPoint(rect.left, rect.top),
1102		BPoint(rect.right, rect.top), darkenmax);
1103
1104	view->EndLineArray();
1105}
1106
1107
1108void
1109BeControlLook::DrawSliderThumb(BView* view, BRect& rect, const BRect& updateRect,
1110	const rgb_color& base, uint32 flags, orientation orientation)
1111{
1112	if (!ShouldDraw(view, rect, updateRect))
1113		return;
1114
1115	rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
1116	rgb_color dark = tint_color(base, 1.333); // 144
1117	rgb_color darker = tint_color(base, 1.444); // 120
1118	rgb_color darkenmax = tint_color(base, B_DARKEN_MAX_TINT);
1119
1120	view->BeginLineArray(14);
1121
1122	// outline
1123	view->AddLine(BPoint(rect.left, rect.bottom - 2),
1124		BPoint(rect.left, rect.top + 1), darker);
1125	view->AddLine(BPoint(rect.left + 1, rect.top),
1126		BPoint(rect.right - 2, rect.top), darker);
1127	view->AddLine(BPoint(rect.right, rect.top + 2),
1128		BPoint(rect.right, rect.bottom - 1), darker);
1129	view->AddLine(BPoint(rect.left + 2, rect.bottom),
1130		BPoint(rect.right - 1, rect.bottom), darker);
1131
1132	// first bevel
1133	rect.InsetBy(1, 1);
1134
1135	view->SetHighColor(lighten2);
1136	view->FillRect(rect);
1137
1138	view->AddLine(BPoint(rect.left, rect.bottom),
1139		BPoint(rect.right - 1, rect.bottom), darkenmax);
1140	view->AddLine(BPoint(rect.right, rect.bottom - 1),
1141		BPoint(rect.right, rect.top), darkenmax);
1142
1143	rect.InsetBy(1, 1);
1144
1145	// second bevel and center dots
1146	view->SetHighColor(dark);
1147	view->AddLine(BPoint(rect.left, rect.bottom),
1148		BPoint(rect.right, rect.bottom), dark);
1149	view->AddLine(BPoint(rect.right, rect.top),
1150		BPoint(rect.right, rect.bottom), dark);
1151
1152	// center dots
1153	float hCenter = rect.Width() / 2;
1154	float vMiddle = rect.Height() / 2;
1155	if (orientation == B_HORIZONTAL) {
1156		view->AddLine(BPoint(rect.left + hCenter, rect.top + 1),
1157			BPoint(rect.left + hCenter, rect.top + 1), dark);
1158		view->AddLine(BPoint(rect.left + hCenter, rect.top + 3),
1159			BPoint(rect.left + hCenter, rect.top + 3), dark);
1160		view->AddLine(BPoint(rect.left + hCenter, rect.top + 5),
1161			BPoint(rect.left + hCenter, rect.top + 5), dark);
1162	} else {
1163		view->AddLine(BPoint(rect.left + 1, rect.top + vMiddle),
1164			BPoint(rect.left + 1, rect.top + vMiddle), dark);
1165		view->AddLine(BPoint(rect.left + 3, rect.top + vMiddle),
1166			BPoint(rect.left + 3, rect.top + vMiddle), dark);
1167		view->AddLine(BPoint(rect.left + 5, rect.top + vMiddle - 1),
1168			BPoint(rect.left + 5, rect.top + vMiddle), dark);
1169	}
1170
1171	view->AddLine(BPoint(rect.right + 1, rect.bottom + 1),
1172		BPoint(rect.right + 1, rect.bottom + 1), dark);
1173
1174	rect.InsetBy(1, 1);
1175
1176	// third bevel
1177	view->AddLine(BPoint(rect.left, rect.bottom),
1178		BPoint(rect.right, rect.bottom), base);
1179	view->AddLine(BPoint(rect.right, rect.top),
1180		BPoint(rect.right, rect.bottom), base);
1181
1182	view->EndLineArray();
1183}
1184
1185
1186void
1187BeControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1188	const BRect& updateRect, const rgb_color& base, uint32 flags,
1189	orientation orientation)
1190{
1191	DrawSliderTriangle(view, rect, updateRect, base, base, flags, orientation);
1192}
1193
1194
1195void
1196BeControlLook::DrawSliderTriangle(BView* view, BRect& rect,
1197	const BRect& updateRect, const rgb_color& base, const rgb_color& fill,
1198	uint32 flags, orientation orientation)
1199{
1200	if (!ShouldDraw(view, rect, updateRect))
1201		return;
1202
1203	rgb_color lighten1 = tint_color(base, B_LIGHTEN_1_TINT);
1204	rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT);
1205	rgb_color darkenmax = tint_color(base, B_DARKEN_MAX_TINT);
1206
1207	if (orientation == B_HORIZONTAL) {
1208		view->SetHighColor(lighten1);
1209		view->FillTriangle(BPoint(rect.left, rect.bottom - 1),
1210			BPoint(rect.left + 6, rect.top),
1211			BPoint(rect.right, rect.bottom - 1));
1212
1213		view->SetHighColor(darkenmax);
1214		view->StrokeLine(BPoint(rect.right, rect.bottom + 1),
1215			BPoint(rect.left, rect.bottom + 1));
1216		view->StrokeLine(BPoint(rect.right, rect.bottom),
1217			BPoint(rect.left + 6, rect.top));
1218
1219		view->SetHighColor(darken2);
1220		view->StrokeLine(BPoint(rect.right - 1, rect.bottom),
1221			BPoint(rect.left, rect.bottom));
1222		view->StrokeLine(BPoint(rect.left, rect.bottom),
1223			BPoint(rect.left + 5, rect.top + 1));
1224
1225		view->SetHighColor(base);
1226		view->StrokeLine(BPoint(rect.right - 2, rect.bottom - 1),
1227			BPoint(rect.left + 3, rect.bottom - 1));
1228		view->StrokeLine(BPoint(rect.right - 3, rect.bottom - 2),
1229			BPoint(rect.left + 6, rect.top + 1));
1230	} else {
1231		view->SetHighColor(lighten1);
1232		view->FillTriangle(BPoint(rect.left + 1, rect.top),
1233			BPoint(rect.left + 7, rect.top + 6),
1234			BPoint(rect.left + 1, rect.bottom));
1235
1236		view->SetHighColor(darkenmax);
1237		view->StrokeLine(BPoint(rect.left, rect.top + 1),
1238			BPoint(rect.left, rect.bottom));
1239		view->StrokeLine(BPoint(rect.left + 1, rect.bottom),
1240			BPoint(rect.left + 7, rect.top + 6));
1241
1242		view->SetHighColor(darken2);
1243		view->StrokeLine(BPoint(rect.left, rect.top),
1244			BPoint(rect.left, rect.bottom - 1));
1245		view->StrokeLine(BPoint(rect.left + 1, rect.top),
1246			BPoint(rect.left + 6, rect.top + 5));
1247
1248		view->SetHighColor(base);
1249		view->StrokeLine(BPoint(rect.left + 1, rect.top + 2),
1250			BPoint(rect.left + 1, rect.bottom - 1));
1251		view->StrokeLine(BPoint(rect.left + 2, rect.bottom - 2),
1252			BPoint(rect.left + 6, rect.top + 6));
1253	}
1254}
1255
1256
1257void
1258BeControlLook::DrawSliderHashMarks(BView* view, BRect& rect,
1259	const BRect& updateRect, const rgb_color& base, int32 count,
1260	hash_mark_location location, uint32 flags, orientation orientation)
1261{
1262	if (!ShouldDraw(view, rect, updateRect))
1263		return;
1264
1265	rgb_color lightColor;
1266	rgb_color darkColor;
1267
1268	if ((flags & B_DISABLED) != 0) {
1269		lightColor = tint_color(base, 0.9);
1270		darkColor = tint_color(base, 1.07);
1271	} else {
1272		lightColor = tint_color(base, 0.8);
1273		darkColor = tint_color(base, 1.14);
1274	}
1275
1276	int32 hashMarkCount = std::max(count, (int32)2);
1277		// draw at least two hashmarks at min/max if
1278		// fHashMarks != B_HASH_MARKS_NONE
1279	float factor;
1280	float startPos;
1281	if (orientation == B_HORIZONTAL) {
1282		factor = (rect.Width() - 2) / (hashMarkCount - 1);
1283		startPos = rect.left + 1;
1284	} else {
1285		factor = (rect.Height() - 2) / (hashMarkCount - 1);
1286		startPos = rect.top + 1;
1287	}
1288
1289	if (location & B_HASH_MARKS_TOP) {
1290		view->BeginLineArray(hashMarkCount * 2);
1291
1292		if (orientation == B_HORIZONTAL) {
1293			float pos = startPos;
1294			for (int32 i = 0; i < hashMarkCount; i++) {
1295				view->AddLine(BPoint(pos, rect.top),
1296							  BPoint(pos, rect.top + 4), darkColor);
1297				view->AddLine(BPoint(pos + 1, rect.top),
1298							  BPoint(pos + 1, rect.top + 4), lightColor);
1299
1300				pos += factor;
1301			}
1302		} else {
1303			float pos = startPos;
1304			for (int32 i = 0; i < hashMarkCount; i++) {
1305				view->AddLine(BPoint(rect.left, pos),
1306							  BPoint(rect.left + 4, pos), darkColor);
1307				view->AddLine(BPoint(rect.left, pos + 1),
1308							  BPoint(rect.left + 4, pos + 1), lightColor);
1309
1310				pos += factor;
1311			}
1312		}
1313
1314		view->EndLineArray();
1315	}
1316
1317	if ((location & B_HASH_MARKS_BOTTOM) != 0) {
1318		view->BeginLineArray(hashMarkCount * 2);
1319
1320		if (orientation == B_HORIZONTAL) {
1321			float pos = startPos;
1322			for (int32 i = 0; i < hashMarkCount; i++) {
1323				view->AddLine(BPoint(pos, rect.bottom - 4),
1324							  BPoint(pos, rect.bottom), darkColor);
1325				view->AddLine(BPoint(pos + 1, rect.bottom - 4),
1326							  BPoint(pos + 1, rect.bottom), lightColor);
1327
1328				pos += factor;
1329			}
1330		} else {
1331			float pos = startPos;
1332			for (int32 i = 0; i < hashMarkCount; i++) {
1333				view->AddLine(BPoint(rect.right - 4, pos),
1334							  BPoint(rect.right, pos), darkColor);
1335				view->AddLine(BPoint(rect.right - 4, pos + 1),
1336							  BPoint(rect.right, pos + 1), lightColor);
1337
1338				pos += factor;
1339			}
1340		}
1341
1342		view->EndLineArray();
1343	}
1344}
1345
1346
1347void
1348BeControlLook::DrawTabFrame(BView* view, BRect& rect, const BRect& updateRect,
1349	const rgb_color& base, uint32 flags, uint32 borders,
1350	border_style borderStyle, uint32 side)
1351{
1352	view->SetHighColor(base);
1353	view->FillRect(rect);
1354
1355	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
1356
1357	view->BeginLineArray(1);
1358
1359	switch(side) {
1360		case BTabView::kLeftSide:
1361			view->AddLine(BPoint(rect.right, rect.top),
1362				BPoint(rect.right, rect.bottom), lightenmax);
1363			break;
1364
1365		case BTabView::kRightSide:
1366			view->AddLine(BPoint(rect.left, rect.top),
1367				BPoint(rect.left, rect.bottom), lightenmax);
1368			break;
1369
1370		default:
1371		case BTabView::kTopSide:
1372			view->AddLine(BPoint(rect.left, rect.bottom),
1373				BPoint(rect.right, rect.bottom), lightenmax);
1374			break;
1375
1376		case BTabView::kBottomSide:
1377			view->AddLine(BPoint(rect.left, rect.top),
1378				BPoint(rect.right, rect.top), lightenmax);
1379			break;
1380	}
1381
1382	view->EndLineArray();
1383}
1384
1385
1386void
1387BeControlLook::DrawActiveTab(BView* view, BRect& rect,
1388	const BRect& updateRect, const rgb_color& base, uint32 flags,
1389	uint32 borders, uint32 side, int32, int32, int32, int32)
1390{
1391	if (!ShouldDraw(view, rect, updateRect))
1392		return;
1393
1394	view->PushState();
1395
1396	// clip draw rect to rect plus 2px
1397	view->ClipToRect(rect.InsetByCopy(-2, -2));
1398
1399	// set colors and draw
1400
1401	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
1402	rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT);
1403	rgb_color darkenmax = tint_color(base, B_DARKEN_MAX_TINT);
1404
1405	view->SetHighColor(darkenmax);
1406	view->SetLowColor(base);
1407
1408	view->BeginLineArray(12);
1409
1410	switch (side) {
1411		case BTabView::kLeftSide:
1412			// before going left
1413			view->AddLine(BPoint(rect.right - 1, rect.top - 1),
1414				BPoint(rect.right - 1, rect.top - 1), lightenmax);
1415			view->AddLine(BPoint(rect.right - 2, rect.top),
1416				BPoint(rect.right - 3, rect.top), lightenmax);
1417
1418			// going left
1419			view->AddLine(BPoint(rect.right - 4, rect.top + 1),
1420				BPoint(rect.left + 5, rect.top + 1), lightenmax);
1421
1422			// before going down
1423			view->AddLine(BPoint(rect.left + 2, rect.top + 2),
1424				BPoint(rect.left + 4, rect.top + 2), lightenmax);
1425			view->AddLine(BPoint(rect.left + 1, rect.top + 3),
1426				BPoint(rect.left + 1, rect.top + 4 ), lightenmax);
1427
1428			// going down
1429			view->AddLine(BPoint(rect.left, rect.top + 5),
1430				BPoint(rect.left, rect.bottom - 5), lightenmax);
1431
1432			// after going down
1433			view->AddLine(BPoint(rect.left + 1, rect.bottom - 4),
1434				BPoint(rect.left + 1, rect.bottom - 3), lightenmax);
1435			view->AddLine(BPoint(rect.left + 2, rect.bottom - 2),
1436				BPoint(rect.left + 3, rect.bottom - 2), darken4);
1437
1438			// going right
1439			view->AddLine(BPoint(rect.left + 4, rect.bottom - 1),
1440				BPoint(rect.right - 4, rect.bottom - 1), darken4);
1441
1442			// after going right
1443			view->AddLine(BPoint(rect.right - 3, rect.bottom),
1444				BPoint(rect.right - 2, rect.bottom), darken4);
1445			view->AddLine(BPoint(rect.right - 1, rect.bottom + 1),
1446				BPoint(rect.right - 1, rect.bottom + 1), darken4);
1447			view->AddLine(BPoint(rect.right, rect.bottom + 2),
1448				BPoint(rect.right, rect.bottom + 2), darken4);
1449			break;
1450
1451		case BTabView::kRightSide:
1452			// before going right
1453			view->AddLine(BPoint(rect.left - 1, rect.top - 1),
1454				BPoint(rect.left - 1, rect.top - 1), lightenmax);
1455			view->AddLine(BPoint(rect.left - 2, rect.top),
1456				BPoint(rect.left - 3, rect.top), lightenmax);
1457
1458			// going right
1459			view->AddLine(BPoint(rect.left - 4, rect.top + 1),
1460				BPoint(rect.right + 5, rect.top + 1), lightenmax);
1461
1462			// before going down
1463			view->AddLine(BPoint(rect.right + 2, rect.top + 2),
1464				BPoint(rect.right + 4, rect.top + 2), lightenmax);
1465			view->AddLine(BPoint(rect.right + 1, rect.top + 3),
1466				BPoint(rect.right + 1, rect.top + 4 ), lightenmax);
1467
1468			// going down
1469			view->AddLine(BPoint(rect.right, rect.top + 5),
1470				BPoint(rect.right, rect.bottom - 5), lightenmax);
1471
1472			// after going down
1473			view->AddLine(BPoint(rect.right + 1, rect.bottom - 4),
1474				BPoint(rect.right + 1, rect.bottom - 3), lightenmax);
1475			view->AddLine(BPoint(rect.right + 2, rect.bottom - 2),
1476				BPoint(rect.right + 3, rect.bottom - 2), darken4);
1477
1478			// going left
1479			view->AddLine(BPoint(rect.right + 4, rect.bottom - 1),
1480				BPoint(rect.left - 4, rect.bottom - 1), darken4);
1481
1482			// after going left
1483			view->AddLine(BPoint(rect.left - 3, rect.bottom),
1484				BPoint(rect.left - 2, rect.bottom), darken4);
1485			view->AddLine(BPoint(rect.left - 1, rect.bottom + 1),
1486				BPoint(rect.left - 1, rect.bottom + 1), darken4);
1487			view->AddLine(BPoint(rect.left, rect.bottom + 2),
1488				BPoint(rect.left, rect.bottom + 2), darken4);
1489			break;
1490
1491		default:
1492		case BTabView::kTopSide:
1493			// before going up
1494			view->AddLine(BPoint(rect.left - 1, rect.bottom - 1),
1495				BPoint(rect.left - 1, rect.bottom - 1), lightenmax);
1496			view->AddLine(BPoint(rect.left, rect.bottom - 2),
1497				BPoint(rect.left, rect.bottom - 3), lightenmax);
1498
1499			// going up
1500			view->AddLine(BPoint(rect.left + 1, rect.bottom - 4),
1501				BPoint(rect.left + 1, rect.top + 5), lightenmax);
1502
1503			// before going right
1504			view->AddLine(BPoint(rect.left + 2, rect.top + 4),
1505				BPoint(rect.left + 2, rect.top + 2), lightenmax);
1506			view->AddLine(BPoint(rect.left + 3, rect.top + 1),
1507				BPoint(rect.left + 4, rect.top + 1), lightenmax);
1508
1509			// going right
1510			view->AddLine(BPoint(rect.left + 5, rect.top),
1511				BPoint(rect.right - 5, rect.top), lightenmax);
1512
1513			// after going right
1514			view->AddLine(BPoint(rect.right - 4, rect.top + 1),
1515				BPoint(rect.right - 3, rect.top + 1), lightenmax);
1516			view->AddLine(BPoint(rect.right - 2, rect.top + 2),
1517				BPoint(rect.right - 2, rect.top + 3), darken4);
1518
1519			// going down
1520			view->AddLine(BPoint(rect.right - 1, rect.top + 4),
1521				BPoint(rect.right - 1, rect.bottom - 4), darken4);
1522
1523			// after going down
1524			view->AddLine(BPoint(rect.right, rect.bottom - 3),
1525				BPoint(rect.right, rect.bottom - 2), darken4);
1526			view->AddLine(BPoint(rect.right + 1, rect.bottom - 1),
1527				BPoint(rect.right + 1, rect.bottom - 1), darken4);
1528			view->AddLine(BPoint(rect.right + 2, rect.bottom),
1529				BPoint(rect.right + 2, rect.bottom), darken4);
1530			break;
1531
1532		case BTabView::kBottomSide:
1533			// before going down
1534			view->AddLine(BPoint(rect.left - 1, rect.top - 1),
1535				BPoint(rect.left - 1, rect.top - 1), lightenmax);
1536			view->AddLine(BPoint(rect.left, rect.top - 2),
1537				BPoint(rect.left, rect.top - 3), lightenmax);
1538
1539			// going down
1540			view->AddLine(BPoint(rect.left + 1, rect.top - 4),
1541				BPoint(rect.left + 1, rect.bottom + 5), lightenmax);
1542
1543			// before going right
1544			view->AddLine(BPoint(rect.left + 2, rect.bottom + 4),
1545				BPoint(rect.left + 2, rect.bottom + 2), lightenmax);
1546			view->AddLine(BPoint(rect.left + 3, rect.bottom + 1),
1547				BPoint(rect.left + 4, rect.bottom + 1), lightenmax);
1548
1549			// going right
1550			view->AddLine(BPoint(rect.left + 5, rect.bottom),
1551				BPoint(rect.right - 5, rect.bottom), lightenmax);
1552
1553			// after going right
1554			view->AddLine(BPoint(rect.right - 4, rect.bottom + 1),
1555				BPoint(rect.right - 3, rect.bottom + 1), lightenmax);
1556			view->AddLine(BPoint(rect.right - 2, rect.bottom + 2),
1557				BPoint(rect.right - 2, rect.bottom + 3), darken4);
1558
1559			// going up
1560			view->AddLine(BPoint(rect.right - 1, rect.bottom + 4),
1561				BPoint(rect.right - 1, rect.top - 4), darken4);
1562
1563			// after going up
1564			view->AddLine(BPoint(rect.right, rect.top - 3),
1565				BPoint(rect.right, rect.top - 2), darken4);
1566			view->AddLine(BPoint(rect.right + 1, rect.top - 1),
1567				BPoint(rect.right + 1, rect.top - 1), darken4);
1568			view->AddLine(BPoint(rect.right + 2, rect.top),
1569				BPoint(rect.right + 2, rect.top), darken4);
1570			break;
1571	}
1572	view->EndLineArray();
1573
1574	// undraw white line
1575	view->BeginLineArray(1);
1576	switch (side) {
1577		case BTabView::kLeftSide:
1578			view->AddLine(BPoint(rect.right, rect.top - 1),
1579				BPoint(rect.right, rect.bottom + 1), base);
1580			break;
1581
1582		case BTabView::kRightSide:
1583			view->AddLine(BPoint(rect.left, rect.top - 1),
1584				BPoint(rect.left, rect.bottom + 1), base);
1585			break;
1586
1587		default:
1588		case BTabView::kTopSide:
1589			view->AddLine(BPoint(rect.left - 1, rect.bottom),
1590				BPoint(rect.right + 1, rect.bottom), base);
1591			break;
1592
1593		case BTabView::kBottomSide:
1594			view->AddLine(BPoint(rect.left - 1, rect.top),
1595				BPoint(rect.right + 1, rect.top), base);
1596			break;
1597	}
1598	view->EndLineArray();
1599
1600	// inset rect for view contents
1601	rect.InsetBy(2, 2);
1602
1603	view->PopState();
1604}
1605
1606
1607void
1608BeControlLook::DrawInactiveTab(BView* view, BRect& rect,
1609	const BRect& updateRect, const rgb_color& base, uint32 flags,
1610	uint32 borders, uint32 side, int32 index, int32 selected,
1611	int32 first, int32 last)
1612{
1613	if (!ShouldDraw(view, rect, updateRect))
1614		return;
1615
1616	bool isFirst = index == first;
1617	bool isFull = index != selected - 1;
1618
1619	view->PushState();
1620
1621	// clip draw rect to rect plus 2px
1622	view->ClipToRect(rect.InsetByCopy(-2, -2));
1623
1624	// set colors and draw
1625
1626	rgb_color lightenmax = tint_color(base, B_LIGHTEN_MAX_TINT);
1627	rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT);
1628	rgb_color darkenmax = tint_color(base, B_DARKEN_MAX_TINT);
1629
1630	view->SetHighColor(darkenmax);
1631	view->SetLowColor(base);
1632
1633	view->BeginLineArray(12);
1634
1635	switch (side) {
1636		case BTabView::kLeftSide:
1637			// only draw if first tab is unselected
1638			if (isFirst) {
1639				// before going left
1640				view->AddLine(BPoint(rect.right - 1, rect.top - 1),
1641					BPoint(rect.right - 1, rect.top - 1), lightenmax);
1642				view->AddLine(BPoint(rect.right - 2, rect.top),
1643					BPoint(rect.right - 3, rect.top), lightenmax);
1644			}
1645
1646			// going left
1647			view->AddLine(BPoint(rect.right - 4, rect.top + 1),
1648				BPoint(rect.left + 5, rect.top + 1), lightenmax);
1649
1650			// before going down
1651			view->AddLine(BPoint(rect.left + 2, rect.top + 2),
1652				BPoint(rect.left + 4, rect.top + 2), lightenmax);
1653			view->AddLine(BPoint(rect.left + 1, rect.top + 3),
1654				BPoint(rect.left + 1, rect.top + 4 ), lightenmax);
1655
1656			// going down
1657			view->AddLine(BPoint(rect.left, rect.top + 5),
1658				BPoint(rect.left, rect.bottom - 5), lightenmax);
1659
1660			// after going down
1661			view->AddLine(BPoint(rect.left + 1, rect.bottom - 4),
1662				BPoint(rect.left + 1, rect.bottom - 3), lightenmax);
1663			view->AddLine(BPoint(rect.left + 2, rect.bottom - 2),
1664				BPoint(rect.left + 3, rect.bottom - 2), darken4);
1665
1666			// going right
1667			view->AddLine(BPoint(rect.left + 4, rect.bottom - 1),
1668				BPoint(rect.right - 4, rect.bottom - 1), darken4);
1669
1670			// only draw if not before selected tab
1671			if (isFull) {
1672				// after going right
1673				view->AddLine(BPoint(rect.right - 3, rect.bottom),
1674					BPoint(rect.right - 2, rect.bottom), darken4);
1675				view->AddLine(BPoint(rect.right - 1, rect.bottom + 1),
1676					BPoint(rect.right - 1, rect.bottom + 1), darken4);
1677			}
1678			break;
1679
1680		case BTabView::kRightSide:
1681			// only draw if first tab is unselected
1682			if (isFirst) {
1683				// before going right
1684				view->AddLine(BPoint(rect.left - 1, rect.top - 1),
1685					BPoint(rect.left - 1, rect.top - 1), lightenmax);
1686				view->AddLine(BPoint(rect.left - 2, rect.top),
1687					BPoint(rect.left - 3, rect.top), lightenmax);
1688			}
1689
1690			// going right
1691			view->AddLine(BPoint(rect.left - 4, rect.top + 1),
1692				BPoint(rect.right + 5, rect.top + 1), lightenmax);
1693
1694			// before going down
1695			view->AddLine(BPoint(rect.right + 2, rect.top + 2),
1696				BPoint(rect.right + 4, rect.top + 2), lightenmax);
1697			view->AddLine(BPoint(rect.right + 1, rect.top + 3),
1698				BPoint(rect.right + 1, rect.top + 4 ), lightenmax);
1699
1700			// going down
1701			view->AddLine(BPoint(rect.right, rect.top + 5),
1702				BPoint(rect.right, rect.bottom - 5), lightenmax);
1703
1704			// after going down
1705			view->AddLine(BPoint(rect.right + 1, rect.bottom - 4),
1706				BPoint(rect.right + 1, rect.bottom - 3), lightenmax);
1707			view->AddLine(BPoint(rect.right + 2, rect.bottom - 2),
1708				BPoint(rect.right + 3, rect.bottom - 2), darken4);
1709
1710			// going left
1711			view->AddLine(BPoint(rect.right + 4, rect.bottom - 1),
1712				BPoint(rect.left - 4, rect.bottom - 1), darken4);
1713
1714			// only draw if not before selected tab
1715			if (isFull) {
1716				// after going left
1717				view->AddLine(BPoint(rect.left - 3, rect.bottom),
1718					BPoint(rect.left - 2, rect.bottom), darken4);
1719				view->AddLine(BPoint(rect.left - 1, rect.bottom + 1),
1720					BPoint(rect.left - 1, rect.bottom + 1), darken4);
1721			}
1722			break;
1723
1724		default:
1725		case BTabView::kTopSide:
1726			// only draw if first tab is unselected
1727			if (isFirst) {
1728				// before going up
1729				view->AddLine(BPoint(rect.left - 1, rect.bottom - 1),
1730					BPoint(rect.left - 1, rect.bottom - 1), lightenmax);
1731				view->AddLine(BPoint(rect.left, rect.bottom - 2),
1732					BPoint(rect.left, rect.bottom - 3), lightenmax);;
1733			}
1734
1735			// going up
1736			view->AddLine(BPoint(rect.left + 1, rect.bottom - 4),
1737				BPoint(rect.left + 1, rect.top + 5), lightenmax);
1738
1739			// before going right
1740			view->AddLine(BPoint(rect.left + 2, rect.top + 4),
1741				BPoint(rect.left + 2, rect.top + 2), lightenmax);
1742			view->AddLine(BPoint(rect.left + 3, rect.top + 1),
1743				BPoint(rect.left + 4, rect.top + 1), lightenmax);
1744
1745			// going right
1746			view->AddLine(BPoint(rect.left + 5, rect.top),
1747				BPoint(rect.right - 5, rect.top), lightenmax);
1748
1749			// after going right
1750			view->AddLine(BPoint(rect.right - 4, rect.top + 1),
1751				BPoint(rect.right - 3, rect.top + 1), lightenmax);
1752			view->AddLine(BPoint(rect.right - 2, rect.top + 2),
1753				BPoint(rect.right - 2, rect.top + 3), darken4);
1754
1755			// going down
1756			view->AddLine(BPoint(rect.right - 1, rect.top + 4),
1757				BPoint(rect.right - 1, rect.bottom - 4), darken4);
1758
1759			// only draw if not before selected tab
1760			if (isFull) {
1761				// after going down
1762				view->AddLine(BPoint(rect.right, rect.bottom - 3),
1763					BPoint(rect.right, rect.bottom - 2), darken4);
1764				view->AddLine(BPoint(rect.right + 1, rect.bottom - 1),
1765					BPoint(rect.right + 1, rect.bottom - 1), darken4);
1766			}
1767			break;
1768
1769		case BTabView::kBottomSide:
1770			// only draw if first tab is unselected
1771			if (isFirst) {
1772				// before going down
1773				view->AddLine(BPoint(rect.left - 1, rect.top - 1),
1774					BPoint(rect.left - 1, rect.top - 1), lightenmax);
1775				view->AddLine(BPoint(rect.left, rect.top - 2),
1776					BPoint(rect.left, rect.top - 3), lightenmax);
1777			}
1778
1779			// before going down
1780			view->AddLine(BPoint(rect.left + 1, rect.top - 4),
1781				BPoint(rect.left + 1, rect.bottom + 5), lightenmax);
1782
1783			// before going right
1784			view->AddLine(BPoint(rect.left + 2, rect.bottom + 4),
1785				BPoint(rect.left + 2, rect.bottom + 2), lightenmax);
1786			view->AddLine(BPoint(rect.left + 3, rect.bottom + 1),
1787				BPoint(rect.left + 4, rect.bottom + 1), lightenmax);
1788
1789			// going right
1790			view->AddLine(BPoint(rect.left + 5, rect.bottom),
1791				BPoint(rect.right - 5, rect.bottom), lightenmax);
1792
1793			// after going right
1794			view->AddLine(BPoint(rect.right - 4, rect.bottom + 1),
1795				BPoint(rect.right - 3, rect.bottom + 1), lightenmax);
1796			view->AddLine(BPoint(rect.right - 2, rect.bottom + 2),
1797				BPoint(rect.right - 2, rect.bottom + 3), darken4);
1798
1799			// going up
1800			view->AddLine(BPoint(rect.right - 1, rect.bottom + 4),
1801				BPoint(rect.right - 1, rect.top - 4), darken4);
1802
1803			// only draw if not before selected tab
1804			if (isFull) {
1805				// after going up
1806				view->AddLine(BPoint(rect.right, rect.top - 3),
1807					BPoint(rect.right, rect.top - 2), darken4);
1808				view->AddLine(BPoint(rect.right + 1, rect.top - 1),
1809					BPoint(rect.right + 1, rect.top - 1), darken4);
1810			}
1811			break;
1812	}
1813
1814	view->EndLineArray();
1815
1816	// inset rect for view contents
1817	rect.InsetBy(2, 2);
1818
1819	view->PopState();
1820}
1821
1822
1823void
1824BeControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect,
1825	const rgb_color& base, orientation orientation, uint32 flags,
1826	uint32 borders)
1827{
1828	if (!ShouldDraw(view, rect, updateRect))
1829		return;
1830
1831	rgb_color background;
1832	if ((flags & (B_CLICKED | B_ACTIVATED)) != 0)
1833		background = tint_color(base, B_DARKEN_1_TINT);
1834	else
1835		background = base;
1836
1837	rgb_color light = tint_color(background, 0.6);
1838	rgb_color shadow = tint_color(background, 1.21);
1839
1840	// frame
1841	if (borders != 0 && rect.Width() > 3 && rect.Height() > 3)
1842		DrawRaisedBorder(view, rect, updateRect, background, flags, borders);
1843
1844	// dots and rest of background
1845	if (orientation == B_HORIZONTAL) {
1846		if (rect.Width() > 2) {
1847			// background on left/right
1848			BRegion region(rect);
1849			rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5);
1850			rect.right = rect.left + 1;
1851			region.Exclude(rect);
1852			view->SetHighColor(background);
1853			view->FillRegion(&region);
1854		}
1855
1856		BPoint dot = rect.LeftTop();
1857		BPoint stop = rect.LeftBottom();
1858		int32 num = 1;
1859		while (dot.y <= stop.y) {
1860			rgb_color col1;
1861			rgb_color col2;
1862			switch (num) {
1863				case 1:
1864					col1 = background;
1865					col2 = background;
1866					break;
1867				case 2:
1868					col1 = shadow;
1869					col2 = background;
1870					break;
1871				case 3:
1872				default:
1873					col1 = background;
1874					col2 = light;
1875					num = 0;
1876					break;
1877			}
1878			view->SetHighColor(col1);
1879			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1880			view->SetHighColor(col2);
1881			dot.x++;
1882			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1883			dot.x -= 1.0;
1884			// next pixel
1885			num++;
1886			dot.y++;
1887		}
1888	} else {
1889		if (rect.Height() > 2) {
1890			// background on left/right
1891			BRegion region(rect);
1892			rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5);
1893			rect.bottom = rect.top + 1;
1894			region.Exclude(rect);
1895			view->SetHighColor(background);
1896			view->FillRegion(&region);
1897		}
1898
1899		BPoint dot = rect.LeftTop();
1900		BPoint stop = rect.RightTop();
1901		int32 num = 1;
1902		while (dot.x <= stop.x) {
1903			rgb_color col1;
1904			rgb_color col2;
1905			switch (num) {
1906				case 1:
1907					col1 = background;
1908					col2 = background;
1909					break;
1910				case 2:
1911					col1 = shadow;
1912					col2 = background;
1913					break;
1914				case 3:
1915				default:
1916					col1 = background;
1917					col2 = light;
1918					num = 0;
1919					break;
1920			}
1921			view->SetHighColor(col1);
1922			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1923			view->SetHighColor(col2);
1924			dot.y++;
1925			view->StrokeLine(dot, dot, B_SOLID_HIGH);
1926			dot.y -= 1.0;
1927			// next pixel
1928			num++;
1929			dot.x++;
1930		}
1931	}
1932}
1933
1934
1935//	#pragma mark - various borders
1936
1937
1938void
1939BeControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect,
1940	const rgb_color& base, border_style borderStyle, uint32 flags,
1941	uint32 borders)
1942{
1943	if (borderStyle == B_NO_BORDER)
1944		return;
1945
1946	if (!ShouldDraw(view, rect, updateRect))
1947		return;
1948
1949	view->PushState();
1950
1951	view->ClipToRect(rect);
1952
1953	rgb_color lightColor;
1954	rgb_color shadowColor;
1955	if (base.IsLight()) {
1956		lightColor = tint_color(base, B_DARKEN_2_TINT);
1957		shadowColor = tint_color(base, B_LIGHTEN_2_TINT);
1958	} else {
1959		lightColor = tint_color(base, B_LIGHTEN_MAX_TINT);
1960		shadowColor = tint_color(base, B_DARKEN_3_TINT);
1961	}
1962
1963	view->BeginLineArray(8);
1964
1965	if (borderStyle == B_FANCY_BORDER) {
1966		if ((borders & B_LEFT_BORDER) != 0) {
1967			view->AddLine(rect.LeftBottom(), rect.LeftTop(), shadowColor);
1968			rect.left++;
1969		}
1970		if ((borders & B_TOP_BORDER) != 0) {
1971			view->AddLine(rect.LeftTop(), rect.RightTop(), shadowColor);
1972			rect.top++;
1973		}
1974		if ((borders & B_RIGHT_BORDER) != 0) {
1975			view->AddLine(rect.RightTop(), rect.RightBottom(), shadowColor);
1976			rect.right--;
1977		}
1978		if ((borders & B_BOTTOM_BORDER) != 0) {
1979			view->AddLine(rect.RightBottom(), rect.LeftBottom(), shadowColor);
1980			rect.bottom--;
1981		}
1982
1983		if ((borders & B_LEFT_BORDER) != 0) {
1984			view->AddLine(rect.LeftBottom(), rect.LeftTop(), lightColor);
1985			rect.left++;
1986		}
1987		if ((borders & B_TOP_BORDER) != 0) {
1988			view->AddLine(rect.LeftTop(), rect.RightTop(), lightColor);
1989			rect.top++;
1990		}
1991		if ((borders & B_RIGHT_BORDER) != 0) {
1992			view->AddLine(rect.RightTop(), rect.RightBottom(), lightColor);
1993			rect.right--;
1994		}
1995		if ((borders & B_BOTTOM_BORDER) != 0) {
1996			view->AddLine(rect.RightBottom(), rect.LeftBottom(), lightColor);
1997			rect.bottom--;
1998		}
1999	} else if (borderStyle == B_PLAIN_BORDER) {
2000		if ((borders & B_LEFT_BORDER) != 0) {
2001			view->AddLine(rect.LeftBottom(), rect.LeftTop(), shadowColor);
2002			rect.left++;
2003		}
2004		if ((borders & B_TOP_BORDER) != 0) {
2005			view->AddLine(rect.LeftTop(), rect.RightTop(), shadowColor);
2006			rect.top++;
2007		}
2008		if ((borders & B_RIGHT_BORDER) != 0) {
2009			view->AddLine(rect.RightTop(), rect.RightBottom(), shadowColor);
2010			rect.right--;
2011		}
2012		if ((borders & B_BOTTOM_BORDER) != 0) {
2013			view->AddLine(rect.RightBottom(), rect.LeftBottom(), shadowColor);
2014			rect.bottom--;
2015		}
2016
2017		if ((borders & B_LEFT_BORDER) != 0) {
2018			view->AddLine(rect.LeftBottom(), rect.LeftTop(), lightColor);
2019			rect.left++;
2020		}
2021		if ((borders & B_TOP_BORDER) != 0) {
2022			view->AddLine(rect.LeftTop(), rect.RightTop(), lightColor);
2023			rect.top++;
2024		}
2025		if ((borders & B_RIGHT_BORDER) != 0) {
2026			view->AddLine(rect.RightTop(), rect.RightBottom(), lightColor);
2027			rect.right--;
2028		}
2029		if ((borders & B_BOTTOM_BORDER) != 0) {
2030			view->AddLine(rect.RightBottom(), rect.LeftBottom(), lightColor);
2031			rect.bottom--;
2032		}
2033	}
2034
2035	view->EndLineArray();
2036
2037	view->PopState();
2038}
2039
2040
2041void
2042BeControlLook::DrawRaisedBorder(BView* view, BRect& rect,
2043	const BRect& updateRect, const rgb_color& base, uint32 flags,
2044	uint32 borders)
2045{
2046	if (!ShouldDraw(view, rect, updateRect))
2047		return;
2048
2049	view->PushState();
2050
2051	view->ClipToRect(rect);
2052
2053	rgb_color lightColor;
2054	rgb_color shadowColor;
2055
2056	if ((flags & B_DISABLED) != 0) {
2057		lightColor = base;
2058		shadowColor = base;
2059	} else {
2060		lightColor = tint_color(base, 0.85);
2061		shadowColor = tint_color(base, 1.07);
2062	}
2063
2064	view->BeginLineArray(8);
2065
2066	if ((borders & B_LEFT_BORDER) != 0) {
2067		view->AddLine(rect.LeftBottom(), rect.LeftTop(), lightColor);
2068		rect.left++;
2069	}
2070	if ((borders & B_TOP_BORDER) != 0) {
2071		view->AddLine(rect.LeftTop(), rect.RightTop(), lightColor);
2072		rect.top++;
2073	}
2074	if ((borders & B_RIGHT_BORDER) != 0) {
2075		view->AddLine(rect.RightTop(), rect.RightBottom(), lightColor);
2076		rect.right--;
2077	}
2078	if ((borders & B_BOTTOM_BORDER) != 0) {
2079		view->AddLine(rect.RightBottom(), rect.LeftBottom(), lightColor);
2080		rect.bottom--;
2081	}
2082
2083	if ((borders & B_LEFT_BORDER) != 0) {
2084		view->AddLine(rect.LeftBottom(), rect.LeftTop(), shadowColor);
2085		rect.left++;
2086	}
2087	if ((borders & B_TOP_BORDER) != 0) {
2088		view->AddLine(rect.LeftTop(), rect.RightTop(), shadowColor);
2089		rect.top++;
2090	}
2091	if ((borders & B_RIGHT_BORDER) != 0) {
2092		view->AddLine(rect.RightTop(), rect.RightBottom(), shadowColor);
2093		rect.right--;
2094	}
2095	if ((borders & B_BOTTOM_BORDER) != 0) {
2096		view->AddLine(rect.RightBottom(), rect.LeftBottom(), shadowColor);
2097		rect.bottom--;
2098	}
2099
2100	view->EndLineArray();
2101
2102	view->PopState();
2103}
2104
2105
2106void
2107BeControlLook::DrawTextControlBorder(BView* view, BRect& rect,
2108	const BRect& updateRect, const rgb_color& base, uint32 flags,
2109	uint32 borders)
2110{
2111	if (!ShouldDraw(view, rect, updateRect))
2112		return;
2113
2114	view->PushState();
2115
2116	view->ClipToRect(rect);
2117
2118	bool isEnabled = (flags & B_DISABLED) == 0;
2119	bool isFocused = (flags & B_FOCUSED) != 0;
2120
2121	rgb_color dark;
2122	rgb_color light;
2123
2124	// outer bevel
2125
2126	dark = tint_color(base, (isEnabled ? B_DARKEN_1_TINT : B_DARKEN_2_TINT));
2127	light = tint_color(base, (isEnabled ? B_LIGHTEN_MAX_TINT : B_LIGHTEN_2_TINT));
2128
2129	_DrawFrame(view, rect, dark, dark, light, light);
2130
2131	// inner bevel
2132
2133	if (isEnabled && isFocused) {
2134		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
2135		view->StrokeRect(rect);
2136		rect.InsetBy(1, 1);
2137	} else {
2138		dark = tint_color(base, (isEnabled ? B_DARKEN_4_TINT : B_LIGHTEN_2_TINT));
2139		light = base;
2140
2141		_DrawFrame(view, rect, dark, dark, light, light);
2142	}
2143
2144	view->PopState();
2145}
2146
2147
2148void
2149BeControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
2150	const rgb_color& base, uint32 borders)
2151{
2152	DrawBorder(view, rect, updateRect, base, B_FANCY_BORDER, 0, borders);
2153}
2154
2155
2156//	#pragma mark - Labels
2157
2158
2159void
2160BeControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2161	const BRect& updateRect, const rgb_color& base, uint32 flags,
2162	const rgb_color* textColor)
2163{
2164	DrawLabel(view, label, NULL, rect, updateRect, base, flags,
2165		DefaultLabelAlignment(), textColor);
2166}
2167
2168
2169void
2170BeControlLook::DrawLabel(BView* view, const char* label, BRect rect,
2171	const BRect& updateRect, const rgb_color& base, uint32 flags,
2172	const BAlignment& alignment, const rgb_color* textColor)
2173{
2174	DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment,
2175		textColor);
2176}
2177
2178
2179void
2180BeControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base,
2181	uint32 flags, const BPoint& where, const rgb_color* textColor)
2182{
2183	view->PushState();
2184
2185	bool isButton = (flags & B_FLAT) != 0 || (flags & B_HOVER) != 0
2186		|| (flags & B_DEFAULT_BUTTON) != 0;
2187	bool isEnabled = (flags & B_DISABLED) == 0;
2188	bool isActivated = (flags & B_ACTIVATED) != 0;
2189
2190	BWindow* window = view->Window();
2191	bool isDesktop = window != NULL
2192		&& window->Feel() == kDesktopWindowFeel
2193		&& window->Look() == kDesktopWindowLook
2194		&& view->Parent()
2195		&& view->Parent()->Parent() == NULL
2196		&& (flags & B_IGNORE_OUTLINE) == 0;
2197
2198	rgb_color low;
2199	rgb_color color;
2200	rgb_color glowColor;
2201
2202	if (textColor != NULL)
2203		glowColor = *textColor;
2204	else if ((flags & B_IS_CONTROL) != 0)
2205		glowColor = ui_color(B_CONTROL_TEXT_COLOR);
2206	else
2207		glowColor = ui_color(B_PANEL_TEXT_COLOR);
2208
2209	color = glowColor;
2210
2211	if (isDesktop)
2212		low = view->Parent()->ViewColor();
2213	else
2214		low = base;
2215
2216	if (!isEnabled) {
2217		color.red = (uint8)(((int32)low.red + color.red + 1) / 2);
2218		color.green = (uint8)(((int32)low.green + color.green + 1) / 2);
2219		color.blue = (uint8)(((int32)low.blue + color.blue + 1) / 2);
2220	}
2221
2222	if (isDesktop) {
2223		// enforce proper use of desktop label colors
2224		if (low.IsDark()) {
2225			if (textColor == NULL)
2226				color = make_color(255, 255, 255);
2227
2228			glowColor = make_color(0, 0, 0);
2229		} else {
2230			if (textColor == NULL)
2231				color = make_color(0, 0, 0);
2232
2233			glowColor = make_color(255, 255, 255);
2234		}
2235
2236		// drawing occurs on the desktop
2237		if (fCachedWorkspace != current_workspace()) {
2238			int8 indice = 0;
2239			int32 mask;
2240			bool tmpOutline;
2241			while (fBackgroundInfo.FindInt32("be:bgndimginfoworkspaces",
2242					indice, &mask) == B_OK
2243				&& fBackgroundInfo.FindBool("be:bgndimginfoerasetext",
2244					indice, &tmpOutline) == B_OK) {
2245
2246				if (((1 << current_workspace()) & mask) != 0) {
2247					fCachedOutline = tmpOutline;
2248					fCachedWorkspace = current_workspace();
2249					break;
2250				}
2251				indice++;
2252			}
2253		}
2254
2255		if (fCachedOutline) {
2256			BFont font;
2257			view->GetFont(&font);
2258
2259			view->SetDrawingMode(B_OP_ALPHA);
2260			view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
2261			// Draw glow or outline
2262			if (glowColor.IsLight()) {
2263				font.SetFalseBoldWidth(2.0);
2264				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2265
2266				glowColor.alpha = 30;
2267				view->SetHighColor(glowColor);
2268				view->DrawString(label, where);
2269
2270				font.SetFalseBoldWidth(1.0);
2271				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2272
2273				glowColor.alpha = 65;
2274				view->SetHighColor(glowColor);
2275				view->DrawString(label, where);
2276
2277				font.SetFalseBoldWidth(0.0);
2278				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2279			} else {
2280				font.SetFalseBoldWidth(1.0);
2281				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2282
2283				glowColor.alpha = 30;
2284				view->SetHighColor(glowColor);
2285				view->DrawString(label, where);
2286
2287				font.SetFalseBoldWidth(0.0);
2288				view->SetFont(&font, B_FONT_FALSE_BOLD_WIDTH);
2289
2290				glowColor.alpha = 200;
2291				view->SetHighColor(glowColor);
2292				view->DrawString(label, BPoint(where.x + 1, where.y + 1));
2293			}
2294		}
2295	}
2296
2297	rgb_color invertedIfClicked = color;
2298	if (isButton && isEnabled && isActivated) {
2299		// only for enabled and activated buttons
2300		invertedIfClicked.red = 255 - invertedIfClicked.red;
2301		invertedIfClicked.green = 255 - invertedIfClicked.green;
2302		invertedIfClicked.blue = 255 - invertedIfClicked.blue;
2303	}
2304
2305	view->SetLowColor(invertedIfClicked);
2306	view->SetHighColor(invertedIfClicked);
2307	view->SetDrawingMode(B_OP_OVER);
2308	view->DrawString(label, where);
2309	view->SetDrawingMode(B_OP_COPY);
2310
2311	view->PopState();
2312}
2313
2314
2315void
2316BeControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon,
2317	BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags,
2318	const BAlignment& alignment, const rgb_color* textColor)
2319{
2320	if (!ShouldDraw(view, rect, updateRect))
2321		return;
2322
2323	if (label == NULL && icon == NULL)
2324		return;
2325
2326	if (label == NULL && icon != NULL) {
2327		// icon only
2328		BRect alignedRect = BLayoutUtils::AlignInFrame(
2329			rect.OffsetByCopy(-2, -2),
2330			icon->Bounds().Size(), alignment);
2331		view->SetDrawingMode(B_OP_OVER);
2332		view->DrawBitmap(icon, alignedRect.LeftTop());
2333		view->SetDrawingMode(B_OP_COPY);
2334		return;
2335	}
2336
2337	view->PushState();
2338
2339	// label, possibly with icon
2340	float availableWidth = rect.Width() + 1;
2341	float width = 0;
2342	float textOffset = 0;
2343	float height = 0;
2344
2345	if (icon != NULL && label != NULL) {
2346		// move text over to fit icon
2347		width = icon->Bounds().Width() + DefaultLabelSpacing() + 1;
2348		height = icon->Bounds().Height() + 1;
2349		textOffset = width;
2350		availableWidth -= textOffset;
2351	}
2352
2353	// truncate the label if necessary and get the width and height
2354	BString truncatedLabel(label);
2355
2356	BFont font;
2357	view->GetFont(&font);
2358
2359	font.TruncateString(&truncatedLabel, B_TRUNCATE_MIDDLE, availableWidth);
2360	width += ceilf(font.StringWidth(truncatedLabel.String()));
2361
2362	font_height fontHeight;
2363	font.GetHeight(&fontHeight);
2364	float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
2365	height = std::max(height, textHeight);
2366
2367	// handle alignment
2368	BRect alignedRect(BLayoutUtils::AlignOnRect(rect,
2369		BSize(width - 1, height - 1), alignment));
2370
2371	if (icon != NULL) {
2372		BPoint location(alignedRect.LeftTop());
2373		if (icon->Bounds().Height() + 1 < height)
2374			location.y += ceilf((height - icon->Bounds().Height() - 1) / 2);
2375
2376		view->SetDrawingMode(B_OP_OVER);
2377		view->DrawBitmap(icon, location);
2378		view->SetDrawingMode(B_OP_COPY);
2379	}
2380
2381	BPoint location(alignedRect.left + textOffset,
2382		alignedRect.top + ceilf(fontHeight.ascent));
2383	if (textHeight < height)
2384		location.y += ceilf((height - textHeight) / 2);
2385
2386	if ((flags & B_FOCUSED) != 0) {
2387		// draw underline under label
2388		float x = location.x;
2389		float y = location.y + ceilf(fontHeight.descent);
2390		view->SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
2391		view->StrokeLine(BPoint(x, y),
2392			BPoint(x + view->StringWidth(truncatedLabel.String()), y));
2393	}
2394
2395	DrawLabel(view, truncatedLabel.String(), base, flags, location, textColor);
2396
2397	view->PopState();
2398}
2399
2400
2401void
2402BeControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left,
2403	float& _top, float& _right, float& _bottom)
2404{
2405	// All frames have the same inset on each side.
2406	float inset = 0;
2407
2408	switch (frameType) {
2409		case B_BUTTON_FRAME:
2410			inset = (flags & B_DEFAULT_BUTTON) != 0 ? 5 : 2;
2411			break;
2412
2413		case B_GROUP_FRAME:
2414		case B_MENU_FIELD_FRAME:
2415			inset = 3;
2416			break;
2417
2418		case B_SCROLL_VIEW_FRAME:
2419		case B_TEXT_CONTROL_FRAME:
2420			inset = 2;
2421			break;
2422	}
2423
2424	_left = inset;
2425	_top = inset;
2426	_right = inset;
2427	_bottom = inset;
2428}
2429
2430
2431void
2432BeControlLook::GetBackgroundInsets(background_type backgroundType,
2433	uint32 flags, float& _left, float& _top, float& _right, float& _bottom)
2434{
2435	// Most backgrounds have the same inset on each side.
2436	float inset = 0;
2437
2438	switch (backgroundType) {
2439		case B_BUTTON_BACKGROUND:
2440		case B_MENU_BACKGROUND:
2441		case B_MENU_BAR_BACKGROUND:
2442		case B_MENU_FIELD_BACKGROUND:
2443		case B_MENU_ITEM_BACKGROUND:
2444			inset = 1;
2445			break;
2446		case B_BUTTON_WITH_POP_UP_BACKGROUND:
2447			_left = 1;
2448			_top = 1;
2449			_right = 1 + kButtonPopUpIndicatorWidth;
2450			_bottom = 1;
2451			return;
2452		case B_HORIZONTAL_SCROLL_BAR_BACKGROUND:
2453			_left = 2;
2454			_top = 0;
2455			_right = 1;
2456			_bottom = 0;
2457			return;
2458		case B_VERTICAL_SCROLL_BAR_BACKGROUND:
2459			_left = 0;
2460			_top = 2;
2461			_right = 0;
2462			_bottom = 1;
2463			return;
2464	}
2465
2466	_left = inset;
2467	_top = inset;
2468	_right = inset;
2469	_bottom = inset;
2470}
2471
2472
2473void
2474BeControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2475	const BRect& updateRect, const rgb_color& base, uint32 flags,
2476	uint32 borders, orientation orientation)
2477{
2478	_DrawButtonBackground(view, rect, updateRect, 0.0f, 0.0f, 0.0f, 0.0f,
2479		base, true, flags, borders, orientation);
2480}
2481
2482
2483void
2484BeControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2485	const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
2486	uint32 borders, orientation orientation)
2487{
2488	_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
2489		radius, base, true, flags, borders, orientation);
2490}
2491
2492
2493void
2494BeControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
2495	const BRect& updateRect, float leftTopRadius, float rightTopRadius,
2496	float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
2497	uint32 flags, uint32 borders, orientation orientation)
2498{
2499	_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
2500		rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
2501		borders, orientation);
2502}
2503
2504
2505//	#pragma mark - protected methods
2506
2507
2508void
2509BeControlLook::_DrawButtonFrame(BView* view, BRect& rect,
2510	const BRect& updateRect, float, float, float, float, const rgb_color& base,
2511	const rgb_color& background, float contrast, float brightness,
2512	uint32 flags, uint32 borders)
2513{
2514	if (!ShouldDraw(view, rect, updateRect))
2515		return;
2516
2517	view->PushState();
2518
2519	view->ClipToRect(rect);
2520
2521	// flags
2522	bool isEnabled = (flags & B_DISABLED) == 0;
2523	bool isDefault = (flags & B_DEFAULT_BUTTON) != 0;
2524
2525	// colors
2526	rgb_color lighten1 = tint_color(base, B_LIGHTEN_1_TINT); // 231
2527	lighten1.red++; lighten1.green++; lighten1.blue++; // 232 = 231 + 1
2528	rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
2529	rgb_color lightenMax = tint_color(base, B_LIGHTEN_MAX_TINT);
2530	rgb_color darken1 = tint_color(base, B_DARKEN_1_TINT); // 184
2531	rgb_color darken2 = tint_color(base, B_DARKEN_2_TINT); // 158
2532	rgb_color darken3 = tint_color(base, B_DARKEN_3_TINT);
2533	rgb_color darken4 = tint_color(base, B_DARKEN_4_TINT); // 96
2534
2535	rgb_color buttonBgColor = lighten1;
2536	rgb_color lightColor;
2537
2538	rgb_color dark1BorderColor;
2539	rgb_color dark2BorderColor;
2540
2541	rgb_color bevelColor1;
2542	rgb_color bevelColor2;
2543	rgb_color bevelColorRBCorner;
2544
2545	rgb_color borderBevelShadow;
2546	rgb_color borderBevelLight;
2547
2548	if (isEnabled) {
2549		lightColor = tint_color(base, B_LIGHTEN_2_TINT);
2550		dark1BorderColor = darken3;
2551		dark2BorderColor = darken4;
2552		bevelColor1 = darken2;
2553		bevelColor2 = lighten1;
2554
2555		if (isDefault) {
2556			borderBevelShadow = tint_color(dark1BorderColor,
2557				(B_NO_TINT + B_DARKEN_1_TINT) / 2);
2558			borderBevelLight = tint_color(dark1BorderColor, B_LIGHTEN_1_TINT);
2559
2560			borderBevelLight.red = (borderBevelLight.red + base.red) / 2;
2561			borderBevelLight.green = (borderBevelLight.green + base.green) / 2;
2562			borderBevelLight.blue = (borderBevelLight.blue + base.blue) / 2;
2563
2564			dark1BorderColor = darken3;
2565			dark2BorderColor = darken4;
2566
2567			bevelColorRBCorner = borderBevelShadow;
2568		} else {
2569			borderBevelShadow = tint_color(base,
2570				(B_NO_TINT + B_DARKEN_1_TINT) / 2);
2571			borderBevelLight = buttonBgColor;
2572			bevelColorRBCorner = dark1BorderColor;
2573		}
2574	} else {
2575		lightColor = lighten2;
2576		dark1BorderColor = darken1;
2577		dark2BorderColor = darken2;
2578		bevelColor1 = base;
2579		bevelColor2 = buttonBgColor;
2580
2581		if (isDefault) {
2582			borderBevelShadow = dark1BorderColor;
2583			borderBevelLight = base;
2584			dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_1_TINT);
2585			dark2BorderColor = tint_color(dark1BorderColor, 1.16);
2586		} else {
2587			borderBevelShadow = base;
2588			borderBevelLight = base;
2589		}
2590
2591		bevelColorRBCorner = tint_color(base, 1.08);
2592	}
2593
2594	if (isDefault) {
2595		if (isEnabled) {
2596			// dark border
2597			view->BeginLineArray(4);
2598			if ((borders & B_LEFT_BORDER) != 0) {
2599				view->AddLine(BPoint(rect.left, rect.top + 1),
2600					BPoint(rect.left, rect.bottom - 1), dark2BorderColor);
2601				rect.left++;
2602			}
2603			if ((borders & B_TOP_BORDER) != 0) {
2604				view->AddLine(BPoint(rect.left, rect.top),
2605					BPoint(rect.right - 1, rect.top), dark2BorderColor);
2606				rect.top++;
2607			}
2608			if ((borders & B_RIGHT_BORDER) != 0) {
2609				view->AddLine(BPoint(rect.right, rect.top),
2610					BPoint(rect.right, rect.bottom - 1), dark2BorderColor);
2611				rect.right--;
2612			}
2613			if ((borders & B_BOTTOM_BORDER) != 0) {
2614				view->AddLine(BPoint(rect.left, rect.bottom),
2615					BPoint(rect.right, rect.bottom), dark2BorderColor);
2616				rect.bottom--;
2617			}
2618			view->EndLineArray();
2619
2620			// bevel
2621			view->SetHighColor(darken1);
2622			view->StrokeRect(rect);
2623
2624			rect.InsetBy(1, 1);
2625
2626			// fill
2627			view->SetHighColor(lighten1);
2628			view->FillRect(rect);
2629
2630			rect.InsetBy(2, 2);
2631		} else {
2632			// dark border
2633			view->BeginLineArray(4);
2634			if ((borders & B_LEFT_BORDER) != 0) {
2635				view->AddLine(BPoint(rect.left, rect.top + 1),
2636					BPoint(rect.left, rect.bottom - 1), darken1);
2637				rect.left++;
2638			}
2639			if ((borders & B_TOP_BORDER) != 0) {
2640				view->AddLine(BPoint(rect.left, rect.top),
2641					BPoint(rect.right - 1, rect.top), darken1);
2642				rect.top++;
2643			}
2644			if ((borders & B_RIGHT_BORDER) != 0) {
2645				view->AddLine(BPoint(rect.right, rect.top),
2646					BPoint(rect.right, rect.bottom - 1), darken1);
2647				rect.right--;
2648			}
2649			if ((borders & B_BOTTOM_BORDER) != 0) {
2650				view->AddLine(BPoint(rect.left, rect.bottom),
2651					BPoint(rect.right, rect.bottom), darken1);
2652				rect.bottom--;
2653			}
2654			view->EndLineArray();
2655
2656			// fill
2657			view->SetHighColor(lighten1);
2658			view->FillRect(rect);
2659
2660			rect.InsetBy(3, 3);
2661		}
2662	} else {
2663		// if not default button, inset top and bottom by 1px
2664		rect.InsetBy(1, 0);
2665	}
2666
2667	// stroke frame to draw four corners, then write on top
2668	view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
2669	view->StrokeRect(rect);
2670
2671	view->BeginLineArray(16);
2672
2673	// external border
2674	view->AddLine(BPoint(rect.left, rect.top + 1),
2675		BPoint(rect.left, rect.bottom - 1),
2676		(borders & B_LEFT_BORDER) != 0 ? dark2BorderColor : darken1);
2677	view->AddLine(BPoint(rect.left + 1, rect.top),
2678		BPoint(rect.right - 1, rect.top),
2679		(borders & B_TOP_BORDER) != 0 ? dark2BorderColor : darken1);
2680	view->AddLine(BPoint(rect.right, rect.top + 1),
2681		BPoint(rect.right, rect.bottom - 1),
2682		(borders & B_RIGHT_BORDER) != 0 ? dark2BorderColor : darken1);
2683	view->AddLine(BPoint(rect.left + 1, rect.bottom),
2684		BPoint(rect.right - 1, rect.bottom),
2685		(borders & B_BOTTOM_BORDER) != 0 ? dark2BorderColor : darken1);
2686
2687	// inset past external border
2688	rect.InsetBy(1, 1);
2689
2690	// internal bevel
2691	view->AddLine(rect.LeftBottom(), rect.LeftTop(), bevelColor2);
2692	view->AddLine(rect.LeftTop(), rect.RightTop(), bevelColor2);
2693	view->AddLine(BPoint(rect.right, rect.top + 1), rect.RightBottom(),
2694		bevelColor1);
2695	view->AddLine(rect.RightBottom(), BPoint(rect.left + 1, rect.bottom),
2696		bevelColor1);
2697
2698	// inset past internal bevel
2699	rect.InsetBy(1, 1);
2700
2701	// internal gloss outside
2702	view->AddLine(BPoint(rect.left, rect.bottom + 1), rect.LeftTop(),
2703		lightenMax); // come down an extra pixel
2704	view->AddLine(rect.LeftTop(), rect.RightTop(), lightenMax);
2705	view->AddLine(rect.RightTop(), rect.RightBottom(), base);
2706	view->AddLine(rect.RightBottom(), BPoint(rect.left + 1, rect.bottom),
2707		base); // compensate for extra pixel
2708
2709	// inset past gloss outside
2710	rect.InsetBy(1, 1);
2711
2712	// internal gloss inside
2713	view->AddLine(BPoint(rect.left, rect.bottom + 1), rect.LeftTop(),
2714		lightenMax); // come down an extra pixel
2715	view->AddLine(rect.LeftTop(), rect.RightTop(), lightenMax);
2716	view->AddLine(rect.RightTop(), rect.RightBottom(), buttonBgColor);
2717	view->AddLine(rect.RightBottom(), BPoint(rect.left + 1, rect.bottom),
2718		buttonBgColor); // compensate for extra pixel
2719
2720	// inset past gloss inside
2721	rect.InsetBy(1, 1);
2722
2723	view->EndLineArray();
2724
2725	view->PopState();
2726}
2727
2728
2729void
2730BeControlLook::_DrawButtonBackground(BView* view, BRect& rect,
2731	const BRect& updateRect, float, float, float, float, const rgb_color& base,
2732	bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
2733{
2734	if (!ShouldDraw(view, rect, updateRect))
2735		return;
2736
2737	// fill the button area
2738	view->SetHighColor(tint_color(base, B_LIGHTEN_1_TINT));
2739	view->FillRect(rect);
2740
2741	bool isEnabled = (flags & B_DISABLED) == 0;
2742	bool isActivated = (flags & B_ACTIVATED) != 0;
2743
2744	if (isEnabled && isActivated) {
2745		// invert if clicked without altering rect
2746		BRect invertRect(rect.InsetByCopy(-3, -3));
2747		view->SetDrawingMode(B_OP_INVERT);
2748		view->FillRect(invertRect);
2749	}
2750}
2751
2752
2753void
2754BeControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
2755	const rgb_color& base, uint32 flags)
2756{
2757	bool isEnabled = (flags & B_DISABLED) == 0;
2758
2759	BPoint position(rect.right - 8, rect.bottom - 8);
2760	BPoint triangle[3];
2761	triangle[0] = position + BPoint(-2.5, -0.5);
2762	triangle[1] = position + BPoint(2.5, -0.5);
2763	triangle[2] = position + BPoint(0.0, 2.0);
2764
2765	uint32 viewFlags = view->Flags();
2766	view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
2767
2768	rgb_color markerColor = isEnabled
2769		? tint_color(base, B_DARKEN_4_TINT)
2770		: tint_color(base, B_DARKEN_2_TINT);
2771
2772	view->SetHighColor(markerColor);
2773	view->FillTriangle(triangle[0], triangle[1], triangle[2]);
2774
2775	view->SetFlags(viewFlags);
2776}
2777
2778
2779void
2780BeControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
2781	const BRect& updateRect, float, float, float, float, const rgb_color& base,
2782	bool popupIndicator, uint32 flags)
2783{
2784	if (!ShouldDraw(view, rect, updateRect))
2785		return;
2786
2787	// BeControlLook does not support rounded corners and it never will
2788	if (popupIndicator) {
2789		BRect rightRect(rect);
2790		rightRect.left = rect.right - 10;
2791
2792		_DrawMenuFieldBackgroundInside(view, rect, updateRect,
2793			0, 0, 0, 0, base, flags, B_ALL_BORDERS);
2794		_DrawPopUpMarker(view, rightRect, base, flags);
2795	} else {
2796		_DrawMenuFieldBackgroundInside(view, rect, updateRect, 0, 0,
2797			0, 0, base, flags);
2798	}
2799}
2800
2801
2802void
2803BeControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
2804	const BRect& updateRect, float, float, float, float, const rgb_color& base,
2805	uint32 flags, uint32 borders)
2806{
2807	if (!ShouldDraw(view, rect, updateRect))
2808		return;
2809
2810	view->PushState();
2811
2812	view->ClipToRect(rect);
2813
2814	// flags
2815	bool isEnabled = (flags & B_DISABLED) == 0;
2816
2817	// colors
2818	rgb_color darken4;
2819	rgb_color darken1;
2820	rgb_color lighten1;
2821	rgb_color lighten2;
2822
2823	if (isEnabled) {
2824		darken4 = tint_color(base, B_DARKEN_4_TINT);
2825		darken1 = tint_color(base, B_DARKEN_1_TINT);
2826		lighten1 = tint_color(base, B_LIGHTEN_1_TINT);
2827		lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
2828	} else {
2829		darken4 = tint_color(base, B_DARKEN_2_TINT);
2830		darken1 = tint_color(base, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
2831		lighten1 = tint_color(base, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
2832		lighten2 = tint_color(base, B_LIGHTEN_1_TINT);
2833	}
2834
2835	// fill background
2836	view->SetHighColor(base);
2837	view->FillRect(rect);
2838
2839	// draw shadow lines around bottom and right sides
2840	view->BeginLineArray(6);
2841
2842	// bottom below item text, darker then BMenuBar
2843	// would normaly draw it
2844	view->AddLine(BPoint(rect.left, rect.bottom),
2845		BPoint(rect.left - 1, rect.bottom), darken4);
2846
2847	// bottom below popup marker
2848	view->AddLine(BPoint(rect.left, rect.bottom),
2849		BPoint(rect.right, rect.bottom), darken4);
2850	// right of popup marker
2851	view->AddLine(BPoint(rect.right, rect.bottom - 1),
2852		BPoint(rect.right, rect.top), darken4);
2853	// top above popup marker
2854	view->AddLine(BPoint(rect.left, rect.top),
2855		BPoint(rect.right - 2, rect.top), lighten2);
2856
2857	rect.top += 1;
2858	rect.bottom -= 1;
2859	rect.right -= 1;
2860
2861	// bottom below popup marker
2862	view->AddLine(BPoint(rect.left, rect.bottom),
2863		BPoint(rect.right, rect.bottom), darken1);
2864	// right of popup marker
2865	view->AddLine(BPoint(rect.right, rect.bottom - 1),
2866		BPoint(rect.right, rect.top), darken1);
2867
2868	view->EndLineArray();
2869
2870	rect.bottom -= 1;
2871	rect.right -= 1;
2872	view->SetHighColor(base);
2873	view->FillRect(rect);
2874
2875	view->PopState();
2876}
2877
2878
2879void
2880BeControlLook::_DrawScrollBarBackgroundFirst(BView* view, BRect& rect,
2881	const BRect& updateRect, const rgb_color& base, uint32 flags,
2882	orientation orientation)
2883{
2884	if (!ShouldDraw(view, rect, updateRect))
2885		return;
2886
2887	view->PushState();
2888
2889	view->ClipToRect(rect);
2890
2891	bool isEnabled = (flags & B_DISABLED) == 0;
2892	BRect orig(rect);
2893
2894	// border = 152
2895	rgb_color border = tint_color(base, B_DARKEN_2_TINT);
2896	rgb_color shine, shadow, bg;
2897	if (isEnabled) {
2898		// shine = 216, shadow = 184, bg = 200
2899		shine = base;
2900		shadow = tint_color(base, B_DARKEN_1_TINT);
2901		bg = tint_color(base, 1.074);
2902	} else {
2903		// shine = 255, shadow = bg = 240
2904		shine = tint_color(base, B_LIGHTEN_MAX_TINT);
2905		rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
2906		lighten2.red++; lighten2.green++; lighten2.blue++;
2907			// lighten2 = 239, 240 = 239 + 1
2908		shadow = bg = lighten2;
2909	}
2910
2911	// fill background, we'll draw arrows and thumb on top
2912	view->SetDrawingMode(B_OP_COPY);
2913
2914	view->BeginLineArray(5);
2915	if (orientation == B_VERTICAL) {
2916		// left shadow
2917		view->AddLine(rect.LeftTop(), rect.LeftBottom(),
2918			isEnabled ? shadow : shine);
2919		rect.left++;
2920		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shadow);
2921		rect.left++;
2922		// top shadow
2923		view->AddLine(rect.LeftTop(), rect.RightTop(),
2924			isEnabled ? shadow : shine);
2925		rect.top++;
2926		view->AddLine(rect.LeftTop(), rect.RightTop(), shadow);
2927		rect.top++;
2928		// shine
2929		view->AddLine(rect.RightTop(), rect.RightBottom(), base);
2930		rect.right--;
2931	} else {
2932		// left shadow
2933		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shadow);
2934		rect.left++;
2935		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shadow);
2936		rect.left++;
2937		// top shadow
2938		view->AddLine(rect.LeftTop(), rect.RightTop(), shadow);
2939		rect.top++;
2940		view->AddLine(rect.LeftTop(), rect.RightTop(), shadow);
2941		rect.top++;
2942		// shine
2943		view->AddLine(rect.LeftBottom(), rect.RightBottom(), base);
2944		rect.bottom--;
2945	}
2946	view->EndLineArray();
2947
2948	// fill bg
2949	view->SetHighColor(bg);
2950	view->FillRect(rect);
2951
2952	rect = orig;
2953
2954	// draw border last
2955	view->BeginLineArray(2);
2956	if (orientation == B_VERTICAL) {
2957		// top border
2958		view->AddLine(rect.LeftTop(), rect.RightTop(), border);
2959		// bottom border
2960		view->AddLine(rect.LeftBottom(), rect.RightBottom(), border);
2961	} else {
2962		// left border
2963		view->AddLine(rect.LeftTop(), rect.LeftBottom(), border);
2964		// right border
2965		view->AddLine(rect.RightTop(), rect.RightBottom(), border);
2966	}
2967	view->EndLineArray();
2968
2969	view->PopState();
2970}
2971
2972
2973void
2974BeControlLook::_DrawScrollBarBackgroundSecond(BView* view, BRect& rect,
2975	const BRect& updateRect, const rgb_color& base, uint32 flags,
2976	orientation orientation)
2977{
2978	if (!ShouldDraw(view, rect, updateRect))
2979		return;
2980
2981	view->PushState();
2982
2983	view->ClipToRect(rect);
2984
2985	bool isEnabled = (flags & B_DISABLED) == 0;
2986
2987	BRect orig(rect);
2988
2989	// border = 152
2990	rgb_color border = tint_color(base, B_DARKEN_2_TINT);
2991	rgb_color darkBorder, shine, shadow, bg;
2992	if (isEnabled) {
2993		// darkBorder = 96 shine = 216, shadow = 184, bg = 200
2994		darkBorder = tint_color(base, B_DARKEN_4_TINT);
2995		shine = base;
2996		shadow = tint_color(base, B_DARKEN_1_TINT);
2997		bg = tint_color(base, 1.074);
2998	} else {
2999		// darkBorder = 184, shine = 255, shadow = bg = 240
3000		darkBorder = tint_color(base, B_DARKEN_1_TINT);
3001		shine = tint_color(base, B_LIGHTEN_MAX_TINT);
3002		rgb_color lighten2 = tint_color(base, B_LIGHTEN_2_TINT);
3003		lighten2.red++; lighten2.green++; lighten2.blue++;
3004			// lighten2 = 239, 240 = 239 + 1
3005		shadow = bg = lighten2;
3006	}
3007
3008	// fill background, we'll draw arrows and thumb on top
3009	view->SetDrawingMode(B_OP_COPY);
3010
3011	view->BeginLineArray(3);
3012	if (orientation == B_VERTICAL) {
3013		// left shadow (no top shadow on second rect)
3014		view->AddLine(rect.LeftTop(), rect.LeftBottom(),
3015			isEnabled ? shadow : shine);
3016		rect.left++;
3017		view->AddLine(rect.LeftTop(), rect.LeftBottom(), shadow);
3018		rect.left++;
3019		// shine (use base color)
3020		view->AddLine(rect.RightTop(), rect.RightBottom(), base);
3021		rect.right--;
3022	} else {
3023		// left shadow (no top shadow on second rect)
3024		view->AddLine(rect.LeftTop(), rect.RightTop(),
3025			isEnabled ? shadow : shine);
3026		rect.top++;
3027		view->AddLine(rect.LeftTop(), rect.RightTop(), shadow);
3028		rect.top++;
3029		// shine (use base color)
3030		view->AddLine(rect.LeftBottom(), rect.RightBottom(), base);
3031		rect.bottom--;
3032	}
3033	view->EndLineArray();
3034
3035	// fill bg
3036	view->SetHighColor(bg);
3037	view->FillRect(rect);
3038
3039	rect = orig;
3040
3041	// draw border over bg
3042	view->BeginLineArray(2);
3043	if (orientation == B_VERTICAL) {
3044		// top border
3045		view->AddLine(rect.LeftTop(), rect.RightTop(), darkBorder);
3046		// bottom border
3047		view->AddLine(rect.LeftBottom(), rect.RightBottom(), border);
3048	} else {
3049		// left border
3050		view->AddLine(rect.LeftTop(), rect.LeftBottom(), darkBorder);
3051		// right border
3052		view->AddLine(rect.RightTop(), rect.RightBottom(), border);
3053	}
3054	view->EndLineArray();
3055
3056	view->PopState();
3057}
3058
3059void
3060BeControlLook::_DrawScrollBarKnobDot(BView* view,
3061	float hcenter, float vmiddle, rgb_color dark, rgb_color light,
3062	orientation orientation)
3063{
3064	// orientation is unused
3065	view->BeginLineArray(4);
3066	view->AddLine(BPoint(hcenter + 2, vmiddle - 2),
3067		BPoint(hcenter + 2, vmiddle + 2), dark);
3068	view->AddLine(BPoint(hcenter + 2, vmiddle + 2),
3069		BPoint(hcenter - 2, vmiddle + 2), dark);
3070	view->AddLine(BPoint(hcenter - 2, vmiddle + 1),
3071		BPoint(hcenter - 2, vmiddle - 1), light);
3072	view->AddLine(BPoint(hcenter - 2, vmiddle - 1),
3073		BPoint(hcenter - 2, vmiddle + 1), light);
3074	view->EndLineArray();
3075}
3076
3077
3078void
3079BeControlLook::_DrawScrollBarKnobLine(BView* view,
3080	float hcenter, float vmiddle, rgb_color dark, rgb_color light,
3081	orientation orientation)
3082{
3083	if (orientation == B_HORIZONTAL) {
3084		view->BeginLineArray(4);
3085		view->AddLine(BPoint(hcenter, vmiddle + 3),
3086			BPoint(hcenter + 1, vmiddle + 3), dark);
3087		view->AddLine(BPoint(hcenter + 1, vmiddle + 3),
3088			BPoint(hcenter + 1, vmiddle - 3), dark);
3089		view->AddLine(BPoint(hcenter, vmiddle - 3),
3090			BPoint(hcenter - 1, vmiddle - 3), light);
3091		view->AddLine(BPoint(hcenter - 1, vmiddle - 3),
3092			BPoint(hcenter - 1, vmiddle + 3), light);
3093		view->EndLineArray();
3094	} else {
3095		view->BeginLineArray(4);
3096		view->AddLine(BPoint(hcenter + 3, vmiddle),
3097			BPoint(hcenter + 3, vmiddle + 1), dark);
3098		view->AddLine(BPoint(hcenter + 3, vmiddle + 1),
3099			BPoint(hcenter - 3, vmiddle + 1), dark);
3100		view->AddLine(BPoint(hcenter - 3, vmiddle),
3101			BPoint(hcenter - 3, vmiddle - 1), light);
3102		view->AddLine(BPoint(hcenter - 3, vmiddle - 1),
3103			BPoint(hcenter + 3, vmiddle - 1), light);
3104		view->EndLineArray();
3105	}
3106}
3107
3108
3109void
3110BeControlLook::_DrawFrame(BView* view, BRect& rect, const rgb_color& left,
3111	const rgb_color& top, const rgb_color& right, const rgb_color& bottom,
3112	uint32 borders)
3113{
3114	view->BeginLineArray(4);
3115
3116	// draw in reverse so that bottom and right corners cover top and left
3117
3118	if ((borders & B_BOTTOM_BORDER) != 0) {
3119		view->AddLine(
3120			BPoint(rect.left, rect.bottom),
3121			BPoint(rect.right, rect.bottom), bottom);
3122		rect.bottom--;
3123	}
3124	if ((borders & B_RIGHT_BORDER) != 0) {
3125		view->AddLine(
3126			BPoint(rect.right, rect.top),
3127			BPoint(rect.right, rect.bottom), right);
3128		rect.right--;
3129	}
3130	if ((borders & B_TOP_BORDER) != 0) {
3131		view->AddLine(
3132			BPoint(rect.left, rect.top),
3133			BPoint(rect.right, rect.top), top);
3134		rect.top++;
3135	}
3136	if ((borders & B_LEFT_BORDER) != 0) {
3137		view->AddLine(
3138			BPoint(rect.left, rect.bottom),
3139			BPoint(rect.left, rect.top), left);
3140		rect.left++;
3141	}
3142
3143	view->EndLineArray();
3144}
3145
3146} // namespace BPrivate
3147
3148
3149extern "C" BControlLook* (instantiate_control_look)(image_id id)
3150{
3151	return new (std::nothrow)BPrivate::BeControlLook(id);
3152}
3153