xref: /haiku/src/kits/interface/Button.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 /*
2  *	Copyright 2001-2005, Haiku.
3  *  Distributed under the terms of the MIT License.
4  *
5  *	Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Mike Wilber
8  *		Stefano Ceccherini (burton666@libero.it)
9  *		Ivan Tonizza
10  *		Stephan Aßmus, <superstippi@gmx.de>
11  */
12 
13 
14 #include <Button.h>
15 #include <Font.h>
16 #include <String.h>
17 #include <Window.h>
18 
19 
20 BButton::BButton(BRect frame, const char *name, const char *label, BMessage *message,
21 				  uint32 resizingMode, uint32 flags)
22 	:	BControl(frame, name, label, message, resizingMode, flags |= B_WILL_DRAW),
23 		fDrawAsDefault(false)
24 {
25 	// Resize to minimum height if needed
26 	font_height fh;
27 	GetFontHeight(&fh);
28 	float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent);
29 	if (Bounds().Height() < minHeight)
30 		ResizeTo(Bounds().Width(), minHeight);
31 }
32 
33 
34 BButton::~BButton()
35 {
36 }
37 
38 
39 BButton::BButton(BMessage *archive)
40 	:	BControl (archive)
41 {
42 	if (archive->FindBool("_default", &fDrawAsDefault) != B_OK)
43 		fDrawAsDefault = false;
44 }
45 
46 
47 BArchivable *
48 BButton::Instantiate(BMessage *archive)
49 {
50 	if (validate_instantiation(archive, "BButton"))
51 		return new BButton(archive);
52 
53 	return NULL;
54 }
55 
56 
57 status_t
58 BButton::Archive(BMessage* archive, bool deep) const
59 {
60 	status_t err = BControl::Archive(archive, deep);
61 
62 	if (err != B_OK)
63 		return err;
64 
65 	if (IsDefault())
66 		err = archive->AddBool("_default", true);
67 
68 	return err;
69 }
70 
71 
72 void
73 BButton::Draw(BRect updateRect)
74 {
75 	font_height fh;
76 	GetFontHeight(&fh);
77 
78 	const BRect bounds = Bounds();
79 	BRect rect = bounds;
80 
81 	const bool enabled = IsEnabled();
82 	const bool pushed = Value() == B_CONTROL_ON;
83 #if 0
84 	// Default indicator
85 	if (IsDefault())
86 		rect = DrawDefault(rect, enabled);
87 	else
88 		rect.InsetBy(1.0f, 1.0f);
89 
90 	BRect fillArea = rect;
91 	fillArea.InsetBy(3.0f, 3.0f);
92 
93 	BString text = Label();
94 
95 #if 1
96 	// Label truncation
97 	BFont font;
98 	GetFont(&font);
99 	font.TruncateString(&text, B_TRUNCATE_END, fillArea.Width());
100 #endif
101 
102 	// Label position
103 	const float stringWidth = StringWidth(text.String());
104 	const float x = (bounds.right - stringWidth) / 2.0f;
105 	const float labelY = bounds.top
106 		+ ((bounds.Height() - fh.ascent - fh.descent) / 2.0f)
107 		+ fh.ascent +  1.0f;
108 	const float focusLineY = labelY + fh.descent;
109 
110 	/* speed trick:
111 	   if the focus changes but the button is not pressed then we can
112 	   redraw only the focus line,
113 	   if the focus changes and the button is pressed invert the internal rect
114 	   this block takes care of all the focus changes
115 	*/
116 	if (IsFocusChanging()) {
117 		if (pushed) {
118 			rect.InsetBy(2.0, 2.0);
119 			InvertRect(rect);
120 		} else
121 			DrawFocusLine(x, focusLineY, stringWidth, IsFocus() && Window()->IsActive());
122 
123 		return;
124 	}
125 
126 	// Colors
127 	const rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
128 	const rgb_color buttonBgColor=tint_color(panelBgColor, B_LIGHTEN_1_TINT);
129 	const rgb_color maxLightColor=tint_color(panelBgColor, B_LIGHTEN_MAX_TINT);
130 	const rgb_color maxShadowColor=tint_color(panelBgColor, B_DARKEN_MAX_TINT);
131 	const rgb_color darkBorderColor = tint_color(panelBgColor,
132 		enabled ? B_DARKEN_4_TINT : B_DARKEN_2_TINT);
133 	const rgb_color firstBevelColor = enabled ? tint_color(panelBgColor, B_DARKEN_2_TINT)
134 		: panelBgColor;
135 	const rgb_color cornerColor = IsDefault() ? firstBevelColor : panelBgColor;
136 
137 	// Fill the button area
138 	SetHighColor(buttonBgColor);
139 	FillRect(fillArea);
140 
141 	// external border
142 	SetHighColor(darkBorderColor);
143 	StrokeRect(rect);
144 
145 	BeginLineArray(14);
146 
147 	// Corners
148 	AddLine(rect.LeftTop(), rect.LeftTop(), cornerColor);
149 	AddLine(rect.LeftBottom(), rect.LeftBottom(), cornerColor);
150 	AddLine(rect.RightTop(), rect.RightTop(), cornerColor);
151 	AddLine(rect.RightBottom(), rect.RightBottom(), cornerColor);
152 
153 	rect.InsetBy(1.0f,1.0f);
154 
155 	// Shadow
156 	AddLine(rect.LeftBottom(), rect.RightBottom(), firstBevelColor);
157 	AddLine(rect.RightBottom(), rect.RightTop(), firstBevelColor);
158 	// Light
159 	AddLine(rect.LeftTop(), rect.LeftBottom(),buttonBgColor);
160 	AddLine(rect.LeftTop(), rect.RightTop(), buttonBgColor);
161 
162 	rect.InsetBy(1.0f, 1.0f);
163 
164 	// Shadow
165 	AddLine(rect.LeftBottom(), rect.RightBottom(), panelBgColor);
166 	AddLine(rect.RightBottom(), rect.RightTop(), panelBgColor);
167 	// Light
168 	AddLine(rect.LeftTop(), rect.LeftBottom(),maxLightColor);
169 	AddLine(rect.LeftTop(), rect.RightTop(), maxLightColor);
170 
171 	rect.InsetBy(1.0f,1.0f);
172 
173 	// Light
174 	AddLine(rect.LeftTop(), rect.LeftBottom(),maxLightColor);
175 	AddLine(rect.LeftTop(), rect.RightTop(), maxLightColor);
176 
177 	EndLineArray();
178 
179 	// Invert if clicked
180 	if (enabled && pushed) {
181 		rect.InsetBy(-2.0f, -2.0f);
182 		InvertRect(rect);
183 	}
184 
185 	// Label color
186 	if (enabled) {
187 		if (pushed) {
188 			SetHighColor(maxLightColor);
189 			SetLowColor(maxShadowColor);
190 		} else {
191 			SetHighColor(maxShadowColor);
192 			SetLowColor(tint_color(panelBgColor, B_LIGHTEN_2_TINT));
193 		}
194 	} else {
195 		SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT));
196 		SetLowColor(tint_color(panelBgColor, B_LIGHTEN_2_TINT));
197 	}
198 
199 	// Draw the label
200 	DrawString(text.String(), BPoint(x, labelY));
201 
202 	// Focus line
203 	if (enabled && IsFocus() && Window()->IsActive() && !pushed)
204 		DrawFocusLine(x,focusLineY,stringWidth,true);
205 #else
206 	// Default indicator
207 	if (IsDefault())
208 		rect = DrawDefault(rect, enabled);
209 
210 	BRect fillArea = rect;
211 	fillArea.InsetBy(3.0, 3.0);
212 
213 	BString text = Label();
214 
215 #if 1
216 	// Label truncation
217 	BFont font;
218 	GetFont(&font);
219 	font.TruncateString(&text, B_TRUNCATE_END, fillArea.Width() - 4);
220 #endif
221 
222 	// Label position
223 	const float stringWidth = StringWidth(text.String());
224 	const float x = (rect.right - stringWidth) / 2.0;
225 	const float labelY = bounds.top
226 		+ ((bounds.Height() - fh.ascent - fh.descent) / 2.0)
227 		+ fh.ascent +  1.0;
228 	const float focusLineY = labelY + fh.descent;
229 
230 	/* speed trick:
231 	   if the focus changes but the button is not pressed then we can
232 	   redraw only the focus line,
233 	   if the focus changes and the button is pressed invert the internal rect
234 	   this block takes care of all the focus changes
235 	*/
236 	if (IsFocusChanging()) {
237 		if (pushed) {
238 			rect.InsetBy(2.0, 2.0);
239 			InvertRect(rect);
240 		} else
241 			DrawFocusLine(x, focusLineY, stringWidth, IsFocus() && Window()->IsActive());
242 
243 		return;
244 	}
245 
246 	// colors
247 	const rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
248 	const rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT);
249 	const rgb_color lightColor = tint_color(panelBgColor, enabled ? B_LIGHTEN_2_TINT
250 																  : B_LIGHTEN_1_TINT);
251 	const rgb_color maxLightColor = tint_color(panelBgColor, enabled ? B_LIGHTEN_MAX_TINT
252 																	 : B_LIGHTEN_2_TINT);
253 	const rgb_color maxShadowColor = tint_color(panelBgColor, B_DARKEN_MAX_TINT);
254 
255 	rgb_color dark1BorderColor = tint_color(panelBgColor, enabled ? B_DARKEN_3_TINT
256 																  : B_DARKEN_1_TINT);
257 	rgb_color dark2BorderColor = tint_color(panelBgColor, enabled ? B_DARKEN_4_TINT
258 																  : B_DARKEN_2_TINT);
259 
260 	rgb_color bevelColor1 = enabled ? tint_color(panelBgColor, B_DARKEN_2_TINT)
261 									: panelBgColor;
262 	rgb_color bevelColor2 = enabled ? panelBgColor : buttonBgColor;
263 
264 	rgb_color borderBevelShadow;
265 	rgb_color borderBevelLight;
266 	if (IsDefault()) {
267 		rgb_color focusColor = dark1BorderColor;
268 
269 		borderBevelShadow = enabled ? tint_color(focusColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2)
270 									: focusColor;
271 		borderBevelLight = enabled ? tint_color(focusColor, B_LIGHTEN_1_TINT) : focusColor;
272 
273 		borderBevelLight.red = (borderBevelLight.red + panelBgColor.red) / 2;
274 		borderBevelLight.green = (borderBevelLight.green + panelBgColor.green) / 2;
275 		borderBevelLight.blue = (borderBevelLight.blue + panelBgColor.blue) / 2;
276 
277 		dark1BorderColor = tint_color(focusColor, enabled ? B_DARKEN_3_TINT
278 														  : B_DARKEN_1_TINT);
279 		dark2BorderColor = tint_color(focusColor, enabled ? B_DARKEN_4_TINT
280 														  : B_DARKEN_2_TINT);
281 	} else {
282 		borderBevelShadow = enabled ? tint_color(panelBgColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2)
283 									: panelBgColor;
284 		borderBevelLight = enabled ? buttonBgColor : panelBgColor;
285 	}
286 
287 	// fill the button area
288 	SetHighColor(buttonBgColor);
289 	FillRect(fillArea);
290 
291 	BeginLineArray(16);
292 	// bevel around external border
293 	AddLine(BPoint(rect.left, rect.bottom),
294 			BPoint(rect.left, rect.top), borderBevelShadow);
295 	AddLine(BPoint(rect.left + 1, rect.top),
296 			BPoint(rect.right, rect.top), borderBevelShadow);
297 
298 	AddLine(BPoint(rect.right, rect.top + 1),
299 			BPoint(rect.right, rect.bottom), borderBevelLight);
300 	AddLine(BPoint(rect.left + 1, rect.bottom),
301 			BPoint(rect.right - 1, rect.bottom), borderBevelLight);
302 
303 	rect.InsetBy(1.0, 1.0);
304 
305 	// external border
306 	AddLine(BPoint(rect.left, rect.bottom),
307 			BPoint(rect.left, rect.top), dark1BorderColor);
308 	AddLine(BPoint(rect.left + 1, rect.top),
309 			BPoint(rect.right, rect.top), dark1BorderColor);
310 	AddLine(BPoint(rect.right, rect.top + 1),
311 			BPoint(rect.right, rect.bottom), dark2BorderColor);
312 	AddLine(BPoint(rect.right - 1, rect.bottom),
313 			BPoint(rect.left + 1, rect.bottom), dark2BorderColor);
314 
315 	rect.InsetBy(1.0, 1.0);
316 
317 	// Light
318 	AddLine(BPoint(rect.left, rect.top),
319 			BPoint(rect.left, rect.bottom), lightColor);
320 	AddLine(BPoint(rect.left + 1, rect.top),
321 			BPoint(rect.right, rect.top), lightColor);
322 	// Shadow
323 	AddLine(BPoint(rect.left + 1, rect.bottom),
324 			BPoint(rect.right, rect.bottom), bevelColor1);
325 	AddLine(BPoint(rect.right, rect.bottom - 1),
326 			BPoint(rect.right, rect.top + 1), bevelColor1);
327 
328 	rect.InsetBy(1.0, 1.0);
329 
330 	// Light
331 	AddLine(BPoint(rect.left, rect.top),
332 			BPoint(rect.left, rect.bottom), maxLightColor);
333 	AddLine(BPoint(rect.left + 1, rect.top),
334 			BPoint(rect.right, rect.top), maxLightColor);
335 	// Shadow
336 	AddLine(BPoint(rect.left + 1, rect.bottom),
337 			BPoint(rect.right, rect.bottom), bevelColor2);
338 	AddLine(BPoint(rect.right, rect.bottom - 1),
339 			BPoint(rect.right, rect.top + 1), bevelColor2);
340 
341 	rect.InsetBy(1.0,1.0);
342 
343 	EndLineArray();
344 
345 	// Invert if clicked
346 	if (enabled && pushed) {
347 		rect.InsetBy(-2.0, -2.0);
348 		InvertRect(rect);
349 	}
350 
351 	// Label color
352 	if (enabled) {
353 		if (pushed) {
354 			SetHighColor(maxLightColor);
355 			SetLowColor(255 - buttonBgColor.red,
356 						255 - buttonBgColor.green,
357 						255 - buttonBgColor.blue);
358 		} else {
359 			SetHighColor(maxShadowColor);
360 			SetLowColor(buttonBgColor);
361 		}
362 	} else {
363 		SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT));
364 		SetLowColor(buttonBgColor);
365 	}
366 
367 	// Draw the label
368 	DrawString(text.String(), BPoint(x, labelY));
369 
370 	// Focus line
371 	if (enabled && IsFocus() && Window()->IsActive() && !pushed)
372 		DrawFocusLine(x, focusLineY, stringWidth, true);
373 #endif
374 }
375 
376 
377 void
378 BButton::MouseDown(BPoint point)
379 {
380 	if (!IsEnabled())
381 		return;
382 
383 	SetValue(B_CONTROL_ON);
384 
385 	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
386  		SetTracking(true);
387  		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
388  	} else {
389 		BRect bounds = Bounds();
390 		uint32 buttons;
391 
392 		do {
393 			Window()->UpdateIfNeeded();
394 			snooze(40000);
395 
396 			GetMouse(&point, &buttons, true);
397 
398  			bool inside = bounds.Contains(point);
399 
400 			if ((Value() == B_CONTROL_ON) != inside)
401 				SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
402 		} while (buttons != 0);
403 
404 		if (Value() == B_CONTROL_ON)
405 			Invoke();
406 	}
407 }
408 
409 
410 void
411 BButton::AttachedToWindow()
412 {
413 	BControl::AttachedToWindow();
414 		// low color will now be the parents view color
415 
416 	if (IsDefault())
417 		Window()->SetDefaultButton(this);
418 
419 	SetViewColor(B_TRANSPARENT_COLOR);
420 }
421 
422 
423 void
424 BButton::KeyDown(const char *bytes, int32 numBytes)
425 {
426 	if (*bytes == B_ENTER || *bytes == B_SPACE) {
427 		if (!IsEnabled())
428 			return;
429 
430 		SetValue(B_CONTROL_ON);
431 
432 		// make sure the user saw that
433 		Window()->UpdateIfNeeded();
434 		snooze(25000);
435 
436 		Invoke();
437 
438 	} else
439 		BControl::KeyDown(bytes, numBytes);
440 }
441 
442 
443 void
444 BButton::MakeDefault(bool flag)
445 {
446 	BButton *oldDefault = NULL;
447 	BWindow *window = Window();
448 
449 	if (window)
450 		oldDefault = window->DefaultButton();
451 
452 	if (flag) {
453 		if (fDrawAsDefault && oldDefault == this)
454 			return;
455 
456 		if (!fDrawAsDefault) {
457 			fDrawAsDefault = true;
458 
459 			ResizeBy(6.0f, 6.0f);
460 			MoveBy(-3.0f, -3.0f);
461 		}
462 
463 		if (window && oldDefault != this)
464 			window->SetDefaultButton(this);
465 	} else {
466 		if (!fDrawAsDefault)
467 			return;
468 
469 		fDrawAsDefault = false;
470 
471 		ResizeBy(-6.0f, -6.0f);
472 		MoveBy(3.0f, 3.0f);
473 
474 		if (window && oldDefault == this)
475 			window->SetDefaultButton(NULL);
476 	}
477 }
478 
479 
480 void
481 BButton::SetLabel(const char *string)
482 {
483 	BControl::SetLabel(string);
484 }
485 
486 
487 bool
488 BButton::IsDefault() const
489 {
490 	return fDrawAsDefault;
491 }
492 
493 
494 void
495 BButton::MessageReceived(BMessage *message)
496 {
497 	BControl::MessageReceived(message);
498 }
499 
500 
501 void
502 BButton::WindowActivated(bool active)
503 {
504 	BControl::WindowActivated(active);
505 }
506 
507 
508 void
509 BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
510 {
511 	if (!IsTracking())
512 		return;
513 
514 	bool inside = Bounds().Contains(point);
515 
516 	if ((Value() == B_CONTROL_ON) != inside)
517 		SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
518 }
519 
520 
521 void
522 BButton::MouseUp(BPoint point)
523 {
524 	if (!IsTracking())
525 		return;
526 
527 	if (Bounds().Contains(point))
528 		Invoke();
529 
530 	SetTracking(false);
531 }
532 
533 
534 void
535 BButton::DetachedFromWindow()
536 {
537 	BControl::DetachedFromWindow();
538 }
539 
540 
541 void
542 BButton::SetValue(int32 value)
543 {
544 	if (value != Value()) {
545 		BControl::SetValue(value);
546 		Invalidate();
547 	}
548 }
549 
550 
551 void
552 BButton::GetPreferredSize(float *_width, float *_height)
553 {
554 	if (_height) {
555 		font_height fontHeight;
556 		GetFontHeight(&fontHeight);
557 
558 		*_height = 12.0f + (float)ceil(fontHeight.ascent + fontHeight.descent)
559 			+ (fDrawAsDefault ? 6.0f : 0);
560 	}
561 
562 	if (_width) {
563 		float width = 20.0f + (float)ceil(StringWidth(Label()));
564 		if (width < 75.0f)
565 			width = 75.0f;
566 
567 		if (fDrawAsDefault)
568 			width += 6.0f;
569 
570 		*_width = width;
571 	}
572 }
573 
574 
575 void
576 BButton::ResizeToPreferred()
577 {
578 	 BControl::ResizeToPreferred();
579 }
580 
581 
582 status_t
583 BButton::Invoke(BMessage *message)
584 {
585 	Sync();
586 	snooze(50000);
587 
588 	status_t err = BControl::Invoke(message);
589 
590 	SetValue(B_CONTROL_OFF);
591 
592 	return err;
593 }
594 
595 
596 void
597 BButton::FrameMoved(BPoint newLocation)
598 {
599 	BControl::FrameMoved(newLocation);
600 }
601 
602 
603 void
604 BButton::FrameResized(float width, float height)
605 {
606 	BControl::FrameResized(width, height);
607 }
608 
609 
610 void
611 BButton::MakeFocus(bool focused)
612 {
613 	BControl::MakeFocus(focused);
614 }
615 
616 
617 void
618 BButton::AllAttached()
619 {
620 	BControl::AllAttached();
621 }
622 
623 
624 void
625 BButton::AllDetached()
626 {
627 	BControl::AllDetached();
628 }
629 
630 
631 BHandler *
632 BButton::ResolveSpecifier(BMessage *message, int32 index,
633 									BMessage *specifier, int32 what,
634 									const char *property)
635 {
636 	return BControl::ResolveSpecifier(message, index, specifier, what, property);
637 }
638 
639 
640 status_t
641 BButton::GetSupportedSuites(BMessage *message)
642 {
643 	return BControl::GetSupportedSuites(message);
644 }
645 
646 
647 status_t
648 BButton::Perform(perform_code d, void *arg)
649 {
650 	return BControl::Perform(d, arg);
651 }
652 
653 
654 void BButton::_ReservedButton1() {}
655 void BButton::_ReservedButton2() {}
656 void BButton::_ReservedButton3() {}
657 
658 
659 BButton &
660 BButton::operator=(const BButton &)
661 {
662 	return *this;
663 }
664 
665 
666 BRect
667 BButton::DrawDefault(BRect bounds, bool enabled)
668 {
669 #if 0
670 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR),
671 	lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT),
672 	darken1 = tint_color(no_tint, B_DARKEN_1_TINT);
673 
674 	rgb_color borderColor;
675 	if (enabled)
676 		borderColor = tint_color(no_tint, B_DARKEN_4_TINT);
677 	else
678 		borderColor = darken1;
679 
680 	// Dark border
681 	BeginLineArray(4);
682 	AddLine(BPoint(bounds.left, bounds.bottom - 1.0f),
683 		BPoint(bounds.left, bounds.top + 1.0f), borderColor);
684 	AddLine(BPoint(bounds.left + 1.0f, bounds.top),
685 		BPoint(bounds.right - 1.0f, bounds.top), borderColor);
686 	AddLine(BPoint(bounds.right, bounds.top + 1.0f),
687 		BPoint(bounds.right, bounds.bottom - 1.0f), borderColor);
688 	AddLine(BPoint(bounds.left + 1.0f, bounds.bottom),
689 		BPoint(bounds.right - 1.0f, bounds.bottom), borderColor);
690 	EndLineArray();
691 
692 	if (enabled) {
693 		// Bevel
694 		bounds.InsetBy(1.0f, 1.0f);
695 		SetHighColor(darken1);
696 		StrokeRect(bounds);
697 	}
698 
699 	bounds.InsetBy(1.0f, 1.0f);
700 
701 	// Filling
702 	float inset = enabled? 2.0f : 3.0f;
703 	SetHighColor(lighten1);
704 
705 	FillRect(BRect(bounds.left, bounds.top,
706 		bounds.right, bounds.top+inset-1.0f));
707 	FillRect(BRect(bounds.left, bounds.bottom-inset+1.0f,
708 		bounds.right, bounds.bottom));
709 	FillRect(BRect(bounds.left, bounds.top+inset-1.0f,
710 		bounds.left+inset-1.0f, bounds.bottom-inset+1.0f));
711 	FillRect(BRect(bounds.right-inset+1.0f, bounds.top+inset-1.0f,
712 		bounds.right, bounds.bottom-inset+1.0f));
713 
714 	bounds.InsetBy(inset,inset);
715 
716 	return bounds;
717 #else
718 	rgb_color low = LowColor();
719 	rgb_color focusColor = tint_color(low, enabled ? (B_DARKEN_1_TINT + B_DARKEN_2_TINT) / 2
720 												   : (B_NO_TINT + B_DARKEN_1_TINT) / 2);
721 
722 	SetHighColor(focusColor);
723 
724 	StrokeRect(bounds, B_SOLID_LOW);
725 	bounds.InsetBy(1.0, 1.0);
726 	StrokeRect(bounds);
727 	bounds.InsetBy(1.0, 1.0);
728 	StrokeRect(bounds);
729 	bounds.InsetBy(1.0, 1.0);
730 
731 	return bounds;
732 #endif
733 }
734 
735 
736 status_t
737 BButton::Execute()
738 {
739 	if (!IsEnabled())
740 		return B_ERROR;
741 
742 	SetValue(B_CONTROL_ON);
743 	return Invoke();
744 }
745 
746 
747 void
748 BButton::DrawFocusLine(float x, float y, float width, bool visible)
749 {
750 	if (visible)
751 		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
752 	else {
753 		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
754 			B_LIGHTEN_1_TINT));
755 	}
756 
757 	// Blue Line
758 	StrokeLine(BPoint(x, y), BPoint(x + width, y));
759 
760 	if (visible)
761 		SetHighColor(255, 255, 255);
762 	// White Line
763 	StrokeLine(BPoint(x, y + 1.0f), BPoint(x + width, y + 1.0f));
764 }
765