xref: /haiku/src/kits/interface/Button.cpp (revision 0e50eab75e25d0d82090e22dbff766dfaa6f5e86)
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 	rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
248 	rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT);
249 	rgb_color lightColor;
250 	rgb_color maxLightColor;
251 	rgb_color maxShadowColor = tint_color(panelBgColor, B_DARKEN_MAX_TINT);
252 
253 	rgb_color dark1BorderColor;
254 	rgb_color dark2BorderColor;
255 
256 	rgb_color bevelColor1;
257 	rgb_color bevelColor2;
258 	rgb_color bevelColorRBCorner;
259 
260 	rgb_color borderBevelShadow;
261 	rgb_color borderBevelLight;
262 
263 	if (enabled) {
264 		lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT);
265 		maxLightColor = tint_color(panelBgColor, B_LIGHTEN_MAX_TINT);
266 
267 		dark1BorderColor = tint_color(panelBgColor, B_DARKEN_3_TINT);
268 		dark2BorderColor = tint_color(panelBgColor, B_DARKEN_4_TINT);
269 
270 		bevelColor1 = tint_color(panelBgColor, B_DARKEN_2_TINT);
271 		bevelColor2 = panelBgColor;
272 
273 		if (IsDefault()) {
274 			borderBevelShadow = tint_color(dark1BorderColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2);
275 			borderBevelLight = tint_color(dark1BorderColor, B_LIGHTEN_1_TINT);
276 
277 			borderBevelLight.red = (borderBevelLight.red + panelBgColor.red) / 2;
278 			borderBevelLight.green = (borderBevelLight.green + panelBgColor.green) / 2;
279 			borderBevelLight.blue = (borderBevelLight.blue + panelBgColor.blue) / 2;
280 
281 			dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_3_TINT);
282 			dark2BorderColor = tint_color(dark1BorderColor, B_DARKEN_4_TINT);
283 
284 			bevelColorRBCorner = borderBevelShadow;
285 		} else {
286 			borderBevelShadow = tint_color(panelBgColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2);
287 			borderBevelLight = buttonBgColor;
288 
289 			bevelColorRBCorner = dark1BorderColor;
290 		}
291 	} else {
292 		lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT);
293 		maxLightColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT);
294 
295 		dark1BorderColor = tint_color(panelBgColor, B_DARKEN_1_TINT);
296 		dark2BorderColor = tint_color(panelBgColor, B_DARKEN_2_TINT);
297 
298 		bevelColor1 = panelBgColor;
299 		bevelColor2 = buttonBgColor;
300 
301 		if (IsDefault()) {
302 			borderBevelShadow = dark1BorderColor;
303 			borderBevelLight = panelBgColor;
304 			dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_1_TINT);
305 			dark2BorderColor = tint_color(dark1BorderColor, 1.16);
306 
307 		} else {
308 			borderBevelShadow = panelBgColor;
309 			borderBevelLight = panelBgColor;
310 		}
311 
312 		bevelColorRBCorner = tint_color(panelBgColor, 1.08);;
313 	}
314 
315 	// fill the button area
316 	SetHighColor(buttonBgColor);
317 	FillRect(fillArea);
318 
319 	BeginLineArray(22);
320 	// bevel around external border
321 	AddLine(BPoint(rect.left, rect.bottom),
322 			BPoint(rect.left, rect.top), borderBevelShadow);
323 	AddLine(BPoint(rect.left + 1, rect.top),
324 			BPoint(rect.right, rect.top), borderBevelShadow);
325 
326 	AddLine(BPoint(rect.right, rect.top + 1),
327 			BPoint(rect.right, rect.bottom), borderBevelLight);
328 	AddLine(BPoint(rect.left + 1, rect.bottom),
329 			BPoint(rect.right - 1, rect.bottom), borderBevelLight);
330 
331 	rect.InsetBy(1.0, 1.0);
332 
333 	// external border
334 	AddLine(BPoint(rect.left, rect.bottom),
335 			BPoint(rect.left, rect.top), dark1BorderColor);
336 	AddLine(BPoint(rect.left + 1, rect.top),
337 			BPoint(rect.right, rect.top), dark1BorderColor);
338 	AddLine(BPoint(rect.right, rect.top + 1),
339 			BPoint(rect.right, rect.bottom), dark2BorderColor);
340 	AddLine(BPoint(rect.right - 1, rect.bottom),
341 			BPoint(rect.left + 1, rect.bottom), dark2BorderColor);
342 
343 	rect.InsetBy(1.0, 1.0);
344 
345 	// Light
346 	AddLine(BPoint(rect.left, rect.top),
347 			BPoint(rect.left, rect.top), buttonBgColor);
348 	AddLine(BPoint(rect.left, rect.top + 1),
349 			BPoint(rect.left, rect.bottom - 1), lightColor);
350 	AddLine(BPoint(rect.left, rect.bottom),
351 			BPoint(rect.left, rect.bottom), bevelColor2);
352 	AddLine(BPoint(rect.left + 1, rect.top),
353 			BPoint(rect.right - 1, rect.top), lightColor);
354 	AddLine(BPoint(rect.right, rect.top),
355 			BPoint(rect.right, rect.top), bevelColor2);
356 	// Shadow
357 	AddLine(BPoint(rect.left + 1, rect.bottom),
358 			BPoint(rect.right - 1, rect.bottom), bevelColor1);
359 	AddLine(BPoint(rect.right, rect.bottom),
360 			BPoint(rect.right, rect.bottom), bevelColorRBCorner);
361 	AddLine(BPoint(rect.right, rect.bottom - 1),
362 			BPoint(rect.right, rect.top + 1), bevelColor1);
363 
364 	rect.InsetBy(1.0, 1.0);
365 
366 	// Light
367 	AddLine(BPoint(rect.left, rect.top),
368 			BPoint(rect.left, rect.bottom - 1), maxLightColor);
369 	AddLine(BPoint(rect.left, rect.bottom),
370 			BPoint(rect.left, rect.bottom), buttonBgColor);
371 	AddLine(BPoint(rect.left + 1, rect.top),
372 			BPoint(rect.right - 1, rect.top), maxLightColor);
373 	AddLine(BPoint(rect.right, rect.top),
374 			BPoint(rect.right, rect.top), buttonBgColor);
375 	// Shadow
376 	AddLine(BPoint(rect.left + 1, rect.bottom),
377 			BPoint(rect.right, rect.bottom), bevelColor2);
378 	AddLine(BPoint(rect.right, rect.bottom - 1),
379 			BPoint(rect.right, rect.top + 1), bevelColor2);
380 
381 	rect.InsetBy(1.0,1.0);
382 
383 	EndLineArray();
384 
385 	// Invert if clicked
386 	if (enabled && pushed) {
387 		rect.InsetBy(-2.0, -2.0);
388 		InvertRect(rect);
389 	}
390 
391 	// Label color
392 	if (enabled) {
393 		if (pushed) {
394 			SetHighColor(maxLightColor);
395 			SetLowColor(255 - buttonBgColor.red,
396 						255 - buttonBgColor.green,
397 						255 - buttonBgColor.blue);
398 		} else {
399 			SetHighColor(maxShadowColor);
400 			SetLowColor(buttonBgColor);
401 		}
402 	} else {
403 		SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT));
404 		SetLowColor(buttonBgColor);
405 	}
406 
407 	// Draw the label
408 	DrawString(text.String(), BPoint(x, labelY));
409 
410 	// Focus line
411 	if (enabled && IsFocus() && Window()->IsActive() && !pushed)
412 		DrawFocusLine(x, focusLineY, stringWidth, true);
413 #endif
414 }
415 
416 
417 void
418 BButton::MouseDown(BPoint point)
419 {
420 	if (!IsEnabled())
421 		return;
422 
423 	SetValue(B_CONTROL_ON);
424 
425 	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
426  		SetTracking(true);
427  		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
428  	} else {
429 		BRect bounds = Bounds();
430 		uint32 buttons;
431 
432 		do {
433 			Window()->UpdateIfNeeded();
434 			snooze(40000);
435 
436 			GetMouse(&point, &buttons, true);
437 
438  			bool inside = bounds.Contains(point);
439 
440 			if ((Value() == B_CONTROL_ON) != inside)
441 				SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
442 		} while (buttons != 0);
443 
444 		if (Value() == B_CONTROL_ON)
445 			Invoke();
446 	}
447 }
448 
449 
450 void
451 BButton::AttachedToWindow()
452 {
453 	BControl::AttachedToWindow();
454 		// low color will now be the parents view color
455 
456 	if (IsDefault())
457 		Window()->SetDefaultButton(this);
458 
459 	SetViewColor(B_TRANSPARENT_COLOR);
460 }
461 
462 
463 void
464 BButton::KeyDown(const char *bytes, int32 numBytes)
465 {
466 	if (*bytes == B_ENTER || *bytes == B_SPACE) {
467 		if (!IsEnabled())
468 			return;
469 
470 		SetValue(B_CONTROL_ON);
471 
472 		// make sure the user saw that
473 		Window()->UpdateIfNeeded();
474 		snooze(25000);
475 
476 		Invoke();
477 
478 	} else
479 		BControl::KeyDown(bytes, numBytes);
480 }
481 
482 
483 void
484 BButton::MakeDefault(bool flag)
485 {
486 	BButton *oldDefault = NULL;
487 	BWindow *window = Window();
488 
489 	if (window)
490 		oldDefault = window->DefaultButton();
491 
492 	if (flag) {
493 		if (fDrawAsDefault && oldDefault == this)
494 			return;
495 
496 		if (!fDrawAsDefault) {
497 			fDrawAsDefault = true;
498 
499 			ResizeBy(6.0f, 6.0f);
500 			MoveBy(-3.0f, -3.0f);
501 		}
502 
503 		if (window && oldDefault != this)
504 			window->SetDefaultButton(this);
505 	} else {
506 		if (!fDrawAsDefault)
507 			return;
508 
509 		fDrawAsDefault = false;
510 
511 		ResizeBy(-6.0f, -6.0f);
512 		MoveBy(3.0f, 3.0f);
513 
514 		if (window && oldDefault == this)
515 			window->SetDefaultButton(NULL);
516 	}
517 }
518 
519 
520 void
521 BButton::SetLabel(const char *string)
522 {
523 	BControl::SetLabel(string);
524 }
525 
526 
527 bool
528 BButton::IsDefault() const
529 {
530 	return fDrawAsDefault;
531 }
532 
533 
534 void
535 BButton::MessageReceived(BMessage *message)
536 {
537 	BControl::MessageReceived(message);
538 }
539 
540 
541 void
542 BButton::WindowActivated(bool active)
543 {
544 	BControl::WindowActivated(active);
545 }
546 
547 
548 void
549 BButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
550 {
551 	if (!IsTracking())
552 		return;
553 
554 	bool inside = Bounds().Contains(point);
555 
556 	if ((Value() == B_CONTROL_ON) != inside)
557 		SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
558 }
559 
560 
561 void
562 BButton::MouseUp(BPoint point)
563 {
564 	if (!IsTracking())
565 		return;
566 
567 	if (Bounds().Contains(point))
568 		Invoke();
569 
570 	SetTracking(false);
571 }
572 
573 
574 void
575 BButton::DetachedFromWindow()
576 {
577 	BControl::DetachedFromWindow();
578 }
579 
580 
581 void
582 BButton::SetValue(int32 value)
583 {
584 	if (value != Value())
585 		BControl::SetValue(value);
586 }
587 
588 
589 void
590 BButton::GetPreferredSize(float *_width, float *_height)
591 {
592 	if (_height) {
593 		font_height fontHeight;
594 		GetFontHeight(&fontHeight);
595 
596 //		*_height = 12.0f + ceilf(fontHeight.ascent + fontHeight.descent)
597 		*_height = ceilf((fontHeight.ascent + fontHeight.descent) * 1.8)
598 			+ (fDrawAsDefault ? 6.0f : 0);
599 	}
600 
601 	if (_width) {
602 		float width = 20.0f + (float)ceil(StringWidth(Label()));
603 		if (width < 75.0f)
604 			width = 75.0f;
605 
606 		if (fDrawAsDefault)
607 			width += 6.0f;
608 
609 		*_width = width;
610 	}
611 }
612 
613 
614 void
615 BButton::ResizeToPreferred()
616 {
617 	 BControl::ResizeToPreferred();
618 }
619 
620 
621 status_t
622 BButton::Invoke(BMessage *message)
623 {
624 	Sync();
625 	snooze(50000);
626 
627 	status_t err = BControl::Invoke(message);
628 
629 	SetValue(B_CONTROL_OFF);
630 
631 	return err;
632 }
633 
634 
635 void
636 BButton::FrameMoved(BPoint newLocation)
637 {
638 	BControl::FrameMoved(newLocation);
639 }
640 
641 
642 void
643 BButton::FrameResized(float width, float height)
644 {
645 	BControl::FrameResized(width, height);
646 }
647 
648 
649 void
650 BButton::MakeFocus(bool focused)
651 {
652 	BControl::MakeFocus(focused);
653 }
654 
655 
656 void
657 BButton::AllAttached()
658 {
659 	BControl::AllAttached();
660 }
661 
662 
663 void
664 BButton::AllDetached()
665 {
666 	BControl::AllDetached();
667 }
668 
669 
670 BHandler *
671 BButton::ResolveSpecifier(BMessage *message, int32 index,
672 									BMessage *specifier, int32 what,
673 									const char *property)
674 {
675 	return BControl::ResolveSpecifier(message, index, specifier, what, property);
676 }
677 
678 
679 status_t
680 BButton::GetSupportedSuites(BMessage *message)
681 {
682 	return BControl::GetSupportedSuites(message);
683 }
684 
685 
686 status_t
687 BButton::Perform(perform_code d, void *arg)
688 {
689 	return BControl::Perform(d, arg);
690 }
691 
692 
693 void BButton::_ReservedButton1() {}
694 void BButton::_ReservedButton2() {}
695 void BButton::_ReservedButton3() {}
696 
697 
698 BButton &
699 BButton::operator=(const BButton &)
700 {
701 	return *this;
702 }
703 
704 
705 BRect
706 BButton::DrawDefault(BRect bounds, bool enabled)
707 {
708 #if 0
709 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR),
710 	lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT),
711 	darken1 = tint_color(no_tint, B_DARKEN_1_TINT);
712 
713 	rgb_color borderColor;
714 	if (enabled)
715 		borderColor = tint_color(no_tint, B_DARKEN_4_TINT);
716 	else
717 		borderColor = darken1;
718 
719 	// Dark border
720 	BeginLineArray(4);
721 	AddLine(BPoint(bounds.left, bounds.bottom - 1.0f),
722 		BPoint(bounds.left, bounds.top + 1.0f), borderColor);
723 	AddLine(BPoint(bounds.left + 1.0f, bounds.top),
724 		BPoint(bounds.right - 1.0f, bounds.top), borderColor);
725 	AddLine(BPoint(bounds.right, bounds.top + 1.0f),
726 		BPoint(bounds.right, bounds.bottom - 1.0f), borderColor);
727 	AddLine(BPoint(bounds.left + 1.0f, bounds.bottom),
728 		BPoint(bounds.right - 1.0f, bounds.bottom), borderColor);
729 	EndLineArray();
730 
731 	if (enabled) {
732 		// Bevel
733 		bounds.InsetBy(1.0f, 1.0f);
734 		SetHighColor(darken1);
735 		StrokeRect(bounds);
736 	}
737 
738 	bounds.InsetBy(1.0f, 1.0f);
739 
740 	// Filling
741 	float inset = enabled? 2.0f : 3.0f;
742 	SetHighColor(lighten1);
743 
744 	FillRect(BRect(bounds.left, bounds.top,
745 		bounds.right, bounds.top+inset-1.0f));
746 	FillRect(BRect(bounds.left, bounds.bottom-inset+1.0f,
747 		bounds.right, bounds.bottom));
748 	FillRect(BRect(bounds.left, bounds.top+inset-1.0f,
749 		bounds.left+inset-1.0f, bounds.bottom-inset+1.0f));
750 	FillRect(BRect(bounds.right-inset+1.0f, bounds.top+inset-1.0f,
751 		bounds.right, bounds.bottom-inset+1.0f));
752 
753 	bounds.InsetBy(inset,inset);
754 
755 	return bounds;
756 #else
757 	rgb_color low = LowColor();
758 	rgb_color focusColor = tint_color(low, enabled ? (B_DARKEN_1_TINT + B_DARKEN_2_TINT) / 2
759 												   : (B_NO_TINT + B_DARKEN_1_TINT) / 2);
760 
761 	SetHighColor(focusColor);
762 
763 	StrokeRect(bounds, B_SOLID_LOW);
764 	bounds.InsetBy(1.0, 1.0);
765 	StrokeRect(bounds);
766 	bounds.InsetBy(1.0, 1.0);
767 	StrokeRect(bounds);
768 	bounds.InsetBy(1.0, 1.0);
769 
770 	return bounds;
771 #endif
772 }
773 
774 
775 status_t
776 BButton::Execute()
777 {
778 	if (!IsEnabled())
779 		return B_ERROR;
780 
781 	SetValue(B_CONTROL_ON);
782 	return Invoke();
783 }
784 
785 
786 void
787 BButton::DrawFocusLine(float x, float y, float width, bool visible)
788 {
789 	if (visible)
790 		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
791 	else {
792 		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
793 			B_LIGHTEN_1_TINT));
794 	}
795 
796 	// Blue Line
797 	StrokeLine(BPoint(x, y), BPoint(x + width, y));
798 
799 	if (visible)
800 		SetHighColor(255, 255, 255);
801 	// White Line
802 	StrokeLine(BPoint(x, y + 1.0f), BPoint(x + width, y + 1.0f));
803 }
804