00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <cmath>
00021 #include <cstdlib>
00022
00023
00024
00025 #include <qpixmap.h>
00026 #include <qpainter.h>
00027 #include <qpoint.h>
00028 #include <qpen.h>
00029 #include <qevent.h>
00030 #include <qtimer.h>
00031 #include <qrect.h>
00032 #include <qfont.h>
00033 #include <qfontmetrics.h>
00034
00035
00036
00037 #include <kdebug.h>
00038 #include <kcursor.h>
00039 #include <klocale.h>
00040
00041
00042
00043 #include "kcurve.h"
00044
00045 KCurve::KCurve(QWidget *parent, const char *name, WFlags f)
00046 : QWidget(parent, name, f)
00047 {
00048 m_grab_point = NULL;
00049 m_readOnlyMode = false;
00050 m_guideVisible = false;
00051 m_dragging = false;
00052 m_pix = NULL;
00053
00054 setMouseTracking(true);
00055 setPaletteBackgroundColor(Qt::NoBackground);
00056 setMinimumSize(150, 50);
00057 QPair<double,double> *p = new QPair<double,double>;
00058 p->first = 0.0; p->second=0.0;
00059 m_points.append(p);
00060 p = new QPair<double,double>;
00061 p->first = 1.0; p->second=1.0;
00062 m_points.append(p);
00063 m_points.setAutoDelete(true);
00064 setFocusPolicy(QWidget::StrongFocus);
00065 }
00066
00067 KCurve::~KCurve()
00068 {
00069 if (m_pix) delete m_pix;
00070 }
00071
00072 void KCurve::reset(void)
00073 {
00074 m_grab_point = NULL;
00075 m_guideVisible = false;
00076 repaint(false);
00077 }
00078
00079 void KCurve::setCurveGuide(QColor color)
00080 {
00081 m_guideVisible = true;
00082 m_colorGuide = color;
00083 repaint(false);
00084 }
00085
00086 void KCurve::setPixmap(QPixmap pix)
00087 {
00088 if (m_pix) delete m_pix;
00089 m_pix = new QPixmap(pix);
00090 repaint(false);
00091 }
00092
00093 void KCurve::keyPressEvent(QKeyEvent *e)
00094 {
00095 if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
00096 {
00097 QPair<double,double> *closest_point=NULL;
00098 if(m_grab_point)
00099 {
00100
00101 QPair<double,double> *p = m_points.first();
00102 double distance = 1000;
00103 while(p)
00104 {
00105 if(p!=m_grab_point)
00106 if (fabs (m_grab_point->first - p->first) < distance)
00107 {
00108 distance = fabs(m_grab_point->first - p->first);
00109 closest_point = p;
00110 }
00111 p = m_points.next();
00112 }
00113 m_points.remove(m_grab_point);
00114 }
00115 m_grab_point = closest_point;
00116 repaint(false);
00117 }
00118 else
00119 QWidget::keyPressEvent(e);
00120 }
00121
00122 void KCurve::paintEvent(QPaintEvent *)
00123 {
00124 int x, y;
00125 int wWidth = width();
00126 int wHeight = height();
00127
00128 x = 0;
00129 y = 0;
00130
00131
00132
00133
00134 QPixmap pm(size());
00135 QPainter p1;
00136 p1.begin(&pm, this);
00137
00138
00139 if(m_pix)
00140 {
00141 p1.scale(1.0*wWidth/m_pix->width(), 1.0*wHeight/m_pix->height());
00142 p1.drawPixmap(0, 0, *m_pix);
00143 p1.resetXForm();
00144 }
00145 else
00146 pm.fill();
00147
00148
00149 p1.setPen(QPen::QPen(Qt::gray, 1, Qt::SolidLine));
00150 p1.drawLine(wWidth/3, 0, wWidth/3, wHeight);
00151 p1.drawLine(2*wWidth/3, 0, 2*wWidth/3, wHeight);
00152 p1.drawLine(0, wHeight/3, wWidth, wHeight/3);
00153 p1.drawLine(0, 2*wHeight/3, wWidth, 2*wHeight/3);
00154
00155
00156 double curvePrevVal = getCurveValue(0.0);
00157 p1.setPen(QPen::QPen(Qt::black, 1, Qt::SolidLine));
00158 for (x = 0 ; x < wWidth ; x++)
00159 {
00160 double curveX;
00161 double curveVal;
00162
00163 curveX = (x + 0.5) / wWidth;
00164
00165 curveVal = getCurveValue(curveX);
00166
00167 p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight),
00168 x, wHeight - int(curveVal * wHeight));
00169
00170 curvePrevVal = curveVal;
00171 }
00172 p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight),
00173 x, wHeight - int(getCurveValue(1.0) * wHeight));
00174
00175
00176 if ( !m_readOnlyMode )
00177 {
00178 QPair<double,double> *p = m_points.first();
00179
00180 while(p)
00181 {
00182 double curveX = p->first;
00183 double curveY = p->second;
00184
00185 if(p == m_grab_point)
00186 {
00187 p1.setPen(QPen::QPen(Qt::red, 3, Qt::SolidLine));
00188 p1.drawEllipse( int(curveX * wWidth) - 2,
00189 wHeight - 2 - int(curveY * wHeight), 4, 4 );
00190 }
00191 else
00192 {
00193 p1.setPen(QPen::QPen(Qt::red, 1, Qt::SolidLine));
00194
00195 p1.drawEllipse( int(curveX * wWidth) - 3,
00196 wHeight - 3 - int(curveY * wHeight), 6, 6 );
00197 }
00198
00199 p = m_points.next();
00200 }
00201 }
00202
00203 p1.end();
00204 bitBlt(this, 0, 0, &pm);
00205 }
00206
00207 void KCurve::mousePressEvent ( QMouseEvent * e )
00208 {
00209 if (m_readOnlyMode) return;
00210
00211 QPair<double,double> *closest_point=NULL;
00212 double distance;
00213
00214 if (e->button() != Qt::LeftButton)
00215 return;
00216
00217 double x = e->pos().x() / (float)width();
00218 double y = 1.0 - e->pos().y() / (float)height();
00219
00220 distance = 1000;
00221
00222 QPair<double,double> *p = m_points.first();
00223 int insert_pos,pos=0;
00224 while(p)
00225 {
00226 if (fabs (x - p->first) < distance)
00227 {
00228 distance = fabs(x - p->first);
00229 closest_point = p;
00230 if(x < p->first)
00231 insert_pos = pos;
00232 else
00233 insert_pos = pos + 1;
00234 }
00235 p = m_points.next();
00236 pos++;
00237 }
00238
00239
00240 if(closest_point == NULL)
00241 {
00242 closest_point = new QPair<double,double>;
00243 closest_point->first = x;
00244 closest_point->second = y;
00245 m_points.append(closest_point);
00246 }
00247 else if(distance * width() > 5)
00248 {
00249 closest_point = new QPair<double,double>;
00250 closest_point->first = x;
00251 closest_point->second = y;
00252 m_points.insert(insert_pos, closest_point);
00253 }
00254 else
00255 if(fabs(y - closest_point->second) * width() > 5)
00256 return;
00257
00258
00259 m_grab_point = closest_point;
00260 m_grabOffsetX = m_grab_point->first - x;
00261 m_grabOffsetY = m_grab_point->second - y;
00262 m_grab_point->first = x + m_grabOffsetX;
00263 m_grab_point->second = y + m_grabOffsetY;
00264 m_dragging = true;
00265
00266 setCursor( KCursor::crossCursor() );
00267
00268
00269 m_leftmost = 0;
00270 m_rightmost = 1;
00271
00272 p = m_points.first();
00273 while(p)
00274 {
00275 if (p != m_grab_point)
00276 {
00277 if(p->first> m_leftmost && p->first < x)
00278 m_leftmost = p->first;
00279 if(p->first < m_rightmost && p->first > x)
00280 m_rightmost = p->first;
00281 }
00282 p = m_points.next();
00283 }
00284 repaint(false);
00285 }
00286
00287 void KCurve::mouseReleaseEvent ( QMouseEvent * e )
00288 {
00289 if (m_readOnlyMode) return;
00290
00291 if (e->button() != Qt::LeftButton)
00292 return;
00293
00294 setCursor( KCursor::arrowCursor() );
00295 m_dragging = false;
00296 repaint(false);
00297 emit modified();
00298 }
00299
00300 void KCurve::mouseMoveEvent ( QMouseEvent * e )
00301 {
00302 if (m_readOnlyMode) return;
00303
00304 double x = e->pos().x() / (float)width();
00305 double y = 1.0 - e->pos().y() / (float)height();
00306
00307 if (m_dragging == false)
00308 {
00309 double distance = 1000;
00310 double ydistance = 1000;
00311 QPair<double,double> *p = m_points.first();
00312 while(p)
00313 {
00314 if (fabs (x - p->first) < distance)
00315 {
00316 distance = fabs(x - p->first);
00317 ydistance = fabs(y - p->second);
00318 }
00319 p = m_points.next();
00320 }
00321
00322 if (distance * width() > 5 || ydistance * height() > 5)
00323 setCursor( KCursor::arrowCursor() );
00324 else
00325 setCursor( KCursor::crossCursor() );
00326 }
00327 else
00328 {
00329 setCursor( KCursor::crossCursor() );
00330
00331 x += m_grabOffsetX;
00332 y += m_grabOffsetY;
00333
00334 if (x <= m_leftmost)
00335 x = m_leftmost + 1E-4;
00336
00337 if(x >= m_rightmost)
00338 x = m_rightmost - 1E-4;
00339
00340 if(y > 1.0)
00341 y = 1.0;
00342
00343 if(y < 0.0)
00344 y = 0.0;
00345
00346 m_grab_point->first = x;
00347 m_grab_point->second = y;
00348
00349 emit modified();
00350 }
00351
00352 repaint(false);
00353 }
00354
00355 double KCurve::getCurveValue(double x)
00356 {
00357 return getCurveValue(m_points, x);
00358 }
00359
00360 double KCurve::getCurveValue(QPtrList<QPair<double,double> > &curve, double x)
00361 {
00362 double t;
00363 QPair<double,double> *p;
00364 QPair<double,double> *p0,*p1,*p2,*p3;
00365 double c0,c1,c2,c3;
00366 double val;
00367
00368 if(curve.count() == 0)
00369 return 0.5;
00370
00371
00372 p = curve.first();
00373 if(x < p->first)
00374 return p->second;
00375
00376 p = curve.last();
00377 if(x >= p->first)
00378 return p->second;
00379
00380
00381 p = curve.first();
00382 while(x >= p->first)
00383 {
00384 p = curve.next();
00385 }
00386 curve.prev();
00387
00388 if((p0 = curve.prev()) == NULL)
00389 p1 = p0 = curve.first();
00390 else
00391 p1 = curve.next();
00392
00393 p2 = curve.next();
00394 if( (p = curve.next()) )
00395 p3 = p;
00396 else
00397 p3 = p2;
00398
00399
00400 t = (x - p1->first) / (p2->first - p1->first);
00401 c2 = (p2->second - p0->second) * (p2->first-p1->first) / (p2->first-p0->first);
00402 c3 = p1->second;
00403 c0 = -2*p2->second + 2*c3 + c2 + (p3->second - p1->second) * (p2->first - p1->first) / (p3->first - p1->first);
00404 c1 = p2->second - c3 - c2 - c0;
00405 val = ((c0*t + c1)*t + c2)*t + c3;
00406
00407 if(val < 0.0)
00408 val = 0.0;
00409 if(val > 1.0)
00410 val = 1.0;
00411 return val;
00412 }
00413
00414 QPtrList<QPair<double,double> > KCurve::getCurve()
00415 {
00416 QPtrList<QPair<double,double> > outlist;
00417 QPair<double,double> *p;
00418 QPair<double,double> *outpoint;
00419
00420 p = m_points.first();
00421 while(p)
00422 {
00423 outpoint = new QPair<double,double>(p->first, p->second);
00424 outlist.append(outpoint);
00425 p = m_points.next();
00426 }
00427 return outlist;
00428 }
00429
00430 void KCurve::setCurve(QPtrList<QPair<double,double> >inlist)
00431 {
00432 QPair<double,double> *p;
00433 QPair<double,double> *inpoint;
00434
00435 m_points.clear();
00436
00437 inpoint = inlist.first();
00438 while(inpoint)
00439 {
00440 p = new QPair<double,double>(inpoint->first, inpoint->second);
00441 m_points.append(p);
00442 inpoint = inlist.next();
00443 }
00444 }
00445
00446 void KCurve::leaveEvent( QEvent * )
00447 {
00448 }
00449
00450 #include "kcurve.moc"