Commit 3918b186 authored by Yuri Chornoivan's avatar Yuri Chornoivan
Browse files

Get rid of extra KDoubleNumInput reimplementation

parent b89152a0
......@@ -97,7 +97,6 @@ set(box2d_SRCS
set(kolf_LIB_SRCS
game.cpp
kolf.cpp
kolfNumInput.cpp
newgame.cpp
canvasitem.cpp
ball.cpp
......
/* This file is part of the KDE libraries
* Initial implementation:
* Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
* Rewritten and maintained by:
* Copyright (c) 2000 Dirk Mueller <mueller@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kolfNumInput.h"
#include <cmath>
#include <QApplication>
#include <QLabel>
#include <QResizeEvent>
#include <QSlider>
#include <QStyle>
#include <KConfigDialogManager>
static inline int calcDiffByTen(int x, int y)
{
// calculate ( x - y ) / 10 without overflowing ints:
return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10;
}
// ----------------------------------------------------------------------------
class kolfNumInputPrivate
{
public:
kolfNumInputPrivate(kolfNumInput *q) :
q(q),
column1Width(0),
column2Width(0),
label(0),
slider(0),
labelAlignment(0)
{
}
static kolfNumInputPrivate *get(const kolfNumInput *i)
{
return i->d;
}
kolfNumInput *q;
int column1Width, column2Width;
QLabel *label;
QSlider *slider;
QSize sliderSize, labelSize;
Qt::Alignment labelAlignment;
};
#define K_USING_kolfNumInput_P(_d) kolfNumInputPrivate *_d = kolfNumInputPrivate::get(this)
kolfNumInput::kolfNumInput(QWidget *parent)
: QWidget(parent), d(new kolfNumInputPrivate(this))
{
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
setFocusPolicy(Qt::StrongFocus);
KConfigDialogManager::changedMap()->insert(QStringLiteral("kpIntNumInput"), SIGNAL(valueChanged(int)));
KConfigDialogManager::changedMap()->insert(QStringLiteral("QSpinBox"), SIGNAL(valueChanged(int)));
KConfigDialogManager::changedMap()->insert(QStringLiteral("kolfDoubleSpinBox"), SIGNAL(valueChanged(double)));
}
kolfNumInput::~kolfNumInput()
{
delete d;
}
QSlider *kolfNumInput::slider() const
{
return d->slider;
}
bool kolfNumInput::showSlider() const
{
return d->slider;
}
void kolfNumInput::setLabel(const QString &label, Qt::Alignment a)
{
if (label.isEmpty()) {
delete d->label;
d->label = 0;
d->labelAlignment = {};
} else {
if (!d->label) {
d->label = new QLabel(this);
}
d->label->setText(label);
d->label->setObjectName(QStringLiteral("kolfNumInput::QLabel"));
d->label->setAlignment(a);
// if no vertical alignment set, use Top alignment
if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) {
a |= Qt::AlignTop;
}
d->labelAlignment = a;
}
layout();
}
QString kolfNumInput::label() const
{
return d->label ? d->label->text() : QString();
}
void kolfNumInput::layout()
{
// label sizeHint
d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0));
if (d->label && (d->labelAlignment & Qt::AlignVCenter)) {
d->column1Width = d->labelSize.width() + 4;
} else {
d->column1Width = 0;
}
// slider sizeHint
d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0));
doLayout();
}
QSize kolfNumInput::sizeHint() const
{
return minimumSizeHint();
}
void kolfNumInput::setSteps(int minor, int major)
{
if (d->slider) {
d->slider->setSingleStep(minor);
d->slider->setPageStep(major);
}
}
// ----------------------------------------------------------------------------
class kolfDoubleNumInput::kolfDoubleNumInputPrivate
{
public:
kolfDoubleNumInputPrivate()
: spin(0) {}
QDoubleSpinBox *spin;
QSize editSize;
QString specialValue;
};
kolfDoubleNumInput::kolfDoubleNumInput(QWidget *parent)
: kolfNumInput(parent)
, d(new kolfDoubleNumInputPrivate())
{
initWidget(0.0, 0.0, 9999.0, 0.01, 2);
}
kolfDoubleNumInput::kolfDoubleNumInput(double lower, double upper, double value, QWidget *parent,
double singleStep, int precision)
: kolfNumInput(parent)
, d(new kolfDoubleNumInputPrivate())
{
initWidget(value, lower, upper, singleStep, precision);
}
kolfDoubleNumInput::~kolfDoubleNumInput()
{
delete d;
}
QString kolfDoubleNumInput::specialValueText() const
{
return d->specialValue;
}
void kolfDoubleNumInput::initWidget(double value, double lower, double upper,
double singleStep, int precision)
{
d->spin = new QDoubleSpinBox(this);
d->spin->setRange(lower, upper);
d->spin->setSingleStep(singleStep);
d->spin->setValue(value);
d->spin->setDecimals(precision);
d->spin->setObjectName(QStringLiteral("kolfDoubleNumInput::QDoubleSpinBox"));
setFocusProxy(d->spin);
connect(d->spin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this, &kolfDoubleNumInput::valueChanged);
layout();
}
double kolfDoubleNumInput::mapSliderToSpin(int val) const
{
K_USING_kolfNumInput_P(priv);
// map [slidemin,slidemax] to [spinmin,spinmax]
const double spinmin = d->spin->minimum();
const double spinmax = d->spin->maximum();
const double slidemin = priv->slider->minimum(); // cast int to double to avoid
const double slidemax = priv->slider->maximum(); // overflow in rel denominator
const double rel = (double(val) - slidemin) / (slidemax - slidemin);
return spinmin + rel * (spinmax - spinmin);
}
void kolfDoubleNumInput::sliderMoved(int val)
{
d->spin->setValue(mapSliderToSpin(val));
}
void kolfDoubleNumInput::spinBoxChanged(double val)
{
K_USING_kolfNumInput_P(priv);
const double spinmin = d->spin->minimum();
const double spinmax = d->spin->maximum();
const double slidemin = priv->slider->minimum(); // cast int to double to avoid
const double slidemax = priv->slider->maximum(); // overflow in rel denominator
const double rel = (val - spinmin) / (spinmax - spinmin);
if (priv->slider) {
priv->slider->blockSignals(true);
priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin)));
priv->slider->blockSignals(false);
}
}
QSize kolfDoubleNumInput::minimumSizeHint() const
{
K_USING_kolfNumInput_P(priv);
ensurePolished();
int w;
int h;
h = qMax(d->editSize.height(), priv->sliderSize.height());
// if in extra row, then count it here
if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
h += 4 + priv->labelSize.height();
} else {
// label is in the same row as the other widgets
h = qMax(h, priv->labelSize.height() + 2);
}
const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0;
w += priv->column1Width + priv->column2Width;
if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
w = qMax(w, priv->labelSize.width() + 4);
}
return QSize(w, h);
}
void kolfDoubleNumInput::resizeEvent(QResizeEvent *e)
{
K_USING_kolfNumInput_P(priv);
int w = priv->column1Width;
int h = 0;
const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
h += priv->labelSize.height() + 4;
}
if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
priv->label->setGeometry(0, 0, w, d->editSize.height());
}
if (qApp->layoutDirection() == Qt::RightToLeft) {
d->spin->setGeometry(w, h, priv->slider ? priv->column2Width
: e->size().width() - w, d->editSize.height());
w += priv->column2Width + spacingHint;
if (priv->slider) {
priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + spacingHint);
}
} else if (priv->slider) {
priv->slider->setGeometry(w, h, e->size().width() -
(priv->column1Width + priv->column2Width + spacingHint),
d->editSize.height() + spacingHint);
d->spin->setGeometry(w + priv->slider->width() + spacingHint, h,
priv->column2Width, d->editSize.height());
} else {
d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height());
}
h += d->editSize.height() + 2;
if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
}
}
void kolfDoubleNumInput::doLayout()
{
K_USING_kolfNumInput_P(priv);
d->editSize = d->spin->sizeHint();
priv->column2Width = d->editSize.width();
}
void kolfDoubleNumInput::setValue(double val)
{
d->spin->setValue(val);
}
void kolfDoubleNumInput::setRange(double lower, double upper, double singleStep)
{
K_USING_kolfNumInput_P(priv);
QDoubleSpinBox *spin = d->spin;
d->spin->setRange(lower, upper);
d->spin->setSingleStep(singleStep);
const double range = spin->maximum() - spin->minimum();
const double steps = range * pow(10.0, spin->decimals());
if (!priv->slider) {
priv->slider = new QSlider(Qt::Horizontal, this);
priv->slider->setTickPosition(QSlider::TicksBelow);
// feedback line: when one moves, the other moves, too:
connect(priv->slider, &QSlider::valueChanged,
this, &kolfDoubleNumInput::sliderMoved);
layout();
}
if (steps > 1000 ) {
priv->slider->setRange(0, 1000);
priv->slider->setSingleStep(1);
priv->slider->setPageStep(50);
} else {
const int singleSteps = qRound(steps);
priv->slider->setRange(0, singleSteps);
priv->slider->setSingleStep(1);
const int pageSteps = qBound(1, singleSteps / 20, 10);
priv->slider->setPageStep(pageSteps);
}
spinBoxChanged(spin->value());
connect(spin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &kolfDoubleNumInput::spinBoxChanged);
layout();
}
void kolfDoubleNumInput::setMinimum(double min)
{
setRange(min, maximum(), d->spin->singleStep());
}
double kolfDoubleNumInput::minimum() const
{
return d->spin->minimum();
}
void kolfDoubleNumInput::setMaximum(double max)
{
setRange(minimum(), max, d->spin->singleStep());
}
double kolfDoubleNumInput::maximum() const
{
return d->spin->maximum();
}
double kolfDoubleNumInput::singleStep() const
{
return d->spin->singleStep();
}
void kolfDoubleNumInput::setSingleStep(double singleStep)
{
d->spin->setSingleStep(singleStep);
}
double kolfDoubleNumInput::value() const
{
return d->spin->value();
}
QString kolfDoubleNumInput::suffix() const
{
return d->spin->suffix();
}
void kolfDoubleNumInput::setSuffix(const QString &suffix)
{
d->spin->setSuffix(suffix);
layout();
}
void kolfDoubleNumInput::setDecimals(int decimals)
{
d->spin->setDecimals(decimals);
layout();
}
int kolfDoubleNumInput::decimals() const
{
return d->spin->decimals();
}
void kolfDoubleNumInput::setSpecialValueText(const QString &text)
{
d->spin->setSpecialValueText(text);
layout();
}
void kolfDoubleNumInput::setLabel(const QString &label, Qt::Alignment a)
{
K_USING_kolfNumInput_P(priv);
kolfNumInput::setLabel(label, a);
if (priv->label) {
priv->label->setBuddy(d->spin);
}
}
#include "moc_kolfNumInput.cpp"
/* This file is part of the KDE libraries
* Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
* Copyright (c) 2000 Dirk Mueller <mueller@kde.org>
* Copyright (c) 2002 Marc Mutz <mutz@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef kolfNumInput_H
#define kolfNumInput_H
#include <QWidget>
#include <QSpinBox>
class QSlider;
class QSpinBox;
class kolfNumInputPrivate;
class kolfNumInput : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString label READ label WRITE setLabel)
public:
/**
* Default constructor
* @param parent If parent is 0, the new widget becomes a top-level
* window. If parent is another widget, this widget becomes a child
* window inside parent. The new widget is deleted when its parent is deleted.
*/
explicit kolfNumInput(QWidget *parent = 0);
/**
* Destructor
*/
~kolfNumInput();
/**
* Sets the text and alignment of the main description label.
*
* @param label The text of the label.
* Use QString() to remove an existing one.
*
* @param a The alignment of the label (Qt::Alignment).
* Default is @p Qt:AlignLeft | @p Qt:AlignTop.
*
* The vertical alignment flags have special meaning with this
* widget:
*
* @li @p Qt:AlignTop The label is placed above the edit/slider
* @li @p Qt:AlignVCenter The label is placed left beside the edit
* @li @p Qt:AlignBottom The label is placed below the edit/slider
*
*/
virtual void setLabel(const QString &label, Qt::Alignment a = Qt::AlignLeft | Qt::AlignTop);
/**
* @return the text of the label.
*/
QString label() const;
/**
* @return if the num input has a slider.
*/
bool showSlider() const;
/**
* Sets the spacing of tickmarks for the slider.
*
* @param minor Minor tickmark separation.
* @param major Major tickmark separation.
*/
void setSteps(int minor, int major);
/**
* Returns a size which fits the contents of the control.
*
* @return the preferred size necessary to show the control
*/
QSize sizeHint() const Q_DECL_OVERRIDE;
protected:
/**
* @return the slider widget.
* @internal
*/
QSlider *slider() const;
/**
* Call this function whenever you change something in the geometry
* of your kolfNumInput child.
*
*/
void layout();
/**
* You need to overwrite this method and implement your layout
* calculations there.
*
* See kpIntNumInput::doLayout and kolfDoubleNumInput::doLayout implementation
* for details.
*
*/
virtual void doLayout() = 0;
private:
friend class kolfNumInputPrivate;
kolfNumInputPrivate *const d;
Q_DISABLE_COPY(kolfNumInput)
};
class kolfDoubleLine;
/**
* @short An input control for real numbers, consisting of a spinbox and a slider.
*
* kolfDoubleNumInput combines a QSpinBox and optionally a QSlider
* with a label to make an easy to use control for setting some float
* parameter. This is especially nice for configuration dialogs,
* which can have many such combinated controls.
*
* The slider is created only when the user specifies a range
* for the control using the setRange function with the slider
* parameter set to "true".
*
* A special feature of kolfDoubleNumInput, designed specifically for
* the situation when there are several instances in a column,
* is that you can specify what portion of the control is taken by the
* QSpinBox (the remaining portion is used by the slider). This makes
* it very simple to have all the sliders in a column be the same size.
*/
class kolfDoubleNumInput : public kolfNumInput
{
Q_OBJECT
Q_PROPERTY(double value READ value WRITE setValue NOTIFY valueChanged USER true)
Q_PROPERTY(double minimum READ minimum WRITE setMinimum)
Q_PROPERTY(double maximum READ maximum WRITE setMaximum)
Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep)
Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
Q_PROPERTY(QString specialValueText READ specialValueText WRITE setSpecialValueText)
Q_PROPERTY(int decimals READ decimals WRITE setDecimals)
public:
/**
* Constructs an input control for double values
* with initial value 0.00.
*/
explicit kolfDoubleNumInput(QWidget *parent = 0);
/**
* Constructor
*
* @param lower lower boundary value
* @param upper upper boundary value
* @param value initial value for the control
* @param singleStep step size to use for up/down arrow clicks
* @param precision number of digits after the decimal point
* @param parent parent QWidget
*/
kolfDoubleNumInput(double