Krita Source Code Documentation
Loading...
Searching...
No Matches
KisCurveWidgetControlsManager.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QSpinBox>
10#include <QDoubleSpinBox>
11#include <kis_curve_widget.h>
12#include <kis_signals_blocker.h>
13#include "kis_debug.h"
14
16
17namespace detail {
18qreal io2sp(int x, int min, int max)
19{
21 return unitConverter.io2sp(x, min, max);
22}
23
24int sp2io(qreal x, int min, int max)
25{
27 return unitConverter.sp2io(x, min, max);
28}
29
30qreal io2sp(qreal x, qreal min, qreal max)
31{
32 const qreal rangeLen = max - min;
33 return !qFuzzyIsNull(rangeLen) ? (x - min) / rangeLen : 0.0;
34}
35
36qreal sp2io(qreal x, qreal min, qreal max)
37{
38 const qreal rangeLen = max - min;
39 return x * rangeLen + min;
40}
41
42void setupStep(QSpinBox *spinBox, int min, int max) {
43 Q_UNUSED(min);
44 Q_UNUSED(max);
45 spinBox->setSingleStep(1);
46}
47
48void setupStep(QDoubleSpinBox *spinBox, qreal min, qreal max) {
49 if (qAbs(max - min) > 10) {
50 spinBox->setSingleStep(1.0);
51 } else {
52 spinBox->setSingleStep(0.1);
53 }
54}
55
56bool willChangeSpinBox(const QSpinBox *spinBox, int newValue)
57{
58 return spinBox->value() != newValue;
59}
60
61bool willChangeSpinBox(const QDoubleSpinBox *spinBox, qreal newValue)
62{
63 return qRound(spinBox->value() * spinBox->decimals()) !=
64 qRound(newValue * spinBox->decimals());
65}
66
67} // namespace detail
68
76
80
81
82template <typename SpinBox>
89
90template <typename SpinBox>
93 SpinBox *in, SpinBox *out,
94 ValueType inMin, ValueType inMax,
95 ValueType outMin, ValueType outMax)
97{
98 setupInOutControls(in, out, inMin, inMax, outMin, outMax);
99}
100
101template <typename SpinBox>
106
107template <typename SpinBox>
109setupInOutControls(SpinBox *in, SpinBox *out,
110 ValueType inMin, ValueType inMax,
111 ValueType outMin, ValueType outMax)
112{
113 dropInOutControls();
114
115 m_intIn = in;
116 m_intOut = out;
117
118 if (!m_intIn || !m_intOut)
119 return;
120
121 m_inMin = inMin;
122 m_inMax = inMax;
123 m_outMin = outMin;
124 m_outMax = outMax;
125
126 ValueType realInMin = qMin(inMin, inMax); // tilt elevation has range (90, 0), which QSpinBox can't handle
127 ValueType realInMax = qMax(inMin, inMax);
128
129 m_intIn->setRange(realInMin, realInMax);
130 m_intOut->setRange(m_outMin, m_outMax);
131
132 detail::setupStep(m_intIn, realInMin, realInMax);
133 detail::setupStep(m_intOut, m_outMin, m_outMax);
134
135 connect(m_intIn, qOverload<ValueType>(&SpinBox::valueChanged), this, &KisCurveWidgetControlsManager::inOutChanged, Qt::UniqueConnection);
136 connect(m_intOut, qOverload<ValueType>(&SpinBox::valueChanged), this, &KisCurveWidgetControlsManager::inOutChanged, Qt::UniqueConnection);
137
138 syncIOControls();
139}
140
141template <typename SpinBox>
144{
145 if (!m_intIn || !m_intOut)
146 return;
147
148 disconnect(m_intIn, qOverload<ValueType>(&SpinBox::valueChanged), this, &KisCurveWidgetControlsManager::inOutChanged);
149 disconnect(m_intOut, qOverload<ValueType>(&SpinBox::valueChanged), this, &KisCurveWidgetControlsManager::inOutChanged);
150
151 m_intIn = m_intOut = nullptr;
152
153}
154
155template <typename SpinBox>
158{
159 QPointF pt;
160
161 KIS_SAFE_ASSERT_RECOVER_RETURN(m_curveWidget->currentPoint());
162
163 pt.setX(detail::io2sp(m_intIn->value(), m_inMin, m_inMax));
164 pt.setY(detail::io2sp(m_intOut->value(), m_outMin, m_outMax));
165
166 if (m_curveWidget->setCurrentPointPosition(pt)) {
167 syncIOControls();
168 }
169}
170
171template <typename SpinBox>
174{
175 if (!m_intIn || !m_intOut)
176 return;
177
178 std::optional<QPointF> currentPointPosition = m_curveWidget->currentPointPosition();
179
180 m_intIn->setEnabled(currentPointPosition.has_value());
181 m_intOut->setEnabled(currentPointPosition.has_value());
182
183 if (currentPointPosition) {
184 KisSignalsBlocker b(m_intIn, m_intOut);
185
186 const ValueType inValue = detail::sp2io(currentPointPosition->x(), m_inMin, m_inMax);
187 const ValueType outValue = detail::sp2io(currentPointPosition->y(), m_outMin, m_outMax);
188
189 if (detail::willChangeSpinBox(m_intIn, inValue)) {
190 m_intIn->setValue(inValue);
191 }
192
193 if (detail::willChangeSpinBox(m_intOut, outValue)) {
194 m_intOut->setValue(outValue);
195 }
196 } else {
197 /*FIXME: Ideally, these controls should hide away now */
198 }
199}
200
201template <typename SpinBox>
204{
205 if (m_intIn) {
206 m_intIn->setFocus();
207 }
208}
209
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisCurveWidgetControlsManagerBase(KisCurveWidget *curveWidget)
void setupInOutControls(SpinBox *in, SpinBox *out, ValueType inMin, ValueType inMax, ValueType outMin, ValueType outMax)
KisCurveWidgetControlsManager(KisCurveWidget *curveWidget)
detail::value_of_spin_box_t< SpinBox > ValueType
void shouldSyncIOControls()
void shouldFocusIOControls()
double io2sp(int x, int min, int max)
int sp2io(double x, int min, int max)
static bool qFuzzyIsNull(half h)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KRITAUI_EXPORT_INSTANCE
void setupStep(QSpinBox *spinBox, int min, int max)
qreal io2sp(int x, int min, int max)
bool willChangeSpinBox(const QSpinBox *spinBox, int newValue)
int sp2io(qreal x, int min, int max)