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