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 } 00143 00144 void KPixmapRegionSelectorWidget::Private::updatePixmap() 00145 { 00146 Q_ASSERT(!m_originalPixmap.isNull()); 00147 if (m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; } 00148 if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() ); 00149 if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() ); 00150 00151 QPainter painter; 00152 if (m_linedPixmap.isNull()) 00153 { 00154 m_linedPixmap = m_originalPixmap; 00155 QPainter p(&m_linedPixmap); 00156 p.setCompositionMode(QPainter::CompositionMode_SourceAtop); 00157 p.fillRect(m_linedPixmap.rect(), QColor(0, 0, 0, 100)); 00158 } 00159 00160 QPixmap pixmap = m_linedPixmap; 00161 painter.begin(&pixmap); 00162 painter.drawPixmap( m_selectedRegion.topLeft(), 00163 m_originalPixmap, m_selectedRegion ); 00164 00165 00166 painter.end(); 00167 00168 m_label->setPixmap(pixmap); 00169 00170 qApp->sendPostedEvents(0,QEvent::LayoutRequest); 00171 00172 if (m_selectedRegion == m_originalPixmap.rect())//d->m_label->rect()) //### CHECK! 00173 m_rubberBand->hide(); 00174 else 00175 { 00176 m_rubberBand->setGeometry(QRect(m_selectedRegion.topLeft(), 00177 m_selectedRegion.size())); 00178 00179 /* m_rubberBand->setGeometry(QRect(m_label -> mapToGlobal(m_selectedRegion.topLeft()), 00180 m_selectedRegion.size())); 00181 */ 00182 if (m_state!=None) m_rubberBand->show(); 00183 } 00184 00185 } 00186 00187 00188 KMenu *KPixmapRegionSelectorWidget::createPopupMenu() 00189 { 00190 KMenu *popup=new KMenu(this ); 00191 KActionCollection *actions=new KActionCollection(popup); 00192 popup->setObjectName( "PixmapRegionSelectorPopup"); 00193 popup->addTitle(i18n("Image Operations")); 00194 00195 QAction *action = actions->addAction("rotateclockwise"); 00196 action->setText(i18n("&Rotate Clockwise")); 00197 action->setIcon( KIcon( "object-rotate-right" ) ); 00198 connect( action, SIGNAL(triggered(bool)), this, SLOT(rotateClockwise()) ); 00199 00200 popup->addAction(action); 00201 00202 action = actions->addAction("rotatecounterclockwise"); 00203 action->setText(i18n("Rotate &Counterclockwise")); 00204 action->setIcon( KIcon( "object-rotate-left" ) ); 00205 connect( action, SIGNAL(triggered(bool)), this, SLOT(rotateCounterclockwise()) ); 00206 00207 popup->addAction(action); 00208 00209 /* 00210 I wonder if it would be appropriate to have here an "Open with..." option to 00211 edit the image (antlarr) 00212 */ 00213 return popup; 00214 } 00215 00216 void KPixmapRegionSelectorWidget::rotate(RotateDirection direction) 00217 { 00218 int w=d->m_originalPixmap.width(); 00219 int h=d->m_originalPixmap.height(); 00220 QImage img=d->m_unzoomedPixmap.toImage(); 00221 if(direction == Rotate90) 00222 img = img.transformed(QTransform().rotate(90.0)); 00223 else if(direction == Rotate180) 00224 img = img.transformed(QTransform().rotate(180.0)); 00225 else 00226 img = img.transformed(QTransform().rotate(270.0)); 00227 00228 d->m_unzoomedPixmap=QPixmap::fromImage(img); 00229 00230 img=d->m_originalPixmap.toImage(); 00231 if(direction == Rotate90) 00232 img = img.transformed(QTransform().rotate(90.0)); 00233 else if(direction == Rotate180) 00234 img = img.transformed(QTransform().rotate(180.0)); 00235 else 00236 img = img.transformed(QTransform().rotate(270.0)); 00237 00238 d->m_originalPixmap=QPixmap::fromImage(img); 00239 00240 d->m_linedPixmap=QPixmap(); 00241 00242 if (d->m_forcedAspectRatio>0 && d->m_forcedAspectRatio!=1) 00243 resetSelection(); 00244 else 00245 { 00246 switch (direction) 00247 { 00248 case ( Rotate90 ): 00249 { 00250 int x=h-d->m_selectedRegion.y()-d->m_selectedRegion.height(); 00251 int y=d->m_selectedRegion.x(); 00252 d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width() ); 00253 d->updatePixmap(); 00254 // qApp->sendPostedEvents(0,QEvent::LayoutRequest); 00255 // updatePixmap(); 00256 00257 } break; 00258 case ( Rotate270 ): 00259 { 00260 int x=d->m_selectedRegion.y(); 00261 int y=w-d->m_selectedRegion.x()-d->m_selectedRegion.width(); 00262 d->m_selectedRegion.setRect(x, y, d->m_selectedRegion.height(), d->m_selectedRegion.width() ); 00263 d->updatePixmap(); 00264 // qApp->sendPostedEvents(0,QEvent::LayoutRequest); 00265 // updatePixmap(); 00266 } break; 00267 default: resetSelection(); 00268 } 00269 } 00270 00271 emit pixmapRotated(); 00272 } 00273 00274 void KPixmapRegionSelectorWidget::rotateClockwise() 00275 { 00276 rotate(Rotate90); 00277 } 00278 00279 void KPixmapRegionSelectorWidget::rotateCounterclockwise() 00280 { 00281 rotate(Rotate270); 00282 } 00283 00284 bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev) 00285 { 00286 if ( ev->type() == QEvent::MouseButtonPress ) 00287 { 00288 QMouseEvent *mev= (QMouseEvent *)(ev); 00289 //kDebug() << QString("click at %1,%2").arg( mev->x() ).arg( mev->y() ); 00290 00291 if ( mev->button() == Qt::RightButton ) 00292 { 00293 KMenu *popup = createPopupMenu( ); 00294 popup->exec( mev->globalPos() ); 00295 delete popup; 00296 return true; 00297 } 00298 00299 QCursor cursor; 00300 00301 if ( d->m_selectedRegion.contains( mev->pos() ) 00302 && d->m_selectedRegion!=d->m_originalPixmap.rect() ) 00303 { 00304 d->m_state=Private::Moving; 00305 cursor.setShape( Qt::SizeAllCursor ); 00306 d->m_rubberBand->show(); 00307 } 00308 else 00309 { 00310 d->m_state=Private::Resizing; 00311 cursor.setShape( Qt::CrossCursor ); 00312 } 00313 QApplication::setOverrideCursor(cursor); 00314 00315 d->m_tempFirstClick=mev->pos(); 00316 00317 00318 return true; 00319 } 00320 00321 if ( ev->type() == QEvent::MouseMove ) 00322 { 00323 QMouseEvent *mev= (QMouseEvent *)(ev); 00324 00325 //kDebug() << QString("move to %1,%2").arg( mev->x() ).arg( mev->y() ); 00326 00327 if ( d->m_state == Private::Resizing ) 00328 { 00329 setSelectedRegion ( 00330 d->calcSelectionRectangle( d->m_tempFirstClick, mev->pos() ) ); 00331 } 00332 else if (d->m_state == Private::Moving ) 00333 { 00334 int mevx = mev->x(); 00335 int mevy = mev->y(); 00336 bool mouseOutside=false; 00337 if ( mevx < 0 ) 00338 { 00339 d->m_selectedRegion.translate(-d->m_selectedRegion.x(),0); 00340 mouseOutside=true; 00341 } 00342 else if ( mevx > d->m_originalPixmap.width() ) 00343 { 00344 d->m_selectedRegion.translate(d->m_originalPixmap.width()-d->m_selectedRegion.width()-d->m_selectedRegion.x(),0); 00345 mouseOutside=true; 00346 } 00347 if ( mevy < 0 ) 00348 { 00349 d->m_selectedRegion.translate(0,-d->m_selectedRegion.y()); 00350 mouseOutside=true; 00351 } 00352 else if ( mevy > d->m_originalPixmap.height() ) 00353 { 00354 d->m_selectedRegion.translate(0,d->m_originalPixmap.height()-d->m_selectedRegion.height()-d->m_selectedRegion.y()); 00355 mouseOutside=true; 00356 } 00357 if (mouseOutside) { d->updatePixmap(); return true; }; 00358 00359 d->m_selectedRegion.translate( mev->x()-d->m_tempFirstClick.x(), 00360 mev->y()-d->m_tempFirstClick.y() ); 00361 00362 // Check that the region has not fallen outside the image 00363 if (d->m_selectedRegion.x() < 0) 00364 d->m_selectedRegion.translate(-d->m_selectedRegion.x(),0); 00365 else if (d->m_selectedRegion.right() > d->m_originalPixmap.width()) 00366 d->m_selectedRegion.translate(-(d->m_selectedRegion.right()-d->m_originalPixmap.width()),0); 00367 00368 if (d->m_selectedRegion.y() < 0) 00369 d->m_selectedRegion.translate(0,-d->m_selectedRegion.y()); 00370 else if (d->m_selectedRegion.bottom() > d->m_originalPixmap.height()) 00371 d->m_selectedRegion.translate(0,-(d->m_selectedRegion.bottom()-d->m_originalPixmap.height())); 00372 00373 d->m_tempFirstClick=mev->pos(); 00374 d->updatePixmap(); 00375 } 00376 return true; 00377 } 00378 00379 if ( ev->type() == QEvent::MouseButtonRelease ) 00380 { 00381 QMouseEvent *mev= (QMouseEvent *)(ev); 00382 00383 if ( d->m_state == Private::Resizing && mev->pos() == d->m_tempFirstClick) 00384 resetSelection(); 00385 00386 d->m_state=Private::None; 00387 QApplication::restoreOverrideCursor(); 00388 d->m_rubberBand->hide(); 00389 return true; 00390 } 00391 00392 QWidget::eventFilter(obj, ev); 00393 return false; 00394 } 00395 00396 QRect KPixmapRegionSelectorWidget::Private::calcSelectionRectangle( const QPoint & startPoint, const QPoint & _endPoint ) 00397 { 00398 QPoint endPoint = _endPoint; 00399 if ( endPoint.x() < 0 ) endPoint.setX(0); 00400 else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width()); 00401 if ( endPoint.y() < 0 ) endPoint.setY(0); 00402 else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height()); 00403 int w=abs(startPoint.x()-endPoint.x()); 00404 int h=abs(startPoint.y()-endPoint.y()); 00405 00406 if (m_forcedAspectRatio>0) 00407 { 00408 double aspectRatio=w/double(h); 00409 00410 if (aspectRatio>m_forcedAspectRatio) 00411 h=(int)(w/m_forcedAspectRatio); 00412 else 00413 w=(int)(h*m_forcedAspectRatio); 00414 } 00415 00416 int x,y; 00417 if ( startPoint.x() < endPoint.x() ) 00418 x=startPoint.x(); 00419 else 00420 x=startPoint.x()-w; 00421 if ( startPoint.y() < endPoint.y() ) 00422 y=startPoint.y(); 00423 else 00424 y=startPoint.y()-h; 00425 00426 if (x<0) 00427 { 00428 w+=x; 00429 x=0; 00430 h=(int)(w/m_forcedAspectRatio); 00431 00432 if ( startPoint.y() > endPoint.y() ) 00433 y=startPoint.y()-h; 00434 } 00435 else if (x+w>m_originalPixmap.width()) 00436 { 00437 w=m_originalPixmap.width()-x; 00438 h=(int)(w/m_forcedAspectRatio); 00439 00440 if ( startPoint.y() > endPoint.y() ) 00441 y=startPoint.y()-h; 00442 } 00443 if (y<0) 00444 { 00445 h+=y; 00446 y=0; 00447 w=(int)(h*m_forcedAspectRatio); 00448 00449 if ( startPoint.x() > endPoint.x() ) 00450 x=startPoint.x()-w; 00451 } 00452 else if (y+h>m_originalPixmap.height()) 00453 { 00454 h=m_originalPixmap.height()-y; 00455 w=(int)(h*m_forcedAspectRatio); 00456 00457 if ( startPoint.x() > endPoint.x() ) 00458 x=startPoint.x()-w; 00459 } 00460 00461 return QRect(x,y,w,h); 00462 } 00463 00464 QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const 00465 { 00466 return QRect((int)(d->m_selectedRegion.x()/d->m_zoomFactor), 00467 (int)(d->m_selectedRegion.y()/d->m_zoomFactor), 00468 (int)(d->m_selectedRegion.width()/d->m_zoomFactor), 00469 (int)(d->m_selectedRegion.height()/d->m_zoomFactor)); 00470 } 00471 00472 QImage KPixmapRegionSelectorWidget::selectedImage() const 00473 { 00474 QImage origImage=d->m_unzoomedPixmap.toImage(); 00475 return origImage.copy(unzoomedSelectedRegion()); 00476 } 00477 00478 void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height) 00479 { 00480 d->m_forcedAspectRatio=width/double(height); 00481 } 00482 00483 void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio() 00484 { 00485 d->m_forcedAspectRatio=0; 00486 } 00487 00488 void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height) 00489 { 00490 d->m_maxWidth=width; 00491 d->m_maxHeight=height; 00492 00493 if (d->m_selectedRegion == d->m_originalPixmap.rect()) d->m_selectedRegion=QRect(); 00494 d->m_originalPixmap=d->m_unzoomedPixmap; 00495 00496 // kDebug() << QString(" original Pixmap :") << d->m_originalPixmap.rect(); 00497 // kDebug() << QString(" unzoomed Pixmap : %1 x %2 ").arg(d->m_unzoomedPixmap.width()).arg(d->m_unzoomedPixmap.height()); 00498 00499 if ( !d->m_originalPixmap.isNull() && 00500 ( d->m_originalPixmap.width() > d->m_maxWidth || 00501 d->m_originalPixmap.height() > d->m_maxHeight ) ) 00502 { 00503 /* We have to resize the pixmap to get it complete on the screen */ 00504 QImage image=d->m_originalPixmap.toImage(); 00505 d->m_originalPixmap=QPixmap::fromImage( image.scaled( width, height, Qt::KeepAspectRatio,Qt::SmoothTransformation ) ); 00506 double oldZoomFactor = d->m_zoomFactor; 00507 d->m_zoomFactor=d->m_originalPixmap.width()/(double)d->m_unzoomedPixmap.width(); 00508 00509 if (d->m_selectedRegion.isValid()) 00510 { 00511 d->m_selectedRegion= 00512 QRect((int)(d->m_selectedRegion.x()*d->m_zoomFactor/oldZoomFactor), 00513 (int)(d->m_selectedRegion.y()*d->m_zoomFactor/oldZoomFactor), 00514 (int)(d->m_selectedRegion.width()*d->m_zoomFactor/oldZoomFactor), 00515 (int)(d->m_selectedRegion.height()*d->m_zoomFactor/oldZoomFactor) ); 00516 } 00517 } 00518 00519 if (!d->m_selectedRegion.isValid()) d->m_selectedRegion = d->m_originalPixmap.rect(); 00520 00521 d->m_linedPixmap=QPixmap(); 00522 d->updatePixmap(); 00523 resize(d->m_label->width(), d->m_label->height()); 00524 } 00525 00526 #include "kpixmapregionselectorwidget.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:42 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:42 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.