repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / cortex / ValControl / NumericValControl.cpp
blob08a4c647023a4ab07d8d86eafed21a73b23047f0
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // NumericValControl.cpp
33 // e.moon 30jan99
36 #include "NumericValControl.h"
37 #include "ValControlDigitSegment.h"
38 #include "ValCtrlLayoutEntry.h"
40 #include <Debug.h>
41 #include <MediaKit.h>
42 #include <ParameterWeb.h>
44 #include <cstdio>
45 #include <stdlib.h>
46 #include <string.h>
48 __USE_CORTEX_NAMESPACE
51 NumericValControl::NumericValControl(BRect frame, const char* name, BContinuousParameter* param,
52 uint16 wholeDigits, uint16 fractionalDigits, align_mode alignMode, align_flags alignFlags)
53 : ValControl(frame, name, 0, 0, alignMode, alignFlags, UPDATE_ASYNC, false),
54 fParam(param),
55 fWholeDigits(wholeDigits),
56 fFractionalDigits(fractionalDigits)
59 // ensure that the parameter represents a continuous value
60 ASSERT(fParam->ValueType() == B_FLOAT_TYPE ||
61 fParam->ValueType() == B_DOUBLE_TYPE
62 /*|| unimplemented so far
63 m_pParam->ValueType() == B_INT8_TYPE ||
64 m_pParam->ValueType() == B_UINT8_TYPE ||
65 m_pParam->ValueType() == B_INT16_TYPE ||
66 m_pParam->ValueType() == B_UINT16_TYPE ||
67 m_pParam->ValueType() == B_INT32_TYPE ||
68 m_pParam->ValueType() == B_UINT32_TYPE ||
69 m_pParam->ValueType() == B_INT64_TYPE ||
70 m_pParam->ValueType() == B_UINT64_TYPE*/ );
72 initConstraintsFromParam();
73 initSegments();
74 mediaParameterChanged();
78 NumericValControl::NumericValControl(BRect frame, const char* name, BMessage* message,
79 uint16 wholeDigits, uint16 fractionalDigits, bool negativeVisible,
80 align_mode alignMode, align_flags alignFlags)
81 : ValControl(frame, name, 0, message, alignMode, alignFlags, UPDATE_ASYNC, false),
82 fParam(0),
83 fWholeDigits(wholeDigits),
84 fFractionalDigits(fractionalDigits)
86 _SetDefaultConstraints(negativeVisible);
87 initSegments();
91 NumericValControl::~NumericValControl()
96 BContinuousParameter*
97 NumericValControl::param() const
99 return fParam;
103 void
104 NumericValControl::initSegments()
106 ASSERT(fWholeDigits);
108 bool negativeVisible = fMinFixed < 0.0;
110 // *** SEGMENT DIVISION NEEDS TO BE CONFIGURABLE +++++
111 // GOOD 23aug99
112 // init segments:
113 _Add(new ValControlDigitSegment(fWholeDigits, 0, negativeVisible), RIGHT_MOST);
115 if (fFractionalDigits)
116 _Add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST);
118 for (int n = 0; n < fFractionalDigits; ++n)
119 _Add(new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL),
120 RIGHT_MOST);
121 // add(new ValControlDigitSegment(fFractionalDigits, -fFractionalDigits,
122 // false, ValControlDigitSegment::ZERO_FILL),
123 // RIGHT_MOST);
124 // }
126 // // +++++ individual-segment test
128 // for(int n = 0; n < fWholeDigits; ++n)
129 // add(
130 // new ValControlDigitSegment(1, fWholeDigits-n, bNegativeCapable),
131 // RIGHT_MOST);
133 // if(fFractionalDigits)
134 // add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST);
136 // for(int n = 0; n < fFractionalDigits; ++n)
137 // add(
138 // new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL),
139 // RIGHT_MOST);
143 void
144 NumericValControl::initConstraintsFromParam()
146 ASSERT(fParam);
148 printf("NumericValControl::initConstraintsFromParam():\n ");
149 int r;
150 float fFactor;
151 float fOffset;
152 fParam->GetResponse(&r, &fFactor, &fOffset);
153 switch (r) {
154 case BContinuousParameter::B_LINEAR:
155 printf("Linear");
156 break;
158 case BContinuousParameter::B_POLYNOMIAL:
159 printf("Polynomial");
160 break;
162 case BContinuousParameter::B_EXPONENTIAL:
163 printf("Exponential");
164 break;
166 case BContinuousParameter::B_LOGARITHMIC:
167 printf("Logarithmic");
168 break;
170 default:
171 printf("unknown (?)");
173 printf(" response; factor %.2f, offset %.2f\n", fFactor, fOffset);
175 setConstraints(fParam->MinValue(), fParam->MaxValue());
177 // step not yet supported +++++ 19sep99
179 float fStep = fParam->ValueStep();
181 printf(" min value: %f\n", fParam->MinValue());
182 printf(" max value: %f\n", fParam->MaxValue());
183 printf(" value step: %f\n\n", fStep);
187 //! Value constraints (by default, the min/max allowed by the
188 // setting of nWholeDigits, nFractionalDigits, and bNegativeCapable)
189 void
190 NumericValControl::getConstraints(double* outMinValue, double* outMaxValue)
192 double factor = pow(10, -fFractionalDigits);
194 *outMinValue = (double)fMinFixed * factor;
195 *outMaxValue = (double)fMaxFixed * factor;
199 status_t
200 NumericValControl::setConstraints(double minValue, double maxValue)
202 if (maxValue < minValue)
203 return B_BAD_VALUE;
205 double factor = pow(10, fFractionalDigits);
207 fMinFixed = (minValue < 0.0) ?
208 (int64)floor(minValue * factor) :
209 (int64)ceil(minValue * factor);
211 fMaxFixed = (maxValue < 0.0) ?
212 (int64)floor(maxValue * factor) :
213 (int64)ceil(maxValue * factor);
215 return B_OK;
219 //! Fetches the current value (calculated on the spot from each
220 // segment.)
221 double
222 NumericValControl::value() const
224 // double acc = 0.0;
226 // // walk segments, adding the value of each
227 // for(int n = CountEntries(); n > 0; --n) {
228 // const ValCtrlLayoutEntry& e = entryAt(n-1);
229 // if(e.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
230 // const ValControlDigitSegment* digitSegment =
231 // dynamic_cast<ValControlDigitSegment*>(e.pView);
232 // ASSERT(digitSegment);
234 // PRINT((
235 // "\t...segment %d: %d digits at %d: %Ld\n",
236 // n-1,
237 // digitSegment->digitCount(),
238 // digitSegment->scaleFactor(),
239 // digitSegment->value()));
241 // acc += ((double)digitSegment->value() *
242 // pow(
243 // 10,
244 // digitSegment->scaleFactor()));
246 // PRINT((
247 // "\t-> %.12f\n\n", acc));
248 // }
249 // }
251 // return acc;
253 double ret = (double)_ValueFixed() / pow(10, fFractionalDigits);
255 // PRINT((
256 // "### NumericValControl::value(): %.12f\n", ret));
258 return ret;
262 //! Set the displayed value (and, if setParam is true, the
263 // linked parameter.) The value will be constrained if necessary.
264 void
265 NumericValControl::setValue(double value, bool setParam)
268 // PRINT((
269 // "### NumericValControl::setValue(%.12f)\n", value));
271 // round to displayed precision
272 double scaleFactor = pow(10, fFractionalDigits);
274 int64 fixed = (int64)(value * scaleFactor);
275 double junk = (value * scaleFactor) - (double)fixed;
277 // PRINT((
278 // " : junk == %.12f\n", junk));
280 if (value < 0.0) {
281 if (junk * scaleFactor < 0.5)
282 fixed--;
283 } else {
284 if (junk * scaleFactor >= 0.5)
285 fixed++;
288 value = (double)fixed / scaleFactor;
290 // PRINT((
291 // " -> %.12f, %Ld\n", value, fixed));
293 _SetValueFixed(fixed);
295 // notify target
296 Invoke();
298 // set parameter
299 if (setParam && fParam)
300 updateParameter(value);
302 // +++++ redraw?
305 //double NumericValControl::value() const {
306 // return m_dfValue;
307 // /*
308 // double dfCur = 0.0;
310 // // sum the values of all segments
311 // for(int nIndex = CountEntries()-1; nIndex >= 0; nIndex--) {
312 // if(entryAt(nIndex).type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
313 // const ValControlDigitSegment* pSeg =
314 // dynamic_cast<ValControlDigitSegment*>(entryAt(nIndex).pView);
315 // ASSERT(pSeg);
316 // dfCur += pSeg->value();
317 // }
318 // }
320 // return dfCur;*/
323 //void NumericValControl::setValue(double dfValue, bool bSetParam) {
325 // printf("setValue(%.12f)\n", dfValue);
328 // // constrain
329 // if(dfValue > m_maxValue)
330 // dfValue = m_maxValue;
331 // else if(dfValue < m_minValue)
332 // dfValue = m_minValue;
334 // // +++++ round to displayed precision
336 // // set value
337 // m_dfValue = dfValue;
339 // // set parameter
340 // if(bSetParam && fParam)
341 // updateParameter();
343 // // notify target (ugh. what if the target called this? +++++)
344 // Invoke();
346 // // hand value to each segment
347 // for(int nIndex = 0; nIndex < CountEntries(); nIndex++) {
348 // if(entryAt(nIndex).type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
349 // const ValControlDigitSegment* pSeg =
350 // dynamic_cast<ValControlDigitSegment*>(entryAt(nIndex).pView);
351 // ASSERT(pSeg);
352 // pSeg->setValue(!nIndex ? m_dfValue : fabs(m_dfValue));
353 // }
354 // }
357 // ---------------------------------------------------------------- //
358 // segment interface
359 // ---------------------------------------------------------------- //
361 //void NumericValControl::offsetValue(double dfDelta) {
362 //// printf("offset: %lf\t", dfDelta);
363 // setValue(value() + dfDelta, true);
364 //// printf("%lf\n", value());
367 // 18sep99: new segment interface. 'offset' is given
368 // in the segment's units.
370 void
371 NumericValControl::offsetSegmentValue(ValControlDigitSegment* segment,
372 int64 offset)
375 // PRINT((
376 // "### offsetSegmentValue(): %Ld\n",
377 // offset));
379 int64 segmentFactor = (int64)pow(10, fFractionalDigits + segment->scaleFactor());
381 int64 value = _ValueFixed();
383 // cut values below domain of the changed segment
384 value /= segmentFactor;
386 // add offset
387 value += offset;
389 // restore
390 value *= segmentFactor;
392 _SetValueFixed(value);
394 // notify target
395 Invoke();
397 if (fParam)
398 updateParameter((double)value * (double)segmentFactor);
402 void
403 NumericValControl::mediaParameterChanged()
405 // fetch value
406 size_t nSize;
407 bigtime_t tLastChanged;
408 status_t err;
409 switch (fParam->ValueType()) {
410 case B_FLOAT_TYPE:
411 { // +++++ left-channel hack
412 float fParamValue[4];
413 nSize = sizeof(float) * 4;
414 // +++++ broken
415 err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged);
416 // if (err != B_OK)
417 // break;
419 setValue(fParamValue[0]);
420 break;
423 case B_DOUBLE_TYPE:
425 double fParamValue;
426 nSize = sizeof(double);
427 err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged);
428 if (err != B_OK)
429 break;
431 setValue(fParamValue);
432 break;
438 void
439 NumericValControl::updateParameter(double value)
441 ASSERT(fParam);
443 // // is this kosher? +++++
444 // // ++++++ 18sep99: no.
445 // bigtime_t tpNow = system_time();
447 // store value
448 status_t err;
449 switch (fParam->ValueType()) {
450 case B_FLOAT_TYPE:
451 { // +++++ left-channel hack
452 float fValue[2];
453 fValue[0] = value;
454 fValue[1] = value;
455 err = fParam->SetValue((void*)&fValue, sizeof(float)*2, 0LL);
456 break;
459 case B_DOUBLE_TYPE: {
460 double fValue = value;
461 err = fParam->SetValue((void*)&fValue, sizeof(double), 0LL);
462 break;
468 void
469 NumericValControl::setValue(const void* data, size_t size)
474 void
475 NumericValControl::getValue(void* data, size_t* ioSize)
480 status_t
481 NumericValControl::setValueFrom(const char* text)
483 double d = atof(text);
484 setValue(d, true);
486 return B_OK;
490 status_t
491 NumericValControl::getString(BString& buffer)
493 // should provide the same # of digits as the control! +++++
494 BString format = "%.";
495 format << (int32)fFractionalDigits << 'f';
496 char cbuf[120];
497 sprintf(cbuf, format.String(), value());
498 buffer = cbuf;
500 return B_OK;
504 void
505 NumericValControl::MessageReceived(BMessage* pMsg)
507 status_t err;
508 double dfValue;
510 switch (pMsg->what) {
511 case M_SET_VALUE:
512 err = pMsg->FindDouble("value", &dfValue);
513 if (err < B_OK) {
514 _inherited::MessageReceived(pMsg);
515 break;
518 setValue(dfValue);
519 break;
521 case B_MEDIA_PARAMETER_CHANGED:
523 int32 id;
524 if (pMsg->FindInt32("be:parameter", &id) != B_OK)
525 break;
527 ASSERT(id == fParam->ID());
528 mediaParameterChanged();
529 break;
532 default:
533 _inherited::MessageReceived(pMsg);
534 break;
539 void
540 NumericValControl::_SetDefaultConstraints(bool negativeVisible)
542 double max = pow(10, fWholeDigits) - pow(10, -fFractionalDigits);
543 double min = (negativeVisible) ? -max : 0.0;
545 setConstraints(min, max);
549 //! calculates the current value as an int64
550 int64
551 NumericValControl::_ValueFixed() const {
553 // PRINT((
554 // "### NumericValControl::_ValueFixed()\n", value));
556 int64 acc = 0LL;
558 int64 scaleBase = fFractionalDigits;
560 // walk segments, adding the value of each
561 for (int n = CountEntries(); n > 0; --n) {
562 const ValCtrlLayoutEntry& entry = _EntryAt(n-1);
563 if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
564 const ValControlDigitSegment* digitSegment =
565 dynamic_cast<ValControlDigitSegment*>(entry.pView);
566 ASSERT(digitSegment);
568 // PRINT((
569 // "\t...segment %d: %d digits at %d: %Ld\n",
570 // n-1,
571 // digitSegment->digitCount(),
572 // digitSegment->scaleFactor(),
573 // digitSegment->value()));
575 acc += digitSegment->value() * (int64)pow(10,
576 scaleBase + digitSegment->scaleFactor());
578 // PRINT((
579 // "\t-> %Ld\n\n", acc));
583 return acc;
587 //! sets the value of each segment based on an int64 value;
588 // does not constrain the value
589 void
590 NumericValControl::_SetValueFixed(int64 fixed)
592 // PRINT((
593 // "### NumericValControl::_SetValueFixed(%Ld)\n", fixed));
595 // constrain
596 if (fixed > fMaxFixed)
597 fixed = fMaxFixed;
599 if (fixed < fMinFixed)
600 fixed = fMinFixed;
602 int64 scaleBase = fFractionalDigits;
604 // set segments
605 for (int n = CountEntries(); n > 0; --n) {
606 const ValCtrlLayoutEntry& entry = _EntryAt(n-1);
608 if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
609 ValControlDigitSegment* digitSegment =
610 dynamic_cast<ValControlDigitSegment*>(entry.pView);
611 ASSERT(digitSegment);
613 // PRINT((
614 // "\tsegment %d: %d digits at %d:\n",
615 // n-1,
616 // digitSegment->digitCount(),
617 // digitSegment->scaleFactor()));
619 // subtract higher-magnitude segments' value
620 int64 hiCut = fixed % (int64)pow(10,
621 scaleBase + digitSegment->scaleFactor() + digitSegment->digitCount());
623 // PRINT((
624 // "\t [] %Ld\n", hiCut));
626 // shift value
627 int64 segmentValue = hiCut / (int64)pow(10,
628 scaleBase + digitSegment->scaleFactor());
630 // PRINT((
631 // "\t -> %Ld\n\n", segmentValue));
633 digitSegment->setValue(segmentValue, fixed < 0);