2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
36 #include "NumericValControl.h"
37 #include "ValControlDigitSegment.h"
38 #include "ValCtrlLayoutEntry.h"
42 #include <ParameterWeb.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),
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();
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),
83 fWholeDigits(wholeDigits
),
84 fFractionalDigits(fractionalDigits
)
86 _SetDefaultConstraints(negativeVisible
);
91 NumericValControl::~NumericValControl()
97 NumericValControl::param() const
104 NumericValControl::initSegments()
106 ASSERT(fWholeDigits
);
108 bool negativeVisible
= fMinFixed
< 0.0;
110 // *** SEGMENT DIVISION NEEDS TO BE CONFIGURABLE +++++
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
),
121 // add(new ValControlDigitSegment(fFractionalDigits, -fFractionalDigits,
122 // false, ValControlDigitSegment::ZERO_FILL),
126 // // +++++ individual-segment test
128 // for(int n = 0; n < fWholeDigits; ++n)
130 // new ValControlDigitSegment(1, fWholeDigits-n, bNegativeCapable),
133 // if(fFractionalDigits)
134 // add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST);
136 // for(int n = 0; n < fFractionalDigits; ++n)
138 // new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL),
144 NumericValControl::initConstraintsFromParam()
148 printf("NumericValControl::initConstraintsFromParam():\n ");
152 fParam
->GetResponse(&r
, &fFactor
, &fOffset
);
154 case BContinuousParameter::B_LINEAR
:
158 case BContinuousParameter::B_POLYNOMIAL
:
159 printf("Polynomial");
162 case BContinuousParameter::B_EXPONENTIAL
:
163 printf("Exponential");
166 case BContinuousParameter::B_LOGARITHMIC
:
167 printf("Logarithmic");
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)
190 NumericValControl::getConstraints(double* outMinValue
, double* outMaxValue
)
192 double factor
= pow(10, -fFractionalDigits
);
194 *outMinValue
= (double)fMinFixed
* factor
;
195 *outMaxValue
= (double)fMaxFixed
* factor
;
200 NumericValControl::setConstraints(double minValue
, double maxValue
)
202 if (maxValue
< minValue
)
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
);
219 //! Fetches the current value (calculated on the spot from each
222 NumericValControl::value() const
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);
235 // "\t...segment %d: %d digits at %d: %Ld\n",
237 // digitSegment->digitCount(),
238 // digitSegment->scaleFactor(),
239 // digitSegment->value()));
241 // acc += ((double)digitSegment->value() *
244 // digitSegment->scaleFactor()));
247 // "\t-> %.12f\n\n", acc));
253 double ret
= (double)_ValueFixed() / pow(10, fFractionalDigits
);
256 // "### NumericValControl::value(): %.12f\n", ret));
262 //! Set the displayed value (and, if setParam is true, the
263 // linked parameter.) The value will be constrained if necessary.
265 NumericValControl::setValue(double value
, bool setParam
)
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
;
278 // " : junk == %.12f\n", junk));
281 if (junk
* scaleFactor
< 0.5)
284 if (junk
* scaleFactor
>= 0.5)
288 value
= (double)fixed
/ scaleFactor
;
291 // " -> %.12f, %Ld\n", value, fixed));
293 _SetValueFixed(fixed
);
299 if (setParam
&& fParam
)
300 updateParameter(value
);
305 //double NumericValControl::value() const {
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);
316 // dfCur += pSeg->value();
323 //void NumericValControl::setValue(double dfValue, bool bSetParam) {
325 // printf("setValue(%.12f)\n", dfValue);
329 // if(dfValue > m_maxValue)
330 // dfValue = m_maxValue;
331 // else if(dfValue < m_minValue)
332 // dfValue = m_minValue;
334 // // +++++ round to displayed precision
337 // m_dfValue = dfValue;
340 // if(bSetParam && fParam)
341 // updateParameter();
343 // // notify target (ugh. what if the target called this? +++++)
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);
352 // pSeg->setValue(!nIndex ? m_dfValue : fabs(m_dfValue));
357 // ---------------------------------------------------------------- //
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.
371 NumericValControl::offsetSegmentValue(ValControlDigitSegment
* segment
,
376 // "### offsetSegmentValue(): %Ld\n",
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
;
390 value
*= segmentFactor
;
392 _SetValueFixed(value
);
398 updateParameter((double)value
* (double)segmentFactor
);
403 NumericValControl::mediaParameterChanged()
407 bigtime_t tLastChanged
;
409 switch (fParam
->ValueType()) {
411 { // +++++ left-channel hack
412 float fParamValue
[4];
413 nSize
= sizeof(float) * 4;
415 err
= fParam
->GetValue((void*)&fParamValue
, &nSize
, &tLastChanged
);
419 setValue(fParamValue
[0]);
426 nSize
= sizeof(double);
427 err
= fParam
->GetValue((void*)&fParamValue
, &nSize
, &tLastChanged
);
431 setValue(fParamValue
);
439 NumericValControl::updateParameter(double value
)
443 // // is this kosher? +++++
444 // // ++++++ 18sep99: no.
445 // bigtime_t tpNow = system_time();
449 switch (fParam
->ValueType()) {
451 { // +++++ left-channel hack
455 err
= fParam
->SetValue((void*)&fValue
, sizeof(float)*2, 0LL);
459 case B_DOUBLE_TYPE
: {
460 double fValue
= value
;
461 err
= fParam
->SetValue((void*)&fValue
, sizeof(double), 0LL);
469 NumericValControl::setValue(const void* data
, size_t size
)
475 NumericValControl::getValue(void* data
, size_t* ioSize
)
481 NumericValControl::setValueFrom(const char* text
)
483 double d
= atof(text
);
491 NumericValControl::getString(BString
& buffer
)
493 // should provide the same # of digits as the control! +++++
494 BString format
= "%.";
495 format
<< (int32
)fFractionalDigits
<< 'f';
497 sprintf(cbuf
, format
.String(), value());
505 NumericValControl::MessageReceived(BMessage
* pMsg
)
510 switch (pMsg
->what
) {
512 err
= pMsg
->FindDouble("value", &dfValue
);
514 _inherited::MessageReceived(pMsg
);
521 case B_MEDIA_PARAMETER_CHANGED
:
524 if (pMsg
->FindInt32("be:parameter", &id
) != B_OK
)
527 ASSERT(id
== fParam
->ID());
528 mediaParameterChanged();
533 _inherited::MessageReceived(pMsg
);
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
551 NumericValControl::_ValueFixed() const {
554 // "### NumericValControl::_ValueFixed()\n", value));
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
);
569 // "\t...segment %d: %d digits at %d: %Ld\n",
571 // digitSegment->digitCount(),
572 // digitSegment->scaleFactor(),
573 // digitSegment->value()));
575 acc
+= digitSegment
->value() * (int64
)pow(10,
576 scaleBase
+ digitSegment
->scaleFactor());
579 // "\t-> %Ld\n\n", acc));
587 //! sets the value of each segment based on an int64 value;
588 // does not constrain the value
590 NumericValControl::_SetValueFixed(int64 fixed
)
593 // "### NumericValControl::_SetValueFixed(%Ld)\n", fixed));
596 if (fixed
> fMaxFixed
)
599 if (fixed
< fMinFixed
)
602 int64 scaleBase
= fFractionalDigits
;
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
);
614 // "\tsegment %d: %d digits at %d:\n",
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());
624 // "\t [] %Ld\n", hiCut));
627 int64 segmentValue
= hiCut
/ (int64
)pow(10,
628 scaleBase
+ digitSegment
->scaleFactor());
631 // "\t -> %Ld\n\n", segmentValue));
633 digitSegment
->setValue(segmentValue
, fixed
< 0);