1049818e0SStefano Ceccherini/*
27a96554cSlooncraz *	Copyright 2001-2015 Haiku Inc. All rights reserved.
3fbb143cdSStephan Aßmus *  Distributed under the terms of the MIT License.
4049818e0SStefano Ceccherini *
5049818e0SStefano Ceccherini *	Authors:
68196fa8dSAxel Dörfler *		Marc Flerackers (mflerackers@androme.be)
78196fa8dSAxel Dörfler *		Mike Wilber
88196fa8dSAxel Dörfler *		Stefano Ceccherini (burton666@libero.it)
98196fa8dSAxel Dörfler *		Ivan Tonizza
1062b9a2ceSStephan Aßmus *		Stephan A��mus <superstippi@gmx.de>
11b998f9f0SIngo Weinhold *		Ingo Weinhold, ingo_weinhold@gmx.de
12049818e0SStefano Ceccherini */
13049818e0SStefano Ceccherini
148196fa8dSAxel Dörfler
15ac6f7aa8SMarc Flerackers#include <Button.h>
169ecf9d1cSIngo Weinhold
17fe878769SIngo Weinhold#include <algorithm>
18eaccfb9dSAxel Dörfler#include <new>
19eaccfb9dSAxel Dörfler
20fe878769SIngo Weinhold#include <Bitmap.h>
212f86ba45SStephan Aßmus#include <ControlLook.h>
22f9399379SStefano Ceccherini#include <Font.h>
239ecf9d1cSIngo Weinhold#include <LayoutUtils.h>
24f9399379SStefano Ceccherini#include <String.h>
25ac6f7aa8SMarc Flerackers#include <Window.h>
26ac6f7aa8SMarc Flerackers
2739fbf550SOliver Tappe#include <binary_compatibility/Interface.h>
2839fbf550SOliver Tappe
298196fa8dSAxel Dörfler
30a249edfbSIngo Weinholdenum {
31b998f9f0SIngo Weinhold	FLAG_DEFAULT 		= 0x01,
32b998f9f0SIngo Weinhold	FLAG_FLAT			= 0x02,
33b998f9f0SIngo Weinhold	FLAG_INSIDE			= 0x04,
34b998f9f0SIngo Weinhold	FLAG_WAS_PRESSED	= 0x08,
35a249edfbSIngo Weinhold};
36a249edfbSIngo Weinhold
37a249edfbSIngo Weinhold
38fe878769SIngo Weinholdstatic const float kLabelMargin = 3;
39fe878769SIngo Weinhold
40fe878769SIngo Weinhold
41eaccfb9dSAxel DörflerBButton::BButton(BRect frame, const char* name, const char* label,
42a631719fSJohn Scipione	BMessage* message, uint32 resizingMode, uint32 flags)
43a631719fSJohn Scipione	:
44a631719fSJohn Scipione	BControl(frame, name, label, message, resizingMode,
45a631719fSJohn Scipione		flags | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
46eaccfb9dSAxel Dörfler	fPreferredSize(-1, -1),
47b998f9f0SIngo Weinhold	fFlags(0),
48a0848a19SIngo Weinhold	fBehavior(B_BUTTON_BEHAVIOR),
49a0848a19SIngo Weinhold	fPopUpMessage(NULL)
50ac6f7aa8SMarc Flerackers{
51ac6f7aa8SMarc Flerackers	// Resize to minimum height if needed
52ac6f7aa8SMarc Flerackers	font_height fh;
53ac6f7aa8SMarc Flerackers	GetFontHeight(&fh);
54ac6f7aa8SMarc Flerackers	float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent);
55ac6f7aa8SMarc Flerackers	if (Bounds().Height() < minHeight)
56ac6f7aa8SMarc Flerackers		ResizeTo(Bounds().Width(), minHeight);
57ac6f7aa8SMarc Flerackers}
58049818e0SStefano Ceccherini
59049818e0SStefano Ceccherini
60eaccfb9dSAxel DörflerBButton::BButton(const char* name, const char* label, BMessage* message,
61a631719fSJohn Scipione	uint32 flags)
62a631719fSJohn Scipione	:
63a631719fSJohn Scipione	BControl(name, label, message,
64a631719fSJohn Scipione		flags | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
65eaccfb9dSAxel Dörfler	fPreferredSize(-1, -1),
66b998f9f0SIngo Weinhold	fFlags(0),
67a0848a19SIngo Weinhold	fBehavior(B_BUTTON_BEHAVIOR),
68a0848a19SIngo Weinhold	fPopUpMessage(NULL)
699ecf9d1cSIngo Weinhold{
709ecf9d1cSIngo Weinhold}
719ecf9d1cSIngo Weinhold
729ecf9d1cSIngo Weinhold
73eaccfb9dSAxel DörflerBButton::BButton(const char* label, BMessage* message)
74a631719fSJohn Scipione	:
75a631719fSJohn Scipione	BControl(NULL, label, message,
76a631719fSJohn Scipione		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE),
77eaccfb9dSAxel Dörfler	fPreferredSize(-1, -1),
78b998f9f0SIngo Weinhold	fFlags(0),
79a0848a19SIngo Weinhold	fBehavior(B_BUTTON_BEHAVIOR),
80a0848a19SIngo Weinhold	fPopUpMessage(NULL)
819ecf9d1cSIngo Weinhold{
829ecf9d1cSIngo Weinhold}
839ecf9d1cSIngo Weinhold
849ecf9d1cSIngo Weinhold
85ac6f7aa8SMarc FlerackersBButton::~BButton()
86ac6f7aa8SMarc Flerackers{
87a0848a19SIngo Weinhold	SetPopUpMessage(NULL);
88ac6f7aa8SMarc Flerackers}
89049818e0SStefano Ceccherini
90049818e0SStefano Ceccherini
918ad6baf7SJohn ScipioneBButton::BButton(BMessage* data)
92a631719fSJohn Scipione	:
938ad6baf7SJohn Scipione	BControl(data),
94a249edfbSIngo Weinhold	fPreferredSize(-1, -1),
95b998f9f0SIngo Weinhold	fFlags(0),
96a0848a19SIngo Weinhold	fBehavior(B_BUTTON_BEHAVIOR),
97a0848a19SIngo Weinhold	fPopUpMessage(NULL)
98ac6f7aa8SMarc Flerackers{
99a249edfbSIngo Weinhold	bool isDefault = false;
1008ad6baf7SJohn Scipione	if (data->FindBool("_default", &isDefault) == B_OK && isDefault)
101a249edfbSIngo Weinhold		_SetFlag(FLAG_DEFAULT, true);
1024d2baf30SStephan Aßmus	// NOTE: Default button state will be synchronized with the window
1034d2baf30SStephan Aßmus	// in AttachedToWindow().
104ac6f7aa8SMarc Flerackers}
105049818e0SStefano Ceccherini
106049818e0SStefano Ceccherini
107eaccfb9dSAxel DörflerBArchivable*
1088ad6baf7SJohn ScipioneBButton::Instantiate(BMessage* data)
109ac6f7aa8SMarc Flerackers{
1108ad6baf7SJohn Scipione	if (validate_instantiation(data, "BButton"))
1118ad6baf7SJohn Scipione		return new(std::nothrow) BButton(data);
1128196fa8dSAxel Dörfler
1138196fa8dSAxel Dörfler	return NULL;
114ac6f7aa8SMarc Flerackers}
115049818e0SStefano Ceccherini
116049818e0SStefano Ceccherini
117049818e0SStefano Ceccherinistatus_t
1188ad6baf7SJohn ScipioneBButton::Archive(BMessage* data, bool deep) const
119ac6f7aa8SMarc Flerackers{
1208ad6baf7SJohn Scipione	status_t err = BControl::Archive(data, deep);
121ac6f7aa8SMarc Flerackers
122ac6f7aa8SMarc Flerackers	if (err != B_OK)
123ac6f7aa8SMarc Flerackers		return err;
124eaccfb9dSAxel Dörfler
12547bc8348SMarc Flerackers	if (IsDefault())
1268ad6baf7SJohn Scipione		err = data->AddBool("_default", true);
127ac6f7aa8SMarc Flerackers
128ac6f7aa8SMarc Flerackers	return err;
129ac6f7aa8SMarc Flerackers}
130049818e0SStefano Ceccherini
131049818e0SStefano Ceccherini
132049818e0SStefano Ceccherinivoid
133049818e0SStefano CeccheriniBButton::Draw(BRect updateRect)
134ac6f7aa8SMarc Flerackers{
135fe878769SIngo Weinhold	BRect rect(Bounds());
136d2d239f4Slooncraz	rgb_color background = ViewColor();
137d2d239f4Slooncraz	rgb_color base = LowColor();
138de9c53f8Slooncraz	rgb_color textColor = ui_color(B_CONTROL_TEXT_COLOR);
139c9bd4d84Slooncraz
140fe878769SIngo Weinhold	uint32 flags = be_control_look->Flags(this);
141a249edfbSIngo Weinhold	if (_Flag(FLAG_DEFAULT))
142fe878769SIngo Weinhold		flags |= BControlLook::B_DEFAULT_BUTTON;
143a249edfbSIngo Weinhold	if (_Flag(FLAG_FLAT) && !IsTracking())
144a249edfbSIngo Weinhold		flags |= BControlLook::B_FLAT;
145a249edfbSIngo Weinhold	if (_Flag(FLAG_INSIDE))
146a249edfbSIngo Weinhold		flags |= BControlLook::B_HOVER;
147a249edfbSIngo Weinhold
148fe878769SIngo Weinhold	be_control_look->DrawButtonFrame(this, rect, updateRect,
149fe878769SIngo Weinhold		base, background, flags);
150a0848a19SIngo Weinhold
151a0848a19SIngo Weinhold	if (fBehavior == B_POP_UP_BEHAVIOR) {
152a0848a19SIngo Weinhold		be_control_look->DrawButtonWithPopUpBackground(this, rect, updateRect,
153a0848a19SIngo Weinhold			base, flags);
154a0848a19SIngo Weinhold	} else {
155a0848a19SIngo Weinhold		be_control_look->DrawButtonBackground(this, rect, updateRect,
156a0848a19SIngo Weinhold			base, flags);
157a0848a19SIngo Weinhold	}
158eaccfb9dSAxel Dörfler
159fe878769SIngo Weinhold	// always leave some room around the label
160fe878769SIngo Weinhold	rect.InsetBy(kLabelMargin, kLabelMargin);
161eaccfb9dSAxel Dörfler
162fe878769SIngo Weinhold	const BBitmap* icon = IconBitmap(
1635414b3c4SIngo Weinhold		(Value() == B_CONTROL_OFF
1645414b3c4SIngo Weinhold				? B_INACTIVE_ICON_BITMAP : B_ACTIVE_ICON_BITMAP)
1655414b3c4SIngo Weinhold			| (IsEnabled() ? 0 : B_DISABLED_ICON_BITMAP));
166d2d239f4Slooncraz
167d2d239f4Slooncraz	be_control_look->DrawLabel(this, Label(), icon, rect, updateRect, base,
168d2d239f4Slooncraz		flags, BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE), &textColor);
169ac6f7aa8SMarc Flerackers}
17033413e49SMatthew Wilber
171049818e0SStefano Ceccherini
172049818e0SStefano Ceccherinivoid
1738ad6baf7SJohn ScipioneBButton::MouseDown(BPoint where)
174ac6f7aa8SMarc Flerackers{
175ac6f7aa8SMarc Flerackers	if (!IsEnabled())
176ac6f7aa8SMarc Flerackers		return;
177ac6f7aa8SMarc Flerackers
1788ad6baf7SJohn Scipione	if (fBehavior == B_POP_UP_BEHAVIOR && _PopUpRect().Contains(where)) {
179a0848a19SIngo Weinhold		InvokeNotify(fPopUpMessage, B_CONTROL_MODIFIED);
180a0848a19SIngo Weinhold		return;
181a0848a19SIngo Weinhold	}
182a0848a19SIngo Weinhold
183b998f9f0SIngo Weinhold	bool toggleBehavior = fBehavior == B_TOGGLE_BEHAVIOR;
184b998f9f0SIngo Weinhold
185b998f9f0SIngo Weinhold	if (toggleBehavior) {
186b998f9f0SIngo Weinhold		bool wasPressed = Value() == B_CONTROL_ON;
187b998f9f0SIngo Weinhold		_SetFlag(FLAG_WAS_PRESSED, wasPressed);
188b998f9f0SIngo Weinhold		SetValue(wasPressed ? B_CONTROL_OFF : B_CONTROL_ON);
189b998f9f0SIngo Weinhold		Invalidate();
190b998f9f0SIngo Weinhold	} else
191b998f9f0SIngo Weinhold		SetValue(B_CONTROL_ON);
19247bc8348SMarc Flerackers
193049818e0SStefano Ceccherini	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
1947c3d316bSAdrien Destugues		SetTracking(true);
1957c3d316bSAdrien Destugues		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1967c3d316bSAdrien Destugues	} else {
19747bc8348SMarc Flerackers		BRect bounds = Bounds();
19847bc8348SMarc Flerackers		uint32 buttons;
199b998f9f0SIngo Weinhold		bool inside = false;
20047bc8348SMarc Flerackers
201049818e0SStefano Ceccherini		do {
2023ceb31b9SDarkWyrm			Window()->UpdateIfNeeded();
20347bc8348SMarc Flerackers			snooze(40000);
20447bc8348SMarc Flerackers
2058ad6baf7SJohn Scipione			GetMouse(&where, &buttons, true);
2067c3d316bSAdrien Destugues			inside = bounds.Contains(where);
20747bc8348SMarc Flerackers
208b998f9f0SIngo Weinhold			if (toggleBehavior) {
209b998f9f0SIngo Weinhold				bool pressed = inside ^ _Flag(FLAG_WAS_PRESSED);
210b998f9f0SIngo Weinhold				SetValue(pressed ? B_CONTROL_ON : B_CONTROL_OFF);
211b998f9f0SIngo Weinhold			} else {
212b998f9f0SIngo Weinhold				if ((Value() == B_CONTROL_ON) != inside)
213b998f9f0SIngo Weinhold					SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
214b998f9f0SIngo Weinhold			}
21547bc8348SMarc Flerackers		} while (buttons != 0);
21647bc8348SMarc Flerackers
217b998f9f0SIngo Weinhold		if (inside) {
218b998f9f0SIngo Weinhold			if (toggleBehavior) {
219b998f9f0SIngo Weinhold				SetValue(
220b998f9f0SIngo Weinhold					_Flag(FLAG_WAS_PRESSED) ? B_CONTROL_OFF : B_CONTROL_ON);
221b998f9f0SIngo Weinhold			}
222b998f9f0SIngo Weinhold
22347bc8348SMarc Flerackers			Invoke();
224b998f9f0SIngo Weinhold		} else if (_Flag(FLAG_FLAT))
225b998f9f0SIngo Weinhold			Invalidate();
22647bc8348SMarc Flerackers	}
227ac6f7aa8SMarc Flerackers}
228049818e0SStefano Ceccherini
229049818e0SStefano Ceccherinivoid
230049818e0SStefano CeccheriniBButton::AttachedToWindow()
231ac6f7aa8SMarc Flerackers{
232ac6f7aa8SMarc Flerackers	BControl::AttachedToWindow();
233ac6f7aa8SMarc Flerackers
234d2d239f4Slooncraz	// Tint default control background color to match default panel background.
235d2d239f4Slooncraz	SetLowUIColor(B_CONTROL_BACKGROUND_COLOR, 1.115);
236d2d239f4Slooncraz	SetHighUIColor(B_CONTROL_TEXT_COLOR);
237d2d239f4Slooncraz
238ac6f7aa8SMarc Flerackers	if (IsDefault())
239ac6f7aa8SMarc Flerackers		Window()->SetDefaultButton(this);
240ac6f7aa8SMarc Flerackers}
241049818e0SStefano Ceccherini
242049818e0SStefano Ceccherini
243049818e0SStefano Ceccherinivoid
244a631719fSJohn ScipioneBButton::KeyDown(const char* bytes, int32 numBytes)
245ac6f7aa8SMarc Flerackers{
246049818e0SStefano Ceccherini	if (*bytes == B_ENTER || *bytes == B_SPACE) {
24747bc8348SMarc Flerackers		if (!IsEnabled())
24847bc8348SMarc Flerackers			return;
24947bc8348SMarc Flerackers
25047bc8348SMarc Flerackers		SetValue(B_CONTROL_ON);
251e1d08bc6SStephan Aßmus
252e1d08bc6SStephan Aßmus		// make sure the user saw that
253e1d08bc6SStephan Aßmus		Window()->UpdateIfNeeded();
254e1d08bc6SStephan Aßmus		snooze(25000);
255e1d08bc6SStephan Aßmus
25647bc8348SMarc Flerackers		Invoke();
257049818e0SStefano Ceccherini	} else
258ac6f7aa8SMarc Flerackers		BControl::KeyDown(bytes, numBytes);
259ac6f7aa8SMarc Flerackers}
260049818e0SStefano Ceccherini
261049818e0SStefano Ceccherini
262049818e0SStefano Ceccherinivoid
263049818e0SStefano CeccheriniBButton::MakeDefault(bool flag)
264ac6f7aa8SMarc Flerackers{
265a631719fSJohn Scipione	BButton* oldDefault = NULL;
266a631719fSJohn Scipione	BWindow* window = Window();
267eaccfb9dSAxel Dörfler
2688ad6baf7SJohn Scipione	if (window != NULL)
26947bc8348SMarc Flerackers		oldDefault = window->DefaultButton();
27047bc8348SMarc Flerackers
271049818e0SStefano Ceccherini	if (flag) {
272a249edfbSIngo Weinhold		if (_Flag(FLAG_DEFAULT) && oldDefault == this)
27347bc8348SMarc Flerackers			return;
27447bc8348SMarc Flerackers
275a249edfbSIngo Weinhold		if (_SetFlag(FLAG_DEFAULT, true)) {
276a66b66ffSStephan Aßmus			if ((Flags() & B_SUPPORTS_LAYOUT) != 0)
277a66b66ffSStephan Aßmus				InvalidateLayout();
278a66b66ffSStephan Aßmus			else {
279a66b66ffSStephan Aßmus				ResizeBy(6.0f, 6.0f);
280a66b66ffSStephan Aßmus				MoveBy(-3.0f, -3.0f);
281a66b66ffSStephan Aßmus			}
2829daa1363SIngo Weinhold		}
283ac6f7aa8SMarc Flerackers
28447bc8348SMarc Flerackers		if (window && oldDefault != this)
28547bc8348SMarc Flerackers			window->SetDefaultButton(this);
286049818e0SStefano Ceccherini	} else {
287a249edfbSIngo Weinhold		if (!_SetFlag(FLAG_DEFAULT, false))
28847bc8348SMarc Flerackers			return;
28947bc8348SMarc Flerackers
290a66b66ffSStephan Aßmus		if ((Flags() & B_SUPPORTS_LAYOUT) != 0)
291a66b66ffSStephan Aßmus			InvalidateLayout();
292a66b66ffSStephan Aßmus		else {
293a66b66ffSStephan Aßmus			ResizeBy(-6.0f, -6.0f);
294a66b66ffSStephan Aßmus			MoveBy(3.0f, 3.0f);
295a66b66ffSStephan Aßmus		}
29647bc8348SMarc Flerackers
29747bc8348SMarc Flerackers		if (window && oldDefault == this)
298ac6f7aa8SMarc Flerackers			window->SetDefaultButton(NULL);
299ac6f7aa8SMarc Flerackers	}
300ac6f7aa8SMarc Flerackers}
301049818e0SStefano Ceccherini
302049818e0SStefano Ceccherini
303049818e0SStefano Ceccherinivoid
3048ad6baf7SJohn ScipioneBButton::SetLabel(const char* label)
305ac6f7aa8SMarc Flerackers{
3068ad6baf7SJohn Scipione	BControl::SetLabel(label);
307ac6f7aa8SMarc Flerackers}
308049818e0SStefano Ceccherini
309049818e0SStefano Ceccherini
310049818e0SStefano Ceccherinibool
311049818e0SStefano CeccheriniBButton::IsDefault() const
312ac6f7aa8SMarc Flerackers{
313a249edfbSIngo Weinhold	return _Flag(FLAG_DEFAULT);
314a249edfbSIngo Weinhold}
315a249edfbSIngo Weinhold
316a249edfbSIngo Weinhold
317a249edfbSIngo Weinholdbool
318a249edfbSIngo WeinholdBButton::IsFlat() const
319a249edfbSIngo Weinhold{
320a249edfbSIngo Weinhold	return _Flag(FLAG_FLAT);
321a249edfbSIngo Weinhold}
322a249edfbSIngo Weinhold
323a249edfbSIngo Weinhold
324a249edfbSIngo Weinholdvoid
325a249edfbSIngo WeinholdBButton::SetFlat(bool flat)
326a249edfbSIngo Weinhold{
327a249edfbSIngo Weinhold	if (_SetFlag(FLAG_FLAT, flat))
328a249edfbSIngo Weinhold		Invalidate();
329ac6f7aa8SMarc Flerackers}
330049818e0SStefano Ceccherini
331049818e0SStefano Ceccherini
332b998f9f0SIngo WeinholdBButton::BBehavior
333b998f9f0SIngo WeinholdBButton::Behavior() const
334b998f9f0SIngo Weinhold{
335b998f9f0SIngo Weinhold	return fBehavior;
336b998f9f0SIngo Weinhold}
337b998f9f0SIngo Weinhold
338b998f9f0SIngo Weinhold
339b998f9f0SIngo Weinholdvoid
340b998f9f0SIngo WeinholdBButton::SetBehavior(BBehavior behavior)
341b998f9f0SIngo Weinhold{
342a0848a19SIngo Weinhold	if (behavior != fBehavior) {
343b998f9f0SIngo Weinhold		fBehavior = behavior;
344a0848a19SIngo Weinhold		InvalidateLayout();
345a0848a19SIngo Weinhold		Invalidate();
346a0848a19SIngo Weinhold	}
347a0848a19SIngo Weinhold}
348a0848a19SIngo Weinhold
349a0848a19SIngo Weinhold
350a0848a19SIngo WeinholdBMessage*
351a0848a19SIngo WeinholdBButton::PopUpMessage() const
352a0848a19SIngo Weinhold{
353a0848a19SIngo Weinhold	return fPopUpMessage;
354a0848a19SIngo Weinhold}
355a0848a19SIngo Weinhold
356a0848a19SIngo Weinhold
357a0848a19SIngo Weinholdvoid
358a0848a19SIngo WeinholdBButton::SetPopUpMessage(BMessage* message)
359a0848a19SIngo Weinhold{
360a0848a19SIngo Weinhold	delete fPopUpMessage;
361a0848a19SIngo Weinhold	fPopUpMessage = message;
362b998f9f0SIngo Weinhold}
363b998f9f0SIngo Weinhold
364b998f9f0SIngo Weinhold
365049818e0SStefano Ceccherinivoid
366a631719fSJohn ScipioneBButton::MessageReceived(BMessage* message)
367ac6f7aa8SMarc Flerackers{
368ac6f7aa8SMarc Flerackers	BControl::MessageReceived(message);
369ac6f7aa8SMarc Flerackers}
370049818e0SStefano Ceccherini
371049818e0SStefano Ceccherini
372049818e0SStefano Ceccherinivoid
373049818e0SStefano CeccheriniBButton::WindowActivated(bool active)
374ac6f7aa8SMarc Flerackers{
375ac6f7aa8SMarc Flerackers	BControl::WindowActivated(active);
376ac6f7aa8SMarc Flerackers}
377049818e0SStefano Ceccherini
378049818e0SStefano Ceccherini
379049818e0SStefano Ceccherinivoid
3808ad6baf7SJohn ScipioneBButton::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
381ac6f7aa8SMarc Flerackers{
38283a02adbSStefano Ceccherini	bool inside = (code != B_EXITED_VIEW) && Bounds().Contains(where);
383a249edfbSIngo Weinhold	if (_SetFlag(FLAG_INSIDE, inside))
384a249edfbSIngo Weinhold		Invalidate();
385a249edfbSIngo Weinhold
38647bc8348SMarc Flerackers	if (!IsTracking())
38747bc8348SMarc Flerackers		return;
38847bc8348SMarc Flerackers
389b998f9f0SIngo Weinhold	if (fBehavior == B_TOGGLE_BEHAVIOR) {
390b998f9f0SIngo Weinhold		bool pressed = inside ^ _Flag(FLAG_WAS_PRESSED);
391b998f9f0SIngo Weinhold		SetValue(pressed ? B_CONTROL_ON : B_CONTROL_OFF);
392b998f9f0SIngo Weinhold	} else {
393b998f9f0SIngo Weinhold		if ((Value() == B_CONTROL_ON) != inside)
394b998f9f0SIngo Weinhold			SetValue(inside ? B_CONTROL_ON : B_CONTROL_OFF);
395b998f9f0SIngo Weinhold	}
396ac6f7aa8SMarc Flerackers}
397049818e0SStefano Ceccherini
398049818e0SStefano Ceccherini
399049818e0SStefano Ceccherinivoid
4008ad6baf7SJohn ScipioneBButton::MouseUp(BPoint where)
401ac6f7aa8SMarc Flerackers{
40247bc8348SMarc Flerackers	if (!IsTracking())
40347bc8348SMarc Flerackers		return;
40447bc8348SMarc Flerackers
4058ad6baf7SJohn Scipione	if (Bounds().Contains(where)) {
406b998f9f0SIngo Weinhold		if (fBehavior == B_TOGGLE_BEHAVIOR)
407b998f9f0SIngo Weinhold			SetValue(_Flag(FLAG_WAS_PRESSED) ? B_CONTROL_OFF : B_CONTROL_ON);
408b998f9f0SIngo Weinhold
40947bc8348SMarc Flerackers		Invoke();
410b998f9f0SIngo Weinhold	} else if (_Flag(FLAG_FLAT))
411a249edfbSIngo Weinhold		Invalidate();
412eaccfb9dSAxel Dörfler
41347bc8348SMarc Flerackers	SetTracking(false);
414ac6f7aa8SMarc Flerackers}
415049818e0SStefano Ceccherini
416049818e0SStefano Ceccherini
417049818e0SStefano Ceccherinivoid
418049818e0SStefano CeccheriniBButton::DetachedFromWindow()
419ac6f7aa8SMarc Flerackers{
420ac6f7aa8SMarc Flerackers	BControl::DetachedFromWindow();
421ac6f7aa8SMarc Flerackers}
422049818e0SStefano Ceccherini
423049818e0SStefano Ceccherini
424049818e0SStefano Ceccherinivoid
425049818e0SStefano CeccheriniBButton::SetValue(int32 value)
426ac6f7aa8SMarc Flerackers{
427a71c9607SAxel Dörfler	if (value != Value())
4280c3344f4SStephan Aßmus		BControl::SetValue(value);
429ac6f7aa8SMarc Flerackers}
430049818e0SStefano Ceccherini
431049818e0SStefano Ceccherini
432049818e0SStefano Ceccherinivoid
433a631719fSJohn ScipioneBButton::GetPreferredSize(float* _width, float* _height)
434ac6f7aa8SMarc Flerackers{
4356bef4a07SIngo Weinhold	_ValidatePreferredSize();
436ac6f7aa8SMarc Flerackers
4376bef4a07SIngo Weinhold	if (_width)
4386bef4a07SIngo Weinhold		*_width = fPreferredSize.width;
439ac6f7aa8SMarc Flerackers
4406bef4a07SIngo Weinhold	if (_height)
4416bef4a07SIngo Weinhold		*_height = fPreferredSize.height;
442ac6f7aa8SMarc Flerackers}
443049818e0SStefano Ceccherini
444049818e0SStefano Ceccherini
445049818e0SStefano Ceccherinivoid
446049818e0SStefano CeccheriniBButton::ResizeToPreferred()
447ac6f7aa8SMarc Flerackers{
4487c3d316bSAdrien Destugues	BControl::ResizeToPreferred();
449ac6f7aa8SMarc Flerackers}
450049818e0SStefano Ceccherini
451049818e0SStefano Ceccherini
452049818e0SStefano Ceccherinistatus_t
453a631719fSJohn ScipioneBButton::Invoke(BMessage* message)
454ac6f7aa8SMarc Flerackers{
45547bc8348SMarc Flerackers	Sync();
45647bc8348SMarc Flerackers	snooze(50000);
457eaccfb9dSAxel Dörfler
45847bc8348SMarc Flerackers	status_t err = BControl::Invoke(message);
45947bc8348SMarc Flerackers
460b998f9f0SIngo Weinhold	if (fBehavior != B_TOGGLE_BEHAVIOR)
461b998f9f0SIngo Weinhold		SetValue(B_CONTROL_OFF);
46247bc8348SMarc Flerackers
46347bc8348SMarc Flerackers	return err;
464ac6f7aa8SMarc Flerackers}
465049818e0SStefano Ceccherini
466049818e0SStefano Ceccherini
467049818e0SStefano Ceccherinivoid
4688ad6baf7SJohn ScipioneBButton::FrameMoved(BPoint newPosition)
469ac6f7aa8SMarc Flerackers{
4708ad6baf7SJohn Scipione	BControl::FrameMoved(newPosition);
471ac6f7aa8SMarc Flerackers}
472049818e0SStefano Ceccherini
473049818e0SStefano Ceccherini
474049818e0SStefano Ceccherinivoid
4751f424632SJohn ScipioneBButton::FrameResized(float newWidth, float newHeight)
476ac6f7aa8SMarc Flerackers{
4771f424632SJohn Scipione	BControl::FrameResized(newWidth, newHeight);
478ac6f7aa8SMarc Flerackers}
479049818e0SStefano Ceccherini
480049818e0SStefano Ceccherini
481049818e0SStefano Ceccherinivoid
4821f424632SJohn ScipioneBButton::MakeFocus(bool focus)
483ac6f7aa8SMarc Flerackers{
4841f424632SJohn Scipione	BControl::MakeFocus(focus);
485ac6f7aa8SMarc Flerackers}
486049818e0SStefano Ceccherini
487049818e0SStefano Ceccherini
488049818e0SStefano Ceccherinivoid
489049818e0SStefano CeccheriniBButton::AllAttached()
490ac6f7aa8SMarc Flerackers{
491ac6f7aa8SMarc Flerackers	BControl::AllAttached();
492ac6f7aa8SMarc Flerackers}
493049818e0SStefano Ceccherini
494049818e0SStefano Ceccherini
495049818e0SStefano Ceccherinivoid
496049818e0SStefano CeccheriniBButton::AllDetached()
497ac6f7aa8SMarc Flerackers{
498ac6f7aa8SMarc Flerackers	BControl::AllDetached();
499ac6f7aa8SMarc Flerackers}
500049818e0SStefano Ceccherini
501049818e0SStefano Ceccherini
502a631719fSJohn ScipioneBHandler*
503a631719fSJohn ScipioneBButton::ResolveSpecifier(BMessage* message, int32 index,
504a631719fSJohn Scipione	BMessage* specifier, int32 what, const char* property)
505ac6f7aa8SMarc Flerackers{
506a631719fSJohn Scipione	return BControl::ResolveSpecifier(message, index, specifier, what,
507a631719fSJohn Scipione		property);
508ac6f7aa8SMarc Flerackers}
509049818e0SStefano Ceccherini
510049818e0SStefano Ceccherini
511049818e0SStefano Ceccherinistatus_t
512a631719fSJohn ScipioneBButton::GetSupportedSuites(BMessage* message)
513ac6f7aa8SMarc Flerackers{
514ac6f7aa8SMarc Flerackers	return BControl::GetSupportedSuites(message);
515ac6f7aa8SMarc Flerackers}
516049818e0SStefano Ceccherini
517049818e0SStefano Ceccherini
518049818e0SStefano Ceccherinistatus_t
51939fbf550SOliver TappeBButton::Perform(perform_code code, void* _data)
52039fbf550SOliver Tappe{
52139fbf550SOliver Tappe	switch (code) {
52239fbf550SOliver Tappe		case PERFORM_CODE_MIN_SIZE:
52339fbf550SOliver Tappe			((perform_data_min_size*)_data)->return_value
52439fbf550SOliver Tappe				= BButton::MinSize();
52539fbf550SOliver Tappe			return B_OK;
526a631719fSJohn Scipione
52739fbf550SOliver Tappe		case PERFORM_CODE_MAX_SIZE:
52839fbf550SOliver Tappe			((perform_data_max_size*)_data)->return_value
52939fbf550SOliver Tappe				= BButton::MaxSize();
53039fbf550SOliver Tappe			return B_OK;
531a631719fSJohn Scipione
53239fbf550SOliver Tappe		case PERFORM_CODE_PREFERRED_SIZE:
53339fbf550SOliver Tappe			((perform_data_preferred_size*)_data)->return_value
53439fbf550SOliver Tappe				= BButton::PreferredSize();
53539fbf550SOliver Tappe			return B_OK;
536a631719fSJohn Scipione
53739fbf550SOliver Tappe		case PERFORM_CODE_LAYOUT_ALIGNMENT:
53839fbf550SOliver Tappe			((perform_data_layout_alignment*)_data)->return_value
53939fbf550SOliver Tappe				= BButton::LayoutAlignment();
54039fbf550SOliver Tappe			return B_OK;
541a631719fSJohn Scipione
54239fbf550SOliver Tappe		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
54339fbf550SOliver Tappe			((perform_data_has_height_for_width*)_data)->return_value
54439fbf550SOliver Tappe				= BButton::HasHeightForWidth();
54539fbf550SOliver Tappe			return B_OK;
546a631719fSJohn Scipione
54739fbf550SOliver Tappe		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
54839fbf550SOliver Tappe		{
54939fbf550SOliver Tappe			perform_data_get_height_for_width* data
55039fbf550SOliver Tappe				= (perform_data_get_height_for_width*)_data;
55139fbf550SOliver Tappe			BButton::GetHeightForWidth(data->width, &data->min, &data->max,
55239fbf550SOliver Tappe				&data->preferred);
55339fbf550SOliver Tappe			return B_OK;
554ca4463c2SStephan Aßmus		}
555a631719fSJohn Scipione
55639fbf550SOliver Tappe		case PERFORM_CODE_SET_LAYOUT:
55739fbf550SOliver Tappe		{
55839fbf550SOliver Tappe			perform_data_set_layout* data = (perform_data_set_layout*)_data;
55939fbf550SOliver Tappe			BButton::SetLayout(data->layout);
56039fbf550SOliver Tappe			return B_OK;
56139fbf550SOliver Tappe		}
562a631719fSJohn Scipione
563eee4243dSAlex Wilson		case PERFORM_CODE_LAYOUT_INVALIDATED:
56439fbf550SOliver Tappe		{
565eee4243dSAlex Wilson			perform_data_layout_invalidated* data
566eee4243dSAlex Wilson				= (perform_data_layout_invalidated*)_data;
567eee4243dSAlex Wilson			BButton::LayoutInvalidated(data->descendants);
56839fbf550SOliver Tappe			return B_OK;
56939fbf550SOliver Tappe		}
570a631719fSJohn Scipione
57139fbf550SOliver Tappe		case PERFORM_CODE_DO_LAYOUT:
57239fbf550SOliver Tappe		{
57339fbf550SOliver Tappe			BButton::DoLayout();
57439fbf550SOliver Tappe			return B_OK;
57539fbf550SOliver Tappe		}
576a631719fSJohn Scipione
577be436742SIngo Weinhold		case PERFORM_CODE_SET_ICON:
578be436742SIngo Weinhold		{
579be436742SIngo Weinhold			perform_data_set_icon* data = (perform_data_set_icon*)_data;
580be436742SIngo Weinhold			return BButton::SetIcon(data->icon, data->flags);
581be436742SIngo Weinhold		}
58239fbf550SOliver Tappe	}
58339fbf550SOliver Tappe
58439fbf550SOliver Tappe	return BControl::Perform(code, _data);
585ac6f7aa8SMarc Flerackers}
586049818e0SStefano Ceccherini
587049818e0SStefano Ceccherini
5886bef4a07SIngo WeinholdBSize
5896bef4a07SIngo WeinholdBButton::MinSize()
5906bef4a07SIngo Weinhold{
5916bef4a07SIngo Weinhold	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
5926bef4a07SIngo Weinhold		_ValidatePreferredSize());
5936bef4a07SIngo Weinhold}
5946bef4a07SIngo Weinhold
5956bef4a07SIngo Weinhold
5969ecf9d1cSIngo WeinholdBSize
5979ecf9d1cSIngo WeinholdBButton::MaxSize()
5989ecf9d1cSIngo Weinhold{
5996bef4a07SIngo Weinhold	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
6006bef4a07SIngo Weinhold		_ValidatePreferredSize());
6016bef4a07SIngo Weinhold}
6026bef4a07SIngo Weinhold
6039ecf9d1cSIngo Weinhold
6046bef4a07SIngo WeinholdBSize
6056bef4a07SIngo WeinholdBButton::PreferredSize()
6066bef4a07SIngo Weinhold{
6076bef4a07SIngo Weinhold	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
6086bef4a07SIngo Weinhold		_ValidatePreferredSize());
6099ecf9d1cSIngo Weinhold}
6109ecf9d1cSIngo Weinhold
6119ecf9d1cSIngo Weinhold
612be436742SIngo Weinholdstatus_t
613be436742SIngo WeinholdBButton::SetIcon(const BBitmap* icon, uint32 flags)
614be436742SIngo Weinhold{
615fe878769SIngo Weinhold	return BControl::SetIcon(icon,
6165414b3c4SIngo Weinhold		flags | B_CREATE_ACTIVE_ICON_BITMAP | B_CREATE_DISABLED_ICON_BITMAPS);
617be436742SIngo Weinhold}
618be436742SIngo Weinhold
619be436742SIngo Weinhold
620eee4243dSAlex Wilsonvoid
621eee4243dSAlex WilsonBButton::LayoutInvalidated(bool descendants)
622eee4243dSAlex Wilson{
623eee4243dSAlex Wilson	// invalidate cached preferred size
624eee4243dSAlex Wilson	fPreferredSize.Set(-1, -1);
625eee4243dSAlex Wilson}
626eee4243dSAlex Wilson
627eee4243dSAlex Wilson
628ac6f7aa8SMarc Flerackersvoid BButton::_ReservedButton1() {}
629ac6f7aa8SMarc Flerackersvoid BButton::_ReservedButton2() {}
630ac6f7aa8SMarc Flerackersvoid BButton::_ReservedButton3() {}
631049818e0SStefano Ceccherini
632049818e0SStefano Ceccherini
633049818e0SStefano CeccheriniBButton &
634049818e0SStefano CeccheriniBButton::operator=(const BButton &)
635ac6f7aa8SMarc Flerackers{
636ac6f7aa8SMarc Flerackers	return *this;
637ac6f7aa8SMarc Flerackers}
638049818e0SStefano Ceccherini
639049818e0SStefano Ceccherini
64062b9a2ceSStephan AßmusBSize
64162b9a2ceSStephan AßmusBButton::_ValidatePreferredSize()
64262b9a2ceSStephan Aßmus{
64362b9a2ceSStephan Aßmus	if (fPreferredSize.width < 0) {
644a0848a19SIngo Weinhold		BControlLook::background_type backgroundType
645a0848a19SIngo Weinhold			= fBehavior == B_POP_UP_BEHAVIOR
646a0848a19SIngo Weinhold				? BControlLook::B_BUTTON_WITH_POP_UP_BACKGROUND
647a0848a19SIngo Weinhold				: BControlLook::B_BUTTON_BACKGROUND;
648fe878769SIngo Weinhold		float left, top, right, bottom;
649a0848a19SIngo Weinhold		be_control_look->GetInsets(BControlLook::B_BUTTON_FRAME, backgroundType,
650a249edfbSIngo Weinhold			IsDefault() ? BControlLook::B_DEFAULT_BUTTON : 0,
651fe878769SIngo Weinhold			left, top, right, bottom);
652fe878769SIngo Weinhold
65362b9a2ceSStephan Aßmus		// width
654fe878769SIngo Weinhold		float width = left + right + 2 * kLabelMargin - 1;
655ac6f7aa8SMarc Flerackers
656fe878769SIngo Weinhold		const char* label = Label();
657fe878769SIngo Weinhold		if (label != NULL) {
658fe878769SIngo Weinhold			width = std::max(width, 20.0f);
659fe878769SIngo Weinhold			width += (float)ceil(StringWidth(label));
660fe878769SIngo Weinhold		}
661ac6f7aa8SMarc Flerackers
6625414b3c4SIngo Weinhold		const BBitmap* icon = IconBitmap(B_INACTIVE_ICON_BITMAP);
663fe878769SIngo Weinhold		if (icon != NULL)
664fe878769SIngo Weinhold			width += icon->Bounds().Width() + 1;
665fe878769SIngo Weinhold
666fe878769SIngo Weinhold		if (label != NULL && icon != NULL)
667fe878769SIngo Weinhold			width += be_control_look->DefaultLabelSpacing();
668ac6f7aa8SMarc Flerackers
66962b9a2ceSStephan Aßmus		// height
670fe878769SIngo Weinhold		float minHorizontalMargins = top + bottom + 2 * kLabelMargin;
671fe878769SIngo Weinhold		float height = -1;
672fe878769SIngo Weinhold
673fe878769SIngo Weinhold		if (label != NULL) {
674fe878769SIngo Weinhold			font_height fontHeight;
675fe878769SIngo Weinhold			GetFontHeight(&fontHeight);
676fe878769SIngo Weinhold			float textHeight = fontHeight.ascent + fontHeight.descent;
677fe878769SIngo Weinhold			height = ceilf(textHeight * 1.8);
678fe878769SIngo Weinhold			float margins = height - ceilf(textHeight);
679fe878769SIngo Weinhold			if (margins < minHorizontalMargins)
680fe878769SIngo Weinhold				height += minHorizontalMargins - margins;
681fe878769SIngo Weinhold		}
682fe878769SIngo Weinhold
683fe878769SIngo Weinhold		if (icon != NULL) {
684fe878769SIngo Weinhold			height = std::max(height,
685fe878769SIngo Weinhold				icon->Bounds().Height() + minHorizontalMargins);
686fe878769SIngo Weinhold		}
687fe878769SIngo Weinhold
688fe878769SIngo Weinhold		// force some minimum width/height values
689fe878769SIngo Weinhold		width = std::max(width, label != NULL ? 75.0f : 5.0f);
690fe878769SIngo Weinhold		height = std::max(height, 5.0f);
691ac6f7aa8SMarc Flerackers
692fe878769SIngo Weinhold		fPreferredSize.Set(width, height);
693a66b66ffSStephan Aßmus
694a66b66ffSStephan Aßmus		ResetLayoutInvalidation();
69562b9a2ceSStephan Aßmus	}
696f9399379SStefano Ceccherini
69762b9a2ceSStephan Aßmus	return fPreferredSize;
69862b9a2ceSStephan Aßmus}
699ac6f7aa8SMarc Flerackers
70062b9a2ceSStephan Aßmus
701a0848a19SIngo WeinholdBRect
702a0848a19SIngo WeinholdBButton::_PopUpRect() const
703a0848a19SIngo Weinhold{
704a0848a19SIngo Weinhold	if (fBehavior != B_POP_UP_BEHAVIOR)
705a0848a19SIngo Weinhold		return BRect();
706a0848a19SIngo Weinhold
707a0848a19SIngo Weinhold	float left, top, right, bottom;
708a0848a19SIngo Weinhold	be_control_look->GetInsets(BControlLook::B_BUTTON_FRAME,
709a0848a19SIngo Weinhold		BControlLook::B_BUTTON_WITH_POP_UP_BACKGROUND,
710a0848a19SIngo Weinhold		IsDefault() ? BControlLook::B_DEFAULT_BUTTON : 0,
711a0848a19SIngo Weinhold		left, top, right, bottom);
712a0848a19SIngo Weinhold
713a0848a19SIngo Weinhold	BRect rect(Bounds());
714a0848a19SIngo Weinhold	rect.left = rect.right - right + 1;
715a0848a19SIngo Weinhold	return rect;
716a0848a19SIngo Weinhold}
717a0848a19SIngo Weinhold
718a0848a19SIngo Weinhold
719a249edfbSIngo Weinholdinline bool
720a249edfbSIngo WeinholdBButton::_Flag(uint32 flag) const
721a249edfbSIngo Weinhold{
722a249edfbSIngo Weinhold	return (fFlags & flag) != 0;
723a249edfbSIngo Weinhold}
724a249edfbSIngo Weinhold
725a249edfbSIngo Weinhold
726a249edfbSIngo Weinholdinline bool
727a249edfbSIngo WeinholdBButton::_SetFlag(uint32 flag, bool set)
728a249edfbSIngo Weinhold{
729a249edfbSIngo Weinhold	if (((fFlags & flag) != 0) == set)
730a249edfbSIngo Weinhold		return false;
731a249edfbSIngo Weinhold
732a249edfbSIngo Weinhold	if (set)
733a249edfbSIngo Weinhold		fFlags |= flag;
734a249edfbSIngo Weinhold	else
735a249edfbSIngo Weinhold		fFlags &= ~flag;
736a249edfbSIngo Weinhold
737a249edfbSIngo Weinhold	return true;
738a249edfbSIngo Weinhold}
739a249edfbSIngo Weinhold
740a249edfbSIngo Weinhold
741466f2b8fSRene Gollentextern "C" void
7428adaa6c5SJerome DuvalB_IF_GCC_2(InvalidateLayout__7BButtonb, _ZN7BButton16InvalidateLayoutEb)(
7438adaa6c5SJerome Duval	BView* view, bool descendants)
744466f2b8fSRene Gollent{
745f6c8d242SRene Gollent	perform_data_layout_invalidated data;
746f6c8d242SRene Gollent	data.descendants = descendants;
747f6c8d242SRene Gollent
748f6c8d242SRene Gollent	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
749466f2b8fSRene Gollent}
750