diff options
Diffstat (limited to 'chalk/ui/kcurve.cc')
-rw-r--r-- | chalk/ui/kcurve.cc | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/chalk/ui/kcurve.cc b/chalk/ui/kcurve.cc new file mode 100644 index 00000000..47f9934a --- /dev/null +++ b/chalk/ui/kcurve.cc @@ -0,0 +1,450 @@ +/* ============================================================ + * Copyright 2004-2005 by Gilles Caulier + * Copyright 2005 by Casper Boemann (reworked to be generic) + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqpoint.h> +#include <tqpen.h> +#include <tqevent.h> +#include <tqtimer.h> +#include <tqrect.h> +#include <tqfont.h> +#include <tqfontmetrics.h> + +// KDE includes. + +#include <kdebug.h> +#include <kcursor.h> +#include <klocale.h> + +// Local includes. + +#include "kcurve.h" + +KCurve::KCurve(TQWidget *tqparent, const char *name, WFlags f) + : TQWidget(tqparent, name, f) +{ + m_grab_point = NULL; + m_readOnlyMode = false; + m_guideVisible = false; + m_dragging = false; + m_pix = NULL; + + setMouseTracking(true); + setPaletteBackgroundColor(TQt::NoBackground); + setMinimumSize(150, 50); + TQPair<double,double> *p = new TQPair<double,double>; + p->first = 0.0; p->second=0.0; + m_points.append(p); + p = new TQPair<double,double>; + p->first = 1.0; p->second=1.0; + m_points.append(p); + m_points.setAutoDelete(true); + setFocusPolicy(TQ_StrongFocus); +} + +KCurve::~KCurve() +{ + if (m_pix) delete m_pix; +} + +void KCurve::reset(void) +{ + m_grab_point = NULL; + m_guideVisible = false; + tqrepaint(false); +} + +void KCurve::setCurveGuide(TQColor color) +{ + m_guideVisible = true; + m_colorGuide = color; + tqrepaint(false); +} + +void KCurve::setPixmap(TQPixmap pix) +{ + if (m_pix) delete m_pix; + m_pix = new TQPixmap(pix); + tqrepaint(false); +} + +void KCurve::keyPressEvent(TQKeyEvent *e) +{ + if(e->key() == TQt::Key_Delete || e->key() == TQt::Key_Backspace) + { + TQPair<double,double> *closest_point=NULL; + if(m_grab_point) + { + //first find closest point to get focus afterwards + TQPair<double,double> *p = m_points.first(); + double distance = 1000; // just a big number + while(p) + { + if(p!=m_grab_point) + if (fabs (m_grab_point->first - p->first) < distance) + { + distance = fabs(m_grab_point->first - p->first); + closest_point = p; + } + p = m_points.next(); + } + m_points.remove(m_grab_point); + } + m_grab_point = closest_point; + tqrepaint(false); + } + else + TQWidget::keyPressEvent(e); +} + +void KCurve::paintEvent(TQPaintEvent *) +{ + int x, y; + int wWidth = width(); + int wHeight = height(); + + x = 0; + y = 0; + + // Drawing selection or all histogram values. + // A TQPixmap is used for enable the double buffering. + + TQPixmap pm(size()); + TQPainter p1; + p1.tqbegin(TQT_TQPAINTDEVICE(&pm), this); + + // draw background + if(m_pix) + { + p1.scale(1.0*wWidth/m_pix->width(), 1.0*wHeight/m_pix->height()); + p1.drawPixmap(0, 0, *m_pix); + p1.resetXForm(); + } + else + pm.fill(); + + // Draw grid separators. + p1.setPen(TQPen::TQPen(TQt::gray, 1, TQt::SolidLine)); + p1.drawLine(wWidth/3, 0, wWidth/3, wHeight); + p1.drawLine(2*wWidth/3, 0, 2*wWidth/3, wHeight); + p1.drawLine(0, wHeight/3, wWidth, wHeight/3); + p1.drawLine(0, 2*wHeight/3, wWidth, 2*wHeight/3); + + // Draw curve. + double curvePrevVal = getCurveValue(0.0); + p1.setPen(TQPen::TQPen(TQt::black, 1, TQt::SolidLine)); + for (x = 0 ; x < wWidth ; x++) + { + double curveX; + double curveVal; + + curveX = (x + 0.5) / wWidth; + + curveVal = getCurveValue(curveX); + + p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), + x, wHeight - int(curveVal * wHeight)); + + curvePrevVal = curveVal; + } + p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), + x, wHeight - int(getCurveValue(1.0) * wHeight)); + + // Drawing curve handles. + if ( !m_readOnlyMode ) + { + TQPair<double,double> *p = m_points.first(); + + while(p) + { + double curveX = p->first; + double curveY = p->second; + + if(p == m_grab_point) + { + p1.setPen(TQPen::TQPen(TQt::red, 3, TQt::SolidLine)); + p1.drawEllipse( int(curveX * wWidth) - 2, + wHeight - 2 - int(curveY * wHeight), 4, 4 ); + } + else + { + p1.setPen(TQPen::TQPen(TQt::red, 1, TQt::SolidLine)); + + p1.drawEllipse( int(curveX * wWidth) - 3, + wHeight - 3 - int(curveY * wHeight), 6, 6 ); + } + + p = m_points.next(); + } + } + + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void KCurve::mousePressEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + TQPair<double,double> *closest_point=NULL; + double distance; + + if (e->button() != Qt::LeftButton) + return; + + double x = e->pos().x() / (float)width(); + double y = 1.0 - e->pos().y() / (float)height(); + + distance = 1000; // just a big number + + TQPair<double,double> *p = m_points.first(); + int insert_pos,pos=0; + while(p) + { + if (fabs (x - p->first) < distance) + { + distance = fabs(x - p->first); + closest_point = p; + if(x < p->first) + insert_pos = pos; + else + insert_pos = pos + 1; + } + p = m_points.next(); + pos++; + } + + + if(closest_point == NULL) + { + closest_point = new TQPair<double,double>; + closest_point->first = x; + closest_point->second = y; + m_points.append(closest_point); + } + else if(distance * width() > 5) + { + closest_point = new TQPair<double,double>; + closest_point->first = x; + closest_point->second = y; + m_points.insert(insert_pos, closest_point); + } + else + if(fabs(y - closest_point->second) * width() > 5) + return; + + + m_grab_point = closest_point; + m_grabOffsetX = m_grab_point->first - x; + m_grabOffsetY = m_grab_point->second - y; + m_grab_point->first = x + m_grabOffsetX; + m_grab_point->second = y + m_grabOffsetY; + m_dragging = true; + + setCursor( KCursor::crossCursor() ); + + // Determine the leftmost and rightmost points. + m_leftmost = 0; + m_rightmost = 1; + + p = m_points.first(); + while(p) + { + if (p != m_grab_point) + { + if(p->first> m_leftmost && p->first < x) + m_leftmost = p->first; + if(p->first < m_rightmost && p->first > x) + m_rightmost = p->first; + } + p = m_points.next(); + } + tqrepaint(false); +} + +void KCurve::mouseReleaseEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + if (e->button() != Qt::LeftButton) + return; + + setCursor( KCursor::arrowCursor() ); + m_dragging = false; + tqrepaint(false); + emit modified(); +} + +void KCurve::mouseMoveEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + double x = e->pos().x() / (float)width(); + double y = 1.0 - e->pos().y() / (float)height(); + + if (m_dragging == false) // If no point is selected set the the cursor tqshape if on top + { + double distance = 1000; + double ydistance = 1000; + TQPair<double,double> *p = m_points.first(); + while(p) + { + if (fabs (x - p->first) < distance) + { + distance = fabs(x - p->first); + ydistance = fabs(y - p->second); + } + p = m_points.next(); + } + + if (distance * width() > 5 || ydistance * height() > 5) + setCursor( KCursor::arrowCursor() ); + else + setCursor( KCursor::crossCursor() ); + } + else // Else, drag the selected point + { + setCursor( KCursor::crossCursor() ); + + x += m_grabOffsetX; + y += m_grabOffsetY; + + if (x <= m_leftmost) + x = m_leftmost + 1E-4; // the addition so we can grab the dot later. + + if(x >= m_rightmost) + x = m_rightmost - 1E-4; + + if(y > 1.0) + y = 1.0; + + if(y < 0.0) + y = 0.0; + + m_grab_point->first = x; + m_grab_point->second = y; + + emit modified(); + } + + tqrepaint(false); +} + +double KCurve::getCurveValue(double x) +{ + return getCurveValue(m_points, x); +} + +double KCurve::getCurveValue(TQPtrList<TQPair<double,double> > &curve, double x) +{ + double t; + TQPair<double,double> *p; + TQPair<double,double> *p0,*p1,*p2,*p3; + double c0,c1,c2,c3; + double val; + + if(curve.count() == 0) + return 0.5; + + // First find curve segment + p = curve.first(); + if(x < p->first) + return p->second; + + p = curve.last(); + if(x >= p->first) + return p->second; + + // Find the four control points (two on each side of x) + p = curve.first(); + while(x >= p->first) + { + p = curve.next(); + } + curve.prev(); + + if((p0 = curve.prev()) == NULL) + p1 = p0 = curve.first(); + else + p1 = curve.next(); + + p2 = curve.next(); + if( (p = curve.next()) ) + p3 = p; + else + p3 = p2; + + // Calculate the value + t = (x - p1->first) / (p2->first - p1->first); + c2 = (p2->second - p0->second) * (p2->first-p1->first) / (p2->first-p0->first); + c3 = p1->second; + c0 = -2*p2->second + 2*c3 + c2 + (p3->second - p1->second) * (p2->first - p1->first) / (p3->first - p1->first); + c1 = p2->second - c3 - c2 - c0; + val = ((c0*t + c1)*t + c2)*t + c3; + + if(val < 0.0) + val = 0.0; + if(val > 1.0) + val = 1.0; + return val; +} + +TQPtrList<TQPair<double,double> > KCurve::getCurve() +{ + TQPtrList<TQPair<double,double> > outlist; + TQPair<double,double> *p; + TQPair<double,double> *outpoint; + + p = m_points.first(); + while(p) + { + outpoint = new TQPair<double,double>(p->first, p->second); + outlist.append(outpoint); + p = m_points.next(); + } + return outlist; +} + +void KCurve::setCurve(TQPtrList<TQPair<double,double> >inlist) +{ + TQPair<double,double> *p; + TQPair<double,double> *inpoint; + + m_points.clear(); + + inpoint = inlist.first(); + while(inpoint) + { + p = new TQPair<double,double>(inpoint->first, inpoint->second); + m_points.append(p); + inpoint = inlist.next(); + } +} + +void KCurve::leaveEvent( TQEvent * ) +{ +} + +#include "kcurve.moc" |