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 //---------------------------------------------------------------------