1/***************************************************************************
2 kmagview.cpp - description
3 -------------------
4 begin : Mon Feb 12 23:45:41 EST 2001
5 copyright : (C) 2001-2003 by Sarang Lakare
6 email : sarang#users.sourceforge.net
7 copyright : (C) 2003-2004 by Olaf Schmidt
8 email : ojschmidt@kde.org
9 copyright : (C) 2008 by Matthew Woehlke
10 email : mw_triad@users.sourceforge.net
11 copyright (C) 2010 Sebastian Sauer
12 email sebsauer@kdab.com
13 ***************************************************************************/
14
15/***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24
25// application specific includes
26#include "kmagzoomview.h"
27#include "kmagzoomview.moc"
28#include "colorsim.h"
29
30// include files for Qt
31#include <QtGui/QBitmap>
32#include <QtGui/QCursor>
33#include <QtCore/qglobal.h>
34#include <QtGui/QPainter>
35#include <QtGui/QWidget>
36#include <QtGui/QScrollBar>
37#include <QtGui/QPixmap>
38#include <QtGui/QFocusEvent>
39#include <QtGui/QHideEvent>
40#include <QtGui/QKeyEvent>
41#include <QtGui/QShowEvent>
42#include <QtGui/QResizeEvent>
43#include <QtGui/QMouseEvent>
44#include <QtGui/QDesktopWidget>
45#include <QtDBus/QDBusConnection>
46
47// include files for KDE
48#include <kapplication.h>
49#include <kcursor.h>
50#include <kdebug.h>
51#include <klocale.h>
52#ifdef QAccessibilityClient_FOUND
53#include <qaccessibilityclient/accessibleobject.h>
54#endif
55
56// include bitmaps for cursors
57static uchar left_ptr_bits[] = {
58 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00,
59 0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x07, 0xf8, 0x00, 0xd8, 0x00, 0x88, 0x01,
60 0x80, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00};
61
62static uchar left_ptrmsk_bits[] = {
63 0x0c, 0x00, 0x1c, 0x00, 0x3c, 0x00, 0x7c, 0x00, 0xfc, 0x00, 0xfc, 0x01,
64 0xfc, 0x03, 0xfc, 0x07, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x01, 0xdc, 0x03,
65 0xcc, 0x03, 0x80, 0x07, 0x80, 0x07, 0x00, 0x03};
66
67static uchar phand_bits[] = {
68 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
69 0x7e, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00,
70 0x08, 0x08, 0x00, 0x00, 0x70, 0x14, 0x00, 0x00, 0x08, 0x22, 0x00, 0x00,
71 0x30, 0x41, 0x00, 0x00, 0xc0, 0x20, 0x00, 0x00, 0x40, 0x12, 0x00, 0x00,
72 0x80, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
79 static uchar phandm_bits[] = {
80 0xfe, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
81 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00,
82 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00,
83 0xf8, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00,
84 0xc0, 0x1f, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
85 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
91
92
93KMagZoomView::KMagZoomView(QWidget *parent, const char *name)
94 : QAbstractScrollArea(parent),
95 m_selRect(0, 0, 128, 128, this),
96 m_grabTimer(parent),
97 m_mouseViewTimer(parent),
98 m_latestCursorPos(0,0),
99 m_followMouse(false),
100 m_followFocus(false),
101 m_showMouse(1),
102 m_zoom(1.0),
103 m_rotation(0),
104 m_colormode(0),
105 m_fitToWindow(true)
106{
107 setObjectName( QLatin1String( name ));
108
109 viewport()->setMouseTracking(true);
110 viewport()->setAttribute(Qt::WA_NoSystemBackground, true);
111 viewport()->setAutoFillBackground(false);
112 viewport()->setFocusPolicy(Qt::StrongFocus);
113
114 // init the zoom matrix
115 setupMatrix();
116
117 m_ctrlKeyPressed = false;
118 m_shiftKeyPressed = false;
119 m_refreshSwitch = true;
120 m_refreshSwitchStateOnHide = m_refreshSwitch;
121
122 // set the refresh rate
123 setRefreshRate(10);
124
125 // connect it to grabFrame()
126 connect(&m_grabTimer, SIGNAL(timeout()), SLOT(grabFrame()));
127 // start the grabTimer
128 m_grabTimer.start(static_cast<int>(1000.0/m_fps));
129
130 // connect it to updateMouseView()
131 connect(&m_mouseViewTimer, SIGNAL(timeout()), SLOT(updateMouseView()));
132 // start the grabTimer @ 25 frames per second!
133 m_mouseViewTimer.start(40);
134
135 this->setWhatsThis( i18n("This is the main window which shows the contents of the\
136 selected region. The contents will be magnified according to the zoom level that is set."));
137
138 // different ways to show the cursor.
139 m_showMouseTypes << QLatin1String( "Hidden" ) << QLatin1String( "Box" ) << QLatin1String( "Arrow" ) << QLatin1String( "Actual" );
140
141 if(m_fitToWindow)
142 fitToWindow();
143
144#ifdef QAccessibilityClient_FOUND
145 //subscribe to focus events from registry
146 m_registry.subscribeEventListeners(QAccessibleClient::Registry::Focus | QAccessibleClient::Registry::TextCaretMoved);
147#endif
148}
149
150KMagZoomView::~KMagZoomView()
151{
152}
153
154int KMagZoomView::contentsX() const
155{
156 return horizontalScrollBar()->value();
157}
158
159int KMagZoomView::contentsY() const
160{
161 return verticalScrollBar()->value();
162}
163
164int KMagZoomView::contentsWidth() const
165{
166 return horizontalScrollBar()->pageStep();
167}
168
169int KMagZoomView::contentsHeight() const
170{
171 return verticalScrollBar()->pageStep();
172}
173
174int KMagZoomView::visibleWidth() const
175{
176 return viewport()->width();
177}
178
179int KMagZoomView::visibleHeight() const
180{
181 return viewport()->height();
182}
183
184void KMagZoomView::setContentsPos(int x, int y)
185{
186 horizontalScrollBar()->setValue(x);
187 verticalScrollBar()->setValue(y);
188}
189
190void KMagZoomView::setupMatrix()
191{
192 m_zoomMatrix.reset();
193 m_zoomMatrix.scale(m_zoom, m_zoom);
194 m_zoomMatrix.rotate(m_rotation);
195}
196
197/**
198 * This function will set/reset mouse following of grab window.
199 */
200void KMagZoomView::followMouse(bool follow)
201{
202 m_followMouse = follow;
203 m_mouseMode = Normal;
204 if(follow) {
205 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
206 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
207 } else {
208 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
209 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
210 }
211}
212
213#ifdef QAccessibilityClient_FOUND
214
215void KMagZoomView::followBoth(bool follow)
216{
217 m_followBoth = follow;
218 if(follow){
219 m_followMouse = true;
220 m_followFocus = false;
221 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
222 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
223
224 connect(&m_registry, SIGNAL(focusChanged(QAccessibleClient::AccessibleObject)),
225 this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
226 connect(&m_registry, SIGNAL(textCaretMoved(QAccessibleClient::AccessibleObject,int)),
227 this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
228 } else {
229 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
230 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
231
232 disconnect(this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
233 }
234}
235
236/**
237 * This function will set/reset keyboard focus following of grab window.
238 */
239void KMagZoomView::followFocus(bool follow)
240{
241 if(m_followFocus == follow)
242 return;
243 m_followFocus = follow;
244 m_mouseMode = Normal;
245 if(follow) {
246 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
247 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff);
248
249 connect(&m_registry,SIGNAL(focusChanged(QAccessibleClient::AccessibleObject)),
250 this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
251 connect(&m_registry, SIGNAL(textCaretMoved(QAccessibleClient::AccessibleObject,int)),
252 this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
253 } else {
254 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
255 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOn);
256
257 disconnect(this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
258 }
259}
260
261void KMagZoomView::focusChanged(const QAccessibleClient::AccessibleObject &object)
262{
263 m_oldFocus = object.focusPoint();
264 if(m_followBoth && !m_selRect.contains(m_oldFocus)) {
265 QCursor::setPos(m_oldFocus);
266 m_followFocus = true;
267 m_followMouse = false;
268 }
269}
270
271#endif
272
273/**
274 * Called when the widget is hidden. Stop refresh when this happens.
275 */
276void KMagZoomView::hideEvent( QHideEvent* )
277{
278 // Save the state of the refresh switch.. the state will be restored
279 // when showEvent is called
280 m_refreshSwitchStateOnHide = m_refreshSwitch;
281
282 // Check if refresh is ON
283 if(m_refreshSwitch) {
284 toggleRefresh();
285 }
286}
287
288
289/**
290 * Called when the widget is shown. Start refresh when this happens.
291 */
292void KMagZoomView::showEvent( QShowEvent* )
293{
294 // Check if refresh switch was ON when hide was called and if currently it is OFF
295 if(m_refreshSwitchStateOnHide && !m_refreshSwitch) {
296 // start the refresh in that case
297 toggleRefresh();
298 }
299}
300
301/**
302 * Called when the widget is resized. Check if fitToWindow is active when this happens.
303 */
304void KMagZoomView::resizeEvent( QResizeEvent * e )
305{
306 horizontalScrollBar()->setRange(0, contentsWidth() - visibleWidth());
307 verticalScrollBar()->setRange(0, contentsHeight() - visibleHeight());
308 QAbstractScrollArea::resizeEvent(e);
309 if(m_fitToWindow)
310 fitToWindow();
311}
312
313/**
314 * Called when the widget is to be repainted.
315 *
316 * @param p
317 */
318void KMagZoomView::paintEvent(QPaintEvent *e)
319{
320 if(m_coloredPixmap.isNull())
321 return;
322
323 QPainter p(viewport());
324 int clipx = e->rect().x();
325 int clipy = e->rect().x();
326 int clipw = e->rect().width();
327 int cliph = e->rect().height();
328
329 // Paint empty areas Qt::black
330 if (contentsX()+contentsWidth() < visibleWidth())
331 p.fillRect (
332 QRect (contentsX()+contentsWidth(), clipy, visibleWidth()-contentsX()-contentsWidth(), cliph)
333 & e->rect(),
334 Qt::black);
335 if (contentsY()+contentsHeight() < visibleHeight())
336 p.fillRect (
337 QRect (clipx, contentsY()+contentsHeight(), clipw, visibleHeight()-contentsY()-contentsHeight())
338 & e->rect(),
339 Qt::black);
340
341 p.translate(visibleWidth() / 2.0, visibleHeight() / 2.0);
342 p.setMatrix(m_zoomMatrix, true);
343 p.translate(-m_coloredPixmap.width() / 2.0, -m_coloredPixmap.height() / 2.0);
344 p.drawPixmap(QPoint(clipx-contentsX(), clipy-contentsY()), m_coloredPixmap);
345 p.end();
346
347 if (m_showMouse)
348 paintMouseCursor(viewport(), calcMousePos (m_refreshSwitch));
349}
350
351/**
352 * Draws the mouse cursor according to the current selection of the type of
353 * mouse cursor to draw.
354 */
355void KMagZoomView::paintMouseCursor(QPaintDevice *dev, const QPoint &mousePos)
356{
357 if(!dev)
358 return;
359
360 // painter for the zoom view
361 QPainter pz(dev);
362
363 // How to show the mouse :
364
365 switch(m_showMouse) {
366 case 1:
367 // 1. Square around the pixel
368 pz.setPen(Qt::white);
369#ifdef __GNUC__
370#warning "Port Qt4 pz.setRasterOp(Qt::XorROP);";
371#endif
372 //pz.setRasterOp(Qt::XorROP);
373 pz.drawRect(mousePos.x()-1, mousePos.y()-1, (int)m_zoom+2, (int)m_zoom+2);
374 break;
375
376 case 2:
377 {
378 // 2. Arrow cursor
379 pz.setPen(Qt::black);
380 pz.setBackground(Qt::white);
381
382 QBitmap sCursor = QBitmap::fromData( QSize(16, 16), left_ptr_bits);
383 QBitmap mask = QBitmap::fromData( QSize(16, 16), left_ptrmsk_bits);
384 sCursor.setMask(mask);
385 sCursor = sCursor.transformed(m_zoomMatrix);
386
387 // since hot spot is at 3,1
388 if (m_rotation == 0)
389 pz.drawPixmap(mousePos.x()-(int)(3.0*m_zoom), mousePos.y()-(int)m_zoom, sCursor);
390 else if (m_rotation == 90)
391 pz.drawPixmap(mousePos.x()-(int)(16.0*m_zoom), mousePos.y()-(int)(3.0*m_zoom), sCursor);
392 else if (m_rotation == 180)
393 pz.drawPixmap(mousePos.x()-(int)(13.0*m_zoom), mousePos.y()-(int)(16.0*m_zoom), sCursor);
394 else if (m_rotation == 270)
395 pz.drawPixmap(mousePos.x()-(int)m_zoom, mousePos.y()-(int)(13.0*m_zoom), sCursor);
396 }
397 break;
398
399 case 3:
400 {
401 // 3. Actual cursor
402 // Get the current cursor type
403 QWidget *dummy = KApplication::topLevelAt(QCursor::pos());
404 if(!dummy)
405 break;
406 kDebug() << ">" << dummy->objectName() << ":" << dummy->cursor().shape() << "-";
407 switch(this->cursor().shape()) {
408 case Qt::ArrowCursor :
409 {
410 // 2. Arrow cursor
411 pz.setPen(Qt::black);
412 pz.setBackground(Qt::white);
413
414 QBitmap sCursor = QBitmap::fromData( QSize(16, 16), left_ptr_bits);
415 QBitmap mask = QBitmap::fromData( QSize(16, 16), left_ptrmsk_bits);
416 sCursor.setMask(mask);
417 sCursor = sCursor.transformed(m_zoomMatrix);
418
419 // since hot spot is at 3,1
420 pz.drawPixmap(mousePos.x()-(int)(3.0*m_zoom), mousePos.y()-(int)m_zoom, sCursor);
421 }
422 break;
423 default:
424 QBitmap sCursor = QBitmap::fromData( QSize(32, 32), phand_bits);
425 QBitmap mask = QBitmap::fromData( QSize(32, 32), phandm_bits);
426 sCursor.setMask(mask);
427
428 pz.drawPixmap(mousePos.x(), mousePos.y(), sCursor);
429 break;
430 } // switch(cursor)
431
432
433 }
434 break;
435
436 default:
437 // do not show anything
438 break;
439 } // switch(m_showMouse)
440}
441
442
443QPoint KMagZoomView::calcMousePos(bool updateMousePos)
444{
445 // get position of mouse wrt selRect
446 if(updateMousePos) { // get a new position only if asked
447 m_latestCursorPos = QCursor::pos();
448 m_latestCursorPos -= QPoint(m_selRect.x(), m_selRect.y());
449 }
450
451 // get coordinates of the pixel w.r.t. the zoomed pixmap
452 if (m_rotation == 90)
453 return QPoint ((int)((float)(m_selRect.height()-m_latestCursorPos.y())*m_zoom),
454 (int)((float)m_latestCursorPos.x()*m_zoom));
455 else if (m_rotation == 180)
456 return QPoint ((int)((float)(m_selRect.width()-m_latestCursorPos.x())*m_zoom),
457 (int)((float)(m_selRect.height()-m_latestCursorPos.y())*m_zoom));
458 else if (m_rotation == 270)
459 return QPoint ((int)((float)m_latestCursorPos.y()*m_zoom),
460 (int)((float)(m_selRect.width()-m_latestCursorPos.x())*m_zoom));
461 else
462 return QPoint ((int)((float)m_latestCursorPos.x()*m_zoom),
463 (int)((float)m_latestCursorPos.y()*m_zoom));
464}
465
466
467// MOUSE ACTIONS
468
469/**
470 * Called when mouse is clicked inside the window.
471 *
472 * @param e
473 */
474void KMagZoomView::mousePressEvent(QMouseEvent *e)
475{
476 switch(e->button()) {
477 case Qt::LeftButton :
478 if(m_ctrlKeyPressed) {
479 // check if currently in resize mode
480 // don't do anything if fitToWindow is enabled
481 if ((m_mouseMode != ResizeSelection) && !m_fitToWindow) {
482 // set the mode to ResizeSelection
483 m_mouseMode = ResizeSelection;
484
485 // set mouse cursor to "resize all direction"
486 setCursor(Qt::SizeAllCursor);
487
488 // backup the old position
489 m_oldMousePos.setX(e->globalX());
490 m_oldMousePos.setY(e->globalY());
491
492 // set the cursor position to the bottom-right of the selected region
493 QCursor::setPos(m_selRect.bottomRight());
494
495 // show the selection rectangle
496 m_selRect.show();
497 }
498 else {
499 // ignore this button press.. so it goes to the parent
500 e->ignore();
501 }
502 } else if(m_shiftKeyPressed) {
503 // check if currently in move mode
504 // don't do anything if follow mouse is enabled
505 if ((m_mouseMode != MoveSelection) && !m_followMouse) {
506 m_mouseMode = MoveSelection;
507
508 // set mouse cursor to cross hair
509 setCursor(Qt::CrossCursor);
510
511 // backup the old position
512 m_oldMousePos.setX(e->globalX());
513 m_oldMousePos.setY(e->globalY());
514
515 // set the cursor position to the center of the selected region
516 QCursor::setPos(m_selRect.center());
517
518 // show the selected rectangle
519 m_selRect.show();
520 }
521 else {
522 // ignore this button press.. so it goes to the parent
523 e->ignore();
524 }
525 } else {
526 // check if currently in move mode
527 // don't do anything if follow mouse is enabled
528 if ((m_mouseMode != GrabSelection) && !m_followMouse) {
529 m_mouseMode = GrabSelection;
530
531 // set mouse cursor to hand
532 setCursor(Qt::PointingHandCursor);
533
534 // store the old position
535 m_oldMousePos.setX(e->globalX());
536 m_oldMousePos.setY(e->globalY());
537
538 m_oldCenter = m_selRect.center();
539
540 // show the selected rectangle
541 m_selRect.show();
542 }
543 else {
544 // ignore this button press.. so it goes to the parent
545 e->ignore();
546 }
547 }
548 break;
549
550 case Qt::MidButton :
551 // check if currently in move mode
552 // don't do anything if follow mouse is enabled
553 if ((m_mouseMode != MoveSelection) && !m_followMouse) {
554 m_mouseMode = MoveSelection;
555
556 // set mouse cursor to cross hair
557 setCursor(Qt::CrossCursor);
558
559 // backup the old position
560 m_oldMousePos.setX(e->globalX());
561 m_oldMousePos.setY(e->globalY());
562
563 // set the cursor position to the center of the selected region
564 QCursor::setPos(m_selRect.center());
565
566 // show the selected rectangle
567 m_selRect.show();
568 }
569 else {
570 // ignore this button press.. so it goes to the parent
571 e->ignore();
572 }
573 break;
574 // do nothing
575 default:
576 // ignore this button press.. so it goes to the parent
577 e->ignore();
578 break;
579 }
580}
581
582
583/**
584 * Called when a mouse button is released
585 *
586 * @param e
587 */
588void KMagZoomView::mouseReleaseEvent(QMouseEvent *e)
589{
590 switch(e->button()) {
591 case Qt::LeftButton :
592 case Qt::MidButton :
593 // check if currently in move mode
594 if(m_mouseMode == MoveSelection) {
595 // hide the selection window
596 m_selRect.hide();
597 // set the mouse mode to normal
598 m_mouseMode = Normal;
599
600 // restore the cursor shape
601 setCursor(Qt::ArrowCursor);
602
603 // restore the cursor position
604 QCursor::setPos(m_oldMousePos);
605 } else if(m_mouseMode == ResizeSelection) {
606 // hide the selection window
607 m_selRect.hide();
608 // set the mouse mode to normal
609 m_mouseMode = Normal;
610
611 // restore the cursor shape
612 setCursor(Qt::ArrowCursor);
613
614 // restore the cursor position
615 QCursor::setPos(m_oldMousePos);
616 } else if(m_mouseMode == GrabSelection) {
617 // hide the selection window
618 m_selRect.hide();
619
620 // set the mouse mode to normal
621 m_mouseMode = Normal;
622
623 // restore the cursor shape
624 setCursor(Qt::ArrowCursor);
625 }
626 break;
627
628 case Qt::RightButton :
629 break;
630 case Qt::NoButton :
631 break;
632
633 // do nothing
634 default:
635 ;
636 }
637}
638
639
640/**
641 * Called when mouse is moved inside the window
642 *
643 * @param e
644 */
645void KMagZoomView::mouseMoveEvent(QMouseEvent *e)
646{
647 if(m_mouseMode == ResizeSelection) {
648 // In resize selection mode
649 // set the current mouse position as the bottom, right corner
650 m_selRect.setRight(e->globalX());
651 m_selRect.setBottom(e->globalY());
652 m_selRect.update();
653 grabFrame();
654 } else if(m_mouseMode == MoveSelection) {
655 QPoint newCenter;
656
657 // set new center to be the current mouse position
658 newCenter = e->globalPos();
659
660 // make sure the mouse position is not taking the grab window outside
661 // the display
662 if(newCenter.x() < m_selRect.width()/2) {
663 // set X to the minimum possible X
664 newCenter.setX(m_selRect.width()/2);
665 } else if(newCenter.x() >= QApplication::desktop()->width()-m_selRect.width()/2) {
666 // set X to the maximum possible X
667 newCenter.setX(QApplication::desktop()->width()-m_selRect.width()/2-1);
668 }
669
670 if(newCenter.y() < m_selRect.height()/2) {
671 // set Y to the minimum possible Y
672 newCenter.setY(m_selRect.height()/2);
673 } else if(newCenter.y() >= QApplication::desktop()->height()-m_selRect.height()/2) {
674 // set Y to the maximum possible Y
675 newCenter.setY(QApplication::desktop()->height()-m_selRect.height()/2-1);
676 }
677 // move to the new center
678 m_selRect.moveCenter(newCenter);
679 // update the grab rectangle display
680 m_selRect.update();
681 grabFrame();
682 } else if(m_mouseMode == GrabSelection) {
683 QPoint newPos;
684
685 // get new position
686 newPos = e->globalPos();
687
688 QPoint delta = (newPos - m_oldMousePos)/m_zoom;
689 QPoint newCenter = m_oldCenter-delta;
690
691 // make sure the mouse position is not taking the grab window outside
692 // the display
693 if(newCenter.x() < m_selRect.width()/2) {
694 // set X to the minimum possible X
695 newCenter.setX(m_selRect.width()/2);
696 } else if(newCenter.x() >= QApplication::desktop()->width()-m_selRect.width()/2) {
697 // set X to the maximum possible X
698 newCenter.setX(QApplication::desktop()->width()-m_selRect.width()/2-1);
699 }
700
701 if(newCenter.y() < m_selRect.height()/2) {
702 // set Y to the minimum possible Y
703 newCenter.setY(m_selRect.height()/2);
704 } else if(newCenter.y() >= QApplication::desktop()->height()-m_selRect.height()/2) {
705 // set Y to the maximum possible Y
706 newCenter.setY(QApplication::desktop()->height()-m_selRect.height()/2-1);
707 }
708
709 // move to the new center
710 m_selRect.moveCenter(newCenter);
711 // update the grab rectangle display
712 m_selRect.update();
713 grabFrame();
714 }
715}
716
717void KMagZoomView::keyPressEvent(QKeyEvent *e)
718{
719 int offset = 16;
720 if (e->modifiers() & Qt::ShiftModifier)
721 offset = 1;
722
723 if (e->key() == Qt::Key_Control)
724 m_ctrlKeyPressed = true;
725 else if (e->key() == Qt::Key_Shift)
726 m_shiftKeyPressed = true;
727 else if (e->key() == Qt::Key_Left)
728 {
729 if (e->modifiers() & Qt::ControlModifier)
730 {
731 if (offset >= m_selRect.width())
732 m_selRect.setWidth (1);
733 else
734 m_selRect.setWidth (m_selRect.width()-offset);
735 }
736 else if (contentsX() > 0)
737 {
738 offset = (int)(offset*m_zoom);
739 if (contentsX() > offset)
740 setContentsPos (contentsX()-offset, contentsY());
741 else
742 setContentsPos (0, contentsY());
743 }
744 else if (m_followMouse == false)
745 {
746 if (offset > m_selRect.x())
747 m_selRect.setX (0);
748 else
749 m_selRect.translate (-offset,0);
750 }
751 m_selRect.update();
752 }
753 else if (e->key() == Qt::Key_Right)
754 {
755 if (e->modifiers() & Qt::ControlModifier)
756 {
757 if (m_selRect.right()+offset >= QApplication::desktop()->width())
758 m_selRect.setRight (QApplication::desktop()->width()-1);
759 else
760 m_selRect.setRight (m_selRect.right()+offset);
761 }
762 else if (contentsX() < contentsWidth()-visibleWidth())
763 {
764 offset = (int)(offset*m_zoom);
765 if (contentsX()+offset < contentsWidth()-visibleWidth())
766 setContentsPos (contentsX()+offset, contentsY());
767 else
768 setContentsPos (contentsWidth()-visibleWidth(), contentsY());
769 }
770 else if (m_followMouse == false)
771 {
772 if (m_selRect.right()+offset >= QApplication::desktop()->width())
773 m_selRect.moveTopRight (QPoint (QApplication::desktop()->width()-1, m_selRect.top()));
774 else
775 m_selRect.translate (offset,0);
776 }
777 m_selRect.update();
778 }
779 else if (e->key() == Qt::Key_Up)
780 {
781 if (e->modifiers() & Qt::ControlModifier)
782 {
783 if (offset >= m_selRect.height())
784 m_selRect.setHeight (1);
785 else
786 m_selRect.setHeight (m_selRect.height()-offset);
787 }
788 else if (contentsY() > 0)
789 {
790 offset = (int)(offset*m_zoom);
791 if (contentsY() > offset)
792 setContentsPos (contentsX(), contentsY()-offset);
793 else
794 setContentsPos (contentsX(), 0);
795 }
796 else if (m_followMouse == false)
797 {
798 if (offset > m_selRect.y())
799 m_selRect.setY (0);
800 else
801 m_selRect.translate (0, -offset);
802 }
803 m_selRect.update();
804 }
805 else if (e->key() == Qt::Key_Down)
806 {
807 if (e->modifiers() & Qt::ControlModifier)
808 {
809 if (m_selRect.bottom()+offset >= QApplication::desktop()->height())
810 m_selRect.setBottom (QApplication::desktop()->height()-1);
811 else
812 m_selRect.setBottom (m_selRect.bottom()+offset);
813 }
814 else if (contentsY() < contentsHeight()-visibleHeight())
815 {
816 offset = (int)(offset*m_zoom);
817 if (contentsY()+offset < contentsHeight()-visibleHeight())
818 setContentsPos (contentsX(), contentsY()+offset);
819 else
820 setContentsPos (contentsX(), contentsHeight()-visibleHeight());
821 }
822 else if (m_followMouse == false)
823 {
824 if (m_selRect.bottom()+offset >= QApplication::desktop()->height())
825 m_selRect.moveBottomLeft (QPoint (m_selRect.left(), QApplication::desktop()->height()-1));
826 else
827 m_selRect.translate (0, offset);
828 }
829 m_selRect.update();
830 }
831 else
832 e->ignore();
833}
834
835void KMagZoomView::keyReleaseEvent(QKeyEvent *e)
836{
837 if (e->key() == Qt::Key_Control)
838 m_ctrlKeyPressed = false;
839 else if (e->key() == Qt::Key_Shift)
840 m_shiftKeyPressed = false;
841 else
842 e->ignore();
843}
844
845void KMagZoomView::focusOutEvent(QFocusEvent *e)
846{
847 if(e->lostFocus() == true) {
848 m_ctrlKeyPressed = false;
849 m_shiftKeyPressed = false;
850 }
851}
852
853// SLOTS
854
855/**
856 * This will fit the zoom view to the view window, thus using the maximum
857 * possible space in the window.
858 */
859void KMagZoomView::fitToWindow()
860{
861 unsigned int newWidth, newHeight;
862
863 // this is a temporary solution, cast, maybe newWidth and newHeight should be float
864 if ((m_rotation == 90) || (m_rotation == 270))
865 {
866 newWidth = static_cast<unsigned int>((visibleHeight() + m_zoom - 1) / m_zoom);
867 newHeight = static_cast<unsigned int>((visibleWidth() + m_zoom - 1) / m_zoom);
868 } else {
869 newWidth = static_cast<unsigned int>((visibleWidth() + m_zoom - 1) / m_zoom);
870 newHeight = static_cast<unsigned int>((visibleHeight() + m_zoom - 1) / m_zoom);
871 }
872
873 QPoint currCenter = m_selRect.center();
874
875 m_selRect.setWidth(newWidth);
876 m_selRect.setHeight(newHeight);
877
878 // make sure the selection window does not go outside of the display
879 if(currCenter.x() < m_selRect.width()/2) {
880 // set X to the minimum possible X
881 currCenter.setX(m_selRect.width()/2);
882 } else if(currCenter.x() >= QApplication::desktop()->width()-m_selRect.width()/2) {
883 // set X to the maximum possible X
884 currCenter.setX(QApplication::desktop()->width()-m_selRect.width()/2-1);
885 }
886
887 if(currCenter.y() < m_selRect.height()/2) {
888 // set Y to the minimum possible Y
889 currCenter.setY(m_selRect.height()/2);
890 } else if(currCenter.y() >= QApplication::desktop()->height()-m_selRect.height()/2) {
891 // set Y to the maximum possible Y
892 currCenter.setY(QApplication::desktop()->height()-m_selRect.height()/2-1);
893 }
894
895 m_selRect.moveCenter(currCenter);
896 // update the grab rectangle display
897 m_selRect.update();
898// m_fitToWindow = true;
899 viewport()->update();
900}
901
902void KMagZoomView::setFitToWindow(bool fit)
903{
904 m_fitToWindow = fit;
905 if (fit)
906 fitToWindow();
907}
908
909
910/**
911 * Grabs frame from X
912 */
913void KMagZoomView::grabFrame()
914{
915 // check refresh status
916 if (!m_refreshSwitch)
917 return;
918
919 // check if follow-mouse or follow-focus are enabled
920 if((m_followMouse || m_followFocus) && (m_mouseMode != ResizeSelection)) {
921 // center-position of the grab-area
922 QPoint newCenter;
923
924 if(m_followMouse) {
925 // set new center to be the current mouse position
926 newCenter = QCursor::pos();
927#ifdef QAccessibilityClient_FOUND
928 } else if(m_followFocus) {
929 // set the new center to the current keyboard cursor position
930 newCenter = m_oldFocus;
931 if(m_followBoth) {
932 m_followFocus=false;
933 m_followMouse=true;
934 }
935#endif
936 }
937
938 // make sure the mouse position is not taking the grab window outside
939 // the display
940 if(newCenter.x() < m_selRect.width()/2) {
941 // set X to the minimum possible X
942 newCenter.setX(m_selRect.width()/2);
943 } else if(newCenter.x() >= QApplication::desktop()->width()-m_selRect.width()/2) {
944 // set X to the maximum possible X
945 newCenter.setX(QApplication::desktop()->width()-m_selRect.width()/2-1);
946 }
947
948 if(newCenter.y() < m_selRect.height()/2) {
949 // set Y to the minimum possible Y
950 newCenter.setY(m_selRect.height()/2);
951 } else if(newCenter.y() >= QApplication::desktop()->height()-m_selRect.height()/2) {
952 // set Y to the maximum possible Y
953 newCenter.setY(QApplication::desktop()->height()-m_selRect.height()/2-1);
954 }
955 // move to the new center
956 m_selRect.moveCenter(newCenter);
957
958 // update the grab rectangle display
959 m_selRect.update();
960 }
961
962 // define a normalized rectangle
963 QRect selRect = m_selRect.normalized();
964
965 // grab screenshot from the screen and put it in the pixmap
966 m_coloredPixmap = QPixmap::grabWindow(QApplication::desktop()->winId(), selRect.x(), selRect.y(),
967 selRect.width(), selRect.height());
968
969 // colorize the grabbed pixmap
970 if (m_colormode != 0)
971 m_coloredPixmap = QPixmap::fromImage(ColorSim::recolor(m_coloredPixmap.toImage(), m_colormode));
972
973 QRect r = m_zoomMatrix.mapRect(m_coloredPixmap.rect());
974 // call repaint to display the newly grabbed image
975 horizontalScrollBar()->setPageStep(r.width());
976 verticalScrollBar()->setPageStep(r.height());
977 viewport()->update();
978}
979
980
981/**
982 * Updates the mouse cursor in the zoom view.
983 */
984void KMagZoomView::updateMouseView()
985{
986 if (m_fps < 8)
987 viewport()->update();
988}
989
990/**
991 * Toggles the state of refreshing.
992 */
993void KMagZoomView::toggleRefresh()
994{
995 if(m_refreshSwitch) {
996 m_refreshSwitch = false;
997 m_grabTimer.stop();
998 m_mouseViewTimer.stop();
999 } else {
1000 m_refreshSwitch = true;
1001 m_grabTimer.start(1000/m_fps);
1002 m_mouseViewTimer.start(40);
1003 }
1004}
1005
1006/**
1007 * This function sets the zoom value to be used.
1008 */
1009void KMagZoomView::setZoom(float zoom)
1010{
1011 // use this zoom
1012 m_zoom = zoom;
1013
1014 // update selection window size when zooming in if necessary
1015 if (m_fitToWindow)
1016 fitToWindow();
1017
1018 // recompute the zoom matrix
1019 setupMatrix();
1020
1021 viewport()->update();
1022}
1023
1024/**
1025 * This function sets the rotation value to be used.
1026 */
1027void KMagZoomView::setRotation(int rotation)
1028{
1029 // use this rotation
1030 m_rotation = rotation;
1031
1032 // update selection window size if necessary
1033 if (m_fitToWindow)
1034 fitToWindow();
1035
1036 // recompute the zoom matrix
1037 setupMatrix();
1038
1039 viewport()->update();
1040}
1041
1042/**
1043 * Set a new color simulation mode.
1044 */
1045void KMagZoomView::setColorMode(int mode)
1046{
1047 if (m_colormode != mode) {
1048 m_colormode = mode;
1049 viewport()->update();
1050 }
1051}
1052
1053/**
1054 * Set a new refresh rate.
1055 */
1056void KMagZoomView::setRefreshRate(float fps)
1057{
1058 if(fps < 0.1)
1059 return;
1060 m_fps = static_cast<unsigned int>(fps);
1061
1062 if(m_grabTimer.isActive())
1063 m_grabTimer.start(static_cast<int>(1000.0/m_fps));
1064}
1065
1066void KMagZoomView::showSelRect(bool show)
1067{
1068 m_selRect.alwaysVisible(show);
1069 if(show) {
1070 m_selRect.show();
1071 } else if(m_mouseMode == Normal) {
1072 m_selRect.hide();
1073 }
1074}
1075
1076/**
1077 * Sets the selection rectangle to the given position.
1078 */
1079void KMagZoomView::setSelRectPos(const QRect & rect)
1080{
1081 m_selRect.setRect(rect.x(), rect.y(), rect.width(), rect.height());
1082 m_selRect.update();
1083 grabFrame();
1084}
1085
1086bool KMagZoomView::showMouse(unsigned int type)
1087{
1088 if(int(type) > m_showMouseTypes.count()-1)
1089 return (false);
1090 else
1091 m_showMouse = type;
1092
1093 return(true);
1094}
1095
1096unsigned int KMagZoomView::getShowMouseType() const
1097{
1098 return (m_showMouse);
1099}
1100
1101QStringList KMagZoomView::getShowMouseStringList() const
1102{
1103 return (m_showMouseTypes);
1104}
1105
1106
1107/**
1108 * Returns the image which is being displayed. It's again drawn by adding
1109 * the mouse cursor if needed.
1110 */
1111QImage KMagZoomView::getImage()
1112{
1113 QImage image = m_coloredPixmap.transformed(m_zoomMatrix).toImage();
1114
1115 // show the pixel under mouse cursor
1116 if(m_showMouse && !image.isNull()) {
1117 // paint the mouse cursor w/o updating to a newer position
1118 paintMouseCursor(&image, calcMousePos(false));
1119 }
1120 return(image);
1121}
1122