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