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 SetValue(Value()); 253 } 254 255 256 void 257 BDecimalSpinner::SetMaxValue(double max) 258 { 259 fMaxValue = max; 260 SetValue(Value()); 261 } 262 263 264 void 265 BDecimalSpinner::Range(double* min, double* max) 266 { 267 *min = fMinValue; 268 *max = fMaxValue; 269 } 270 271 272 void 273 BDecimalSpinner::SetRange(double min, double max) 274 { 275 SetMinValue(min); 276 SetMaxValue(max); 277 } 278 279 280 void 281 BDecimalSpinner::SetValue(int32 value) 282 { 283 SetValue((double)value); 284 } 285 286 287 void 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 321 BDecimalSpinner::SetValueFromText() 322 { 323 SetValue(roundTo(atof(TextView()->Text()), Precision())); 324 } 325 326 327 // #pragma mark - BDecimalSpinner private methods 328 329 330 void 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 351 void BDecimalSpinner::_ReservedDecimalSpinner20() {} 352 void BDecimalSpinner::_ReservedDecimalSpinner19() {} 353 void BDecimalSpinner::_ReservedDecimalSpinner18() {} 354 void BDecimalSpinner::_ReservedDecimalSpinner17() {} 355 void BDecimalSpinner::_ReservedDecimalSpinner16() {} 356 void BDecimalSpinner::_ReservedDecimalSpinner15() {} 357 void BDecimalSpinner::_ReservedDecimalSpinner14() {} 358 void BDecimalSpinner::_ReservedDecimalSpinner13() {} 359 void BDecimalSpinner::_ReservedDecimalSpinner12() {} 360 void BDecimalSpinner::_ReservedDecimalSpinner11() {} 361 void BDecimalSpinner::_ReservedDecimalSpinner10() {} 362 void BDecimalSpinner::_ReservedDecimalSpinner9() {} 363 void BDecimalSpinner::_ReservedDecimalSpinner8() {} 364 void BDecimalSpinner::_ReservedDecimalSpinner7() {} 365 void BDecimalSpinner::_ReservedDecimalSpinner6() {} 366 void BDecimalSpinner::_ReservedDecimalSpinner5() {} 367 void BDecimalSpinner::_ReservedDecimalSpinner4() {} 368 void BDecimalSpinner::_ReservedDecimalSpinner3() {} 369 void BDecimalSpinner::_ReservedDecimalSpinner2() {} 370 void BDecimalSpinner::_ReservedDecimalSpinner1() {} 371