Back to index

scribus-ng  1.3.4.dfsg+svn20071115
curvewidget.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "curvewidget.h"
00008 #include "curvewidget.moc"
00009 
00010 #include <cmath>
00011 
00012 #include <qpushbutton.h>
00013 #include <qlabel.h>
00014 #include <qlayout.h>
00015 #include <qtooltip.h>
00016 #include <qwhatsthis.h>
00017 #include <qpainter.h>
00018 #include <qapplication.h>
00019 #include <qcursor.h>
00020 #include <qmessagebox.h>
00021 #include "colorutil.h"
00022 #include "customfdialog.h"
00023 #include "util.h"
00024 #include "prefsmanager.h"
00025 #include "prefsfile.h"
00026 #include "commonstrings.h"
00027 
00028 extern QPixmap loadIcon(QString nam);
00029 
00030 KCurve::KCurve(QWidget *parent) : QWidget(parent)
00031 {
00032        m_grab_point     = FPoint();
00033        m_dragging = false;
00034        m_linear = false;
00035        m_pix = NULL;
00036        m_pos = 0;
00037        setMouseTracking(true);
00038        setPaletteBackgroundColor(Qt::NoBackground);
00039        setMinimumSize(150, 150);
00040        m_points.resize(0);
00041        m_points.addPoint(0.0, 0.0);
00042        m_points.addPoint(1.0, 1.0);
00043        setFocusPolicy(QWidget::StrongFocus);
00044 }
00045 
00046 KCurve::~KCurve()
00047 {
00048        if (m_pix) delete m_pix;
00049 }
00050 
00051 void KCurve::setPixmap(QPixmap pix)
00052 {
00053        if (m_pix) delete m_pix;
00054        m_pix = new QPixmap(pix);
00055        repaint(false);
00056 }
00057 
00058 void KCurve::paintEvent(QPaintEvent *)
00059 {
00060        int    x, y;
00061        int    wWidth = width() - 1;
00062        int    wHeight = height() - 1;
00063        x  = 0;
00064        y  = 0;
00065        // Drawing selection or all histogram values.
00066        // A QPixmap is used for enable the double buffering.
00067        QPixmap pm(size());
00068        QPainter p1;
00069        p1.begin(&pm, this);
00070        //  draw background
00071        if(m_pix)
00072        {
00073               p1.scale(1.0*wWidth/m_pix->width(), 1.0*wHeight/m_pix->height());
00074               p1.drawPixmap(0, 0, *m_pix);
00075               p1.resetXForm();
00076        }
00077        else
00078               pm.fill();
00079        // Draw grid separators.
00080        p1.setPen(QPen::QPen(Qt::gray, 1, Qt::SolidLine));
00081        p1.drawLine(wWidth/4, 0, wWidth/4, wHeight);
00082        p1.drawLine(wWidth/2, 0, wWidth/2, wHeight);
00083        p1.drawLine(3*wWidth/4, 0, 3*wWidth/4, wHeight);
00084        p1.drawLine(0, wHeight/4, wWidth, wHeight/4);
00085        p1.drawLine(0, wHeight/2, wWidth, wHeight/2);
00086        p1.drawLine(0, 3*wHeight/4, wWidth, 3*wHeight/4);
00087 
00088        // Draw curve.
00089        double curvePrevVal = getCurveValue(0.0);
00090        p1.setPen(QPen::QPen(Qt::black, 1, Qt::SolidLine));
00091        for (x = 0 ; x < wWidth ; x++)
00092        {
00093               double curveX;
00094               double curveVal;
00095               //            curveX = (x + 0.5) / wWidth;
00096               curveX = x / static_cast<double>(wWidth);
00097               curveVal = getCurveValue(curveX);
00098               p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), x,     wHeight - int(curveVal * wHeight));
00099               curvePrevVal = curveVal;
00100        }
00101        p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), x,     wHeight - int(getCurveValue(1.0) * wHeight));
00102        for (uint dh = 0; dh < m_points.size(); dh++)
00103        {
00104               FPoint p = m_points.point(dh);
00105               if(p == m_grab_point)
00106               {
00107                      p1.setPen(QPen::QPen(Qt::red, 3, Qt::SolidLine));
00108                      p1.drawEllipse( int(p.x() * wWidth) - 2, wHeight - 2 - int(p.y() * wHeight), 4, 4 );
00109               }
00110               else
00111               {
00112                      p1.setPen(QPen::QPen(Qt::red, 1, Qt::SolidLine));
00113                      p1.drawEllipse( int(p.x() * wWidth) - 3, wHeight - 3 - int(p.y() * wHeight), 6, 6 );
00114               }
00115        }
00116        p1.end();
00117        bitBlt(this, 0, 0, &pm);
00118 }
00119 
00120 void KCurve::keyPressEvent(QKeyEvent *e)
00121 {
00122        if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
00123        {
00124               if (m_points.size() > 2)
00125               {
00126                      FPoint closest_point = m_points.point(0);
00127                      FPoint p = m_points.point(0);
00128                      int pos = 0;
00129                      uint cc =0;
00130                      double distance = 1000; // just a big number
00131                      while(cc < m_points.size())
00132                      {
00133                             if (fabs (m_grab_point.x() - p.x()) < distance)
00134                             {
00135                                    distance = fabs(m_grab_point.x() - p.x());
00136                                    closest_point = p;
00137                                    m_pos = pos;
00138                             }
00139                             cc++;
00140                             p = m_points.point(cc);
00141                             pos++;
00142                      }
00143                      FPointArray cli;
00144                      cli.putPoints(0, m_pos, m_points);
00145                      cli.putPoints(cli.size(), m_points.size()-m_pos-1, m_points, m_pos+1);
00146                      m_points.resize(0);
00147                      m_points = cli.copy();
00148                      m_grab_point = closest_point;
00149                      repaint(false);
00150                      emit modified();
00151                      QWidget::keyPressEvent(e);
00152               }
00153        }
00154 }
00155 
00156 void KCurve::mousePressEvent ( QMouseEvent * e )
00157 {
00158        FPoint closest_point = FPoint();
00159        double distance;
00160        if (e->button() != Qt::LeftButton)
00161               return;
00162        double x = e->pos().x() / (float)width();
00163        double y = 1.0 - e->pos().y() / (float)height();
00164        distance = 1000; // just a big number
00165        FPoint p = m_points.point(0);
00166        int insert_pos =0;
00167        int pos = 0;
00168        uint cc =0;
00169        while(cc < m_points.size())
00170        {
00171               if (fabs (x - p.x()) < distance)
00172               {
00173                      distance = fabs(x - p.x());
00174                      closest_point = p;
00175                      insert_pos = pos;
00176               }
00177               cc++;
00178               p = m_points.point(cc);
00179               pos++;
00180        }
00181        m_pos = insert_pos;
00182        m_grab_point = closest_point;
00183        m_grabOffsetX = m_grab_point.x() - x;
00184        m_grabOffsetY = m_grab_point.y() - y;
00185        m_grab_point = FPoint(x + m_grabOffsetX, y + m_grabOffsetY);
00186        double curveVal = getCurveValue(x);
00187        if(distance * width() > 5)
00188        {
00189               m_dragging = false;
00190               if(fabs(y - curveVal) * width() > 5)
00191                      return;
00192               if (m_points.size() < 14)
00193               {
00194                      if (x > closest_point.x())
00195                             m_pos++;
00196                      FPointArray cli;
00197                      cli.putPoints(0, m_pos, m_points);
00198                      cli.resize(cli.size()+1);
00199                      cli.putPoints(cli.size()-1, 1, x, curveVal);
00200                      cli.putPoints(cli.size(), m_points.size()-m_pos, m_points, m_pos);
00201                      m_points.resize(0);
00202                      m_points = cli.copy();
00203                      m_dragging = true;
00204                      m_grab_point = m_points.point(m_pos);
00205                      m_grabOffsetX = m_grab_point.x() - x;
00206                      m_grabOffsetY = m_grab_point.y() - curveVal;
00207                      m_grab_point = FPoint(x + m_grabOffsetX, curveVal + m_grabOffsetY);
00208                      qApp->setOverrideCursor(QCursor(crossCursor), true);
00209               }
00210        }
00211        else
00212        {
00213               if(fabs(y - closest_point.y()) * width() > 5)
00214                      return;
00215               m_dragging = true;
00216               qApp->setOverrideCursor(QCursor(crossCursor), true);
00217        }
00218        // Determine the leftmost and rightmost points.
00219        m_leftmost = 0;
00220        m_rightmost = 1;
00221        p = m_points.point(0);
00222        cc = 0;
00223        while(cc < m_points.size())
00224        {
00225               if (p != m_grab_point)
00226               {
00227                      if(p.x() > m_leftmost && p.x() < x)
00228                             m_leftmost = p.x();
00229                      if(p.x() < m_rightmost && p.x() > x)
00230                             m_rightmost = p.x();
00231               }
00232               cc++;
00233               p = m_points.point(cc);
00234     }
00235        repaint(false);
00236        emit modified();
00237 }
00238 
00239 void KCurve::mouseReleaseEvent ( QMouseEvent * e )
00240 {
00241        if (e->button() != Qt::LeftButton)
00242               return;
00243        qApp->setOverrideCursor(QCursor(ArrowCursor), true);
00244        m_dragging = false;
00245        repaint(false);
00246        emit modified();
00247 }
00248 
00249 void KCurve::mouseMoveEvent ( QMouseEvent * e )
00250 {
00251        double x = e->pos().x() / (float)width();
00252        double y = 1.0 - e->pos().y() / (float)height();
00253 
00254        if (m_dragging == false)   // If no point is selected set the the cursor shape if on top
00255        {
00256               double distance = 1000;
00257               double ydistance = 1000;
00258               FPoint p = m_points.point(0);
00259               uint cc =0;
00260               while(cc < m_points.size())
00261               {
00262                      if (fabs (x - p.x()) < distance)
00263                      {
00264                             distance = fabs(x - p.x());
00265                             ydistance = fabs(y - p.y());
00266                      }
00267                      cc++;
00268                      p = m_points.point(cc);
00269               }
00270               if (distance * width() > 5 || ydistance * height() > 5)
00271                      qApp->setOverrideCursor(QCursor(ArrowCursor), true);
00272               else
00273                      qApp->setOverrideCursor(QCursor(crossCursor), true);
00274        }
00275        else  // Else, drag the selected point
00276        {
00277               qApp->setOverrideCursor(QCursor(crossCursor), true);
00278               x += m_grabOffsetX;
00279               y += m_grabOffsetY;
00280               if (x <= m_leftmost)
00281                      x = m_leftmost + 1E-4; // the addition so we can grab the dot later.
00282               if(x >= m_rightmost)
00283                      x = m_rightmost - 1E-4;
00284               if(y > 1.0)
00285                      y = 1.0;
00286               if(y < 0.0)
00287                      y = 0.0;
00288               m_grab_point = FPoint(x, y);
00289               m_points.setPoint( m_pos, m_grab_point);
00290               repaint(false);
00291               emit modified();
00292        }
00293 }
00294 
00295 double KCurve::getCurveValue(double x)
00296 {
00297        return getCurveYValue(m_points, x, m_linear);
00298 }
00299 
00300 FPointArray KCurve::getCurve()
00301 {
00302        return m_points.copy();
00303 }
00304 
00305 void KCurve::setCurve(FPointArray inlist)
00306 {
00307        m_points_back = m_points.copy();
00308        m_points.resize(0);
00309        m_points = inlist.copy();
00310        repaint(false);
00311        emit modified();
00312 }
00313 
00314 void KCurve::resetCurve()
00315 {
00316        m_points.resize(0);
00317        m_points = m_points_back.copy();
00318        repaint(false);
00319        emit modified();
00320 }
00321 
00322 void KCurve::setLinear(bool setter)
00323 {
00324        m_linear = setter;
00325        repaint(false);
00326        emit modified();
00327 }
00328 
00329 bool KCurve::isLinear()
00330 {
00331        return m_linear;
00332 }
00333 
00334 void KCurve::leaveEvent( QEvent * )
00335 {
00336        qApp->setOverrideCursor(QCursor(ArrowCursor), true);
00337 }
00338 
00339 CurveWidget::CurveWidget( QWidget* parent ) : QWidget( parent )
00340 {
00341        CurveWidgetLayout = new QHBoxLayout( this, 5, 5, "CurveWidgetLayout");
00342 
00343        layout1 = new QVBoxLayout( 0, 0, 5, "layout1");
00344 
00345        invertButton = new QPushButton( this, "invertButton" );
00346        invertButton->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, invertButton->sizePolicy().hasHeightForWidth() ) );
00347        invertButton->setPixmap( loadIcon("invert.png") );
00348        layout1->addWidget( invertButton );
00349 
00350        resetButton = new QPushButton( this, "resetButton" );
00351        resetButton->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, resetButton->sizePolicy().hasHeightForWidth() ) );
00352        resetButton->setPixmap( loadIcon("reload.png") );
00353        layout1->addWidget( resetButton );
00354        linearButton = new QToolButton( this, "linearButton" );
00355        QIconSet ic;
00356        ic.setPixmap(loadIcon("curvebezier.png"), QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
00357        ic.setPixmap(loadIcon("curvelinear.png"), QIconSet::Automatic, QIconSet::Normal, QIconSet::On);
00358        linearButton->setIconSet(ic);
00359        linearButton->setToggleButton( true );
00360        linearButton->setOn(false);
00361        layout1->addWidget( linearButton );
00362        spacer1 = new QSpacerItem( 21, 31, QSizePolicy::Minimum, QSizePolicy::Expanding );
00363        layout1->addItem( spacer1 );
00364 
00365        loadButton = new QPushButton( this, "loadButton" );
00366        loadButton->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, loadButton->sizePolicy().hasHeightForWidth() ) );
00367        loadButton->setPixmap( loadIcon("22/document-open.png") );
00368        layout1->addWidget( loadButton );
00369 
00370        saveButton = new QPushButton( this, "saveButton" );
00371        saveButton->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, saveButton->sizePolicy().hasHeightForWidth() ) );
00372        saveButton->setPixmap( loadIcon("22/document-save-as.png") );
00373        layout1->addWidget( saveButton );
00374        CurveWidgetLayout->addLayout( layout1 );
00375 
00376        cDisplay = new KCurve(this);
00377        cDisplay->setMinimumSize( QSize( 150, 150 ) );
00378        CurveWidgetLayout->addWidget( cDisplay );
00379        languageChange();
00380        clearWState( WState_Polished );
00381        connect(invertButton, SIGNAL(clicked()), this, SLOT(doInvert()));
00382        connect(resetButton, SIGNAL(clicked()), this, SLOT(doReset()));
00383        connect(linearButton, SIGNAL(clicked()), this, SLOT(doLinear()));
00384        connect(loadButton, SIGNAL(clicked()), this, SLOT(doLoad()));
00385        connect(saveButton, SIGNAL(clicked()), this, SLOT(doSave()));
00386 }
00387 
00388 void CurveWidget::doInvert()
00389 {
00390        FPointArray curve = cDisplay->getCurve();
00391        for (uint a = 0; a < curve.size(); a++)
00392        {
00393               FPoint p = curve.point(a);
00394               curve.setPoint(a, p.x(), 1.0 - p.y());
00395        }
00396        cDisplay->setCurve(curve);
00397 }
00398 
00399 void CurveWidget::doReset()
00400 {
00401        cDisplay->resetCurve();
00402 }
00403 
00404 void CurveWidget::doLinear()
00405 {
00406        cDisplay->setLinear(linearButton->isOn());
00407 }
00408 
00409 void CurveWidget::setLinear(bool setter)
00410 {
00411        cDisplay->setLinear(setter);
00412        linearButton->setOn(setter);
00413 }
00414 
00415 void CurveWidget::doLoad()
00416 {
00417        QString fileName;
00418        PrefsContext* dirs = PrefsManager::instance()->prefsFile->getContext("dirs");
00419        QString wdir = dirs->get("curves", ".");
00420        CustomFDialog dia(this, wdir, tr("Open"), tr("Curve Files (*.scu);;All Files (*)"));
00421        if (dia.exec() == QDialog::Accepted)
00422               fileName = dia.selectedFile();
00423        else
00424               return;
00425        if (!fileName.isEmpty())
00426        {
00427               dirs->set("curves", fileName.left(fileName.findRev("/")));
00428               QFile f(fileName);
00429               if (f.open(IO_ReadOnly))
00430               {
00431                      QTextStream fp(&f);
00432                      int numVals;
00433                      double xval, yval;
00434                      FPointArray curve;
00435                      curve.resize(0);
00436                      fp >> numVals;
00437                      for (int nv = 0; nv < numVals; nv++)
00438                      {
00439                             fp >> xval;
00440                             fp >> yval;
00441                             curve.addPoint(xval, yval);
00442                      }
00443                      cDisplay->setCurve(curve);
00444                      int lin;
00445                      fp >> lin;
00446                      cDisplay->setLinear(lin);
00447               }
00448        }
00449 }
00450 
00451 void CurveWidget::doSave()
00452 {
00453        QString fileName;
00454        QString wdir = PrefsManager::instance()->prefsFile->getContext("dirs")->get("curves", ".");
00455        CustomFDialog dia(this, wdir, tr("Save as"), tr("Curve Files (*.scu);;All Files (*)"), fdNone);
00456        if (dia.exec() == QDialog::Accepted)
00457               fileName = dia.selectedFile();
00458        else
00459               return;
00460        if (!fileName.isEmpty())
00461        {
00462               if (!fileName.endsWith(".scu"))
00463                      fileName += ".scu";
00464               PrefsManager::instance()->prefsFile->getContext("dirs")->set("curves", fileName.left(fileName.findRev("/")));
00465               if (overwrite(this, fileName))
00466               {
00467                      QString efval = "";
00468                      FPointArray Vals = cDisplay->getCurve();
00469                      QString tmp;
00470                      tmp.setNum(Vals.size());
00471                      efval += tmp;
00472                      for (uint p = 0; p < Vals.size(); p++)
00473                      {
00474                             FPoint pv = Vals.point(p);
00475                             efval += QString(" %1 %2").arg(pv.x()).arg(pv.y());
00476                      }
00477                      if (cDisplay->isLinear())
00478                             efval += " 1";
00479                      else
00480                             efval += " 0";
00481                      QFile fx(fileName);
00482                      if (fx.open(IO_WriteOnly))
00483                      {
00484                             QTextStream tsx(&fx);
00485                             tsx << efval;
00486                             fx.close();
00487                      }
00488                      else
00489                             QMessageBox::warning(this, CommonStrings::trWarning, tr("Cannot write the file: \n%1").arg(fileName), CommonStrings::tr_OK);
00490               }
00491        }
00492 }
00493 
00494 /*
00495  *  Sets the strings of the subwidgets using the current
00496  *  language.
00497  */
00498 void CurveWidget::languageChange()
00499 {
00500        invertButton->setText( QString::null );
00501        resetButton->setText( QString::null );
00502        loadButton->setText( QString::null );
00503        saveButton->setText( QString::null );
00504        QToolTip::remove( invertButton );
00505        QToolTip::remove( resetButton );
00506        QToolTip::remove( linearButton );
00507        QToolTip::remove( loadButton );
00508        QToolTip::remove( saveButton );
00509        QToolTip::add( invertButton, tr( "Inverts the curve" ) );
00510        QToolTip::add( resetButton, tr( "Resets the curve" ) );
00511        QToolTip::add( linearButton, tr( "Switches between linear and cubic interpolation of the curve" ) );
00512        QToolTip::add( loadButton, tr( "Loads a curve" ) );
00513        QToolTip::add( saveButton, tr( "Saves this curve" ) );
00514 }
00515