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 resetSelection()
Resets the selection to use the whole image.
void setSelectedRegion(const TQRect &rect)
Sets the selected region to be rect (in zoomed pixmap coordinates)
void rotate(KImageEffect::RotateDirection direction)
Rotates the image as specified by the direction parameter, also tries to rotate the selected region s...
void rotateClockwise()
Rotates the current image 90º clockwise.
KPixmapRegionSelectorWidget(TQWidget *parent=0L, const char *name=0L)
Constructor for a KPixmapRegionSelectorWidget.
void setFreeSelectionAspectRatio()
Allows the user to do a selection which has any aspect ratio.
TQRect unzoomedSelectedRegion() const
Returns the selected region ( in unzoomed, original pixmap coordinates )
void setSelectionAspectRatio(int width, int height)
Sets the aspect ration that the selected subimage should have.
virtual TDEPopupMenu * createPopupMenu()
Creates a TDEPopupMenu with the menu that appears when clicking with the right button on the label.
void setPixmap(const TQPixmap &pixmap)
Sets the pixmap which will be shown for the user to select a region from.
~KPixmapRegionSelectorWidget()
Destructor for a KPixmapRegionSelectorWidget.
void rotateCounterclockwise()
Rotates the current image 90º counterclockwise.
void setMaximumWidgetSize(int width, int height)
Sets the maximum size for the widget.
TQRect selectedRegion() const
Returns the selected region ( in zoomed pixmap coordinates )
TDEPIM classes for drag and drop of mails.