* Copyright (c) 1999-2000, Eric Moon.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "NumericValControl.h"
#include "ValControlDigitSegment.h"
#include "ValCtrlLayoutEntry.h"
#include <Debug.h>
#include <MediaKit.h>
#include <ParameterWeb.h>
#include <cstdio>
#include <stdlib.h>
#include <string.h>
__USE_CORTEX_NAMESPACE
NumericValControl::NumericValControl(BRect frame, const char* name, BContinuousParameter* param,
uint16 wholeDigits, uint16 fractionalDigits, align_mode alignMode, align_flags alignFlags)
: ValControl(frame, name, 0, 0, alignMode, alignFlags, UPDATE_ASYNC, false),
fParam(param),
fWholeDigits(wholeDigits),
fFractionalDigits(fractionalDigits)
{
ASSERT(fParam->ValueType() == B_FLOAT_TYPE ||
fParam->ValueType() == B_DOUBLE_TYPE
m_pParam->ValueType() == B_INT8_TYPE ||
m_pParam->ValueType() == B_UINT8_TYPE ||
m_pParam->ValueType() == B_INT16_TYPE ||
m_pParam->ValueType() == B_UINT16_TYPE ||
m_pParam->ValueType() == B_INT32_TYPE ||
m_pParam->ValueType() == B_UINT32_TYPE ||
m_pParam->ValueType() == B_INT64_TYPE ||
m_pParam->ValueType() == B_UINT64_TYPE*/ );
initConstraintsFromParam();
initSegments();
mediaParameterChanged();
}
NumericValControl::NumericValControl(BRect frame, const char* name, BMessage* message,
uint16 wholeDigits, uint16 fractionalDigits, bool negativeVisible,
align_mode alignMode, align_flags alignFlags)
: ValControl(frame, name, 0, message, alignMode, alignFlags, UPDATE_ASYNC, false),
fParam(0),
fWholeDigits(wholeDigits),
fFractionalDigits(fractionalDigits)
{
_SetDefaultConstraints(negativeVisible);
initSegments();
}
NumericValControl::~NumericValControl()
{
}
BContinuousParameter*
NumericValControl::param() const
{
return fParam;
}
void
NumericValControl::initSegments()
{
ASSERT(fWholeDigits);
bool negativeVisible = fMinFixed < 0.0;
_Add(new ValControlDigitSegment(fWholeDigits, 0, negativeVisible), RIGHT_MOST);
if (fFractionalDigits)
_Add(ValCtrlLayoutEntry::decimalPoint, RIGHT_MOST);
for (int n = 0; n < fFractionalDigits; ++n)
_Add(new ValControlDigitSegment(1, (-1)-n, false, ValControlDigitSegment::ZERO_FILL),
RIGHT_MOST);
}
void
NumericValControl::initConstraintsFromParam()
{
ASSERT(fParam);
printf("NumericValControl::initConstraintsFromParam():\n ");
int r;
float fFactor;
float fOffset;
fParam->GetResponse(&r, &fFactor, &fOffset);
switch (r) {
case BContinuousParameter::B_LINEAR:
printf("Linear");
break;
case BContinuousParameter::B_POLYNOMIAL:
printf("Polynomial");
break;
case BContinuousParameter::B_EXPONENTIAL:
printf("Exponential");
break;
case BContinuousParameter::B_LOGARITHMIC:
printf("Logarithmic");
break;
default:
printf("unknown (?)");
}
printf(" response; factor %.2f, offset %.2f\n", fFactor, fOffset);
setConstraints(fParam->MinValue(), fParam->MaxValue());
float fStep = fParam->ValueStep();
printf(" min value: %f\n", fParam->MinValue());
printf(" max value: %f\n", fParam->MaxValue());
printf(" value step: %f\n\n", fStep);
}
void
NumericValControl::getConstraints(double* outMinValue, double* outMaxValue)
{
double factor = pow(10, -fFractionalDigits);
*outMinValue = (double)fMinFixed * factor;
*outMaxValue = (double)fMaxFixed * factor;
}
status_t
NumericValControl::setConstraints(double minValue, double maxValue)
{
if (maxValue < minValue)
return B_BAD_VALUE;
double factor = pow(10, fFractionalDigits);
fMinFixed = (minValue < 0.0) ?
(int64)floor(minValue * factor) :
(int64)ceil(minValue * factor);
fMaxFixed = (maxValue < 0.0) ?
(int64)floor(maxValue * factor) :
(int64)ceil(maxValue * factor);
return B_OK;
}
double
NumericValControl::value() const
{
double ret = (double)_ValueFixed() / pow(10, fFractionalDigits);
return ret;
}
void
NumericValControl::setValue(double value, bool setParam)
{
double scaleFactor = pow(10, fFractionalDigits);
int64 fixed = (int64)(value * scaleFactor);
double junk = (value * scaleFactor) - (double)fixed;
if (value < 0.0) {
if (junk * scaleFactor < 0.5)
fixed--;
} else {
if (junk * scaleFactor >= 0.5)
fixed++;
}
value = (double)fixed / scaleFactor;
_SetValueFixed(fixed);
Invoke();
if (setParam && fParam)
updateParameter(value);
}
void
NumericValControl::offsetSegmentValue(ValControlDigitSegment* segment,
int64 offset)
{
int64 segmentFactor = (int64)pow(10, fFractionalDigits + segment->scaleFactor());
int64 value = _ValueFixed();
value /= segmentFactor;
value += offset;
value *= segmentFactor;
_SetValueFixed(value);
Invoke();
if (fParam)
updateParameter((double)value * (double)segmentFactor);
}
void
NumericValControl::mediaParameterChanged()
{
size_t nSize;
bigtime_t tLastChanged;
status_t err;
switch (fParam->ValueType()) {
case B_FLOAT_TYPE:
{
float fParamValue[4];
nSize = sizeof(float) * 4;
err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged);
setValue(fParamValue[0]);
break;
}
case B_DOUBLE_TYPE:
{
double fParamValue;
nSize = sizeof(double);
err = fParam->GetValue((void*)&fParamValue, &nSize, &tLastChanged);
if (err != B_OK)
break;
setValue(fParamValue);
break;
}
}
}
void
NumericValControl::updateParameter(double value)
{
ASSERT(fParam);
switch (fParam->ValueType()) {
case B_FLOAT_TYPE:
{
float fValue[2];
fValue[0] = value;
fValue[1] = value;
fParam->SetValue((void*)&fValue, sizeof(float)*2, 0LL);
break;
}
case B_DOUBLE_TYPE: {
double fValue = value;
fParam->SetValue((void*)&fValue, sizeof(double), 0LL);
break;
}
}
}
void
NumericValControl::setValue(const void* data, size_t size)
{
}
void
NumericValControl::getValue(void* data, size_t* ioSize)
{
}
status_t
NumericValControl::setValueFrom(const char* text)
{
double d = atof(text);
setValue(d, true);
return B_OK;
}
status_t
NumericValControl::getString(BString& buffer)
{
BString format = "%.";
format << (int32)fFractionalDigits << 'f';
char cbuf[120];
sprintf(cbuf, format.String(), value());
buffer = cbuf;
return B_OK;
}
void
NumericValControl::MessageReceived(BMessage* pMsg)
{
status_t err;
double dfValue;
switch (pMsg->what) {
case M_SET_VALUE:
err = pMsg->FindDouble("value", &dfValue);
if (err < B_OK) {
_inherited::MessageReceived(pMsg);
break;
}
setValue(dfValue);
break;
case B_MEDIA_PARAMETER_CHANGED:
{
int32 id;
if (pMsg->FindInt32("be:parameter", &id) != B_OK)
break;
ASSERT(id == fParam->ID());
mediaParameterChanged();
break;
}
default:
_inherited::MessageReceived(pMsg);
break;
}
}
void
NumericValControl::_SetDefaultConstraints(bool negativeVisible)
{
double max = pow(10, fWholeDigits) - pow(10, -fFractionalDigits);
double min = (negativeVisible) ? -max : 0.0;
setConstraints(min, max);
}
int64
NumericValControl::_ValueFixed() const {
int64 acc = 0LL;
int64 scaleBase = fFractionalDigits;
for (int n = CountEntries(); n > 0; --n) {
const ValCtrlLayoutEntry& entry = _EntryAt(n-1);
if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
const ValControlDigitSegment* digitSegment =
dynamic_cast<ValControlDigitSegment*>(entry.pView);
ASSERT(digitSegment);
acc += digitSegment->value() * (int64)pow(10,
scaleBase + digitSegment->scaleFactor());
}
}
return acc;
}
void
NumericValControl::_SetValueFixed(int64 fixed)
{
if (fixed > fMaxFixed)
fixed = fMaxFixed;
if (fixed < fMinFixed)
fixed = fMinFixed;
int64 scaleBase = fFractionalDigits;
for (int n = CountEntries(); n > 0; --n) {
const ValCtrlLayoutEntry& entry = _EntryAt(n-1);
if (entry.type == ValCtrlLayoutEntry::SEGMENT_ENTRY) {
ValControlDigitSegment* digitSegment =
dynamic_cast<ValControlDigitSegment*>(entry.pView);
ASSERT(digitSegment);
int64 hiCut = fixed % (int64)pow(10,
scaleBase + digitSegment->scaleFactor() + digitSegment->digitCount());
int64 segmentValue = hiCut / (int64)pow(10,
scaleBase + digitSegment->scaleFactor());
digitSegment->setValue(segmentValue, fixed < 0);
}
}
}