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 19static double 20roundTo(double value, uint32 n) 21{ 22 return floor(value * pow(10.0, n) + 0.5) / pow(10.0, n); 23} 24 25 26static 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 119BDecimalSpinner::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 128BDecimalSpinner::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 137BDecimalSpinner::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 160BDecimalSpinner::~BDecimalSpinner() 161{ 162} 163 164 165BArchivable* 166BDecimalSpinner::Instantiate(BMessage* data) 167{ 168 if (validate_instantiation(data, "DecimalSpinner")) 169 return new BDecimalSpinner(data); 170 171 return NULL; 172} 173 174 175status_t 176BDecimalSpinner::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 200status_t 201BDecimalSpinner::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 212void 213BDecimalSpinner::AttachedToWindow() 214{ 215 SetValue(fValue); 216 217 BAbstractSpinner::AttachedToWindow(); 218} 219 220 221void 222BDecimalSpinner::Decrement() 223{ 224 SetValue(Value() - Step()); 225} 226 227 228void 229BDecimalSpinner::Increment() 230{ 231 SetValue(Value() + Step()); 232} 233 234 235void 236BDecimalSpinner::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 248void 249BDecimalSpinner::SetMinValue(double min) 250{ 251 fMinValue = min; 252 SetValue(Value()); 253} 254 255 256void 257BDecimalSpinner::SetMaxValue(double max) 258{ 259 fMaxValue = max; 260 SetValue(Value()); 261} 262 263 264void 265BDecimalSpinner::Range(double* min, double* max) 266{ 267 *min = fMinValue; 268 *max = fMaxValue; 269} 270 271 272void 273BDecimalSpinner::SetRange(double min, double max) 274{ 275 SetMinValue(min); 276 SetMaxValue(max); 277} 278 279 280void 281BDecimalSpinner::SetValue(int32 value) 282{ 283 SetValue((double)value); 284} 285 286 287void 288BDecimalSpinner::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 320void 321BDecimalSpinner::SetValueFromText() 322{ 323 SetValue(roundTo(atof(TextView()->Text()), Precision())); 324} 325 326 327// #pragma mark - BDecimalSpinner private methods 328 329 330void 331BDecimalSpinner::_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 351void BDecimalSpinner::_ReservedDecimalSpinner20() {} 352void BDecimalSpinner::_ReservedDecimalSpinner19() {} 353void BDecimalSpinner::_ReservedDecimalSpinner18() {} 354void BDecimalSpinner::_ReservedDecimalSpinner17() {} 355void BDecimalSpinner::_ReservedDecimalSpinner16() {} 356void BDecimalSpinner::_ReservedDecimalSpinner15() {} 357void BDecimalSpinner::_ReservedDecimalSpinner14() {} 358void BDecimalSpinner::_ReservedDecimalSpinner13() {} 359void BDecimalSpinner::_ReservedDecimalSpinner12() {} 360void BDecimalSpinner::_ReservedDecimalSpinner11() {} 361void BDecimalSpinner::_ReservedDecimalSpinner10() {} 362void BDecimalSpinner::_ReservedDecimalSpinner9() {} 363void BDecimalSpinner::_ReservedDecimalSpinner8() {} 364void BDecimalSpinner::_ReservedDecimalSpinner7() {} 365void BDecimalSpinner::_ReservedDecimalSpinner6() {} 366void BDecimalSpinner::_ReservedDecimalSpinner5() {} 367void BDecimalSpinner::_ReservedDecimalSpinner4() {} 368void BDecimalSpinner::_ReservedDecimalSpinner3() {} 369void BDecimalSpinner::_ReservedDecimalSpinner2() {} 370void BDecimalSpinner::_ReservedDecimalSpinner1() {} 371