• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kpixmapregionselectorwidget.cpp

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

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal