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 mouse input. 0030 // 0031 0032 #define DEBUG_KP_TOOL 0 0033 0034 #include "tools/kpTool.h" 0035 #include "kpToolPrivate.h" 0036 0037 #include "kpLogCategories.h" 0038 0039 #include "environments/tools/kpToolEnvironment.h" 0040 #include "views/kpView.h" 0041 #include "views/manager/kpViewManager.h" 0042 0043 #include <QMouseEvent> 0044 #include <QApplication> 0045 #include <QClipboard> 0046 0047 //--------------------------------------------------------------------- 0048 0049 // HITODO: If you press a mouse button and move it out of the view _really_ fast 0050 // and let go of the mouse button outside of the view, a mouseRelease 0051 // event will not be generated, so the tool will still be in drawing mode 0052 // (this is especially noticeable with the spraycan). 0053 // 0054 // When you move the mouse back into the view, it will still continue 0055 // continue drawing even though no mouse button is held down. 0056 // 0057 // It is somewhat hard to reproduce so the best way is to position the 0058 // mouse close to an edge of the view. If you do it right, no mouseMoveEvent 0059 // is generated at _all_, until you move it back into the view. 0060 void kpTool::mousePressEvent (QMouseEvent *e) 0061 { 0062 #if DEBUG_KP_TOOL && 1 0063 qCDebug(kpLogTools) << "kpTool::mousePressEvent pos=" << e->pos () 0064 << " button=" << (int) e->button () 0065 << " stateAfter: buttons=" << (int *) (int) e->buttons () 0066 << " modifiers=" << (int *) (int) e->modifiers () 0067 << " beganDraw=" << d->beganDraw << endl; 0068 #endif 0069 0070 if (e->button () == Qt::MiddleButton) 0071 { 0072 const QString text = QApplication::clipboard ()->text (QClipboard::Selection); 0073 #if DEBUG_KP_TOOL && 1 0074 qCDebug(kpLogTools) << "\tMMB pasteText='" << text << "'"; 0075 #endif 0076 if (!text.isEmpty ()) 0077 { 0078 if (hasBegunShape ()) 0079 { 0080 #if DEBUG_KP_TOOL && 1 0081 qCDebug(kpLogTools) << "\t\thasBegunShape - end"; 0082 #endif 0083 endShapeInternal (d->currentPoint, normalizedRect ()); 0084 } 0085 0086 if (viewUnderCursor ()) 0087 { 0088 d->environ->pasteTextAt (text, 0089 viewUnderCursor ()->transformViewToDoc (e->pos ()), 0090 true/*adjust topLeft so that cursor isn't 0091 on top of resize handle*/); 0092 } 0093 0094 return; 0095 } 0096 } 0097 0098 int mb = mouseButton (e->buttons ()); 0099 #if DEBUG_KP_TOOL && 1 0100 qCDebug(kpLogTools) << "\tmb=" << mb << " d->beganDraw=" << d->beganDraw; 0101 #endif 0102 0103 if (mb == -1 && !d->beganDraw) 0104 { 0105 // Ignore mouse press. 0106 return; 0107 } 0108 0109 if (d->beganDraw) 0110 { 0111 if (mb == -1 || mb != d->mouseButton) 0112 { 0113 #if DEBUG_KP_TOOL && 1 0114 qCDebug(kpLogTools) << "\tCancelling operation as " << mb << " == -1 or != " << d->mouseButton; 0115 #endif 0116 0117 kpView *view = viewUnderStartPoint (); 0118 Q_ASSERT (view); 0119 0120 // if we get a mousePressEvent when we're drawing, then the other 0121 // mouse button must have been pressed 0122 d->currentPoint = view->transformViewToDoc (e->pos ()); 0123 d->currentViewPoint = e->pos (); 0124 cancelShapeInternal (); 0125 } 0126 0127 return; 0128 } 0129 0130 kpView *view = viewUnderCursor (); 0131 Q_ASSERT (view); 0132 0133 #if DEBUG_KP_TOOL && 1 0134 if (view) { 0135 qCDebug(kpLogTools) << "\tview=" << view->objectName (); 0136 } 0137 #endif 0138 0139 // let user know what mouse button is being used for entire draw 0140 d->mouseButton = mouseButton (e->buttons ()); 0141 d->shiftPressed = (e->modifiers () & Qt::ShiftModifier); 0142 d->controlPressed = (e->modifiers () & Qt::ControlModifier); 0143 d->altPressed = (e->modifiers () & Qt::AltModifier); 0144 d->startPoint = d->currentPoint = view->transformViewToDoc (e->pos ()); 0145 d->currentViewPoint = e->pos (); 0146 d->viewUnderStartPoint = view; 0147 d->lastPoint = QPoint (-1, -1); 0148 0149 #if DEBUG_KP_TOOL && 1 0150 qCDebug(kpLogTools) << "\tBeginning draw @ " << d->currentPoint; 0151 #endif 0152 0153 beginDrawInternal (); 0154 0155 draw (d->currentPoint, d->lastPoint, QRect (d->currentPoint, d->currentPoint)); 0156 d->lastPoint = d->currentPoint; 0157 } 0158 0159 //--------------------------------------------------------------------- 0160 0161 // OPT: If the mouse is moving in terms of view pixels, it still might 0162 // not be moving in terms of document pixels (when zoomed in). 0163 // 0164 // So we should detect this and not call draw() or hover(). 0165 // 0166 // However, kpToolSelection needs hover() to be called on all view 0167 // point changes, not just document points, since the selection resize 0168 // handles may be smaller than document points. Also, I wonder if 0169 // selections' accidental drag detection feature cares? 0170 void kpTool::mouseMoveEvent (QMouseEvent *e) 0171 { 0172 #if DEBUG_KP_TOOL && 0 0173 qCDebug(kpLogTools) << "kpTool::mouseMoveEvent pos=" << e->pos () 0174 << " stateAfter: buttons=" << (int *) (int) e->buttons () 0175 << " modifiers=" << (int *) (int) e->modifiers (); 0176 kpView *v0 = viewUnderCursor (), 0177 *v1 = viewManager ()->viewUnderCursor (true/*use Qt*/), 0178 *v2 = viewUnderStartPoint (); 0179 qCDebug(kpLogTools) << "\tviewUnderCursor=" << (v0 ? v0->objectName () : "(none)") 0180 << " viewUnderCursorQt=" << (v1 ? v1->objectName () : "(none)") 0181 << " viewUnderStartPoint=" << (v2 ? v2->objectName () : "(none)"); 0182 qCDebug(kpLogTools) << "\tfocusWidget=" << kapp->focusWidget (); 0183 qCDebug(kpLogTools) << "\tbeganDraw=" << d->beganDraw; 0184 #endif 0185 0186 d->shiftPressed = (e->modifiers () & Qt::ShiftModifier); 0187 d->controlPressed = (e->modifiers () & Qt::ControlModifier); 0188 d->altPressed = (e->modifiers () & Qt::AltModifier); 0189 0190 if (d->beganDraw) 0191 { 0192 kpView *view = viewUnderStartPoint (); 0193 Q_ASSERT (view); 0194 0195 d->currentPoint = view->transformViewToDoc (e->pos ()); 0196 d->currentViewPoint = e->pos (); 0197 0198 #if DEBUG_KP_TOOL && 0 0199 qCDebug(kpLogTools) << "\tDraw!"; 0200 #endif 0201 0202 bool dragScrolled = false; 0203 movedAndAboutToDraw (d->currentPoint, d->lastPoint, view->zoomLevelX (), &dragScrolled); 0204 0205 if (dragScrolled) 0206 { 0207 d->currentPoint = calculateCurrentPoint (); 0208 d->currentViewPoint = calculateCurrentPoint (false/*view point*/); 0209 0210 // Scrollview has scrolled contents and has scheduled an update 0211 // for the newly exposed region. If draw() schedules an update 0212 // as well (instead of immediately updating), the scrollview's 0213 // update will be executed first and it'll only update part of 0214 // the screen resulting in ugly tearing of the viewManager's 0215 // tempImage. 0216 viewManager ()->setFastUpdates (); 0217 } 0218 0219 drawInternal (); 0220 0221 if (dragScrolled) { 0222 viewManager ()->restoreFastUpdates (); 0223 } 0224 0225 d->lastPoint = d->currentPoint; 0226 } 0227 else 0228 { 0229 kpView *view = viewUnderCursor (); 0230 if (!view) // possible if cancelShape()'ed but still holding down initial mousebtn 0231 { 0232 d->currentPoint = KP_INVALID_POINT; 0233 d->currentViewPoint = KP_INVALID_POINT; 0234 return; 0235 } 0236 0237 d->currentPoint = view->transformViewToDoc (e->pos ()); 0238 d->currentViewPoint = e->pos (); 0239 hover (d->currentPoint); 0240 } 0241 } 0242 0243 //--------------------------------------------------------------------- 0244 0245 void kpTool::mouseReleaseEvent (QMouseEvent *e) 0246 { 0247 #if DEBUG_KP_TOOL && 1 0248 qCDebug(kpLogTools) << "kpTool::mouseReleaseEvent pos=" << e->pos () 0249 << " button=" << (int) e->button () 0250 << " stateAfter: buttons=" << (int *) (int) e->buttons () 0251 << " modifiers=" << (int *) (int) e->modifiers () 0252 << " beganDraw=" << d->beganDraw; 0253 #endif 0254 0255 // Have _not_ already cancelShape()'ed by pressing other mouse button? 0256 // (e.g. you can cancel a line dragged out with the LMB, by pressing 0257 // the RMB) 0258 if (d->beganDraw) 0259 { 0260 kpView *view = viewUnderStartPoint (); 0261 Q_ASSERT (view); 0262 0263 d->currentPoint = view->transformViewToDoc (e->pos ()); 0264 d->currentViewPoint = e->pos (); 0265 0266 drawInternal (); 0267 0268 endDrawInternal (d->currentPoint, normalizedRect ()); 0269 } 0270 0271 if ((e->buttons () & Qt::MouseButtonMask) == 0) 0272 { 0273 releasedAllButtons (); 0274 } 0275 } 0276 0277 //--------------------------------------------------------------------- 0278 0279 void kpTool::wheelEvent (QWheelEvent *e) 0280 { 0281 #if DEBUG_KP_TOOL 0282 qCDebug(kpLogTools) << "kpTool::wheelEvent() modifiers=" << (int *) (int) e->modifiers () 0283 << " hasBegunDraw=" << hasBegunDraw () 0284 << " delta=" << e->delta (); 0285 #endif 0286 0287 e->ignore (); 0288 0289 // If CTRL not pressed, bye. 0290 if ((e->modifiers () & Qt::ControlModifier) == 0) 0291 { 0292 #if DEBUG_KP_TOOL 0293 qCDebug(kpLogTools) << "\tno CTRL -> bye"; 0294 #endif 0295 return; 0296 } 0297 0298 // If drawing, bye; don't care if a shape in progress though. 0299 if (hasBegunDraw ()) 0300 { 0301 #if DEBUG_KP_TOOL 0302 qCDebug(kpLogTools) << "\thasBegunDraw() -> bye"; 0303 #endif 0304 return; 0305 } 0306 0307 0308 // Zoom in/out depending on wheel direction. 0309 0310 // Moved wheel away from user? 0311 if (e->angleDelta().y() > 0) 0312 { 0313 #if DEBUG_KP_TOOL 0314 qCDebug(kpLogTools) << "\tzoom in"; 0315 #endif 0316 d->environ->zoomIn (true/*center under cursor*/); 0317 e->accept (); 0318 } 0319 // Moved wheel towards user? 0320 else if (e->angleDelta().y() < 0) 0321 { 0322 #if DEBUG_KP_TOOL 0323 qCDebug(kpLogTools) << "\tzoom out"; 0324 #endif 0325 #if 1 0326 d->environ->zoomOut (true/*center under cursor - make zoom in/out 0327 stay under same doc pos*/); 0328 #else 0329 d->environ->zoomOut (false/*don't center under cursor - as is 0330 confusing behaviour when zooming 0331 out*/); 0332 #endif 0333 e->accept (); 0334 } 0335 } 0336 0337 //---------------------------------------------------------------------