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 <tqpainter.h> 00030 #include <tqcolor.h> 00031 #include <tqimage.h> 00032 #include <tqlayout.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 <tqcursor.h> 00040 #include <tqapplication.h> 00041 00042 using namespace KPIM; 00043 00044 KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( TQWidget *parent, 00045 const char *name) : TQWidget( parent, name) 00046 { 00047 TQHBoxLayout * hboxLayout=new TQHBoxLayout( this ); 00048 00049 hboxLayout->addStretch(); 00050 TQVBoxLayout * vboxLayout=new TQVBoxLayout( hboxLayout ); 00051 00052 vboxLayout->addStretch(); 00053 m_label = new TQLabel(this, "pixmapHolder"); 00054 m_label->setBackgroundMode( TQt::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 TQPixmap &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 TQRect KPixmapRegionSelectorWidget::selectedRegion() const 00087 { 00088 return m_selectedRegion; 00089 } 00090 00091 void KPixmapRegionSelectorWidget::setSelectedRegion(const TQRect &rect) 00092 { 00093 if (!rect.isValid()) resetSelection(); 00094 else 00095 { 00096 m_selectedRegion=rect; 00097 updatePixmap(); 00098 00099 TQRect 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 TQPainter painter; 00110 if (m_linedPixmap.isNull()) 00111 { 00112 m_linedPixmap = m_originalPixmap; 00113 00114 painter.begin(&m_linedPixmap); 00115 painter.setRasterOp( TQt::XorROP ); 00116 painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(), 00117 TQBrush( TQColor(255,255,255), TQt::BDiagPattern) ); 00118 painter.end(); 00119 00120 TQImage image=m_linedPixmap.convertToImage(); 00121 image=KImageEffect::fade(image, 0.4, TQColor(0,0,0)); 00122 m_linedPixmap.convertFromImage(image); 00123 } 00124 00125 TQPixmap pixmap = m_linedPixmap; 00126 00127 painter.begin(&pixmap); 00128 painter.drawPixmap( m_selectedRegion.topLeft(), 00129 m_originalPixmap, m_selectedRegion ); 00130 00131 painter.setPen( TQColor(255,255,255) ); 00132 painter.setRasterOp( TQt::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, TQT_TQOBJECT(this), TQT_SLOT(rotateClockwise()), 00148 TQT_TQOBJECT(popup), "rotateclockwise"); 00149 action->plug(popup); 00150 00151 action = new KAction(i18n("Rotate &Counterclockwise"), "rotate_ccw", 00152 0, TQT_TQOBJECT(this), TQT_SLOT(rotateCounterclockwise()), 00153 TQT_TQOBJECT(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 TQImage 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=TQPixmap(); 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(TQObject *obj, TQEvent *ev) 00215 { 00216 if ( ev->type() == TQEvent::MouseButtonPress ) 00217 { 00218 TQMouseEvent *mev= (TQMouseEvent *)(ev); 00219 //kdDebug() << TQString("click at %1,%2").arg( mev->x() ).arg( mev->y() ) << endl; 00220 00221 if ( mev->button() == Qt::RightButton ) 00222 { 00223 KPopupMenu *popup = createPopupMenu( ); 00224 popup->exec( mev->globalPos() ); 00225 delete popup; 00226 return TRUE; 00227 }; 00228 00229 TQCursor cursor; 00230 if ( m_selectedRegion.contains( mev->pos() ) 00231 && m_selectedRegion!=m_originalPixmap.rect() ) 00232 { 00233 m_state=Moving; 00234 cursor=TQCursor(TQt::SizeAllCursor); 00235 } 00236 else 00237 { 00238 m_state=Resizing; 00239 cursor=TQCursor(TQt::CrossCursor); 00240 } 00241 TQApplication::setOverrideCursor(cursor); 00242 00243 m_tempFirstClick=mev->pos(); 00244 00245 return TRUE; 00246 } 00247 00248 if ( ev->type() == TQEvent::MouseMove ) 00249 { 00250 TQMouseEvent *mev= (TQMouseEvent *)(ev); 00251 00252 //kdDebug() << TQString("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() == TQEvent::MouseButtonRelease ) 00307 { 00308 TQMouseEvent *mev= (TQMouseEvent *)(ev); 00309 00310 if ( m_state == Resizing && mev->pos() == m_tempFirstClick) 00311 resetSelection(); 00312 00313 m_state=None; 00314 TQApplication::restoreOverrideCursor(); 00315 00316 return TRUE; 00317 } 00318 00319 TQWidget::eventFilter(obj, ev); 00320 return FALSE; 00321 } 00322 00323 TQRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const TQPoint & startPoint, const TQPoint & _endPoint ) 00324 { 00325 TQPoint 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 TQRect(x,y,w,h); 00389 } 00390 00391 TQRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const 00392 { 00393 return TQRect((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 TQImage KPixmapRegionSelectorWidget::selectedImage() const 00400 { 00401 TQImage 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=TQRect(); 00422 00423 // kdDebug() << TQString(" original Pixmap :") << m_originalPixmap.rect() << endl; 00424 // kdDebug() << TQString(" 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 TQImage image=m_originalPixmap.convertToImage(); 00432 m_originalPixmap.convertFromImage( image.smoothScale( width, height, TQ_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 TQRect((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=TQPixmap(); 00450 updatePixmap(); 00451 resize(m_label->width(), m_label->height()); 00452 } 00453 00454 #include "kpixmapregionselectorwidget.moc"