1a0ba79fbSJohn Scipione/*
2a0ba79fbSJohn Scipione * Copyright 2004 DarkWyrm <darkwyrm@earthlink.net>
3a0ba79fbSJohn Scipione * Copyright 2013 FeemanLou
4a0ba79fbSJohn Scipione * Copyright 2014-2015 Haiku, Inc. All rights reserved.
5a0ba79fbSJohn Scipione *
6a0ba79fbSJohn Scipione * Distributed under the terms of the MIT license.
7a0ba79fbSJohn Scipione *
8a0ba79fbSJohn Scipione * Originally written by DarkWyrm <darkwyrm@earthlink.net>
9a0ba79fbSJohn Scipione * Updated by FreemanLou as part of Google GCI 2013
10a0ba79fbSJohn Scipione *
11a0ba79fbSJohn Scipione * Authors:
12a0ba79fbSJohn Scipione *		DarkWyrm, darkwyrm@earthlink.net
13a0ba79fbSJohn Scipione *		FeemanLou
14a0ba79fbSJohn Scipione *		John Scipione, jscipione@gmail.com
15a0ba79fbSJohn Scipione */
16a0ba79fbSJohn Scipione
17a0ba79fbSJohn Scipione
18a0ba79fbSJohn Scipione#include <AbstractSpinner.h>
19a0ba79fbSJohn Scipione
20a0ba79fbSJohn Scipione#include <algorithm>
21a0ba79fbSJohn Scipione
22a0ba79fbSJohn Scipione#include <AbstractLayoutItem.h>
23a0ba79fbSJohn Scipione#include <Alignment.h>
24a0ba79fbSJohn Scipione#include <ControlLook.h>
25a0ba79fbSJohn Scipione#include <Font.h>
26a0ba79fbSJohn Scipione#include <GradientLinear.h>
27a0ba79fbSJohn Scipione#include <LayoutItem.h>
28a0ba79fbSJohn Scipione#include <LayoutUtils.h>
29a0ba79fbSJohn Scipione#include <Message.h>
30a0ba79fbSJohn Scipione#include <MessageFilter.h>
31a0ba79fbSJohn Scipione#include <Point.h>
32a0ba79fbSJohn Scipione#include <PropertyInfo.h>
33a0ba79fbSJohn Scipione#include <TextView.h>
34a0ba79fbSJohn Scipione#include <View.h>
35a0ba79fbSJohn Scipione#include <Window.h>
36a0ba79fbSJohn Scipione
37a0ba79fbSJohn Scipione#include "Thread.h"
38a0ba79fbSJohn Scipione
39a0ba79fbSJohn Scipione
40a0ba79fbSJohn Scipionestatic const float kFrameMargin			= 2.0f;
41a0ba79fbSJohn Scipione
42a0ba79fbSJohn Scipioneconst char* const kFrameField			= "BAbstractSpinner:layoutItem:frame";
43a0ba79fbSJohn Scipioneconst char* const kLabelItemField		= "BAbstractSpinner:labelItem";
44a0ba79fbSJohn Scipioneconst char* const kTextViewItemField	= "BAbstractSpinner:textViewItem";
45a0ba79fbSJohn Scipione
46a0ba79fbSJohn Scipione
47a0ba79fbSJohn Scipionestatic property_info sProperties[] = {
48a0ba79fbSJohn Scipione	{
49a0ba79fbSJohn Scipione		"Align",
50a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
51a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
52a0ba79fbSJohn Scipione		"Returns the alignment of the spinner label.",
53a0ba79fbSJohn Scipione		0,
54a0ba79fbSJohn Scipione		{ B_INT32_TYPE }
55a0ba79fbSJohn Scipione	},
56a0ba79fbSJohn Scipione	{
57a0ba79fbSJohn Scipione		"Align",
58a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
59a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
60a0ba79fbSJohn Scipione		"Sets the alignment of the spinner label.",
61a0ba79fbSJohn Scipione		0,
62a0ba79fbSJohn Scipione		{ B_INT32_TYPE }
63a0ba79fbSJohn Scipione	},
64a0ba79fbSJohn Scipione
65a0ba79fbSJohn Scipione	{
66a0ba79fbSJohn Scipione		"ButtonStyle",
67a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
68a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
69a0ba79fbSJohn Scipione		"Returns the style of the spinner buttons.",
70a0ba79fbSJohn Scipione		0,
71a0ba79fbSJohn Scipione		{ B_INT32_TYPE }
72a0ba79fbSJohn Scipione	},
73a0ba79fbSJohn Scipione	{
74a0ba79fbSJohn Scipione		"ButtonStyle",
75a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
76a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
77a0ba79fbSJohn Scipione		"Sets the style of the spinner buttons.",
78a0ba79fbSJohn Scipione		0,
79a0ba79fbSJohn Scipione		{ B_INT32_TYPE }
80a0ba79fbSJohn Scipione	},
81a0ba79fbSJohn Scipione
82a0ba79fbSJohn Scipione	{
83a0ba79fbSJohn Scipione		"Divider",
84a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
85a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
86a0ba79fbSJohn Scipione		"Returns the divider position of the spinner.",
87a0ba79fbSJohn Scipione		0,
88a0ba79fbSJohn Scipione		{ B_FLOAT_TYPE }
89a0ba79fbSJohn Scipione	},
90a0ba79fbSJohn Scipione	{
91a0ba79fbSJohn Scipione		"Divider",
92a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
93a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
94a0ba79fbSJohn Scipione		"Sets the divider position of the spinner.",
95a0ba79fbSJohn Scipione		0,
96a0ba79fbSJohn Scipione		{ B_FLOAT_TYPE }
97a0ba79fbSJohn Scipione	},
98a0ba79fbSJohn Scipione
99a0ba79fbSJohn Scipione	{
100a0ba79fbSJohn Scipione		"Enabled",
101a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
102a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
103a0ba79fbSJohn Scipione		"Returns whether or not the spinner is enabled.",
104a0ba79fbSJohn Scipione		0,
105a0ba79fbSJohn Scipione		{ B_BOOL_TYPE }
106a0ba79fbSJohn Scipione	},
107a0ba79fbSJohn Scipione	{
108a0ba79fbSJohn Scipione		"Enabled",
109a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
110a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
111a0ba79fbSJohn Scipione		"Sets whether or not the spinner is enabled.",
112a0ba79fbSJohn Scipione		0,
113a0ba79fbSJohn Scipione		{ B_BOOL_TYPE }
114a0ba79fbSJohn Scipione	},
115a0ba79fbSJohn Scipione
116a0ba79fbSJohn Scipione	{
117a0ba79fbSJohn Scipione		"Label",
118a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
119a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
120a0ba79fbSJohn Scipione		"Returns the spinner label.",
121a0ba79fbSJohn Scipione		0,
122a0ba79fbSJohn Scipione		{ B_STRING_TYPE }
123a0ba79fbSJohn Scipione	},
124a0ba79fbSJohn Scipione	{
125a0ba79fbSJohn Scipione		"Label",
126a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
127a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
128a0ba79fbSJohn Scipione		"Sets the spinner label.",
129a0ba79fbSJohn Scipione		0,
130a0ba79fbSJohn Scipione		{ B_STRING_TYPE }
131a0ba79fbSJohn Scipione	},
132a0ba79fbSJohn Scipione
133a0ba79fbSJohn Scipione	{
134a0ba79fbSJohn Scipione		"Message",
135a0ba79fbSJohn Scipione		{ B_GET_PROPERTY, 0 },
136a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0 },
137a0ba79fbSJohn Scipione		"Returns the spinner invocation message.",
138a0ba79fbSJohn Scipione		0,
139a0ba79fbSJohn Scipione		{ B_MESSAGE_TYPE }
140a0ba79fbSJohn Scipione	},
141a0ba79fbSJohn Scipione	{
142a0ba79fbSJohn Scipione		"Message",
143a0ba79fbSJohn Scipione		{ B_SET_PROPERTY, 0 },
144a0ba79fbSJohn Scipione		{ B_DIRECT_SPECIFIER, 0},
145a0ba79fbSJohn Scipione		"Sets the spinner invocation message.",
146a0ba79fbSJohn Scipione		0,
147a0ba79fbSJohn Scipione		{ B_MESSAGE_TYPE }
148a0ba79fbSJohn Scipione	},
149a0ba79fbSJohn Scipione
150a0ba79fbSJohn Scipione	{ 0 }
151a0ba79fbSJohn Scipione};
152a0ba79fbSJohn Scipione
153a0ba79fbSJohn Scipione
154a0ba79fbSJohn Scipionetypedef enum {
155a0ba79fbSJohn Scipione	SPINNER_INCREMENT,
156a0ba79fbSJohn Scipione	SPINNER_DECREMENT
157a0ba79fbSJohn Scipione} spinner_direction;
158a0ba79fbSJohn Scipione
159a0ba79fbSJohn Scipione
160a0ba79fbSJohn Scipioneclass SpinnerButton : public BView {
161a0ba79fbSJohn Scipionepublic:
162a0ba79fbSJohn Scipione								SpinnerButton(BRect frame, const char* name,
163a0ba79fbSJohn Scipione									spinner_direction direction);
164a0ba79fbSJohn Scipione	virtual						~SpinnerButton();
165a0ba79fbSJohn Scipione
166a0ba79fbSJohn Scipione	virtual	void				AttachedToWindow();
167a0ba79fbSJohn Scipione	virtual	void				DetachedFromWindow();
168a0ba79fbSJohn Scipione	virtual	void				Draw(BRect updateRect);
169a0ba79fbSJohn Scipione	virtual	void				MouseDown(BPoint where);
170a0ba79fbSJohn Scipione	virtual	void				MouseUp(BPoint where);
171a0ba79fbSJohn Scipione	virtual	void				MouseMoved(BPoint where, uint32 transit,
172a0ba79fbSJohn Scipione									const BMessage* message);
173a0ba79fbSJohn Scipione
174a0ba79fbSJohn Scipione			bool				IsEnabled() const { return fIsEnabled; }
175a0ba79fbSJohn Scipione	virtual	void				SetEnabled(bool enable) { fIsEnabled = enable; };
176a0ba79fbSJohn Scipione
177a0ba79fbSJohn Scipioneprivate:
178a0ba79fbSJohn Scipione			void				_DoneTracking(BPoint where);
179a0ba79fbSJohn Scipione			void				_Track(BPoint where, uint32);
180a0ba79fbSJohn Scipione
181a0ba79fbSJohn Scipione			spinner_direction	fSpinnerDirection;
182a0ba79fbSJohn Scipione			BAbstractSpinner*	fParent;
183a0ba79fbSJohn Scipione			bool				fIsEnabled;
184a0ba79fbSJohn Scipione			bool				fIsMouseDown;
185a0ba79fbSJohn Scipione			bool				fIsMouseOver;
186a0ba79fbSJohn Scipione			bigtime_t			fRepeatDelay;
187a0ba79fbSJohn Scipione};
188a0ba79fbSJohn Scipione
189a0ba79fbSJohn Scipione
190a0ba79fbSJohn Scipioneclass SpinnerTextView : public BTextView {
191a0ba79fbSJohn Scipionepublic:
192a0ba79fbSJohn Scipione								SpinnerTextView(BRect rect, BRect textRect);
193a0ba79fbSJohn Scipione	virtual						~SpinnerTextView();
194a0ba79fbSJohn Scipione
195a0ba79fbSJohn Scipione	virtual	void				AttachedToWindow();
196a0ba79fbSJohn Scipione	virtual	void				DetachedFromWindow();
197a0ba79fbSJohn Scipione	virtual	void				KeyDown(const char* bytes, int32 numBytes);
198a0ba79fbSJohn Scipione	virtual	void				MakeFocus(bool focus);
199a0ba79fbSJohn Scipione
200a0ba79fbSJohn Scipioneprivate:
201a0ba79fbSJohn Scipione			BAbstractSpinner*	fParent;
202a0ba79fbSJohn Scipione};
203a0ba79fbSJohn Scipione
204a0ba79fbSJohn Scipione
205a0ba79fbSJohn Scipioneclass BAbstractSpinner::LabelLayoutItem : public BAbstractLayoutItem {
206a0ba79fbSJohn Scipionepublic:
207a0ba79fbSJohn Scipione								LabelLayoutItem(BAbstractSpinner* parent);
208a0ba79fbSJohn Scipione								LabelLayoutItem(BMessage* archive);
209a0ba79fbSJohn Scipione
210a0ba79fbSJohn Scipione	virtual	bool				IsVisible();
211a0ba79fbSJohn Scipione	virtual	void				SetVisible(bool visible);
212a0ba79fbSJohn Scipione
213a0ba79fbSJohn Scipione	virtual	BRect				Frame();
214a0ba79fbSJohn Scipione	virtual	void				SetFrame(BRect frame);
215a0ba79fbSJohn Scipione
216a0ba79fbSJohn Scipione			void				SetParent(BAbstractSpinner* parent);
217a0ba79fbSJohn Scipione	virtual	BView*				View();
218a0ba79fbSJohn Scipione
219a0ba79fbSJohn Scipione	virtual	BSize				BaseMinSize();
220a0ba79fbSJohn Scipione	virtual	BSize				BaseMaxSize();
221a0ba79fbSJohn Scipione	virtual	BSize				BasePreferredSize();
222a0ba79fbSJohn Scipione	virtual	BAlignment			BaseAlignment();
223a0ba79fbSJohn Scipione
224a0ba79fbSJohn Scipione			BRect				FrameInParent() const;
225a0ba79fbSJohn Scipione
226a0ba79fbSJohn Scipione	virtual status_t			Archive(BMessage* into, bool deep = true) const;
227a0ba79fbSJohn Scipione	static	BArchivable*		Instantiate(BMessage* from);
228a0ba79fbSJohn Scipione
229a0ba79fbSJohn Scipioneprivate:
230a0ba79fbSJohn Scipione			BAbstractSpinner*	fParent;
231a0ba79fbSJohn Scipione			BRect				fFrame;
232a0ba79fbSJohn Scipione};
233a0ba79fbSJohn Scipione
234a0ba79fbSJohn Scipione
235a0ba79fbSJohn Scipioneclass BAbstractSpinner::TextViewLayoutItem : public BAbstractLayoutItem {
236a0ba79fbSJohn Scipionepublic:
237a0ba79fbSJohn Scipione								TextViewLayoutItem(BAbstractSpinner* parent);
238a0ba79fbSJohn Scipione								TextViewLayoutItem(BMessage* archive);
239a0ba79fbSJohn Scipione
240a0ba79fbSJohn Scipione	virtual	bool				IsVisible();
241a0ba79fbSJohn Scipione	virtual	void				SetVisible(bool visible);
242a0ba79fbSJohn Scipione
243a0ba79fbSJohn Scipione	virtual	BRect				Frame();
244a0ba79fbSJohn Scipione	virtual	void				SetFrame(BRect frame);
245a0ba79fbSJohn Scipione
246a0ba79fbSJohn Scipione			void				SetParent(BAbstractSpinner* parent);
247a0ba79fbSJohn Scipione	virtual	BView*				View();
248a0ba79fbSJohn Scipione
249a0ba79fbSJohn Scipione	virtual	BSize				BaseMinSize();
250a0ba79fbSJohn Scipione	virtual	BSize				BaseMaxSize();
251a0ba79fbSJohn Scipione	virtual	BSize				BasePreferredSize();
252a0ba79fbSJohn Scipione	virtual	BAlignment			BaseAlignment();
253a0ba79fbSJohn Scipione
254a0ba79fbSJohn Scipione			BRect				FrameInParent() const;
255a0ba79fbSJohn Scipione
256a0ba79fbSJohn Scipione	virtual status_t			Archive(BMessage* into, bool deep = true) const;
257a0ba79fbSJohn Scipione	static	BArchivable*		Instantiate(BMessage* from);
258a0ba79fbSJohn Scipione
259a0ba79fbSJohn Scipioneprivate:
260a0ba79fbSJohn Scipione			BAbstractSpinner*	fParent;
261a0ba79fbSJohn Scipione			BRect				fFrame;
262a0ba79fbSJohn Scipione};
263a0ba79fbSJohn Scipione
264a0ba79fbSJohn Scipione
265a0ba79fbSJohn Scipionestruct BAbstractSpinner::LayoutData {
266a0ba79fbSJohn Scipione	LayoutData(float width, float height)
267a0ba79fbSJohn Scipione	:
268a0ba79fbSJohn Scipione	label_layout_item(NULL),
269a0ba79fbSJohn Scipione	text_view_layout_item(NULL),
270a0ba79fbSJohn Scipione	label_width(0),
271a0ba79fbSJohn Scipione	label_height(0),
272a0ba79fbSJohn Scipione	text_view_width(0),
273a0ba79fbSJohn Scipione	text_view_height(0),
274a0ba79fbSJohn Scipione	previous_width(width),
275a0ba79fbSJohn Scipione	previous_height(height),
276a0ba79fbSJohn Scipione	valid(false)
277a0ba79fbSJohn Scipione	{
278a0ba79fbSJohn Scipione	}
279a0ba79fbSJohn Scipione
280a0ba79fbSJohn Scipione	LabelLayoutItem* label_layout_item;
281a0ba79fbSJohn Scipione	TextViewLayoutItem* text_view_layout_item;
282a0ba79fbSJohn Scipione
283a0ba79fbSJohn Scipione	font_height font_info;
284a0ba79fbSJohn Scipione
285a0ba79fbSJohn Scipione	float label_width;
286a0ba79fbSJohn Scipione	float label_height;
287a0ba79fbSJohn Scipione	float text_view_width;
288a0ba79fbSJohn Scipione	float text_view_height;
289a0ba79fbSJohn Scipione
290a0ba79fbSJohn Scipione	float previous_width;
291a0ba79fbSJohn Scipione	float previous_height;
292a0ba79fbSJohn Scipione
293a0ba79fbSJohn Scipione	BSize min;
294a0ba79fbSJohn Scipione	BAlignment alignment;
295a0ba79fbSJohn Scipione
296a0ba79fbSJohn Scipione	bool valid;
297a0ba79fbSJohn Scipione};
298a0ba79fbSJohn Scipione
299a0ba79fbSJohn Scipione
300a0ba79fbSJohn Scipione//	#pragma mark - SpinnerButton
301a0ba79fbSJohn Scipione
302a0ba79fbSJohn Scipione
303a0ba79fbSJohn ScipioneSpinnerButton::SpinnerButton(BRect frame, const char* name,
304a0ba79fbSJohn Scipione	spinner_direction direction)
305a0ba79fbSJohn Scipione	:
306a0ba79fbSJohn Scipione	BView(frame, name, B_FOLLOW_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW),
307a0ba79fbSJohn Scipione	fSpinnerDirection(direction),
308a0ba79fbSJohn Scipione	fParent(NULL),
309a0ba79fbSJohn Scipione	fIsEnabled(true),
310a0ba79fbSJohn Scipione	fIsMouseDown(false),
311a0ba79fbSJohn Scipione	fIsMouseOver(false),
312a0ba79fbSJohn Scipione	fRepeatDelay(100000)
313a0ba79fbSJohn Scipione{
314a0ba79fbSJohn Scipione}
315a0ba79fbSJohn Scipione
316a0ba79fbSJohn Scipione
317a0ba79fbSJohn ScipioneSpinnerButton::~SpinnerButton()