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