libkdepim

kpixmapregionselectorwidget.cpp

00001 /*
00002     This file is part of libkdepim.
00003 
00004     Copyright (C) 2004 Antonio Larrosa <larrosa@kde.org
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 /* NOTE: There are two copies of this .h and the .cpp file, with subtle differences.
00023  * One copy is in kdelibs/kdeui, and the other copy is in kdepim/libkdepim
00024  * This is because kdepim has to remain backwards compatible.  Any changes
00025  * to either file should be made to the other.
00026  */
00027 
00028 #include "kpixmapregionselectorwidget.h"
00029 #include <qpainter.h>
00030 #include <qcolor.h>
00031 #include <qimage.h>
00032 #include <qlayout.h>
00033 #include <kimageeffect.h>
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 #include <kpopupmenu.h>
00037 #include <kaction.h>
00038 #include <stdlib.h>
00039 #include <qcursor.h>
00040 #include <qapplication.h>
00041 
00042 using namespace KPIM;
00043 
00044 KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( QWidget *parent,
00045       const char *name) : QWidget( parent, name)
00046 {
00047    QHBoxLayout * hboxLayout=new QHBoxLayout( this );
00048 
00049    hboxLayout->addStretch();
00050    QVBoxLayout * vboxLayout=new QVBoxLayout( hboxLayout );
00051 
00052    vboxLayout->addStretch();
00053    m_label = new QLabel(this, "pixmapHolder");
00054    m_label->setBackgroundMode( Qt::NoBackground );
00055    m_label->installEventFilter( this );
00056 
00057    vboxLayout->addWidget(m_label);
00058    vboxLayout->addStretch();
00059 
00060    hboxLayout->addStretch();
00061 
00062    m_forcedAspectRatio=0;
00063 
00064    m_zoomFactor=1.0;
00065 }
00066 
00067 KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget()
00068 {
00069 }
00070 
00071 void KPixmapRegionSelectorWidget::setPixmap( const QPixmap &pixmap )
00072 {
00073    Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps.
00074    m_originalPixmap = pixmap;
00075    m_unzoomedPixmap = pixmap;
00076    m_label->setPixmap( pixmap );
00077    resetSelection();
00078 }
00079 
00080 void KPixmapRegionSelectorWidget::resetSelection()
00081 {
00082    m_selectedRegion = m_originalPixmap.rect();
00083    updatePixmap();
00084 }
00085 
00086 QRect KPixmapRegionSelectorWidget::selectedRegion() const
00087 {
00088      return m_selectedRegion;
00089 }
00090 
00091 void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect)
00092 {
00093    if (!rect.isValid()) resetSelection();
00094    else
00095    {
00096       m_selectedRegion=rect;
00097       updatePixmap();
00098 
00099       QRect r=unzoomedSelectedRegion();
00100    }
00101 }
00102 
00103 void KPixmapRegionSelectorWidget::updatePixmap()
00104 {
00105    Q_ASSERT(!m_originalPixmap.isNull()); if(m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; }
00106    if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() );
00107    if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() );
00108 
00109    QPainter painter;
00110    if (m_linedPixmap.isNull())
00111    {
00112      m_linedPixmap = m_originalPixmap;
00113 
00114      painter.begin(&m_linedPixmap);
00115      painter.setRasterOp( Qt::XorROP );
00116      painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(),
00117                   QBrush( QColor(255,255,255), Qt::BDiagPattern) );
00118      painter.end();
00119 
00120      QImage image=m_linedPixmap.convertToImage();
00121      image=KImageEffect::fade(image, 0.4, QColor(0,0,0));
00122      m_linedPixmap.convertFromImage(image);
00123    }
00124 
00125    QPixmap pixmap = m_linedPixmap;
00126 
00127    painter.begin(&pixmap);
00128    painter.drawPixmap( m_selectedRegion.topLeft(),
00129         m_originalPixmap, m_selectedRegion );
00130 
00131    painter.setPen( QColor(255,255,255) );
00132    painter.setRasterOp( Qt::XorROP );
00133 
00134    painter.drawRect( m_selectedRegion );
00135 
00136    painter.end();
00137 
00138    m_label->setPixmap(pixmap);
00139 }
00140 
00141 KPopupMenu *KPixmapRegionSelectorWidget::createPopupMenu()
00142 {
00143    KPopupMenu *popup=new KPopupMenu(this, "PixmapRegionSelectorPopup");
00144    popup->insertTitle(i18n("Image Operations"));
00145 
00146    KAction *action = new KAction(i18n("&Rotate Clockwise"), "rotate_cw",
00147                                 0, this, SLOT(rotateClockwise()),
00148                                 popup, "rotateclockwise");
00149    action->plug(popup);
00150 
00151    action = new KAction(i18n("Rotate &Counterclockwise"), "rotate_ccw",
00152                                 0, this, SLOT(rotateCounterclockwise()),
00153                                 popup, "rotatecounterclockwise");
00154    action->plug(popup);
00155 
00156 /*
00157    I wonder if it would be appropiate to have here an "Open with..." option to
00158    edit the image (antlarr)
00159 */
00160    return popup;
00161 }
00162 
00163 void KPixmapRegionSelectorWidget::rotate(KImageEffect::RotateDirection direction)
00164 {
00165    int w=m_originalPixmap.width();
00166    int h=m_originalPixmap.height();
00167    QImage img=m_unzoomedPixmap.convertToImage();
00168    img= KImageEffect::rotate(img, direction);
00169    m_unzoomedPixmap.convertFromImage(img);
00170 
00171    img=m_originalPixmap.convertToImage();
00172    img= KImageEffect::rotate(img, direction);
00173    m_originalPixmap.convertFromImage(img);
00174 
00175    m_linedPixmap=QPixmap();
00176 
00177    if (m_forcedAspectRatio>0 && m_forcedAspectRatio!=1)
00178       resetSelection();
00179    else
00180    {
00181       switch (direction)
00182       {
00183          case ( KImageEffect::Rotate90 ):
00184             {
00185               int x=h-m_selectedRegion.y()-m_selectedRegion.height();
00186               int y=m_selectedRegion.x();
00187               m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
00188               updatePixmap();
00189             } break;
00190          case ( KImageEffect::Rotate270 ):
00191             {
00192               int x=m_selectedRegion.y();
00193               int y=w-m_selectedRegion.x()-m_selectedRegion.width();
00194               m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
00195               updatePixmap();
00196             } break;
00197          default: resetSelection();
00198       }
00199    }
00200 }
00201 
00202 void KPixmapRegionSelectorWidget::rotateClockwise()
00203 {
00204    rotate(KImageEffect::Rotate90);
00205 }
00206 
00207 void KPixmapRegionSelectorWidget::rotateCounterclockwise()
00208 {
00209    rotate(KImageEffect::Rotate270);
00210 }
00211 
00212 
00213 
00214 bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev)
00215 {
00216    if ( ev->type() == QEvent::MouseButtonPress )
00217    {
00218       QMouseEvent *mev= (QMouseEvent *)(ev);
00219       //kdDebug() << QString("click at  %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
00220 
00221       if ( mev->button() == RightButton )
00222       {
00223          KPopupMenu *popup = createPopupMenu( );
00224          popup->exec( mev->globalPos() );
00225          delete popup;
00226          return TRUE;
00227       };
00228 
00229       QCursor cursor;
00230       if ( m_selectedRegion.contains( mev->pos() )
00231           && m_selectedRegion!=m_originalPixmap.rect() )
00232       {
00233          m_state=Moving;
00234          cursor=QCursor(Qt::SizeAllCursor);
00235       }
00236       else
00237       {
00238          m_state=Resizing;
00239          cursor=QCursor(Qt::CrossCursor);
00240       }
00241       QApplication::setOverrideCursor(cursor);
00242 
00243       m_tempFirstClick=mev->pos();
00244 
00245       return TRUE;
00246    }
00247 
00248    if ( ev->type() == QEvent::MouseMove )
00249    {
00250       QMouseEvent *mev= (QMouseEvent *)(ev);
00251 
00252       //kdDebug() << QString("move to  %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
00253 
00254       if ( m_state == Resizing )
00255       {
00256          setSelectedRegion (
00257               calcSelectionRectangle( m_tempFirstClick, mev->pos() ) );
00258       }
00259       else if (m_state == Moving )
00260       {
00261          int mevx = mev->x();
00262          int mevy = mev->y();
00263          bool mouseOutside=false;
00264          if ( mevx < 0 )
00265          {
00266            m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
00267            mouseOutside=true;
00268          }
00269          else if ( mevx > m_originalPixmap.width() )
00270          {
00271            m_selectedRegion.moveBy(m_originalPixmap.width()-m_selectedRegion.width()-m_selectedRegion.x(),0);
00272            mouseOutside=true;
00273          }
00274          if ( mevy < 0 )
00275          {
00276            m_selectedRegion.moveBy(0,-m_selectedRegion.y());
00277            mouseOutside=true;
00278          }
00279          else if ( mevy > m_originalPixmap.height() )
00280          {
00281            m_selectedRegion.moveBy(0,m_originalPixmap.height()-m_selectedRegion.height()-m_selectedRegion.y());
00282            mouseOutside=true;
00283          }
00284          if (mouseOutside) { updatePixmap(); return TRUE; };
00285 
00286          m_selectedRegion.moveBy( mev->x()-m_tempFirstClick.x(),
00287                                   mev->y()-m_tempFirstClick.y() );
00288 
00289          // Check that the region has not fallen outside the image
00290          if (m_selectedRegion.x() < 0)
00291             m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
00292          else if (m_selectedRegion.right() > m_originalPixmap.width())
00293             m_selectedRegion.moveBy(-(m_selectedRegion.right()-m_originalPixmap.width()),0);
00294 
00295          if (m_selectedRegion.y() < 0)
00296             m_selectedRegion.moveBy(0,-m_selectedRegion.y());
00297          else if (m_selectedRegion.bottom() > m_originalPixmap.height())
00298             m_selectedRegion.moveBy(0,-(m_selectedRegion.bottom()-m_originalPixmap.height()));
00299 
00300          m_tempFirstClick=mev->pos();
00301          updatePixmap();
00302       }
00303       return TRUE;
00304    }
00305 
00306    if ( ev->type() == QEvent::MouseButtonRelease )
00307    {
00308       QMouseEvent *mev= (QMouseEvent *)(ev);
00309 
00310       if ( m_state == Resizing && mev->pos() == m_tempFirstClick)
00311          resetSelection();
00312 
00313       m_state=None;
00314       QApplication::restoreOverrideCursor();
00315 
00316       return TRUE;
00317    }
00318 
00319    QWidget::eventFilter(obj, ev);
00320    return FALSE;
00321 }
00322 
00323 QRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const QPoint & startPoint, const QPoint & _endPoint )
00324 {
00325    QPoint endPoint = _endPoint;
00326    if ( endPoint.x() < 0 ) endPoint.setX(0);
00327    else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width());
00328    if ( endPoint.y() < 0 ) endPoint.setY(0);
00329    else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height());
00330    int w=abs(startPoint.x()-endPoint.x());
00331    int h=abs(startPoint.y()-endPoint.y());
00332 
00333    if (m_forcedAspectRatio>0)
00334    {
00335       double aspectRatio=w/double(h);
00336 
00337       if (aspectRatio>m_forcedAspectRatio)
00338          h=(int)(w/m_forcedAspectRatio);
00339       else
00340          w=(int)(h*m_forcedAspectRatio);
00341    }
00342 
00343    int x,y;
00344    if ( startPoint.x() < endPoint.x() )
00345      x=startPoint.x();
00346    else
00347      x=startPoint.x()-w;
00348    if ( startPoint.y() < endPoint.y() )
00349      y=startPoint.y();
00350    else
00351      y=startPoint.y()-h;
00352 
00353    if (x<0)
00354    {
00355       w+=x;
00356       x=0;
00357       h=(int)(w/m_forcedAspectRatio);
00358 
00359       if ( startPoint.y() > endPoint.y() )
00360         y=startPoint.y()-h;
00361    }
00362    else if (x+w>m_originalPixmap.width())
00363    {
00364       w=m_originalPixmap.width()-x;
00365       h=(int)(w/m_forcedAspectRatio);
00366 
00367       if ( startPoint.y() > endPoint.y() )
00368         y=startPoint.y()-h;
00369    }
00370    if (y<0)
00371    {
00372       h+=y;
00373       y=0;
00374       w=(int)(h*m_forcedAspectRatio);
00375 
00376       if ( startPoint.x() > endPoint.x() )
00377         x=startPoint.x()-w;
00378    }
00379    else if (y+h>m_originalPixmap.height())
00380    {
00381       h=m_originalPixmap.height()-y;
00382       w=(int)(h*m_forcedAspectRatio);
00383 
00384       if ( startPoint.x() > endPoint.x() )
00385         x=startPoint.x()-w;
00386    }
00387 
00388    return QRect(x,y,w,h);
00389 }
00390 
00391 QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const
00392 {
00393   return QRect((int)(m_selectedRegion.x()/m_zoomFactor),
00394                (int)(m_selectedRegion.y()/m_zoomFactor),
00395                (int)(m_selectedRegion.width()/m_zoomFactor),
00396                (int)(m_selectedRegion.height()/m_zoomFactor));
00397 }
00398 
00399 QImage KPixmapRegionSelectorWidget::selectedImage() const
00400 {
00401    QImage origImage=m_unzoomedPixmap.convertToImage();
00402    return origImage.copy(unzoomedSelectedRegion());
00403 }
00404 
00405 void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height)
00406 {
00407    m_forcedAspectRatio=width/double(height);
00408 }
00409 
00410 void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio()
00411 {
00412    m_forcedAspectRatio=0;
00413 }
00414 
00415 void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height)
00416 {
00417    m_maxWidth=width;
00418    m_maxHeight=height;
00419 
00420    m_originalPixmap=m_unzoomedPixmap;
00421    if (m_selectedRegion == m_originalPixmap.rect()) m_selectedRegion=QRect();
00422 
00423 //   kdDebug() << QString(" original Pixmap :") << m_originalPixmap.rect() << endl;
00424 //   kdDebug() << QString(" unzoomed Pixmap : %1 x %2 ").arg(m_unzoomedPixmap.width()).arg(m_unzoomedPixmap.height()) << endl;
00425 
00426    if ( !m_originalPixmap.isNull() &&
00427        ( m_originalPixmap.width() > m_maxWidth ||
00428          m_originalPixmap.height() > m_maxHeight ) )
00429    {
00430          /* We have to resize the pixmap to get it complete on the screen */
00431          QImage image=m_originalPixmap.convertToImage();
00432          m_originalPixmap.convertFromImage( image.smoothScale( width, height, QImage::ScaleMin ) );
00433          //m_originalPixmap.convertFromImage( KImageEffect::sample( image, width, height ) );
00434          double oldZoomFactor = m_zoomFactor;
00435          m_zoomFactor=m_originalPixmap.width()/(double)m_unzoomedPixmap.width();
00436 
00437          if (m_selectedRegion.isValid())
00438          {
00439             m_selectedRegion=
00440                   QRect((int)(m_selectedRegion.x()*m_zoomFactor/oldZoomFactor),
00441                         (int)(m_selectedRegion.y()*m_zoomFactor/oldZoomFactor),
00442                         (int)(m_selectedRegion.width()*m_zoomFactor/oldZoomFactor),
00443                         (int)(m_selectedRegion.height()*m_zoomFactor/oldZoomFactor) );
00444          }
00445    }
00446 
00447    if (!m_selectedRegion.isValid()) m_selectedRegion = m_originalPixmap.rect();
00448 
00449    m_linedPixmap=QPixmap();
00450    updatePixmap();
00451    resize(m_label->width(), m_label->height());
00452 }
00453 
00454 #include "kpixmapregionselectorwidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys