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