Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_curve_widget_p.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
3 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7#ifndef _KIS_CURVE_WIDGET_P_H_
8#define _KIS_CURVE_WIDGET_P_H_
9#include <kis_cubic_curve.h>
10#include <QApplication>
11#include <QPalette>
12
17
21class Q_DECL_HIDDEN KisCurveWidget::Private
22{
23
24 KisCurveWidget *m_curveWidget {nullptr};
25
26public:
28
29 /* Dragging variables */
30 int m_grab_point_index {-1};
31 double m_grabOffsetX {0.0};
32 double m_grabOffsetY {0.0};
33 double m_grabOriginalX {0.0};
34 double m_grabOriginalY {0.0};
36 int m_draggedAwayPointIndex {0};
37
38 bool m_readOnlyMode {false};
39
40 /* The curve itself */
41 bool m_splineDirty {false};
44
45 QPixmap m_pix;
46 bool m_pixmapDirty {true};
47 QPixmap *m_pixmapCache {nullptr};
48
49 /* view-logic variables */
50 int m_handleSize {12}; // size of the control points (diameter, in logical pixels) - both for painting and for detecting clicks
51
57
58 inline void setState(enumState st);
59 inline enumState state() const;
60
65
66
67 /*** Internal routines ***/
68
72 void setCurveModified(bool rewriteSpinBoxesValues = true);
74
75
76
87 bool jumpOverExistingPoints(QPointF &pt, int skipIndex);
88
89
94
98 int nearestPointInRange(QPointF pt, int wWidth, int wHeight) const;
99
103 inline
104 void drawGrid(QPainter &p, int wWidth, int wHeight);
105
110};
111
112KisCurveWidget::Private::Private(KisCurveWidget *parent)
113 : m_modifiedSignalsCompressor(100, KisSignalCompressor::Mode::FIRST_INACTIVE)
114{
115 m_curveWidget = parent;
116}
117
118bool KisCurveWidget::Private::jumpOverExistingPoints(QPointF &pt, int skipIndex)
119{
120 Q_FOREACH (const KisCubicCurvePoint &it, m_curve.curvePoints()) {
121 if (m_curve.curvePoints().indexOf(it) == skipIndex)
122 continue;
123 if (fabs(it.x() - pt.x()) < POINT_AREA) {
124 pt.rx() = pt.x() >= it.x() ?
125 it.x() + POINT_AREA : it.x() - POINT_AREA;
126 }
127 }
128 return (pt.x() >= 0 && pt.x() <= 1.);
129}
130
131int KisCurveWidget::Private::nearestPointInRange(QPointF pt, int wWidth, int wHeight) const
132{
133 double nearestDistanceSquared = 1000;
134 int nearestIndex = -1;
135 int i = 0;
136
137 // Important:
138 // pt and points from the curve are in (0, 1) ranges
139 // hence the usage of wWidth etc.
140
141 Q_FOREACH (const KisCubicCurvePoint &point, m_curve.curvePoints()) {
142 double distanceSquared = (pt.x() - point.x()) *
143 (pt.x() - point.x()) +
144 (pt.y() - point.y()) *
145 (pt.y() - point.y());
146
147 if (distanceSquared < nearestDistanceSquared) {
148 nearestIndex = i;
149 nearestDistanceSquared = distanceSquared;
150 }
151 ++i;
152 }
153
154 if (nearestIndex >= 0) {
155
156 // difference between points is in (0, 1) range as well (or rather, (-1,1))
157 QPointF distanceVector = QPointF((pt.x() - m_curve.curvePoints()[nearestIndex].x()) *(wWidth - 1),
158 (pt.y() - m_curve.curvePoints()[nearestIndex].y()) *(wHeight - 1));
159
160 if (distanceVector.x() > m_handleSize || distanceVector.y() > m_handleSize) {
161 // small performance optimization
162 // distance is for sure bigger than m_handleSize now, no need to check
163 return -1;
164 }
165
166 double distanceInPixels = QLineF(distanceVector, QPointF(0, 0)).length();
167
168 if (distanceInPixels <= m_handleSize) {
169 return nearestIndex;
170 }
171 }
172
173 return -1;
174}
175
176
177#define div2_round(x) (((x)+1)>>1)
178#define div4_round(x) (((x)+2)>>2)
179
180void KisCurveWidget::Private::drawGrid(QPainter &p, int wWidth, int wHeight)
181{
191 QPalette appPalette = QApplication::palette();
192
193 p.setPen(QPen(appPalette.color(QPalette::Window), 1, Qt::SolidLine));
194 p.drawLine(div4_round(wWidth), 0, div4_round(wWidth), wHeight);
195 p.drawLine(div2_round(wWidth), 0, div2_round(wWidth), wHeight);
196 p.drawLine(div4_round(3*wWidth), 0, div4_round(3*wWidth), wHeight);
197
198 p.drawLine(0, div4_round(wHeight), wWidth, div4_round(wHeight));
199 p.drawLine(0, div2_round(wHeight), wWidth, div2_round(wHeight));
200 p.drawLine(0, div4_round(3*wHeight), wWidth, div4_round(3*wHeight));
201
202}
203
204void KisCurveWidget::Private::syncIOControls()
205{
206 Q_EMIT m_curveWidget->shouldSyncIOControls();
207}
208
209void KisCurveWidget::Private::setCurveModified(bool rewriteSpinBoxesValues)
210{
211 if (rewriteSpinBoxesValues) {
212 syncIOControls();
213 }
214 m_splineDirty = true;
215 m_curveWidget->update();
216 Q_EMIT m_curveWidget->compressorShouldEmitModified();
217}
218
219void KisCurveWidget::Private::setCurveRepaint()
220{
221 m_curveWidget->update();
222}
223
224void KisCurveWidget::Private::setState(enumState st)
225{
226 m_state = st;
227}
228
229
230enumState KisCurveWidget::Private::state() const
231{
232 return m_state;
233}
234
235void KisCurveWidget::Private::applyGlobalPointConstrain()
236{
237 if (m_globalPointConstrain == PointConstrain_AlwaysCorner) {
238 for (int i = 0; i < m_curve.points().size(); ++i) {
239 m_curve.setPointAsCorner(i, true);
240 }
241 } else if (m_globalPointConstrain == PointConstrain_AlwaysSmooth) {
242 for (int i = 0; i < m_curve.points().size(); ++i) {
243 m_curve.setPointAsCorner(i, false);
244 }
245 } // else { // No need to change the points here }
246}
247
248#endif /* _KIS_CURVE_WIDGET_P_H_ */
const Params2D p
KisCubicCurve m_curve
void setCurveRepaint()
void setState(enumState st)
KisCubicCurvePoint m_draggedAwayPoint
void applyGlobalPointConstrain()
void syncIOControls()
bool jumpOverExistingPoints(QPointF &pt, int skipIndex)
void setCurveModified(bool rewriteSpinBoxesValues=true)
KisThreadSafeSignalCompressor m_modifiedSignalsCompressor
void drawGrid(QPainter &p, int wWidth, int wHeight)
enumState state() const
int nearestPointInRange(QPointF pt, int wWidth, int wHeight) const
Private(KisCurveWidget *parent)
KisCurveWidget * m_curveWidget
#define POINT_AREA
@ ST_DRAG
@ ST_NORMAL
#define div4_round(x)
#define div2_round(x)
int size(const Forest< T > &forest)
Definition KisForest.h:1232