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