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
roundTo(double value,uint32 n)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
BDecimalSpinner(BRect frame,const char * name,const char * label,BMessage * message,uint32 resizingMode,uint32 flags)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
BDecimalSpinner(const char * name,const char * label,BMessage * message,uint32 flags)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
BDecimalSpinner(BMessage * data)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
~BDecimalSpinner()160 BDecimalSpinner::~BDecimalSpinner()
161 {
162 }
163
164
165 BArchivable*
Instantiate(BMessage * data)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
Archive(BMessage * data,bool deep) const176 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
GetSupportedSuites(BMessage * message)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
AttachedToWindow()213 BDecimalSpinner::AttachedToWindow()
214 {
215 SetValue(fValue);
216
217 BAbstractSpinner::AttachedToWindow();
218 }
219
220
221 void
Decrement()222 BDecimalSpinner::Decrement()
223 {
224 SetValue(Value() - Step());
225 }
226
227
228 void
Increment()229 BDecimalSpinner::Increment()
230 {
231 SetValue(Value() + Step());
232 }
233
234
235 void
SetEnabled(bool enable)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
SetMinValue(double min)249 BDecimalSpinner::SetMinValue(double min)
250 {
251 fMinValue = min;
252 SetValue(Value());
253 }
254
255
256 void
SetMaxValue(double max)257 BDecimalSpinner::SetMaxValue(double max)
258 {
259 fMaxValue = max;
260 SetValue(Value());
261 }
262
263
264 void
Range(double * min,double * max)265 BDecimalSpinner::Range(double* min, double* max)
266 {
267 *min = fMinValue;
268 *max = fMaxValue;
269 }
270
271
272 void
SetRange(double min,double max)273 BDecimalSpinner::SetRange(double min, double max)
274 {
275 SetMinValue(min);
276 SetMaxValue(max);
277 }
278
279
280 void
SetValue(int32 value)281 BDecimalSpinner::SetValue(int32 value)
282 {
283 SetValue((double)value);
284 }
285
286
287 void
SetValue(double value)288 BDecimalSpinner::SetValue(double value)
289 {
290 // clip to range
291 if (value < fMinValue)
292 value = fMinValue;
293 else if (value > fMaxValue)
294 value = fMaxValue;
295
296 // update the text view
297 char* format;
298 asprintf(&format, "%%.%" B_PRId32 "f", fPrecision);
299 char* valueString;
300 asprintf(&valueString, format, value);
301 TextView()->SetText(valueString);
302 free(format);
303 free(valueString);
304
305 // update the up and down arrows
306 SetIncrementEnabled(IsEnabled() && value < fMaxValue);
307 SetDecrementEnabled(IsEnabled() && value > fMinValue);
308
309 if (value == fValue)
310 return;
311
312 fValue = value;
313 ValueChanged();
314
315 Invoke();
316 Invalidate();
317 }
318
319
320 void
SetValueFromText()321 BDecimalSpinner::SetValueFromText()
322 {
323 SetValue(roundTo(atof(TextView()->Text()), Precision()));
324 }
325
326
327 // #pragma mark - BDecimalSpinner private methods
328
329
330 void
_InitObject()331 BDecimalSpinner::_InitObject()
332 {
333 fMinValue = 0.0;
334 fMaxValue = 100.0;
335 fPrecision = 2;
336 fStep = 1.0;
337 fValue = 0.0;
338
339 TextView()->SetAlignment(B_ALIGN_RIGHT);
340 for (uint32 c = 0; c <= 42; c++)
341 TextView()->DisallowChar(c);
342
343 TextView()->DisallowChar('/');
344 for (uint32 c = 58; c <= 127; c++)
345 TextView()->DisallowChar(c);
346 }
347
348
349 // FBC padding
350
_ReservedDecimalSpinner20()351 void BDecimalSpinner::_ReservedDecimalSpinner20() {}
_ReservedDecimalSpinner19()352 void BDecimalSpinner::_ReservedDecimalSpinner19() {}
_ReservedDecimalSpinner18()353 void BDecimalSpinner::_ReservedDecimalSpinner18() {}
_ReservedDecimalSpinner17()354 void BDecimalSpinner::_ReservedDecimalSpinner17() {}
_ReservedDecimalSpinner16()355 void BDecimalSpinner::_ReservedDecimalSpinner16() {}
_ReservedDecimalSpinner15()356 void BDecimalSpinner::_ReservedDecimalSpinner15() {}
_ReservedDecimalSpinner14()357 void BDecimalSpinner::_ReservedDecimalSpinner14() {}
_ReservedDecimalSpinner13()358 void BDecimalSpinner::_ReservedDecimalSpinner13() {}
_ReservedDecimalSpinner12()359 void BDecimalSpinner::_ReservedDecimalSpinner12() {}
_ReservedDecimalSpinner11()360 void BDecimalSpinner::_ReservedDecimalSpinner11() {}
_ReservedDecimalSpinner10()361 void BDecimalSpinner::_ReservedDecimalSpinner10() {}
_ReservedDecimalSpinner9()362 void BDecimalSpinner::_ReservedDecimalSpinner9() {}
_ReservedDecimalSpinner8()363 void BDecimalSpinner::_ReservedDecimalSpinner8() {}
_ReservedDecimalSpinner7()364 void BDecimalSpinner::_ReservedDecimalSpinner7() {}
_ReservedDecimalSpinner6()365 void BDecimalSpinner::_ReservedDecimalSpinner6() {}
_ReservedDecimalSpinner5()366 void BDecimalSpinner::_ReservedDecimalSpinner5() {}
_ReservedDecimalSpinner4()367 void BDecimalSpinner::_ReservedDecimalSpinner4() {}
_ReservedDecimalSpinner3()368 void BDecimalSpinner::_ReservedDecimalSpinner3() {}
_ReservedDecimalSpinner2()369 void BDecimalSpinner::_ReservedDecimalSpinner2() {}
_ReservedDecimalSpinner1()370 void BDecimalSpinner::_ReservedDecimalSpinner1() {}
371