1/*
2 * Copyright 2001-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Graham MacDonald (macdonag@btopenworld.com)
7 */
8
9
10#include <PictureButton.h>
11
12#include <new>
13
14#include <binary_compatibility/Interface.h>
15
16
17BPictureButton::BPictureButton(BRect frame, const char* name,
18	BPicture* off, BPicture* on, BMessage* message,
19	uint32 behavior, uint32 resizingMode, uint32 flags)
20	:
21	BControl(frame, name, "", message, resizingMode, flags),
22	fEnabledOff(new(std::nothrow) BPicture(*off)),
23	fEnabledOn(new(std::nothrow) BPicture(*on)),
24	fDisabledOff(NULL),
25	fDisabledOn(NULL),
26	fBehavior(behavior)
27{
28}
29
30
31BPictureButton::BPictureButton(BMessage* data)
32	:
33	BControl(data),
34	fEnabledOff(NULL),
35	fEnabledOn(NULL),
36	fDisabledOff(NULL),
37	fDisabledOn(NULL)
38{
39	BMessage pictureArchive;
40
41	// Default to 1 state button if not here - is this valid?
42	if (data->FindInt32("_behave", (int32*)&fBehavior) != B_OK)
43		fBehavior = B_ONE_STATE_BUTTON;
44
45	// Now expand the pictures:
46	if (data->FindMessage("_e_on", &pictureArchive) == B_OK)
47		fEnabledOn = new(std::nothrow) BPicture(&pictureArchive);
48
49	if (data->FindMessage("_e_off", &pictureArchive) == B_OK)
50		fEnabledOff = new(std::nothrow) BPicture(&pictureArchive);
51
52	if (data->FindMessage("_d_on", &pictureArchive) == B_OK)
53		fDisabledOn = new(std::nothrow) BPicture(&pictureArchive);
54
55	if (data->FindMessage("_d_off", &pictureArchive) == B_OK)
56		fDisabledOff = new(std::nothrow) BPicture(&pictureArchive);
57}
58
59
60BPictureButton::~BPictureButton()
61{
62	delete fEnabledOn;
63	delete fEnabledOff;
64	delete fDisabledOn;
65	delete fDisabledOff;
66}
67
68
69BArchivable*
70BPictureButton::Instantiate(BMessage* data)
71{
72	if (validate_instantiation(data, "BPictureButton"))
73		return new (std::nothrow) BPictureButton(data);
74
75	return NULL;
76}
77
78
79status_t
80BPictureButton::Archive(BMessage* data, bool deep) const
81{
82	status_t err = BControl::Archive(data, deep);
83	if (err != B_OK)
84		return err;
85
86	// Fill out message, depending on whether a deep copy is required or not.
87	if (deep) {
88		BMessage pictureArchive;
89		if (fEnabledOn->Archive(&pictureArchive, deep) == B_OK) {
90			err = data->AddMessage("_e_on", &pictureArchive);
91			if (err != B_OK)
92				return err;
93		}
94
95		pictureArchive.MakeEmpty();
96		if (fEnabledOff->Archive(&pictureArchive, deep) == B_OK) {
97			err = data->AddMessage("_e_off", &pictureArchive);
98			if (err != B_OK)
99				return err;
100		}
101
102		pictureArchive.MakeEmpty();
103		if (fDisabledOn && fDisabledOn->Archive(&pictureArchive, deep) == B_OK) {
104			err = data->AddMessage("_d_on", &pictureArchive);
105			if (err != B_OK)
106				return err;
107		}
108
109		pictureArchive.MakeEmpty();
110		if (fDisabledOff && fDisabledOff->Archive(&pictureArchive, deep) == B_OK) {
111			err = data->AddMessage("_d_off", &pictureArchive);
112			if (err != B_OK)
113				return err;
114		}
115	}
116
117	return data->AddInt32("_behave", fBehavior);
118}
119
120
121void
122BPictureButton::AttachedToWindow()
123{
124	BControl::AttachedToWindow();
125}
126
127
128void
129BPictureButton::DetachedFromWindow()
130{
131	BControl::DetachedFromWindow();
132}
133
134
135void
136BPictureButton::AllAttached()
137{
138	BControl::AllAttached();
139}
140
141
142void
143BPictureButton::AllDetached()
144{
145	BControl::AllDetached();
146}
147
148
149void
150BPictureButton::ResizeToPreferred()
151{
152	BControl::ResizeToPreferred();
153}
154
155
156void
157BPictureButton::GetPreferredSize(float* _width, float* _height)
158{
159	BControl::GetPreferredSize(_width, _height);
160}
161
162
163void
164BPictureButton::FrameMoved(BPoint newPosition)
165{
166	BControl::FrameMoved(newPosition);
167}
168
169
170void
171BPictureButton::FrameResized(float newWidth, float newHeight)
172{
173	BControl::FrameResized(newWidth, newHeight);
174}
175
176
177void
178BPictureButton::WindowActivated(bool active)
179{
180	BControl::WindowActivated(active);
181}
182
183
184void
185BPictureButton::MakeFocus(bool focus)
186{
187	BControl::MakeFocus(focus);
188}
189
190
191void
192BPictureButton::Draw(BRect updateRect)
193{
194	if (IsEnabled()) {
195		if (Value() == B_CONTROL_ON)
196			DrawPicture(fEnabledOn);
197		else
198			DrawPicture(fEnabledOff);
199	} else {
200
201		if (fDisabledOff == NULL
202			|| (fDisabledOn == NULL && fBehavior == B_TWO_STATE_BUTTON))
203			debugger("Need to set the 'disabled' pictures for this BPictureButton ");
204
205		if (Value() == B_CONTROL_ON)
206			DrawPicture(fDisabledOn);
207		else
208			DrawPicture(fDisabledOff);
209	}
210
211	if (IsFocus()) {
212		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
213		StrokeRect(Bounds(), B_SOLID_HIGH);
214	}
215}
216
217
218void
219BPictureButton::MessageReceived(BMessage* message)
220{
221	BControl::MessageReceived(message);
222}
223
224
225void
226BPictureButton::KeyDown(const char* bytes, int32 numBytes)
227{
228	if (numBytes == 1) {
229		switch (bytes[0]) {
230			case B_ENTER:
231			case B_SPACE:
232				if (fBehavior == B_ONE_STATE_BUTTON) {
233					SetValue(B_CONTROL_ON);
234					snooze(50000);
235					SetValue(B_CONTROL_OFF);
236				} else {
237					if (Value() == B_CONTROL_ON)
238						SetValue(B_CONTROL_OFF);
239					else
240						SetValue(B_CONTROL_ON);
241				}
242				Invoke();
243				return;
244		}
245	}
246
247	BControl::KeyDown(bytes, numBytes);
248}
249
250
251void
252BPictureButton::MouseDown(BPoint where)
253{
254	if (!IsEnabled()) {
255		BControl::MouseDown(where);
256		return;
257	}
258
259	SetMouseEventMask(B_POINTER_EVENTS,
260		B_NO_POINTER_HISTORY | B_SUSPEND_VIEW_FOCUS);
261
262	if (fBehavior == B_ONE_STATE_BUTTON) {
263		SetValue(B_CONTROL_ON);
264	} else {
265		if (Value() == B_CONTROL_ON)
266			SetValue(B_CONTROL_OFF);
267		else
268			SetValue(B_CONTROL_ON);
269	}
270	SetTracking(true);
271}
272
273
274void
275BPictureButton::MouseUp(BPoint where)
276{
277	if (IsEnabled() && IsTracking()) {
278		if (Bounds().Contains(where)) {
279			if (fBehavior == B_ONE_STATE_BUTTON) {
280				if (Value() == B_CONTROL_ON) {
281					snooze(75000);
282					SetValue(B_CONTROL_OFF);
283				}
284			}
285			Invoke();
286		}
287
288		SetTracking(false);
289	}
290}
291
292
293void
294BPictureButton::MouseMoved(BPoint where, uint32 code,
295	const BMessage* dragMessage)
296{
297	if (IsEnabled() && IsTracking()) {
298		if (code == B_EXITED_VIEW)
299			SetValue(B_CONTROL_OFF);
300		else if (code == B_ENTERED_VIEW)
301			SetValue(B_CONTROL_ON);
302	} else
303		BControl::MouseMoved(where, code, dragMessage);
304}
305
306
307// #pragma mark -
308
309
310void
311BPictureButton::SetEnabledOn(BPicture* picture)
312{
313	delete fEnabledOn;
314	fEnabledOn = new (std::nothrow) BPicture(*picture);
315}
316
317
318void
319BPictureButton::SetEnabledOff(BPicture* picture)
320{
321	delete fEnabledOff;
322	fEnabledOff = new (std::nothrow) BPicture(*picture);
323}
324
325
326void
327BPictureButton::SetDisabledOn(BPicture* picture)
328{
329	delete fDisabledOn;
330	fDisabledOn = new (std::nothrow) BPicture(*picture);
331}
332
333
334void
335BPictureButton::SetDisabledOff(BPicture* picture)
336{
337	delete fDisabledOff;
338	fDisabledOff = new (std::nothrow) BPicture(*picture);
339}
340
341
342BPicture*
343BPictureButton::EnabledOn() const
344{
345	return fEnabledOn;
346}
347
348
349BPicture*
350BPictureButton::EnabledOff() const
351{
352	return fEnabledOff;
353}
354
355
356BPicture*
357BPictureButton::DisabledOn() const
358{
359	return fDisabledOn;
360}
361
362
363BPicture*
364BPictureButton::DisabledOff() const
365{
366	return fDisabledOff;
367}
368
369
370void
371BPictureButton::SetBehavior(uint32 behavior)
372{
373	fBehavior = behavior;
374}
375
376
377uint32
378BPictureButton::Behavior() const
379{
380	return fBehavior;
381}
382
383
384void
385BPictureButton::SetValue(int32 value)
386{
387	BControl::SetValue(value);
388}
389
390
391status_t
392BPictureButton::Invoke(BMessage* message)
393{
394	return BControl::Invoke(message);
395}
396
397
398BHandler*
399BPictureButton::ResolveSpecifier(BMessage* message, int32 index,
400	BMessage* specifier, int32 what, const char* property)
401{
402	return BControl::ResolveSpecifier(message, index, specifier,
403		what, property);
404}
405
406
407status_t
408BPictureButton::GetSupportedSuites(BMessage* data)
409{
410	return BControl::GetSupportedSuites(data);
411}
412
413
414status_t
415BPictureButton::Perform(perform_code code, void* _data)
416{
417	switch (code) {
418		case PERFORM_CODE_MIN_SIZE:
419			((perform_data_min_size*)_data)->return_value
420				= BPictureButton::MinSize();
421			return B_OK;
422		case PERFORM_CODE_MAX_SIZE:
423			((perform_data_max_size*)_data)->return_value
424				= BPictureButton::MaxSize();
425			return B_OK;
426		case PERFORM_CODE_PREFERRED_SIZE:
427			((perform_data_preferred_size*)_data)->return_value
428				= BPictureButton::PreferredSize();
429			return B_OK;
430		case PERFORM_CODE_LAYOUT_ALIGNMENT:
431			((perform_data_layout_alignment*)_data)->return_value
432				= BPictureButton::LayoutAlignment();
433			return B_OK;
434		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
435			((perform_data_has_height_for_width*)_data)->return_value
436				= BPictureButton::HasHeightForWidth();
437			return B_OK;
438		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
439		{
440			perform_data_get_height_for_width* data
441				= (perform_data_get_height_for_width*)_data;
442			BPictureButton::GetHeightForWidth(data->width, &data->min, &data->max,
443				&data->preferred);
444			return B_OK;
445		}
446		case PERFORM_CODE_SET_LAYOUT:
447		{
448			perform_data_set_layout* data = (perform_data_set_layout*)_data;
449			BPictureButton::SetLayout(data->layout);
450			return B_OK;
451		}
452		case PERFORM_CODE_LAYOUT_INVALIDATED:
453		{
454			perform_data_layout_invalidated* data
455				= (perform_data_layout_invalidated*)_data;
456			BPictureButton::LayoutInvalidated(data->descendants);
457			return B_OK;
458		}
459		case PERFORM_CODE_DO_LAYOUT:
460		{
461			BPictureButton::DoLayout();
462			return B_OK;
463		}
464		case PERFORM_CODE_SET_ICON:
465		{
466			perform_data_set_icon* data = (perform_data_set_icon*)_data;
467			return BPictureButton::SetIcon(data->icon, data->flags);
468		}
469	}
470
471	return BControl::Perform(code, _data);
472}
473
474
475status_t
476BPictureButton::SetIcon(const BBitmap* icon, uint32 flags)
477{
478	return BControl::SetIcon(icon, flags);
479}
480
481
482// #pragma mark - BPictureButton private methods
483
484
485void BPictureButton::_ReservedPictureButton1() {}
486void BPictureButton::_ReservedPictureButton2() {}
487void BPictureButton::_ReservedPictureButton3() {}
488
489
490BPictureButton&
491BPictureButton::operator=(const BPictureButton &button)
492{
493	return *this;
494}
495
496