File indexing completed on 2024-04-28 04:20:27

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 //
0029 // Tool reaction to view keyboard input.
0030 //
0031 
0032 
0033 #define DEBUG_KP_TOOL 0
0034 
0035 
0036 // TODO: reduce number of includes
0037 #include "tools/kpTool.h"
0038 #include "kpToolPrivate.h"
0039 
0040 #include <climits>
0041 
0042 #include <QApplication>
0043 #include <QCursor>
0044 #include <QEvent>
0045 #include <QKeyEvent>
0046 
0047 #include "kpLogCategories.h"
0048 #include <KLocalizedString>
0049 
0050 #include "imagelib/kpColor.h"
0051 #include "widgets/toolbars/kpColorToolBar.h"
0052 #include "kpDefs.h"
0053 #include "pixmapfx/kpPixmapFX.h"
0054 #include "environments/tools/kpToolEnvironment.h"
0055 #include "widgets/toolbars/kpToolToolBar.h"
0056 #include "views/kpView.h"
0057 #include "views/manager/kpViewManager.h"
0058 
0059 //---------------------------------------------------------------------
0060 
0061 void kpTool::seeIfAndHandleModifierKey (QKeyEvent *e)
0062 {
0063     switch (e->key ())
0064     {
0065     case 0:
0066     case Qt::Key_unknown:
0067     #if DEBUG_KP_TOOL && 0
0068         qCDebug(kpLogTools) << "kpTool::seeIfAndHandleModifierKey() picked up unknown key!";
0069     #endif
0070         // HACK: around Qt bug: if you hold a modifier before you start the
0071         //                      program and then release it over the view,
0072         //                      Qt reports it as the release of an unknown key
0073         //       Qt4 update: I don't think this happens anymore...
0074         // --- fall thru and update all modifiers ---
0075 
0076     case Qt::Key_Alt:
0077     case Qt::Key_Shift:
0078     case Qt::Key_Control:
0079     #if DEBUG_KP_TOOL && 0
0080         qCDebug(kpLogTools) << "kpTool::setIfAndHandleModifierKey() accepting";
0081     #endif
0082         keyUpdateModifierState (e);
0083 
0084         e->accept ();
0085         break;
0086     }
0087 }
0088 
0089 //---------------------------------------------------------------------
0090 
0091 // Returns in <dx> and <dy> the direction the arrow key "e->key()" is
0092 // pointing in or (0,0) if it's not a recognised arrow key.
0093 void kpTool::arrowKeyPressDirection (const QKeyEvent *e, int *dx, int *dy)
0094 {
0095     int dxLocal = 0, dyLocal = 0;
0096 
0097     switch (e->key ())
0098     {
0099     case Qt::Key_Home:      dxLocal = -1;   dyLocal = -1;   break;
0100     case Qt::Key_Up:                        dyLocal = -1;   break;
0101     case Qt::Key_PageUp:    dxLocal = +1;   dyLocal = -1;   break;
0102 
0103     case Qt::Key_Left:      dxLocal = -1;                   break;
0104     case Qt::Key_Right:     dxLocal = +1;                   break;
0105 
0106     case Qt::Key_End:       dxLocal = -1;   dyLocal = +1;   break;
0107     case Qt::Key_Down:                      dyLocal = +1;   break;
0108     case Qt::Key_PageDown:  dxLocal = +1;   dyLocal = +1;   break;
0109     }
0110 
0111     if (dx) {
0112         *dx = dxLocal;
0113     }
0114     if (dy) {
0115         *dy = dyLocal;
0116     }
0117 }
0118 
0119 //---------------------------------------------------------------------
0120 
0121 void kpTool::seeIfAndHandleArrowKeyPress (QKeyEvent *e)
0122 {
0123     int dx, dy;
0124 
0125     arrowKeyPressDirection (e, &dx, &dy);
0126     if (dx == 0 && dy == 0) {
0127         return;
0128     }
0129 
0130 
0131     kpView * const view = viewUnderCursor ();
0132     if (!view) {
0133         return;
0134     }
0135 
0136 
0137     const QPoint oldPoint = view->mapFromGlobal (QCursor::pos ());
0138 #if DEBUG_KP_TOOL && 0
0139     qCDebug(kpLogTools) << "\toldPoint=" << oldPoint
0140                 << " dx=" << dx << " dy=" << dy << endl;
0141 #endif
0142 
0143 
0144     const int viewIncX = (dx ? qMax (1, view->zoomLevelX () / 100) * dx : 0);
0145     const int viewIncY = (dy ? qMax (1, view->zoomLevelY () / 100) * dy : 0);
0146 
0147     int newViewX = oldPoint.x () + viewIncX;
0148     int newViewY = oldPoint.y () + viewIncY;
0149 
0150 
0151 #if DEBUG_KP_TOOL && 0
0152     qCDebug(kpLogTools) << "\tnewPoint=" << QPoint (newViewX, newViewY);
0153 #endif
0154 
0155     // Make sure we really moved at least one doc point (needed due to
0156     // rounding error).
0157 
0158     if (view->transformViewToDoc (QPoint (newViewX, newViewY)) ==
0159         view->transformViewToDoc (oldPoint))
0160     {
0161         newViewX += viewIncX;
0162         newViewY += viewIncY;
0163 
0164     #if DEBUG_KP_TOOL && 0
0165         qCDebug(kpLogTools) << "\tneed adjust for doc - newPoint="
0166                     << QPoint (newViewX, newViewY) << endl;
0167     #endif
0168     }
0169 
0170 
0171     // TODO: visible width/height (e.g. with scrollbars)
0172     const int x = qMin (qMax (newViewX, 0), view->width () - 1);
0173     const int y = qMin (qMax (newViewY, 0), view->height () - 1);
0174 
0175     // QCursor::setPos conveniently causes mouseMoveEvents
0176     QCursor::setPos (view->mapToGlobal (QPoint (x, y)));
0177     e->accept ();
0178 }
0179 
0180 //---------------------------------------------------------------------
0181 
0182 bool kpTool::isDrawKey (int key)
0183 {
0184     return (key == Qt::Key_Enter ||
0185             key == Qt::Key_Return ||
0186             key == Qt::Key_Insert ||
0187             key == Qt::Key_Clear/*Numpad 5 Key*/ ||
0188             key == Qt::Key_L);
0189 }
0190 
0191 //---------------------------------------------------------------------
0192 
0193 void kpTool::seeIfAndHandleBeginDrawKeyPress (QKeyEvent *e)
0194 {
0195     if (e->isAutoRepeat ()) {
0196         return;
0197     }
0198 
0199     if (!isDrawKey (e->key ())) {
0200         return;
0201     }
0202 
0203 #if DEBUG_KP_TOOL && 0
0204     qCDebug(kpLogTools) << "kpTool::seeIfAndHandleBeginDrawKeyPress() accept";
0205 #endif
0206 
0207 
0208     // TODO: wrong for dragging lines outside of view (for e.g.)
0209     kpView * const view = viewUnderCursor ();
0210     if (!view) {
0211         return;
0212     }
0213 
0214 
0215     // TODO: what about the modifiers?
0216     QMouseEvent me (QEvent::MouseButtonPress,
0217                     view->mapFromGlobal (QCursor::pos ()),
0218                     Qt::LeftButton,
0219                     Qt::LeftButton/*button state after event*/,
0220                     Qt::NoModifier);
0221     mousePressEvent (&me);
0222     e->accept ();
0223 }
0224 
0225 void kpTool::seeIfAndHandleEndDrawKeyPress (QKeyEvent *e)
0226 {
0227 #if DEBUG_KP_TOOL && 0
0228     qCDebug(kpLogTools) << "kpTool::setIfAndHandleEndDrawKeyPress() key=" << e->key ()
0229                << " isAutoRepeat=" << e->isAutoRepeat ()
0230                << " isDrawKey=" << isDrawKey (e->key ())
0231                << " view=" << viewUnderCursor ()
0232                << endl;
0233 #endif
0234 
0235     if (e->isAutoRepeat ()) {
0236         return;
0237     }
0238 
0239     if (!isDrawKey (e->key ())) {
0240         return;
0241     }
0242 
0243 #if DEBUG_KP_TOOL && 0
0244     qCDebug(kpLogTools) << "kpTool::seeIfAndHandleEndDrawKeyPress() accept";
0245 #endif
0246 
0247 
0248     kpView * const view = viewUnderCursor ();
0249     if (!view) {
0250         return;
0251     }
0252 
0253 
0254     // TODO: what about the modifiers?
0255     QMouseEvent me (QEvent::MouseButtonRelease,
0256                     view->mapFromGlobal (QCursor::pos ()),
0257                     Qt::LeftButton,
0258                     Qt::NoButton/*button state after event*/,
0259                     Qt::NoModifier);
0260     mouseReleaseEvent (&me);
0261 
0262     e->accept ();
0263 }
0264 
0265 //---------------------------------------------------------------------
0266 
0267 void kpTool::keyPressEvent (QKeyEvent *e)
0268 {
0269 #if DEBUG_KP_TOOL && 0
0270     qCDebug(kpLogTools) << "kpTool::keyPressEvent() key=" << (int *) e->key ()
0271               << " stateAfter: modifiers=" << (int *) (int) e->modifiers ()
0272               << " isAutoRep=" << e->isAutoRepeat ();
0273 #endif
0274 
0275     e->ignore ();
0276 
0277 
0278     seeIfAndHandleModifierKey (e);
0279     if (e->isAccepted ()) {
0280         return;
0281     }
0282 
0283     seeIfAndHandleArrowKeyPress (e);
0284     if (e->isAccepted ()) {
0285         return;
0286     }
0287 
0288     seeIfAndHandleBeginDrawKeyPress (e);
0289     if (e->isAccepted ()) {
0290         return;
0291     }
0292 
0293 
0294     switch (e->key ())
0295     {
0296     case Qt::Key_Delete:
0297         d->environ->deleteSelection ();
0298         break;
0299 
0300     case Qt::Key_Escape:
0301         if (hasBegunDraw ())
0302         {
0303             cancelShapeInternal ();
0304             e->accept ();
0305         }
0306 
0307         break;
0308     }
0309 }
0310 
0311 //---------------------------------------------------------------------
0312 
0313 void kpTool::keyReleaseEvent (QKeyEvent *e)
0314 {
0315 #if DEBUG_KP_TOOL && 0
0316     qCDebug(kpLogTools) << "kpTool::keyReleaseEvent() key=" << (int *) e->key ()
0317               << " stateAfter: modifiers=" << (int *) (int) e->modifiers ()
0318               << " isAutoRep=" << e->isAutoRepeat ();
0319 #endif
0320 
0321     e->ignore ();
0322 
0323     seeIfAndHandleModifierKey (e);
0324     if (e->isAccepted ()) {
0325         return;
0326     }
0327 
0328     seeIfAndHandleEndDrawKeyPress (e);
0329     if (e->isAccepted ()) {
0330         return;
0331     }
0332 }
0333 
0334 //---------------------------------------------------------------------
0335 
0336 // private
0337 void kpTool::keyUpdateModifierState (QKeyEvent *e)
0338 {
0339 #if DEBUG_KP_TOOL && 0
0340     qCDebug(kpLogTools) << "kpTool::keyUpdateModifierState() e->key=" << (int *) e->key ();
0341     qCDebug(kpLogTools) << "\tshift="
0342                << (e->modifiers () & Qt::ShiftModifier)
0343                << " control="
0344                << (e->modifiers () & Qt::ControlModifier)
0345                << " alt="
0346                << (e->modifiers () & Qt::AltModifier)
0347                << endl;
0348 #endif
0349     if (e->key () & (Qt::Key_Alt | Qt::Key_Shift | Qt::Key_Control))
0350     {
0351     #if DEBUG_KP_TOOL && 0
0352         qCDebug(kpLogTools) << "\t\tmodifier changed - use e's claims";
0353     #endif
0354         setShiftPressed (e->modifiers () & Qt::ShiftModifier);
0355         setControlPressed (e->modifiers () & Qt::ControlModifier);
0356         setAltPressed (e->modifiers () & Qt::AltModifier);
0357     }
0358     // See seeIfAndHandleModifierKey() for why this code path exists.
0359     else
0360     {
0361     #if DEBUG_KP_TOOL && 0
0362         qCDebug(kpLogTools) << "\t\tmodifiers not changed - figure out the truth";
0363     #endif
0364         const Qt::KeyboardModifiers keyState = QApplication::keyboardModifiers ();
0365 
0366         setShiftPressed (keyState & Qt::ShiftModifier);
0367         setControlPressed (keyState & Qt::ControlModifier);
0368         setAltPressed (keyState & Qt::AltModifier);
0369     }
0370 }
0371 
0372 //---------------------------------------------------------------------
0373 
0374 void kpTool::notifyModifierStateChanged ()
0375 {
0376     if (careAboutModifierState ())
0377     {
0378         if (d->beganDraw) {
0379             draw (d->currentPoint, d->lastPoint, normalizedRect ());
0380         }
0381         else
0382         {
0383             d->currentPoint = calculateCurrentPoint ();
0384             d->currentViewPoint = calculateCurrentPoint (false/*view point*/);
0385             hover (d->currentPoint);
0386         }
0387     }
0388 }
0389 
0390 //---------------------------------------------------------------------
0391 
0392 void kpTool::setShiftPressed (bool pressed)
0393 {
0394     if (pressed == d->shiftPressed) {
0395         return;
0396     }
0397 
0398     d->shiftPressed = pressed;
0399 
0400     notifyModifierStateChanged ();
0401 }
0402 
0403 //---------------------------------------------------------------------
0404 
0405 void kpTool::setControlPressed (bool pressed)
0406 {
0407     if (pressed == d->controlPressed) {
0408         return;
0409     }
0410 
0411     d->controlPressed = pressed;
0412 
0413     notifyModifierStateChanged ();
0414 }
0415 
0416 //---------------------------------------------------------------------
0417 
0418 void kpTool::setAltPressed (bool pressed)
0419 {
0420     if (pressed == d->altPressed) {
0421         return;
0422     }
0423 
0424     d->altPressed = pressed;
0425 
0426     notifyModifierStateChanged ();
0427 }
0428 
0429 //---------------------------------------------------------------------