2 * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
3 * Copyright (c) 2009 Dmitry Kazakov <dimula73@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #ifndef _KIS_CURVE_WIDGET_P_H_
20 #define _KIS_CURVE_WIDGET_P_H_
21 #include "kis_cubic_curve.h"
29 * Private members for KisCurveWidget class
31 class KisCurveWidget::Private
34 KisCurveWidget *m_curveWidget;
38 Private(KisCurveWidget *parent);
41 /* Dragging variables */
42 int m_grab_point_index;
45 double m_grabOriginalX;
46 double m_grabOriginalY;
47 QPointF m_draggedAwayPoint;
48 int m_draggedAwayPointIndex;
55 /* The curve itself */
57 KisCubicCurve m_curve;
61 QPixmap *m_pixmapCache;
67 /* Working range of them */
73 * At the moment used only for dragging.
77 inline void setState(enumState st);
78 inline enumState state() const;
82 /*** Internal routins ***/
85 * Common update routins
87 void setCurveModified();
88 void setCurveRepaint();
92 * Convert working range of
93 * In/Out controls to normalized
94 * range of spline (and reverse)
101 * Check whether newly created/moved point @pt doesn't overlap
102 * with any of existing ones from @m_points and adjusts its coordinates.
103 * @skipIndex is the index of the point, that shouldn't be taken
104 * into account during the search
105 * (e.g. beacuse it's @pt itself)
107 * Returns false in case the point can't be placed anywhere
108 * without overlapping
110 bool jumpOverExistingPoints(QPointF &pt, int skipIndex);
114 * Synchronize In/Out spinboxes with the curve
116 void syncIOControls();
119 * Find the nearest point to @pt from m_points
121 int nearestPointInRange(QPointF pt, int wWidth, int wHeight) const;
124 * Nothing to be said! =)
127 void drawGrid(QPainter &p, int wWidth, int wHeight);
131 KisCurveWidget::Private::Private(KisCurveWidget *parent)
133 m_curveWidget = parent;
136 KisCurveWidget::Private::~Private()
141 double KisCurveWidget::Private::io2sp(int x)
143 int rangeLen = m_inOutMax - m_inOutMin;
144 return double(x - m_inOutMin) / rangeLen;
147 int KisCurveWidget::Private::sp2io(double x)
149 int rangeLen = m_inOutMax - m_inOutMin;
150 return int(x*rangeLen + 0.5) + m_inOutMin;
154 bool KisCurveWidget::Private::jumpOverExistingPoints(QPointF &pt, int skipIndex)
156 foreach(const QPointF &it, m_curve.points()) {
157 if (m_curve.points().indexOf(it) == skipIndex)
159 if (fabs(it.x() - pt.x()) < POINT_AREA)
160 pt.rx() = pt.x() >= it.x() ?
161 it.x() + POINT_AREA : it.x() - POINT_AREA;
163 return (pt.x() >= 0 && pt.x() <= 1.);
166 int KisCurveWidget::Private::nearestPointInRange(QPointF pt, int wWidth, int wHeight) const
168 double nearestDistanceSquared = 1000;
169 int nearestIndex = -1;
172 foreach(const QPointF & point, m_curve.points()) {
173 double distanceSquared = (pt.x() - point.x()) *
174 (pt.x() - point.x()) +
175 (pt.y() - point.y()) *
176 (pt.y() - point.y());
178 if (distanceSquared < nearestDistanceSquared) {
180 nearestDistanceSquared = distanceSquared;
185 if (nearestIndex >= 0) {
186 if (fabs(pt.x() - m_curve.points()[nearestIndex].x()) *(wWidth - 1) < 5 &&
187 fabs(pt.y() - m_curve.points()[nearestIndex].y()) *(wHeight - 1) < 5) {
196 #define div2_round(x) (((x)+1)>>1)
197 #define div4_round(x) (((x)+2)>>2)
199 void KisCurveWidget::Private::drawGrid(QPainter &p, int wWidth, int wHeight)
202 * Hint: widget size should conform
203 * formula 4n+5 to draw grid correctly
204 * without curious shifts between
205 * spline and it caused by rounding
207 * That is not mandatory but desirable
210 p.setPen(QPen(Qt::gray, 1, Qt::SolidLine));
211 p.drawLine(div4_round(wWidth), 0, div4_round(wWidth), wHeight);
212 p.drawLine(div2_round(wWidth), 0, div2_round(wWidth), wHeight);
213 p.drawLine(div4_round(3*wWidth), 0, div4_round(3*wWidth), wHeight);
215 p.drawLine(0, div4_round(wHeight), wWidth, div4_round(wHeight));
216 p.drawLine(0, div2_round(wHeight), wWidth, div2_round(wHeight));
217 p.drawLine(0, div4_round(3*wHeight), wWidth, div4_round(3*wHeight));
221 void KisCurveWidget::Private::syncIOControls()
223 if (!m_intIn || !m_intOut)
226 bool somethingSelected = (m_grab_point_index >= 0);
228 m_intIn->setEnabled(somethingSelected);
229 m_intOut->setEnabled(somethingSelected);
231 if (m_grab_point_index >= 0) {
232 m_intIn->blockSignals(true);
233 m_intOut->blockSignals(true);
235 m_intIn->setValue(sp2io(m_curve.points()[m_grab_point_index].x()));
236 m_intOut->setValue(sp2io(m_curve.points()[m_grab_point_index].y()));
238 m_intIn->blockSignals(false);
239 m_intOut->blockSignals(false);
241 /*FIXME: Ideally, these controls should hide away now */
245 void KisCurveWidget::Private::setCurveModified()
248 m_splineDirty = true;
249 m_curveWidget->update();
250 m_curveWidget->emit modified();
253 void KisCurveWidget::Private::setCurveRepaint()
255 m_curveWidget->update();
258 void KisCurveWidget::Private::setState(enumState st)
264 enumState KisCurveWidget::Private::state() const
270 #endif /* _KIS_CURVE_WIDGET_P_H_ */