* Copyright 2015-2025 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#include <DecimalSpinner.h>
#include <stdio.h>
#include <stdlib.h>
#include <PropertyInfo.h>
#include <TextView.h>
static double
roundTo(double value, uint32 n)
{
return floor(value * pow(10.0, n) + 0.5) / pow(10.0, n);
}
static property_info sProperties[] = {
{
"MaxValue",
{ B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 },
"Returns the maximum value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"MaxValue",
{ B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0},
"Sets the maximum value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"MinValue",
{ B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 },
"Returns the minimum value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"MinValue",
{ B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0},
"Sets the minimum value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"Precision",
{ B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0},
"Sets the number of decimal places of precision of the spinner.",
0,
{ B_UINT32_TYPE }
},
{
"Precision",
{ B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 },
"Returns the number of decimal places of precision of the spinner.",
0,
{ B_UINT32_TYPE }
},
{
"Step",
{ B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 },
"Returns the step size of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"Step",
{ B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0},
"Sets the step size of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"Value",
{ B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 },
"Returns the value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{
"Value",
{ B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0},
"Sets the value of the spinner.",
0,
{ B_DOUBLE_TYPE }
},
{ 0 }
};
BDecimalSpinner::BDecimalSpinner(BRect frame, const char* name,
const char* label, BMessage* message, uint32 resizingMode, uint32 flags)
:
BAbstractSpinner(frame, name, label, message, resizingMode, flags)
{
_InitObject();
}
BDecimalSpinner::BDecimalSpinner(const char* name, const char* label,
BMessage* message, uint32 flags)
:
BAbstractSpinner(name, label, message, flags)
{
_InitObject();
}
BDecimalSpinner::BDecimalSpinner(BMessage* data)
:
BAbstractSpinner(data)
{
_InitObject();
if (data->FindDouble("_min", &fMinValue) != B_OK)
fMinValue = 0.0;
if (data->FindDouble("_max", &fMaxValue) != B_OK)
fMaxValue = 100.0;
if (data->FindUInt32("_precision", &fPrecision) != B_OK)
fPrecision = 2;
if (data->FindDouble("_step", &fStep) != B_OK)
fStep = 1.0;
if (data->FindDouble("_val", &fValue) != B_OK)
fValue = 0.0;
}
BDecimalSpinner::~BDecimalSpinner()
{
delete fNumberFormat;
}
BArchivable*
BDecimalSpinner::Instantiate(BMessage* data)
{
if (validate_instantiation(data, "DecimalSpinner"))
return new BDecimalSpinner(data);
return NULL;
}
status_t
BDecimalSpinner::Archive(BMessage* data, bool deep) const
{
status_t status = BAbstractSpinner::Archive(data, deep);
data->AddString("class", "DecimalSpinner");
if (status == B_OK)
status = data->AddDouble("_min", fMinValue);
if (status == B_OK)
status = data->AddDouble("_max", fMaxValue);
if (status == B_OK)
status = data->AddUInt32("_precision", fPrecision);
if (status == B_OK)
status = data->AddDouble("_step", fStep);
if (status == B_OK)
status = data->AddDouble("_val", fValue);
return status;
}
status_t
BDecimalSpinner::GetSupportedSuites(BMessage* message)
{
message->AddString("suites", "suite/vnd.Haiku-decimal-spinner");
BPropertyInfo prop_info(sProperties);
message->AddFlat("messages", &prop_info);
return BView::GetSupportedSuites(message);
}
void
BDecimalSpinner::AttachedToWindow()
{
SetValue(fValue);
BAbstractSpinner::AttachedToWindow();
}
void
BDecimalSpinner::Decrement()
{
SetValue(Value() - Step());
}
void
BDecimalSpinner::Increment()
{
SetValue(Value() + Step());
}
void
BDecimalSpinner::SetEnabled(bool enable)
{
if (IsEnabled() == enable)
return;
SetIncrementEnabled(enable && Value() < fMaxValue);
SetDecrementEnabled(enable && Value() > fMinValue);
BAbstractSpinner::SetEnabled(enable);
}
void
BDecimalSpinner::SetPrecision(uint32 precision)
{
if (precision == fPrecision)
return;
fPrecision = precision;
fNumberFormat->SetPrecision(precision);
}
void
BDecimalSpinner::SetMinValue(double min)
{
fMinValue = min;
SetValue(Value());
}
void
BDecimalSpinner::SetMaxValue(double max)
{
fMaxValue = max;
SetValue(Value());
}
void
BDecimalSpinner::Range(double* min, double* max)
{
*min = fMinValue;
*max = fMaxValue;
}
void
BDecimalSpinner::SetRange(double min, double max)
{
SetMinValue(min);
SetMaxValue(max);
}
void
BDecimalSpinner::SetValue(int32 value)
{
SetValue((double)value);
}
void
BDecimalSpinner::SetValue(double value)
{
if (value < fMinValue)
value = fMinValue;
else if (value > fMaxValue)
value = fMaxValue;
BString valueString;
fNumberFormat->Format(valueString, value);
TextView()->SetText(valueString.String());
SetIncrementEnabled(IsEnabled() && value < fMaxValue);
SetDecrementEnabled(IsEnabled() && value > fMinValue);
if (value == fValue)
return;
fValue = value;
ValueChanged();
Invoke();
Invalidate();
}
void
BDecimalSpinner::SetValueFromText()
{
double parsedValue;
if (fNumberFormat->Parse(TextView()->Text(), parsedValue) == B_OK)
SetValue(roundTo(parsedValue, Precision()));
}
void
BDecimalSpinner::_InitObject()
{
fMinValue = 0.0;
fMaxValue = 100.0;
fPrecision = 2;
fStep = 1.0;
fValue = 0.0;
fNumberFormat = new BNumberFormat();
fNumberFormat->SetPrecision(fPrecision);
TextView()->SetAlignment(B_ALIGN_RIGHT);
for (uint32 c = 0; c <= 42; c++)
TextView()->DisallowChar(c);
TextView()->DisallowChar('/');
for (uint32 c = 58; c <= 127; c++)
TextView()->DisallowChar(c);
}
void BDecimalSpinner::_ReservedDecimalSpinner20() {}
void BDecimalSpinner::_ReservedDecimalSpinner19() {}
void BDecimalSpinner::_ReservedDecimalSpinner18() {}
void BDecimalSpinner::_ReservedDecimalSpinner17() {}
void BDecimalSpinner::_ReservedDecimalSpinner16() {}
void BDecimalSpinner::_ReservedDecimalSpinner15() {}
void BDecimalSpinner::_ReservedDecimalSpinner14() {}
void BDecimalSpinner::_ReservedDecimalSpinner13() {}
void BDecimalSpinner::_ReservedDecimalSpinner12() {}
void BDecimalSpinner::_ReservedDecimalSpinner11() {}
void BDecimalSpinner::_ReservedDecimalSpinner10() {}
void BDecimalSpinner::_ReservedDecimalSpinner9() {}
void BDecimalSpinner::_ReservedDecimalSpinner8() {}
void BDecimalSpinner::_ReservedDecimalSpinner7() {}
void BDecimalSpinner::_ReservedDecimalSpinner6() {}
void BDecimalSpinner::_ReservedDecimalSpinner5() {}
void BDecimalSpinner::_ReservedDecimalSpinner4() {}
void BDecimalSpinner::_ReservedDecimalSpinner3() {}
void BDecimalSpinner::_ReservedDecimalSpinner2() {}
void BDecimalSpinner::_ReservedDecimalSpinner1() {}