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
44KPixmapRegionSelectorWidget::KPixmapRegionSelectorWidget( TQWidget *parent,
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
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.
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.