compile
[kdegraphics.git] / ksnapshot / regiongrabber.cpp
blob5de6abdcfa227b43a0fd6ecc27fc139e3d656cce
1 /*
2 * Copyright (C) 2007 Luca Gugelmann <lucag@student.ethz.ch>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Library General Public License version 2 as
6 * published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
13 * You should have received a copy of the GNU Library General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "regiongrabber.h"
21 #include <QPainter>
22 #include <QMouseEvent>
23 #include <QApplication>
24 #include <QDesktopWidget>
25 #include <QToolTip>
27 #include <klocale.h>
28 #include <KWindowSystem>
30 RegionGrabber::RegionGrabber( ) :
31 QWidget( 0 ), selection(), mouseDown( false ), newSelection( false ),
32 handleSize( 10 ), mouseOverHandle( 0 ), idleTimer(),
33 showHelp( true ), grabbing( false ),
34 TLHandle(0,0,handleSize,handleSize), TRHandle(0,0,handleSize,handleSize),
35 BLHandle(0,0,handleSize,handleSize), BRHandle(0,0,handleSize,handleSize),
36 LHandle(0,0,handleSize,handleSize), THandle(0,0,handleSize,handleSize),
37 RHandle(0,0,handleSize,handleSize), BHandle(0,0,handleSize,handleSize)
39 handles << &TLHandle << &TRHandle << &BLHandle << &BRHandle
40 << &LHandle << &THandle << &RHandle << &BHandle;
41 setMouseTracking( true );
42 setWindowFlags( Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
43 int timeout = KWindowSystem::compositingActive() ? 200 : 50;
44 QTimer::singleShot( timeout, this, SLOT(init()) );
45 connect( &idleTimer, SIGNAL( timeout() ), this, SLOT( displayHelp() ) );
46 idleTimer.start( 3000 );
49 RegionGrabber::~RegionGrabber()
53 void RegionGrabber::init()
55 pixmap = QPixmap::grabWindow( QApplication::desktop()->winId() );
56 showFullScreen();
57 resize( pixmap.size() );
58 move(0, 0);
59 setCursor( Qt::CrossCursor );
62 void RegionGrabber::displayHelp()
64 showHelp = true;
65 update();
68 void RegionGrabber::paintEvent( QPaintEvent* e )
70 Q_UNUSED( e );
71 if ( grabbing ) // grabWindow() should just get the background
72 return;
74 QPainter painter( this );
76 QPalette pal(QToolTip::palette());
77 QFont font = QToolTip::font();
79 QColor handleColor = pal.color( QPalette::Active, QPalette::Highlight );
80 handleColor.setAlpha( 160 );
81 QColor overlayColor( 0, 0, 0, 160 );
82 QColor textColor = pal.color( QPalette::Active, QPalette::Text );
83 QColor textBackgroundColor = pal.color( QPalette::Active, QPalette::Base );
84 painter.drawPixmap(0, 0, pixmap);
85 painter.setFont(font);
87 QRect r = selection.normalized().adjusted( 0, 0, -1, -1 );
88 if ( !selection.isNull() )
90 QRegion grey( rect() );
91 grey = grey.subtracted( r );
92 painter.setPen( handleColor );
93 painter.setBrush( overlayColor );
94 painter.setClipRegion( grey );
95 painter.drawRect( -1, -1, rect().width() + 1, rect().height() + 1 );
96 painter.setClipRect( rect() );
97 painter.setBrush( Qt::NoBrush );
98 painter.drawRect( r );
101 if ( showHelp )
103 painter.setPen( textColor );
104 painter.setBrush( textBackgroundColor );
105 QString helpText = i18n( "Select a region using the mouse. To take the snapshot, press the Enter key. Press Esc to quit." );
106 QRect textRect = painter.boundingRect( rect().adjusted( 2, 2, -2, -2 ), Qt::TextWordWrap, helpText );
107 textRect.adjust( -2, -2, 4, 2 );
108 painter.drawRect( textRect );
109 textRect.moveTopLeft( QPoint( 3, 3 ) );
110 painter.drawText( textRect, helpText );
113 if ( selection.isNull() )
115 return;
118 // The grabbed region is everything which is covered by the drawn
119 // rectangles (border included). This means that there is no 0px
120 // selection, since a 0px wide rectangle will always be drawn as a line.
121 QString txt = QString( "%1x%2" ).arg( selection.width() == 0 ? 2 : selection.width() )
122 .arg( selection.height() == 0 ? 2 : selection.height() );
123 QRect textRect = painter.boundingRect( rect(), Qt::AlignLeft, txt );
124 QRect boundingRect = textRect.adjusted( -4, 0, 0, 0);
126 if ( textRect.width() < r.width() - 2*handleSize &&
127 textRect.height() < r.height() - 2*handleSize &&
128 ( r.width() > 100 && r.height() > 100 ) ) // center, unsuitable for small selections
130 boundingRect.moveCenter( r.center() );
131 textRect.moveCenter( r.center() );
133 else if ( r.y() - 3 > textRect.height() &&
134 r.x() + textRect.width() < rect().right() ) // on top, left aligned
136 boundingRect.moveBottomLeft( QPoint( r.x(), r.y() - 3 ) );
137 textRect.moveBottomLeft( QPoint( r.x() + 2, r.y() - 3 ) );
139 else if ( r.x() - 3 > textRect.width() ) // left, top aligned
141 boundingRect.moveTopRight( QPoint( r.x() - 3, r.y() ) );
142 textRect.moveTopRight( QPoint( r.x() - 5, r.y() ) );
144 else if ( r.bottom() + 3 + textRect.height() < rect().bottom() &&
145 r.right() > textRect.width() ) // at bottom, right aligned
147 boundingRect.moveTopRight( QPoint( r.right(), r.bottom() + 3 ) );
148 textRect.moveTopRight( QPoint( r.right() - 2, r.bottom() + 3 ) );
150 else if ( r.right() + textRect.width() + 3 < rect().width() ) // right, bottom aligned
152 boundingRect.moveBottomLeft( QPoint( r.right() + 3, r.bottom() ) );
153 textRect.moveBottomLeft( QPoint( r.right() + 5, r.bottom() ) );
155 // if the above didn't catch it, you are running on a very tiny screen...
156 painter.setPen( textColor );
157 painter.setBrush( textBackgroundColor );
158 painter.drawRect( boundingRect );
159 painter.drawText( textRect, txt );
161 if ( ( r.height() > handleSize*2 && r.width() > handleSize*2 )
162 || !mouseDown )
164 updateHandles();
165 painter.setPen( handleColor );
166 handleColor.setAlpha( 60 );
167 painter.setBrush( handleColor );
168 painter.drawRects( handleMask().rects() );
172 void RegionGrabber::resizeEvent( QResizeEvent* e )
174 Q_UNUSED( e );
175 if ( selection.isNull() )
176 return;
177 QRect r = selection;
178 r.setTopLeft( limitPointToRect( r.topLeft(), rect() ) );
179 r.setBottomRight( limitPointToRect( r.bottomRight(), rect() ) );
180 if ( r.width() <= 1 || r.height() <= 1 ) //this just results in ugly drawing...
181 r = QRect();
182 selection = r;
185 void RegionGrabber::mousePressEvent( QMouseEvent* e )
187 showHelp = false;
188 idleTimer.stop();
189 if ( e->button() == Qt::LeftButton )
191 mouseDown = true;
192 dragStartPoint = e->pos();
193 selectionBeforeDrag = selection;
194 if ( !selection.contains( e->pos() ) )
196 newSelection = true;
197 selection = QRect();
198 showHelp = true;
200 else
202 setCursor( Qt::ClosedHandCursor );
205 else if ( e->button() == Qt::RightButton )
207 newSelection = false;
208 selection = QRect();
209 setCursor( Qt::CrossCursor );
211 update();
214 void RegionGrabber::mouseMoveEvent( QMouseEvent* e )
216 if ( mouseDown )
218 if ( newSelection )
220 QPoint p = e->pos();
221 QRect r = rect();
222 selection = QRect( dragStartPoint, limitPointToRect( p, r ) ).normalized();
224 else if ( mouseOverHandle == 0 ) // moving the whole selection
226 QRect r = rect().normalized(), s = selectionBeforeDrag.normalized();
227 QPoint p = s.topLeft() + e->pos() - dragStartPoint;
228 r.setBottomRight( r.bottomRight() - QPoint( s.width(), s.height() ) );
229 if ( !r.isNull() && r.isValid() )
230 selection.moveTo( limitPointToRect( p, r ) );
232 else // dragging a handle
234 QRect r = selectionBeforeDrag;
235 QPoint offset = e->pos() - dragStartPoint;
237 if ( mouseOverHandle == &TLHandle || mouseOverHandle == &THandle
238 || mouseOverHandle == &TRHandle ) // dragging one of the top handles
240 r.setTop( r.top() + offset.y() );
243 if ( mouseOverHandle == &TLHandle || mouseOverHandle == &LHandle
244 || mouseOverHandle == &BLHandle ) // dragging one of the left handles
246 r.setLeft( r.left() + offset.x() );
249 if ( mouseOverHandle == &BLHandle || mouseOverHandle == &BHandle
250 || mouseOverHandle == &BRHandle ) // dragging one of the bottom handles
252 r.setBottom( r.bottom() + offset.y() );
255 if ( mouseOverHandle == &TRHandle || mouseOverHandle == &RHandle
256 || mouseOverHandle == &BRHandle ) // dragging one of the right handles
258 r.setRight( r.right() + offset.x() );
260 r = r.normalized();
261 r.setTopLeft( limitPointToRect( r.topLeft(), rect() ) );
262 r.setBottomRight( limitPointToRect( r.bottomRight(), rect() ) );
263 selection = r;
265 update();
267 else
269 if ( selection.isNull() )
270 return;
271 bool found = false;
272 foreach( QRect* r, handles )
274 if ( r->contains( e->pos() ) )
276 mouseOverHandle = r;
277 found = true;
278 break;
281 if ( !found )
283 mouseOverHandle = 0;
284 if ( selection.contains( e->pos() ) )
285 setCursor( Qt::OpenHandCursor );
286 else
287 setCursor( Qt::CrossCursor );
289 else
291 if ( mouseOverHandle == &TLHandle || mouseOverHandle == &BRHandle )
292 setCursor( Qt::SizeFDiagCursor );
293 if ( mouseOverHandle == &TRHandle || mouseOverHandle == &BLHandle )
294 setCursor( Qt::SizeBDiagCursor );
295 if ( mouseOverHandle == &LHandle || mouseOverHandle == &RHandle )
296 setCursor( Qt::SizeHorCursor );
297 if ( mouseOverHandle == &THandle || mouseOverHandle == &BHandle )
298 setCursor( Qt::SizeVerCursor );
303 void RegionGrabber::mouseReleaseEvent( QMouseEvent* e )
305 mouseDown = false;
306 newSelection = false;
307 idleTimer.start();
308 if ( mouseOverHandle == 0 && selection.contains( e->pos() ) )
309 setCursor( Qt::OpenHandCursor );
310 update();
313 void RegionGrabber::mouseDoubleClickEvent( QMouseEvent* )
315 grabRect();
318 void RegionGrabber::keyPressEvent( QKeyEvent* e )
320 if ( e->key() == Qt::Key_Escape )
322 emit regionGrabbed( QPixmap() );
324 else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
326 grabRect();
328 else
330 e->ignore();
334 void RegionGrabber::grabRect()
336 QRect r = selection.normalized();
337 if ( !r.isNull() && r.isValid() )
339 grabbing = true;
340 emit regionGrabbed( pixmap.copy(r) );
344 void RegionGrabber::updateHandles()
346 QRect r = selection.normalized().adjusted( 0, 0, -1, -1 );
347 int s2 = handleSize / 2;
349 TLHandle.moveTopLeft( r.topLeft() );
350 TRHandle.moveTopRight( r.topRight() );
351 BLHandle.moveBottomLeft( r.bottomLeft() );
352 BRHandle.moveBottomRight( r.bottomRight() );
354 LHandle.moveTopLeft( QPoint( r.x(), r.y() + r.height() / 2 - s2) );
355 THandle.moveTopLeft( QPoint( r.x() + r.width() / 2 - s2, r.y() ) );
356 RHandle.moveTopRight( QPoint( r.right(), r.y() + r.height() / 2 - s2 ) );
357 BHandle.moveBottomLeft( QPoint( r.x() + r.width() / 2 - s2, r.bottom() ) );
360 QRegion RegionGrabber::handleMask() const
362 // note: not normalized QRects are bad here, since they will not be drawn
363 QRegion mask;
364 foreach( QRect* rect, handles ) mask += QRegion( *rect );
365 return mask;
368 QPoint RegionGrabber::limitPointToRect( const QPoint &p, const QRect &r ) const
370 QPoint q;
371 q.setX( p.x() < r.x() ? r.x() : p.x() < r.right() ? p.x() : r.right() );
372 q.setY( p.y() < r.y() ? r.y() : p.y() < r.bottom() ? p.y() : r.bottom() );
373 return q;
376 #include "regiongrabber.moc"