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
42using 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
70
71void 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
103void 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
163void 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)
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
214bool 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)
312
313 m_state=None;
314 TQApplication::restoreOverrideCursor();
315
316 return TRUE;
317 }
318
319 TQWidget::eventFilter(obj, ev);
320 return FALSE;
321}
322
323TQRect 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.