libtdepim

kpixmapregionselectorwidget.cpp
1 /*
2  This file is part of libtdepim.
3 
4  Copyright (C) 2004 Antonio Larrosa <larrosa@kde.org
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 /* NOTE: There are two copies of this .h and the .cpp file, with subtle differences.
23  * One copy is in tdelibs/tdeui, and the other copy is in tdepim/libtdepim
24  * This is because tdepim has to remain backwards compatible. Any changes
25  * to either file should be made to the other.
26  */
27 
28 #include "kpixmapregionselectorwidget.h"
29 #include <tqpainter.h>
30 #include <tqcolor.h>
31 #include <tqimage.h>
32 #include <tqlayout.h>
33 #include <kimageeffect.h>
34 #include <kdebug.h>
35 #include <tdelocale.h>
36 #include <tdepopupmenu.h>
37 #include <tdeaction.h>
38 #include <stdlib.h>
39 #include <tqcursor.h>
40 #include <tqapplication.h>
41 
42 using namespace KPIM;
43 
45  const char *name) : TQWidget( parent, name)
46 {
47  TQHBoxLayout * hboxLayout=new TQHBoxLayout( this );
48 
49  hboxLayout->addStretch();
50  TQVBoxLayout * vboxLayout=new TQVBoxLayout( hboxLayout );
51 
52  vboxLayout->addStretch();
53  m_label = new TQLabel(this, "pixmapHolder");
54  m_label->setBackgroundMode( TQt::NoBackground );
55  m_label->installEventFilter( this );
56 
57  vboxLayout->addWidget(m_label);
58  vboxLayout->addStretch();
59 
60  hboxLayout->addStretch();
61 
62  m_forcedAspectRatio=0;
63 
64  m_zoomFactor=1.0;
65 }
66 
68 {
69 }
70 
71 void KPixmapRegionSelectorWidget::setPixmap( const TQPixmap &pixmap )
72 {
73  Q_ASSERT(!pixmap.isNull()); //This class isn't designed to deal with null pixmaps.
74  m_originalPixmap = pixmap;
75  m_unzoomedPixmap = pixmap;
76  m_label->setPixmap( pixmap );
78 }
79 
81 {
82  m_selectedRegion = m_originalPixmap.rect();
83  updatePixmap();
84 }
85 
87 {
88  return m_selectedRegion;
89 }
90 
92 {
93  if (!rect.isValid()) resetSelection();
94  else
95  {
96  m_selectedRegion=rect;
97  updatePixmap();
98 
99  TQRect r=unzoomedSelectedRegion();
100  }
101 }
102 
103 void KPixmapRegionSelectorWidget::updatePixmap()
104 {
105  Q_ASSERT(!m_originalPixmap.isNull()); if(m_originalPixmap.isNull()) { m_label->setPixmap(m_originalPixmap); return; }
106  if (m_selectedRegion.width()>m_originalPixmap.width()) m_selectedRegion.setWidth( m_originalPixmap.width() );
107  if (m_selectedRegion.height()>m_originalPixmap.height()) m_selectedRegion.setHeight( m_originalPixmap.height() );
108 
109  TQPainter painter;
110  if (m_linedPixmap.isNull())
111  {
112  m_linedPixmap = m_originalPixmap;
113 
114  painter.begin(&m_linedPixmap);
115  painter.setRasterOp( TQt::XorROP );
116  painter.fillRect(0,0,m_linedPixmap.width(), m_linedPixmap.height(),
117  TQBrush( TQColor(255,255,255), TQt::BDiagPattern) );
118  painter.end();
119 
120  TQImage image=m_linedPixmap.convertToImage();
121  image=KImageEffect::fade(image, 0.4, TQColor(0,0,0));
122  m_linedPixmap.convertFromImage(image);
123  }
124 
125  TQPixmap pixmap = m_linedPixmap;
126 
127  painter.begin(&pixmap);
128  painter.drawPixmap( m_selectedRegion.topLeft(),
129  m_originalPixmap, m_selectedRegion );
130 
131  painter.setPen( TQColor(255,255,255) );
132  painter.setRasterOp( TQt::XorROP );
133 
134  painter.drawRect( m_selectedRegion );
135 
136  painter.end();
137 
138  m_label->setPixmap(pixmap);
139 }
140 
142 {
143  TDEPopupMenu *popup=new TDEPopupMenu(this, "PixmapRegionSelectorPopup");
144  popup->insertTitle(i18n("Image Operations"));
145 
146  TDEAction *action = new TDEAction(i18n("&Rotate Clockwise"), "object-rotate-right",
147  0, this, TQ_SLOT(rotateClockwise()),
148  popup, "rotateclockwise");
149  action->plug(popup);
150 
151  action = new TDEAction(i18n("Rotate &Counterclockwise"), "object-rotate-left",
152  0, this, TQ_SLOT(rotateCounterclockwise()),
153  popup, "rotatecounterclockwise");
154  action->plug(popup);
155 
156 /*
157  I wonder if it would be appropiate to have here an "Open with..." option to
158  edit the image (antlarr)
159 */
160  return popup;
161 }
162 
163 void KPixmapRegionSelectorWidget::rotate(KImageEffect::RotateDirection direction)
164 {
165  int w=m_originalPixmap.width();
166  int h=m_originalPixmap.height();
167  TQImage img=m_unzoomedPixmap.convertToImage();
168  img= KImageEffect::rotate(img, direction);
169  m_unzoomedPixmap.convertFromImage(img);
170 
171  img=m_originalPixmap.convertToImage();
172  img= KImageEffect::rotate(img, direction);
173  m_originalPixmap.convertFromImage(img);
174 
175  m_linedPixmap=TQPixmap();
176 
177  if (m_forcedAspectRatio>0 && m_forcedAspectRatio!=1)
178  resetSelection();
179  else
180  {
181  switch (direction)
182  {
183  case ( KImageEffect::Rotate90 ):
184  {
185  int x=h-m_selectedRegion.y()-m_selectedRegion.height();
186  int y=m_selectedRegion.x();
187  m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
188  updatePixmap();
189  } break;
190  case ( KImageEffect::Rotate270 ):
191  {
192  int x=m_selectedRegion.y();
193  int y=w-m_selectedRegion.x()-m_selectedRegion.width();
194  m_selectedRegion.setRect(x, y, m_selectedRegion.height(), m_selectedRegion.width() );
195  updatePixmap();
196  } break;
197  default: resetSelection();
198  }
199  }
200 }
201 
203 {
204  rotate(KImageEffect::Rotate90);
205 }
206 
208 {
209  rotate(KImageEffect::Rotate270);
210 }
211 
212 
213 
214 bool KPixmapRegionSelectorWidget::eventFilter(TQObject *obj, TQEvent *ev)
215 {
216  if ( ev->type() == TQEvent::MouseButtonPress )
217  {
218  TQMouseEvent *mev= (TQMouseEvent *)(ev);
219  //kdDebug() << TQString("click at %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
220 
221  if ( mev->button() == TQt::RightButton )
222  {
223  TDEPopupMenu *popup = createPopupMenu( );
224  popup->exec( mev->globalPos() );
225  delete popup;
226  return TRUE;
227  };
228 
229  TQCursor cursor;
230  if ( m_selectedRegion.contains( mev->pos() )
231  && m_selectedRegion!=m_originalPixmap.rect() )
232  {
233  m_state=Moving;
234  cursor=TQCursor(TQt::SizeAllCursor);
235  }
236  else
237  {
238  m_state=Resizing;
239  cursor=TQCursor(TQt::CrossCursor);
240  }
241  TQApplication::setOverrideCursor(cursor);
242 
243  m_tempFirstClick=mev->pos();
244 
245  return TRUE;
246  }
247 
248  if ( ev->type() == TQEvent::MouseMove )
249  {
250  TQMouseEvent *mev= (TQMouseEvent *)(ev);
251 
252  //kdDebug() << TQString("move to %1,%2").arg( mev->x() ).arg( mev->y() ) << endl;
253 
254  if ( m_state == Resizing )
255  {
257  calcSelectionRectangle( m_tempFirstClick, mev->pos() ) );
258  }
259  else if (m_state == Moving )
260  {
261  int mevx = mev->x();
262  int mevy = mev->y();
263  bool mouseOutside=false;
264  if ( mevx < 0 )
265  {
266  m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
267  mouseOutside=true;
268  }
269  else if ( mevx > m_originalPixmap.width() )
270  {
271  m_selectedRegion.moveBy(m_originalPixmap.width()-m_selectedRegion.width()-m_selectedRegion.x(),0);
272  mouseOutside=true;
273  }
274  if ( mevy < 0 )
275  {
276  m_selectedRegion.moveBy(0,-m_selectedRegion.y());
277  mouseOutside=true;
278  }
279  else if ( mevy > m_originalPixmap.height() )
280  {
281  m_selectedRegion.moveBy(0,m_originalPixmap.height()-m_selectedRegion.height()-m_selectedRegion.y());
282  mouseOutside=true;
283  }
284  if (mouseOutside) { updatePixmap(); return TRUE; };
285 
286  m_selectedRegion.moveBy( mev->x()-m_tempFirstClick.x(),
287  mev->y()-m_tempFirstClick.y() );
288 
289  // Check that the region has not fallen outside the image
290  if (m_selectedRegion.x() < 0)
291  m_selectedRegion.moveBy(-m_selectedRegion.x(),0);
292  else if (m_selectedRegion.right() > m_originalPixmap.width())
293  m_selectedRegion.moveBy(-(m_selectedRegion.right()-m_originalPixmap.width()),0);
294 
295  if (m_selectedRegion.y() < 0)
296  m_selectedRegion.moveBy(0,-m_selectedRegion.y());
297  else if (m_selectedRegion.bottom() > m_originalPixmap.height())
298  m_selectedRegion.moveBy(0,-(m_selectedRegion.bottom()-m_originalPixmap.height()));
299 
300  m_tempFirstClick=mev->pos();
301  updatePixmap();
302  }
303  return TRUE;
304  }
305 
306  if ( ev->type() == TQEvent::MouseButtonRelease )
307  {
308  TQMouseEvent *mev= (TQMouseEvent *)(ev);
309 
310  if ( m_state == Resizing && mev->pos() == m_tempFirstClick)
311  resetSelection();
312 
313  m_state=None;
314  TQApplication::restoreOverrideCursor();
315 
316  return TRUE;
317  }
318 
319  TQWidget::eventFilter(obj, ev);
320  return FALSE;
321 }
322 
323 TQRect KPixmapRegionSelectorWidget::calcSelectionRectangle( const TQPoint & startPoint, const TQPoint & _endPoint )
324 {
325  TQPoint endPoint = _endPoint;
326  if ( endPoint.x() < 0 ) endPoint.setX(0);
327  else if ( endPoint.x() > m_originalPixmap.width() ) endPoint.setX(m_originalPixmap.width());
328  if ( endPoint.y() < 0 ) endPoint.setY(0);
329  else if ( endPoint.y() > m_originalPixmap.height() ) endPoint.setY(m_originalPixmap.height());
330  int w=abs(startPoint.x()-endPoint.x());
331  int h=abs(startPoint.y()-endPoint.y());
332 
333  if (m_forcedAspectRatio>0)
334  {
335  double aspectRatio=w/double(h);
336 
337  if (aspectRatio>m_forcedAspectRatio)
338  h=(int)(w/m_forcedAspectRatio);
339  else
340  w=(int)(h*m_forcedAspectRatio);
341  }
342 
343  int x,y;
344  if ( startPoint.x() < endPoint.x() )
345  x=startPoint.x();
346  else
347  x=startPoint.x()-w;
348  if ( startPoint.y() < endPoint.y() )
349  y=startPoint.y();
350  else
351  y=startPoint.y()-h;
352 
353  if (x<0)
354  {
355  w+=x;
356  x=0;
357  h=(int)(w/m_forcedAspectRatio);
358 
359  if ( startPoint.y() > endPoint.y() )
360  y=startPoint.y()-h;
361  }
362  else if (x+w>m_originalPixmap.width())
363  {
364  w=m_originalPixmap.width()-x;
365  h=(int)(w/m_forcedAspectRatio);
366 
367  if ( startPoint.y() > endPoint.y() )
368  y=startPoint.y()-h;
369  }
370  if (y<0)
371  {
372  h+=y;
373  y=0;
374  w=(int)(h*m_forcedAspectRatio);
375 
376  if ( startPoint.x() > endPoint.x() )
377  x=startPoint.x()-w;
378  }
379  else if (y+h>m_originalPixmap.height())
380  {
381  h=m_originalPixmap.height()-y;
382  w=(int)(h*m_forcedAspectRatio);
383 
384  if ( startPoint.x() > endPoint.x() )
385  x=startPoint.x()-w;
386  }
387 
388  return TQRect(x,y,w,h);
389 }
390 
392 {
393  return TQRect((int)(m_selectedRegion.x()/m_zoomFactor),
394  (int)(m_selectedRegion.y()/m_zoomFactor),
395  (int)(m_selectedRegion.width()/m_zoomFactor),
396  (int)(m_selectedRegion.height()/m_zoomFactor));
397 }
398 
400 {
401  TQImage origImage=m_unzoomedPixmap.convertToImage();
402  return origImage.copy(unzoomedSelectedRegion());
403 }
404 
406 {
407  m_forcedAspectRatio=width/double(height);
408 }
409 
411 {
412  m_forcedAspectRatio=0;
413 }
414 
416 {
417  m_maxWidth=width;
418  m_maxHeight=height;
419 
420  m_originalPixmap=m_unzoomedPixmap;
421  if (m_selectedRegion == m_originalPixmap.rect()) m_selectedRegion=TQRect();
422 
423 // kdDebug() << TQString(" original Pixmap :") << m_originalPixmap.rect() << endl;
424 // kdDebug() << TQString(" unzoomed Pixmap : %1 x %2 ").arg(m_unzoomedPixmap.width()).arg(m_unzoomedPixmap.height()) << endl;
425 
426  if ( !m_originalPixmap.isNull() &&
427  ( m_originalPixmap.width() > m_maxWidth ||
428  m_originalPixmap.height() > m_maxHeight ) )
429  {
430  /* We have to resize the pixmap to get it complete on the screen */
431  TQImage image=m_originalPixmap.convertToImage();
432  m_originalPixmap.convertFromImage( image.smoothScale( width, height, TQImage::ScaleMin ) );
433  //m_originalPixmap.convertFromImage( KImageEffect::sample( image, width, height ) );
434  double oldZoomFactor = m_zoomFactor;
435  m_zoomFactor=m_originalPixmap.width()/(double)m_unzoomedPixmap.width();
436 
437  if (m_selectedRegion.isValid())
438  {
439  m_selectedRegion=
440  TQRect((int)(m_selectedRegion.x()*m_zoomFactor/oldZoomFactor),
441  (int)(m_selectedRegion.y()*m_zoomFactor/oldZoomFactor),
442  (int)(m_selectedRegion.width()*m_zoomFactor/oldZoomFactor),
443  (int)(m_selectedRegion.height()*m_zoomFactor/oldZoomFactor) );
444  }
445  }
446 
447  if (!m_selectedRegion.isValid()) m_selectedRegion = m_originalPixmap.rect();
448 
449  m_linedPixmap=TQPixmap();
450  updatePixmap();
451  resize(m_label->width(), m_label->height());
452 }
453 
454 #include "kpixmapregionselectorwidget.moc"
void setSelectedRegion(const TQRect &rect)
Sets the selected region to be rect (in zoomed pixmap coordinates)
TQRect unzoomedSelectedRegion() const
Returns the selected region ( in unzoomed, original pixmap coordinates )
void setMaximumWidgetSize(int width, int height)
Sets the maximum size for the widget.
void setPixmap(const TQPixmap &pixmap)
Sets the pixmap which will be shown for the user to select a region from.
TQRect selectedRegion() const
Returns the selected region ( in zoomed pixmap coordinates )
void rotateCounterclockwise()
Rotates the current image 90º counterclockwise.
void setFreeSelectionAspectRatio()
Allows the user to do a selection which has any aspect ratio.
void setSelectionAspectRatio(int width, int height)
Sets the aspect ration that the selected subimage should have.
TDEPIM classes for drag and drop of mails.
virtual TDEPopupMenu * createPopupMenu()
Creates a TDEPopupMenu with the menu that appears when clicking with the right button on the label.
~KPixmapRegionSelectorWidget()
Destructor for a KPixmapRegionSelectorWidget.
void rotate(KImageEffect::RotateDirection direction)
Rotates the image as specified by the direction parameter, also tries to rotate the selected region s...
void resetSelection()
Resets the selection to use the whole image.
void rotateClockwise()
Rotates the current image 90º clockwise.
KPixmapRegionSelectorWidget(TQWidget *parent=0L, const char *name=0L)
Constructor for a KPixmapRegionSelectorWidget.