1 // NumericValControl.cpp 2 // e.moon 30jan99 3 4 5 #include "NumericValControl.h" 6 #include "ValControlDigitSegment.h" 7 #include "ValCtrlLayoutEntry.h" 8 9 #include <Debug.h> 10 #include <MediaKit.h> 11 #include <ParameterWeb.h> 12 13 #include <cstdio> 14 #include <stdlib.h> 15 #include <string.h> 16 17 __USE_CORTEX_NAMESPACE 18 19 20 NumericValControl::NumericValControl(BRect frame, const char* name, BContinuousParameter* param, 21 uint16 wholeDigits, uint16 fractionalDigits, align_mode alignMode, align_flags alignFlags) 22 : ValControl(frame, name, 0, 0, alignMode, alignFlags, UPDATE_ASYNC, false), 23 fParam(param), 24 fWholeDigits(wholeDigits), 25 fFractionalDigits(fractionalDigits) 26 { 27 28 // ensure that the parameter represents a continuous value 29 ASSERT(fParam->ValueType() == B_FLOAT_TYPE || 30 fParam->ValueType() == B_DOUBLE_TYPE 31 /*|| unimplemented so far 32 m_pParam->ValueType() == B_INT8_TYPE || 33 m_pParam->ValueType() == B_UINT8_TYPE || 34 m_pParam->ValueType() == B_INT16_TYPE || 35 m_pParam->ValueType() == B_UINT16_TYPE || 36 m_pParam->ValueType() == B_INT32_TYPE || 37 m_pParam->ValueType() == B_UINT32_TYPE || 38 m_pParam->ValueType() == B_INT64_TYPE || 39 m_pParam->ValueType() == B_UINT64_TYPE*/ ); 40 41 initConstraintsFromParam(); 42 initSegments(); 43 mediaParameterChanged(); 44 } 45 46 47 NumericValControl::NumericValControl(BRect frame, const char* name, BMessage* message, 48 uint16 wholeDigits, uint16 fractionalDigits, bool negativeVisible, 49 align_mode alignMode, align_flags alignFlags) 50 : ValControl(frame, name, 0, message, alignMode, alignFlags, UPDATE_ASYNC, false), 51 fParam(0), 52 fWholeDigits(wholeDigits), 53 fFractionalDigits(fractionalDigits) 54 { 55 _SetDefaultConstraints(negativeVisible); 56 initSegments(); 57 } 58 59 60 NumericValControl::~NumericValControl() 61 { 62 } 63 64 65 BContinuousParameter* 66 NumericValControl::param() const 67 { 68 return fParam; 69 } 70 71 72 void 73 NumericValControl::initSegments() 74 { 75 ASSERT(fWholeDigits); 76 77 bool negativeVisible = fMinFixed < 0.0; 78 79 // *** SEGMENT DIVISION NEEDS TO BE CONFIGURABLE +++++ 80 // GOOD 23aug99 81 // init segments: 82 _Add(new ValControlDigitSegment(fWholeDigits, 0, negativeVisible), RIGHT_MOST); 83 84 if (fFractionalDigits) 85 _Add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST); 86 87 for (int n = 0; n < fFractionalDigits; ++n) 88 _Add(new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL), 89 RIGHT_MOST); 90 // add(new ValControlDigitSegment(fFractionalDigits, -fFractionalDigits, 91 // false, ValControlDigitSegment::ZERO_FILL), 92 // RIGHT_MOST); 93 // } 94 95 // // +++++ individual-segment test 96 // 97 // for(int n = 0; n < fWholeDigits; ++n) 98 // add( 99 // new ValControlDigitSegment(1, fWholeDigits-n, bNegativeCapable), 100 // RIGHT_MOST); 101 // 102 // if(fFractionalDigits) 103 // add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST); 104 // 105 // for(int n = 0; n < fFractionalDigits; ++n) 106 // add( 107 // new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL), 108 // RIGHT_MOST); 109 } 110 111 112 void 113 NumericValControl::initConstraintsFromParam() 114 { 115 ASSERT(fParam); 116 117 printf("NumericValControl::initConstraintsFromParam():\n "); 118 int r; 119 float fFactor; 120 float fOffset; 121 fParam->GetResponse(&r, &fFactor, &fOffset); 122 switch (r) { 123 case BContinuousParameter::B_LINEAR: 124 printf("Linear"); 125 break; 126 127 case BContinuousParameter::B_POLYNOMIAL: 128 printf("Polynomial"); 129 break; 130 131 case BContinuousParameter::B_EXPONENTIAL: 132 printf("Exponential"); 133 break; 134 135 case BContinuousParameter::B_LOGARITHMIC: 136 printf("Logarithmic"); 137 break; 138 139 default: 140 printf("unknown (?)"); 141 } 142 printf(" response; factor %.2f, offset %.2f\n", fFactor, fOffset); 143 144 setConstraints(fParam->MinValue(), fParam->MaxValue()); 145 146 // step not yet supported +++++ 19sep99 147 // 148 float fStep = fParam->ValueStep(); 149 150 printf(" min value: %f\n", fParam->MinValue()); 151 printf(" max value: %f\n", fParam->MaxValue()); 152 printf(" value step: %f\n\n", fStep); 153 } 154 155 156 //! Value constraints (by default, the min/max allowed by the 157 // setting of nWholeDigits, nFractionalDigits, and bNegativeCapable) 158 void 159 NumericValControl::getConstraints(double* outMinValue, double* outMaxValue) 160 { 161 double factor = pow(10, -fFractionalDigits); 162 163 *outMinValue = (double)fMinFixed * factor; 164 *outMaxValue = (double)fMaxFixed * factor; 165 } 166 167 168 status_t 169 NumericValControl::setConstraints(double minValue, double maxValue) 170 { 171 if (maxValue < minValue) 172 return B_BAD_VALUE; 173 174 double factor = pow(10, fFractionalDigits); 175 176 fMinFixed = (minValue < 0.0) ? 177 (int64)floor(minValue * factor) : 178 (int64)ceil(minValue * factor); 179 180 fMaxFixed = (maxValue < 0.0) ? 181 (int64)floor(maxValue * factor) : 182 (int64)ceil(maxValue * factor); 183 184 return B_OK; 185 } 186 187 188 //! Fetches the current value (calculated on the spot from each 189 // segment.) 190 double 191 NumericValControl::value() const 192 { 193 // double acc = 0.0; 194 // 195 // // walk segments, adding the value of each 196 // for(int n = CountEntries(); n > 0; --n) { 197 // const ValCtrlLayoutEntry& e = entryAt(n-1); 198 // if(e.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) { 199 // const ValControlDigitSegment* digitSegment = 200 // dynamic_cast<ValControlDigitSegment*>(e.pView); 201 // ASSERT(digitSegment); 202 // 203 // PRINT(( 204 // "\t...segment %d: %d digits at %d: %Ld\n", 205 // n-1, 206 // digitSegment->digitCount(), 207 // digitSegment->scaleFactor(), 208 // digitSegment->value())); 209 // 210 // acc += ((double)digitSegment->value() * 211 // pow( 212 // 10, 213 // digitSegment->scaleFactor())); 214 // 215 // PRINT(( 216 // "\t-> %.12f\n\n", acc)); 217 // } 218 // } 219 // 220 // return acc; 221 222 double ret = (double)_ValueFixed() / pow(10, fFractionalDigits); 223 224 // PRINT(( 225 // "### NumericValControl::value(): %.12f\n", ret)); 226 227 return ret; 228 } 229 230 231 //! Set the displayed value (and, if setParam is true, the 232 // linked parameter.) The value will be constrained if necessary. 233 void 234 NumericValControl::setValue(double value, bool setParam) 235 { 236 237 // PRINT(( 238 // "### NumericValControl::setValue(%.12f)\n", value)); 239 240 // round to displayed precision 241 double scaleFactor = pow(10, fFractionalDigits); 242 243 int64 fixed = (int64)(value * scaleFactor); 244 double junk = (value * scaleFactor) - (double)fixed; 245 246 // PRINT(( 247 // " : junk == %.12f\n", junk)); 248 249 if (value < 0.0) { 250 if (junk * scaleFactor < 0.5) 251 fixed--; 252 } else { 253 if (junk * scaleFactor >= 0.5) 254 fixed++; 255 } 256 257 value = (double)fixed / scaleFactor; 258 259 // PRINT(( 260 // " -> %.12f, %Ld\n", value, fixed)); 261 262 _SetValueFixed(fixed); 263 264 // notify target 265 Invoke(); 266 267 // set parameter 268 if (setParam && fParam) 269 updateParameter(value); 270 271 // +++++ redraw? 272 } 273 274 //double NumericValControl::value() const { 275 // return m_dfValue; 276 // /* 277 // double dfCur = 0.0; 278 // 279 // // sum the values of all segments 280 // for(int nIndex = CountEntries()-1; nIndex >= 0; nIndex--) { 281 // if(entryAt(nIndex).type == ValCtrlLayoutEntry::SEGMENT_ENTRY) { 282 // const ValControlDigitSegment* pSeg = 283 // dynamic_cast<ValControlDigitSegment*>(entryAt(nIndex).pView); 284 // ASSERT(pSeg); 285 // dfCur += pSeg->value(); 286 // } 287 // } 288 // 289 // return dfCur;*/ 290 //} 291 // 292 //void NumericValControl::setValue(double dfValue, bool bSetParam) { 293 // 294 // printf("setValue(%.12f)\n", dfValue); 295 // 296 // 297 // // constrain 298 // if(dfValue > m_maxValue) 299 // dfValue = m_maxValue; 300 // else if(dfValue < m_minValue) 301 // dfValue = m_minValue; 302 // 303 // // +++++ round to displayed precision 304 // 305 // // set value 306 // m_dfValue = dfValue; 307 // 308 // // set parameter 309 // if(bSetParam && fParam) 310 // updateParameter(); 311 // 312 // // notify target (ugh. what if the target called this? +++++) 313 // Invoke(); 314 // 315 // // hand value to each segment 316 // for(int nIndex = 0; nIndex < CountEntries(); nIndex++) { 317 // if(entryAt(nIndex).type == ValCtrlLayoutEntry::SEGMENT_ENTRY) { 318 // const ValControlDigitSegment* pSeg = 319 // dynamic_cast<ValControlDigitSegment*>(entryAt(nIndex).pView); 320 // ASSERT(pSeg); 321 // pSeg->setValue(!nIndex ? m_dfValue : fabs(m_dfValue)); 322 // } 323 // } 324 //} 325 326 // ---------------------------------------------------------------- // 327 // segment interface 328 // ---------------------------------------------------------------- // 329 330 //void NumericValControl::offsetValue(double dfDelta) { 331 //// printf("offset: %lf\t", dfDelta); 332 // setValue(value() + dfDelta, true); 333 //// printf("%lf\n", value()); 334 //} 335 336 // 18sep99: new segment interface. 'offset' is given 337 // in the segment's units. 338 339 void 340 NumericValControl::offsetSegmentValue(ValControlDigitSegment* segment, 341 int64 offset) 342 { 343 344 // PRINT(( 345 // "### offsetSegmentValue(): %Ld\n", 346 // offset)); 347 348 int64 segmentFactor = (int64)pow(10, fFractionalDigits + segment->scaleFactor()); 349 350 int64 value = _ValueFixed(); 351 352 // cut values below domain of the changed segment 353 value /= segmentFactor; 354 355 // add offset 356 value += offset; 357 358 // restore 359 value *= segmentFactor; 360 361 _SetValueFixed(value); 362 363 // notify target 364 Invoke(); 365 366 if (fParam) 367 updateParameter((double)value * (double)segmentFactor); 368 } 369 370 371 void 372 NumericValControl::mediaParameterChanged() 373 { 374 // fetch value 375 size_t nSize; 376 bigtime_t tLastChanged; 377 status_t err; 378 switch (fParam->ValueType()) { 379 case B_FLOAT_TYPE: 380 { // +++++ left-channel hack 381 float fParamValue[4]; 382 nSize = sizeof(float) * 4; 383 // +++++ broken 384 err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged); 385 // if (err != B_OK) 386 // break; 387 388 setValue(fParamValue[0]); 389 break; 390 } 391 392 case B_DOUBLE_TYPE: 393 { 394 double fParamValue; 395 nSize = sizeof(double); 396 err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged); 397 if (err != B_OK) 398 break; 399 400 setValue(fParamValue); 401 break; 402 } 403 } 404 } 405 406 407 void 408 NumericValControl::updateParameter(double value) 409 { 410 ASSERT(fParam); 411 412 // // is this kosher? +++++ 413 // // ++++++ 18sep99: no. 414 // bigtime_t tpNow = system_time(); 415 416 // store value 417 status_t err; 418 switch (fParam->ValueType()) { 419 case B_FLOAT_TYPE: 420 { // +++++ left-channel hack 421 float fValue[2]; 422 fValue[0] = value; 423 fValue[1] = value; 424 err = fParam->SetValue((void*)&fValue, sizeof(float)*2, 0LL); 425 break; 426 } 427 428 case B_DOUBLE_TYPE: { 429 double fValue = value; 430 err = fParam->SetValue((void*)&fValue, sizeof(double), 0LL); 431 break; 432 } 433 } 434 } 435 436 437 void 438 NumericValControl::setValue(const void* data, size_t size) 439 { 440 } 441 442 443 void 444 NumericValControl::getValue(void* data, size_t* ioSize) 445 { 446 } 447 448 449 status_t 450 NumericValControl::setValueFrom(const char* text) 451 { 452 double d = atof(text); 453 setValue(d, true); 454 455 return B_OK; 456 } 457 458 459 status_t 460 NumericValControl::getString(BString& buffer) 461 { 462 // should provide the same # of digits as the control! +++++ 463 BString format = "%."; 464 format << (int32)fFractionalDigits << 'f'; 465 char cbuf[120]; 466 sprintf(cbuf, format.String(), value()); 467 buffer = cbuf; 468 469 return B_OK; 470 } 471 472 473 void 474 NumericValControl::MessageReceived(BMessage* pMsg) 475 { 476 status_t err; 477 double dfValue; 478 479 switch (pMsg->what) { 480 case M_SET_VALUE: 481 err = pMsg->FindDouble("value", &dfValue); 482 if (err < B_OK) { 483 _inherited::MessageReceived(pMsg); 484 break; 485 } 486 487 setValue(dfValue); 488 break; 489 490 case B_MEDIA_PARAMETER_CHANGED: 491 { 492 int32 id; 493 if (pMsg->FindInt32("be:parameter", &id) != B_OK) 494 break; 495 496 ASSERT(id == fParam->ID()); 497 mediaParameterChanged(); 498 break; 499 } 500 501 default: 502 _inherited::MessageReceived(pMsg); 503 break; 504 } 505 } 506 507 508 void 509 NumericValControl::_SetDefaultConstraints(bool negativeVisible) 510 { 511 double max = pow(10, fWholeDigits) - pow(10, -fFractionalDigits); 512 double min = (negativeVisible) ? -max : 0.0; 513 514 setConstraints(min, max); 515 } 516 517 518 //! calculates the current value as an int64 519 int64 520 NumericValControl::_ValueFixed() const { 521 522 // PRINT(( 523 // "### NumericValControl::_ValueFixed()\n", value)); 524 525 int64 acc = 0LL; 526 527 int64 scaleBase = fFractionalDigits; 528 529 // walk segments, adding the value of each 530 for (int n = CountEntries(); n > 0; --n) { 531 const ValCtrlLayoutEntry& entry = _EntryAt(n-1); 532 if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) { 533 const ValControlDigitSegment* digitSegment = 534 dynamic_cast<ValControlDigitSegment*>(entry.pView); 535 ASSERT(digitSegment); 536 537 // PRINT(( 538 // "\t...segment %d: %d digits at %d: %Ld\n", 539 // n-1, 540 // digitSegment->digitCount(), 541 // digitSegment->scaleFactor(), 542 // digitSegment->value())); 543 // 544 acc += digitSegment->value() * (int64)pow(10, 545 scaleBase + digitSegment->scaleFactor()); 546 // 547 // PRINT(( 548 // "\t-> %Ld\n\n", acc)); 549 } 550 } 551 552 return acc; 553 } 554 555 556 //! sets the value of each segment based on an int64 value; 557 // does not constrain the value 558 void 559 NumericValControl::_SetValueFixed(int64 fixed) 560 { 561 // PRINT(( 562 // "### NumericValControl::_SetValueFixed(%Ld)\n", fixed)); 563 564 // constrain 565 if (fixed > fMaxFixed) 566 fixed = fMaxFixed; 567 568 if (fixed < fMinFixed) 569 fixed = fMinFixed; 570 571 int64 scaleBase = fFractionalDigits; 572 573 // set segments 574 for (int n = CountEntries(); n > 0; --n) { 575 const ValCtrlLayoutEntry& entry = _EntryAt(n-1); 576 577 if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) { 578 ValControlDigitSegment* digitSegment = 579 dynamic_cast<ValControlDigitSegment*>(entry.pView); 580 ASSERT(digitSegment); 581 582 // PRINT(( 583 // "\tsegment %d: %d digits at %d:\n", 584 // n-1, 585 // digitSegment->digitCount(), 586 // digitSegment->scaleFactor())); 587 588 // subtract higher-magnitude segments' value 589 int64 hiCut = fixed % (int64)pow(10, 590 scaleBase + digitSegment->scaleFactor() + digitSegment->digitCount()); 591 592 // PRINT(( 593 // "\t [] %Ld\n", hiCut)); 594 595 // shift value 596 int64 segmentValue = hiCut / (int64)pow(10, 597 scaleBase + digitSegment->scaleFactor()); 598 599 // PRINT(( 600 // "\t -> %Ld\n\n", segmentValue)); 601 602 digitSegment->setValue(segmentValue, fixed < 0); 603 } 604 } 605 } 606