xref: /haiku/src/kits/interface/DecimalSpinner.cpp (revision 899e0ef82b5624ace2ccfa5f5a58c8ebee54aaef)
1 /*
2  * Copyright 2015 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		John Scipione, jscipione@gmail.com
7  */
8 
9 
10 #include <DecimalSpinner.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 #include <PropertyInfo.h>
16 #include <TextView.h>
17 
18 
19 static double
20 roundTo(double value, uint32 n)
21 {
22 	return floor(value * pow(10.0, n) + 0.5) / pow(10.0, n);
23 }
24 
25 
26 static property_info sProperties[] = {
27 	{
28 		"MaxValue",
29 		{ B_GET_PROPERTY, 0 },
30 		{ B_DIRECT_SPECIFIER, 0 },
31 		"Returns the maximum value of the spinner.",
32 		0,
33 		{ B_DOUBLE_TYPE }
34 	},
35 	{
36 		"MaxValue",
37 		{ B_SET_PROPERTY, 0 },
38 		{ B_DIRECT_SPECIFIER, 0},
39 		"Sets the maximum value of the spinner.",
40 		0,
41 		{ B_DOUBLE_TYPE }
42 	},
43 
44 	{
45 		"MinValue",
46 		{ B_GET_PROPERTY, 0 },
47 		{ B_DIRECT_SPECIFIER, 0 },
48 		"Returns the minimum value of the spinner.",
49 		0,
50 		{ B_DOUBLE_TYPE }
51 	},
52 	{
53 		"MinValue",
54 		{ B_SET_PROPERTY, 0 },
55 		{ B_DIRECT_SPECIFIER, 0},
56 		"Sets the minimum value of the spinner.",
57 		0,
58 		{ B_DOUBLE_TYPE }
59 	},
60 
61 	{
62 		"Precision",
63 		{ B_SET_PROPERTY, 0 },
64 		{ B_DIRECT_SPECIFIER, 0},
65 		"Sets the number of decimal places of precision of the spinner.",
66 		0,
67 		{ B_UINT32_TYPE }
68 	},
69 	{
70 		"Precision",
71 		{ B_GET_PROPERTY, 0 },
72 		{ B_DIRECT_SPECIFIER, 0 },
73 		"Returns the number of decimal places of precision of the spinner.",
74 		0,
75 		{ B_UINT32_TYPE }
76 	},
77 
78 	{
79 		"Step",
80 		{ B_GET_PROPERTY, 0 },
81 		{ B_DIRECT_SPECIFIER, 0 },
82 		"Returns the step size of the spinner.",
83 		0,
84 		{ B_DOUBLE_TYPE }
85 	},
86 	{
87 		"Step",
88 		{ B_SET_PROPERTY, 0 },
89 		{ B_DIRECT_SPECIFIER, 0},
90 		"Sets the step size of the spinner.",
91 		0,
92 		{ B_DOUBLE_TYPE }
93 	},
94 
95 	{
96 		"Value",
97 		{ B_GET_PROPERTY, 0 },
98 		{ B_DIRECT_SPECIFIER, 0 },
99 		"Returns the value of the spinner.",
100 		0,
101 		{ B_DOUBLE_TYPE }
102 	},
103 	{
104 		"Value",
105 		{ B_SET_PROPERTY, 0 },
106 		{ B_DIRECT_SPECIFIER, 0},
107 		"Sets the value of the spinner.",
108 		0,
109 		{ B_DOUBLE_TYPE }
110 	},
111 
112 	{ 0 }
113 };
114 
115 
116 //	#pragma mark - BDecimalSpinner
117 
118 
119 BDecimalSpinner::BDecimalSpinner(BRect frame, const char* name,
120 	const char* label, BMessage* message, uint32 resizingMode, uint32 flags)
121 	:
122 	BAbstractSpinner(frame, name, label, message, resizingMode, flags)
123 {
124 	_InitObject();
125 }
126 
127 
128 BDecimalSpinner::BDecimalSpinner(const char* name, const char* label,
129 	BMessage* message, uint32 flags)
130 	:
131 	BAbstractSpinner(name, label, message, flags)
132 {
133 	_InitObject();
134 }
135 
136 
137 BDecimalSpinner::BDecimalSpinner(BMessage* data)
138 	:
139 	BAbstractSpinner(data)
140 {
141 	_InitObject();
142 
143 	if (data->FindDouble("_min", &fMinValue) != B_OK)
144 		fMinValue = 0.0;
145 
146 	if (data->FindDouble("_max", &fMaxValue) != B_OK)
147 		fMinValue = 100.0;
148 
149 	if (data->FindUInt32("_precision", &fPrecision) != B_OK)
150 		fPrecision = 2;
151 
152 	if (data->FindDouble("_step", &fStep) != B_OK)
153 		fStep = 1.0;
154 
155 	if (data->FindDouble("_val", &fValue) != B_OK)
156 		fValue = 0.0;
157 }
158 
159 
160 BDecimalSpinner::~BDecimalSpinner()
161 {
162 }
163 
164 
165 BArchivable*
166 BDecimalSpinner::Instantiate(BMessage* data)
167 {
168 	if (validate_instantiation(data, "DecimalSpinner"))
169 		return new BDecimalSpinner(data);
170 
171 	return NULL;
172 }
173 
174 
175 status_t
176 BDecimalSpinner::Archive(BMessage* data, bool deep) const
177 {
178 	status_t status = BAbstractSpinner::Archive(data, deep);
179 	data->AddString("class", "DecimalSpinner");
180 
181 	if (status == B_OK)
182 		status = data->AddDouble("_min", fMinValue);
183 
184 	if (status == B_OK)
185 		status = data->AddDouble("_max", fMaxValue);
186 
187 	if (status == B_OK)
188 		status = data->AddUInt32("_precision", fPrecision);
189 
190 	if (status == B_OK)
191 		status = data->AddDouble("_step", fStep);
192 
193 	if (status == B_OK)
194 		status = data->AddDouble("_val", fValue);
195 
196 	return status;
197 }
198 
199 
200 status_t
201 BDecimalSpinner::GetSupportedSuites(BMessage* message)
202 {
203 	message->AddString("suites", "suite/vnd.Haiku-decimal-spinner");
204 
205 	BPropertyInfo prop_info(sProperties);
206 	message->AddFlat("messages", &prop_info);
207 
208 	return BView::GetSupportedSuites(message);
209 }
210 
211 
212 void
213 BDecimalSpinner::AttachedToWindow()
214 {
215 	SetValue(fValue);
216 
217 	BAbstractSpinner::AttachedToWindow();
218 }
219 
220 
221 void
222 BDecimalSpinner::Decrement()
223 {
224 	SetValue(Value() - Step());
225 }
226 
227 
228 void
229 BDecimalSpinner::Increment()
230 {
231 	SetValue(Value() + Step());
232 }
233 
234 
235 void
236 BDecimalSpinner::SetEnabled(bool enable)
237 {
238 	if (IsEnabled() == enable)
239 		return;
240 
241 	SetIncrementEnabled(enable && Value() < fMaxValue);
242 	SetDecrementEnabled(enable && Value() > fMinValue);
243 
244 	BAbstractSpinner::SetEnabled(enable);
245 }
246 
247 
248 void
249 BDecimalSpinner::SetMinValue(double min)
250 {
251 	fMinValue = min;
252 	if (fValue < fMinValue)
253 		SetValue(fMinValue);
254 }
255 
256 
257 void
258 BDecimalSpinner::SetMaxValue(double max)
259 {
260 	fMaxValue = max;
261 	if (fValue > fMaxValue)
262 		SetValue(fMaxValue);
263 }
264 
265 
266 void
267 BDecimalSpinner::Range(double* min, double* max)
268 {
269 	*min = fMinValue;
270 	*max = fMaxValue;
271 }
272 
273 
274 void
275 BDecimalSpinner::SetRange(double min, double max)
276 {
277 	SetMinValue(min);
278 	SetMaxValue(max);
279 }
280 
281 
282 void
283 BDecimalSpinner::SetValue(int32 value)
284 {
285 	SetValue((double)value);
286 }
287 
288 
289 void
290 BDecimalSpinner::SetValue(double value)
291 {
292 	// clip to range
293 	if (value < fMinValue)
294 		value = fMinValue;
295 	else if (value > fMaxValue)
296 		value = fMaxValue;
297 
298 	// update the text view
299 	char* format;
300 	asprintf(&format, "%%.%" B_PRId32 "f", fPrecision);
301 	char* valueString;
302 	asprintf(&valueString, format, value);
303 	TextView()->SetText(valueString);
304 	free(format);
305 	free(valueString);
306 
307 	// update the up and down arrows
308 	SetIncrementEnabled(IsEnabled() && value < fMaxValue);
309 	SetDecrementEnabled(IsEnabled() && value > fMinValue);
310 
311 	if (value == fValue)
312 		return;
313 
314 	fValue = value;
315 	ValueChanged();
316 
317 	Invoke();
318 	Invalidate();
319 }
320 
321 
322 void
323 BDecimalSpinner::SetValueFromText()
324 {
325 	SetValue(roundTo(atof(TextView()->Text()), Precision()));
326 }
327 
328 
329 //	#pragma mark - BDecimalSpinner private methods
330 
331 
332 void
333 BDecimalSpinner::_InitObject()
334 {
335 	fMinValue = 0.0;
336 	fMaxValue = 100.0;
337 	fPrecision = 2;
338 	fStep = 1.0;
339 	fValue = 0.0;
340 
341 	TextView()->SetAlignment(B_ALIGN_RIGHT);
342 	for (uint32 c = 0; c <= 42; c++)
343 		TextView()->DisallowChar(c);
344 
345 	TextView()->DisallowChar('/');
346 	for (uint32 c = 58; c <= 127; c++)
347 		TextView()->DisallowChar(c);
348 }
349 
350 
351 // FBC padding
352 
353 void BDecimalSpinner::_ReservedDecimalSpinner20() {}
354 void BDecimalSpinner::_ReservedDecimalSpinner19() {}
355 void BDecimalSpinner::_ReservedDecimalSpinner18() {}
356 void BDecimalSpinner::_ReservedDecimalSpinner17() {}
357 void BDecimalSpinner::_ReservedDecimalSpinner16() {}
358 void BDecimalSpinner::_ReservedDecimalSpinner15() {}
359 void BDecimalSpinner::_ReservedDecimalSpinner14() {}
360 void BDecimalSpinner::_ReservedDecimalSpinner13() {}
361 void BDecimalSpinner::_ReservedDecimalSpinner12() {}
362 void BDecimalSpinner::_ReservedDecimalSpinner11() {}
363 void BDecimalSpinner::_ReservedDecimalSpinner10() {}
364 void BDecimalSpinner::_ReservedDecimalSpinner9() {}
365 void BDecimalSpinner::_ReservedDecimalSpinner8() {}
366 void BDecimalSpinner::_ReservedDecimalSpinner7() {}
367 void BDecimalSpinner::_ReservedDecimalSpinner6() {}
368 void BDecimalSpinner::_ReservedDecimalSpinner5() {}
369 void BDecimalSpinner::_ReservedDecimalSpinner4() {}
370 void BDecimalSpinner::_ReservedDecimalSpinner3() {}
371 void BDecimalSpinner::_ReservedDecimalSpinner2() {}
372 void BDecimalSpinner::_ReservedDecimalSpinner1() {}
373