Build, if that was not necessary blame cartman who told me "sure" :-D
[kdepim.git] / libkdepim / kpixmapregionselectorwidget.cpp
blob16de9648e15b25caafc714aa4e1cdf13c155c23f
1 /* This file is part of the KDE libraries
2 Copyright (C) 2004 Antonio Larrosa <larrosa@kde.org
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
20 /* NOTE: There are two copies of this .h and the .cpp file, with subtle differences.
21 * One copy is in kdelibs/kdeui, and the other copy is in kdepim/libkdepim
22 * This is because kdepim has to remain backwards compatible. Any changes
23 * to either file should be made to the other.
26 #include "kpixmapregionselectorwidget.h"
27 #include <qpainter.h>
28 #include <qcolor.h>
29 #include <qimage.h>
30 #include <qlayout.h>
31 #include <kimageeffect.h>
32 #include <kdebug.h>
33 #include <klocale.h>
34 #include <kpopupmenu.h>
35 #include <kaction.h>
36 #include <stdlib.h>
37 #include <qcursor.h>
38 #include <qapplication.h>
40 using namespace KPIM;
42 KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( QWidget *parent,
43 const char *name) : QWidget( parent, name)
45 QHBoxLayout * hboxLayout=new QHBoxLayout( this );
47 hboxLayout->addStretch();
48 QVBoxLayout * vboxLayout=new QVBoxLayout( hboxLayout );
50 vboxLayout->addStretch();
51 m_label = new QLabel(this, "pixmapHolder");
52 m_label->setBackgroundMode( Qt::NoBackground );
53 m_label->installEventFilter( this );
55 vboxLayout->addWidget(m_label);
56 vboxLayout->addStretch();
58 hboxLayout->addStretch();
60 m_forcedAspectRatio=0;
62 m_zoomFactor=1.0;
65 KPixmapRegionSelectorWidget::~KPixmapRegionSelectorWidget()
69 void KPixmapRegionSelectorWidget::setPixmap( const QPixmap &pixmap )
71 Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps.
72 m_originalPixmap = pixmap;
73 m_unzoomedPixmap = pixmap;
74 m_label->setPixmap( pixmap );
75 resetSelection();
78 void KPixmapRegionSelectorWidget::resetSelection()
80 m_selectedRegion = m_originalPixmap.rect();
81 updatePixmap();
84 QRect KPixmapRegionSelectorWidget::selectedRegion() const
86 return m_selectedRegion;
89 void KPixmapRegionSelectorWidget::setSelectedRegion(const QRect &rect)
91 if (!rect.isValid()) resetSelection();
92 else
94 m_selectedRegion=rect;
95 updatePixmap();
97 QRect r=unzoomedSelectedRegion();
101 void KPixmapRegionSelectorWidget::updatePixmap()
103 Q_ASSERT(!m_originalPixmap.isNull()); if(m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; }
104 if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() );
105 if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() );
107 QPainter painter;
108 if (m_linedPixmap.isNull())
110 m_linedPixmap = m_originalPixmap;
112 painter.begin(&m_linedPixmap);
113 painter.setRasterOp( Qt::XorROP );
114 painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(),
115 QBrush( QColor(255,255,255), Qt::BDiagPattern) );
116 painter.end();
118 QImage image=m_linedPixmap.convertToImage();
119 image=KImageEffect::fade(image, 0.4, QColor(0,0,0));
120 m_linedPixmap.convertFromImage(image);
123 QPixmap pixmap = m_linedPixmap;
125 painter.begin(&pixmap);
126 painter.drawPixmap( m_selectedRegion.topLeft(),
127 m_originalPixmap, m_selectedRegion );
129 painter.setPen( QColor(255,255,255) );
130 painter.setRasterOp( Qt::XorROP );
132 painter.drawRect( m_selectedRegion );
134 painter.end();
136 m_label->setPixmap(pixmap);
139 KPopupMenu *KPixmapRegionSelectorWidget::createPopupMenu()
141 KPopupMenu *popup=new KPopupMenu(this, "PixmapRegionSelectorPopup");
142 popup->insertTitle(i18n("Image Operations"));
144 KAction *action = new KAction(i18n("&Rotate Clockwise"), "rotate_cw",
145 0, this, SLOT(rotateClockwise()),
146 popup, "rotateclockwise");
147 action->plug(popup);
149 action = new KAction(i18n("Rotate &Counterclockwise"), "rotate_ccw",
150 0, this, SLOT(rotateCounterclockwise()),
151 popup, "rotatecounterclockwise");
152 action->plug(popup);
155 I wonder if it would be appropiate to have here an "Open with..." option to
156 edit the image (antlarr)
158 return popup;
161 void KPixmapRegionSelectorWidget::rotate(KImageEffect::RotateDirection direction)
163 int w=m_originalPixmap.width();
164 int h=m_originalPixmap.height();
165 QImage img=m_unzoomedPixmap.convertToImage();
166 img= KImageEffect::rotate(img, direction);
167 m_unzoomedPixmap.convertFromImage(img);
169 img=m_originalPixmap.convertToImage();
170 img= KImageEffect::rotate(img, direction);
171 m_originalPixmap.convertFromImage(img);
173 m_linedPixmap=QPixmap();
175 if (m_forcedAspectRatio>0 && m_forcedAspectRatio!=1)
176 resetSelection();
177 else
179 switch (direction)
181 case ( KImageEffect::Rotate90 ):
183 int x=h-m_selectedRegion.y()-m_selectedRegion.height();
184 int y=m_selectedRegion.x();
185 m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
186 updatePixmap();
187 } break;
188 case ( KImageEffect::Rotate270 ):
190 int x=m_selectedRegion.y();
191 int y=w-m_selectedRegion.x()-m_selectedRegion.width();
192 m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
193 updatePixmap();
194 } break;
195 default: resetSelection();
200 void KPixmapRegionSelectorWidget::rotateClockwise()
202 rotate(KImageEffect::Rotate90);
205 void KPixmapRegionSelectorWidget::rotateCounterclockwise()
207 rotate(KImageEffect::Rotate270);
212 bool KPixmapRegionSelectorWidget::eventFilter(QObject *obj, QEvent *ev)
214 if ( ev->type() == QEvent::MouseButtonPress )
216 QMouseEvent *mev= (QMouseEvent *)(ev);
217 //kdDebug() << QString("click at %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
219 if ( mev->button() == RightButton )
221 KPopupMenu *popup = createPopupMenu( );
222 popup->exec( mev->globalPos() );
223 delete popup;
224 return TRUE;
227 QCursor cursor;
228 if ( m_selectedRegion.contains( mev->pos() )
229 && m_selectedRegion!=m_originalPixmap.rect() )
231 m_state=Moving;
232 cursor=QCursor(Qt::SizeAllCursor);
234 else
236 m_state=Resizing;
237 cursor=QCursor(Qt::CrossCursor);
239 QApplication::setOverrideCursor(cursor);
241 m_tempFirstClick=mev->pos();
243 return TRUE;
246 if ( ev->type() == QEvent::MouseMove )
248 QMouseEvent *mev= (QMouseEvent *)(ev);
250 //kdDebug() << QString("move to %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
252 if ( m_state == Resizing )
254 setSelectedRegion (
255 calcSelectionRectangle( m_tempFirstClick, mev->pos() ) );
257 else if (m_state == Moving )
259 int mevx = mev->x();
260 int mevy = mev->y();
261 bool mouseOutside=false;
262 if ( mevx < 0 )
264 m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
265 mouseOutside=true;
267 else if ( mevx > m_originalPixmap.width() )
269 m_selectedRegion.moveBy(m_originalPixmap.width()-m_selectedRegion.width()-m_selectedRegion.x(),0);
270 mouseOutside=true;
272 if ( mevy < 0 )
274 m_selectedRegion.moveBy(0,-m_selectedRegion.y());
275 mouseOutside=true;
277 else if ( mevy > m_originalPixmap.height() )
279 m_selectedRegion.moveBy(0,m_originalPixmap.height()-m_selectedRegion.height()-m_selectedRegion.y());
280 mouseOutside=true;
282 if (mouseOutside) { updatePixmap(); return TRUE; };
284 m_selectedRegion.moveBy( mev->x()-m_tempFirstClick.x(),
285 mev->y()-m_tempFirstClick.y() );
287 // Check that the region has not fallen outside the image
288 if (m_selectedRegion.x() < 0)
289 m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
290 else if (m_selectedRegion.right() > m_originalPixmap.width())
291 m_selectedRegion.moveBy(-(m_selectedRegion.right()-m_originalPixmap.width()),0);
293 if (m_selectedRegion.y() < 0)
294 m_selectedRegion.moveBy(0,-m_selectedRegion.y());
295 else if (m_selectedRegion.bottom() > m_originalPixmap.height())
296 m_selectedRegion.moveBy(0,-(m_selectedRegion.bottom()-m_originalPixmap.height()));
298 m_tempFirstClick=mev->pos();
299 updatePixmap();
301 return TRUE;
304 if ( ev->type() == QEvent::MouseButtonRelease )
306 QMouseEvent *mev= (QMouseEvent *)(ev);
308 if ( m_state == Resizing && mev->pos() == m_tempFirstClick)
309 resetSelection();
311 m_state=None;
312 QApplication::restoreOverrideCursor();
314 return TRUE;
317 QWidget::eventFilter(obj, ev);
318 return FALSE;
321 QRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const QPoint & startPoint, const QPoint & _endPoint )
323 QPoint endPoint = _endPoint;
324 if ( endPoint.x() < 0 ) endPoint.setX(0);
325 else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width());
326 if ( endPoint.y() < 0 ) endPoint.setY(0);
327 else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height());
328 int w=abs(startPoint.x()-endPoint.x());
329 int h=abs(startPoint.y()-endPoint.y());
331 if (m_forcedAspectRatio>0)
333 double aspectRatio=w/double(h);
335 if (aspectRatio>m_forcedAspectRatio)
336 h=(int)(w/m_forcedAspectRatio);
337 else
338 w=(int)(h*m_forcedAspectRatio);
341 int x,y;
342 if ( startPoint.x() < endPoint.x() )
343 x=startPoint.x();
344 else
345 x=startPoint.x()-w;
346 if ( startPoint.y() < endPoint.y() )
347 y=startPoint.y();
348 else
349 y=startPoint.y()-h;
351 if (x<0)
353 w+=x;
354 x=0;
355 h=(int)(w/m_forcedAspectRatio);
357 if ( startPoint.y() > endPoint.y() )
358 y=startPoint.y()-h;
360 else if (x+w>m_originalPixmap.width())
362 w=m_originalPixmap.width()-x;
363 h=(int)(w/m_forcedAspectRatio);
365 if ( startPoint.y() > endPoint.y() )
366 y=startPoint.y()-h;
368 if (y<0)
370 h+=y;
371 y=0;
372 w=(int)(h*m_forcedAspectRatio);
374 if ( startPoint.x() > endPoint.x() )
375 x=startPoint.x()-w;
377 else if (y+h>m_originalPixmap.height())
379 h=m_originalPixmap.height()-y;
380 w=(int)(h*m_forcedAspectRatio);
382 if ( startPoint.x() > endPoint.x() )
383 x=startPoint.x()-w;
386 return QRect(x,y,w,h);
389 QRect KPixmapRegionSelectorWidget::unzoomedSelectedRegion() const
391 return QRect((int)(m_selectedRegion.x()/m_zoomFactor),
392 (int)(m_selectedRegion.y()/m_zoomFactor),
393 (int)(m_selectedRegion.width()/m_zoomFactor),
394 (int)(m_selectedRegion.height()/m_zoomFactor));
397 QImage KPixmapRegionSelectorWidget::selectedImage() const
399 QImage origImage=m_unzoomedPixmap.convertToImage();
400 return origImage.copy(unzoomedSelectedRegion());
403 void KPixmapRegionSelectorWidget::setSelectionAspectRatio(int width, int height)
405 m_forcedAspectRatio=width/double(height);
408 void KPixmapRegionSelectorWidget::setFreeSelectionAspectRatio()
410 m_forcedAspectRatio=0;
413 void KPixmapRegionSelectorWidget::setMaximumWidgetSize(int width, int height)
415 m_maxWidth=width;
416 m_maxHeight=height;
418 m_originalPixmap=m_unzoomedPixmap;
419 if (m_selectedRegion == m_originalPixmap.rect()) m_selectedRegion=QRect();
421 // kdDebug() << QString(" original Pixmap :") << m_originalPixmap.rect() << endl;
422 // kdDebug() << QString(" unzoomed Pixmap : %1 x %2 ").arg(m_unzoomedPixmap.width()).arg(m_unzoomedPixmap.height()) << endl;
424 if ( !m_originalPixmap.isNull() &&
425 ( m_originalPixmap.width() > m_maxWidth ||
426 m_originalPixmap.height() > m_maxHeight ) )
428 /* We have to resize the pixmap to get it complete on the screen */
429 QImage image=m_originalPixmap.convertToImage();
430 m_originalPixmap.convertFromImage( image.smoothScale( width, height, QImage::ScaleMin ) );
431 //m_originalPixmap.convertFromImage( KImageEffect::sample( image, width, height ) );
432 double oldZoomFactor = m_zoomFactor;
433 m_zoomFactor=m_originalPixmap.width()/(double)m_unzoomedPixmap.width();
435 if (m_selectedRegion.isValid())
437 m_selectedRegion=
438 QRect((int)(m_selectedRegion.x()*m_zoomFactor/oldZoomFactor),
439 (int)(m_selectedRegion.y()*m_zoomFactor/oldZoomFactor),
440 (int)(m_selectedRegion.width()*m_zoomFactor/oldZoomFactor),
441 (int)(m_selectedRegion.height()*m_zoomFactor/oldZoomFactor) );
445 if (!m_selectedRegion.isValid()) m_selectedRegion = m_originalPixmap.rect();
447 m_linedPixmap=QPixmap();
448 updatePixmap();
449 resize(m_label->width(), m_label->height());
452 #include "kpixmapregionselectorwidget.moc"