File indexing completed on 2024-04-28 04:20:26
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 #ifndef KP_TOOL_H 0030 #define KP_TOOL_H 0031 0032 0033 #include <QObject> 0034 #include <QPoint> 0035 #include <QRect> 0036 #include <QSize> 0037 #include <QString> 0038 0039 #include "kpDefs.h" 0040 #ifdef Q_OS_WIN 0041 #include <stdlib.h> 0042 #undef environ // macro on win32 0043 #endif 0044 0045 0046 class QFocusEvent; 0047 class QInputMethodEvent; 0048 class QKeyEvent; 0049 class QMouseEvent; 0050 class QImage; 0051 class QWheelEvent; 0052 0053 class KToggleAction; 0054 0055 class kpColor; 0056 class kpCommandHistory; 0057 class kpDocument; 0058 class kpView; 0059 class kpViewManager; 0060 class kpToolEnvironment; 0061 class kpToolToolBar; 0062 0063 0064 struct kpToolPrivate; 0065 0066 // Base class for all tools. 0067 // REFACTOR: rearrange method order to make sense and reflect kpTool_*.cpp split. 0068 class kpTool : public QObject 0069 { 0070 Q_OBJECT 0071 0072 public: 0073 // <text> = user-visible name of the tool e.g. "Color Picker" 0074 // <description> = user-visible description used for tooltips 0075 // e.g. "Lets you select a color from the image" 0076 // <key> = optional shortcut key for switching to the tool, or 0 otherwise 0077 // e.g. Qt::Key_C 0078 // <name> = internal QObject name (not user-visible) e.g. "tool_color_picker" 0079 // used for fetching the icon(), the name of the action() and 0080 // debug printing. 0081 kpTool (const QString &text, const QString &description, 0082 int key, 0083 kpToolEnvironment *environ, 0084 QObject *parent, const QString &name); 0085 ~kpTool () override; 0086 0087 KToggleAction *action () const; 0088 0089 QString text () const; 0090 0091 // Given a single <key>, returns a shortcut with <key> 0092 // (disabled when the user is editing text) and as an alternate, 0093 // <some modifiers>+<key>. 0094 static QList<QKeySequence> shortcutForKey (int key); 0095 0096 static QRect neededRect (const QRect &rect, int lineWidth); 0097 static QImage neededPixmap (const QImage &image, const QRect &boundingRect); 0098 0099 bool hasCurrentPoint () const; 0100 // Returns the position of the cursor relative to the topleft point of 0101 // the current view (viewUnderStartPoint() or viewUnderCursor() otherwise). 0102 // 0103 // If neither viewUnderStartPoint() nor viewUnderCursor() 0104 // (i.e. !hasCurrentPoint()), then it returns KP_INVALID_POINT. 0105 // 0106 // If <zoomToDoc> is set (default), then it returns the position in the 0107 // document. This theoretically == m_currentPoint (when m_currentPoint 0108 // is defined) but I wouldn't bet on it. This function is useful when 0109 // m_currentPoint isn't necessarily defined (outside of beginDraw(),draw() 0110 // and hover()). 0111 // 0112 // If <zoomToDoc> is not set, then it returns an unzoomed view coordinate. 0113 // 0114 // Keep in mind that if viewUnderStartPoint(), this can return coordinates 0115 // outside of the document/view. 0116 QPoint calculateCurrentPoint (bool zoomToDoc = true) const; 0117 0118 private: 0119 // Only called by ctor to create action(). 0120 void initAction (); 0121 0122 public Q_SLOTS: 0123 // Call this when something below the mouse cursor may have changed 0124 // and/or if the view has moved relative to the cursor (as opposed to 0125 // the cursor moving relative to the view, which would trigger a 0126 // mouseMoveEvent and all would be well without such hacks) 0127 // e.g. when zooming or scrolling the view or when deleting a selection. 0128 // 0129 // This calls hover() or draw() to let the tool know. The Brush Tool 0130 // can then update the position of the Brush Cursor. The Selection 0131 // Tool can update the real cursor. The Line Tool can update the current 0132 // line. The statubar gets correct coordinates. etc. etc. 0133 void somethingBelowTheCursorChanged (); 0134 0135 private: 0136 // Same as above except that you claim you know better than currentPoint() 0137 void somethingBelowTheCursorChanged (const QPoint ¤tPoint_, 0138 const QPoint ¤tViewPoint_); 0139 0140 protected: 0141 int mouseButton () const; 0142 0143 bool shiftPressed () const; 0144 bool controlPressed () const; 0145 bool altPressed () const; 0146 0147 QPoint startPoint () const; 0148 0149 QPoint currentPoint () const; 0150 QPoint currentViewPoint () const; 0151 0152 QRect normalizedRect () const; 0153 0154 QPoint lastPoint () const; 0155 0156 public: // for kpMainWindow 0157 kpView *viewUnderStartPoint () const; 0158 0159 protected: 0160 kpView *viewUnderCursor () const; 0161 0162 public: 0163 // Called when the tool is selected. 0164 virtual void begin (); 0165 0166 // Called when the tool is deselected. 0167 virtual void end (); 0168 0169 // Returns true after begin() has been called but returns false after end() 0170 // after end() has been called. 0171 bool hasBegun () const; 0172 0173 bool hasBegunDraw () const; 0174 0175 virtual bool hasBegunShape () const; 0176 0177 // Called when user double-left-clicks on a tool in the Tool Box. 0178 virtual void globalDraw (); 0179 0180 // Called when the user clicks on a tool in the Tool Box even though it's 0181 // already the current tool (used by the selection tools to deselect). 0182 virtual void reselect (); 0183 0184 Q_SIGNALS: 0185 // emitted after beginDraw() has been called 0186 void beganDraw (const QPoint &point); 0187 0188 // Emitted just before draw() is called in mouseMoveEvent(). Slots 0189 // connected to this signal should return in <scrolled> whether the 0190 // mouse pos may have changed. Used by drag scrolling. 0191 void movedAndAboutToDraw (const QPoint ¤tPoint, const QPoint &lastPoint, 0192 int zoomLevel, 0193 bool *scrolled); 0194 0195 // emitted after endDraw() has been called 0196 void endedDraw (const QPoint &point); 0197 0198 // emitted after cancelShape() has been called 0199 void cancelledShape (const QPoint &point); 0200 0201 Q_SIGNALS: 0202 // User clicked on the tool's action - i.e. select this tool 0203 void actionActivated(); 0204 0205 protected: 0206 // (this method is called by kpTool just as it is needed - its value 0207 // is not cached, so it is allowed to return different things at 0208 // different times) 0209 // REFACTOR: Misleadingly named as it's also called in cancelShapeInternal(). 0210 // And it seems to be called in endShapeInternal() as well? 0211 virtual bool returnToPreviousToolAfterEndDraw () const { return false; } 0212 0213 virtual bool careAboutModifierState () const { return false; } 0214 virtual bool careAboutColorsSwapped () const { return false; } 0215 0216 virtual void beginDraw (); 0217 0218 // mouse move without button pressed 0219 // (only m_currentPoint & m_currentViewPoint is defined) 0220 virtual void hover (const QPoint &point); 0221 0222 // this is useful for "instant" tools like the Pen & Eraser 0223 virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, 0224 const QRect &normalizedRect); 0225 0226 private: 0227 void drawInternal (); 0228 0229 protected: 0230 // (m_mouseButton will not change from beginDraw()) 0231 virtual void cancelShape (); 0232 virtual void releasedAllButtons (); 0233 0234 virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect); 0235 0236 // TODO: I think reimplementations of this should be calling this base 0237 // implementation, so that endDraw() happens before the custom 0238 // endShape() logic of the reimplementation. 0239 virtual void endShape (const QPoint &thisPoint = QPoint (), 0240 const QRect &normalizedRect = QRect ()) 0241 { 0242 endDraw (thisPoint, normalizedRect); 0243 } 0244 0245 kpDocument *document () const; 0246 kpViewManager *viewManager () const; 0247 kpToolToolBar *toolToolBar () const; 0248 kpCommandHistory *commandHistory () const; 0249 kpToolEnvironment *environ () const; 0250 0251 kpColor color (int which) const; 0252 0253 kpColor foregroundColor () const; 0254 kpColor backgroundColor () const; 0255 0256 double colorSimilarity () const; 0257 int processedColorSimilarity () const; 0258 0259 public Q_SLOTS: 0260 void slotColorsSwappedInternal (const kpColor &newForegroundColor, 0261 const kpColor &newBackgroundColor); 0262 void slotForegroundColorChangedInternal (const kpColor &color); 0263 void slotBackgroundColorChangedInternal (const kpColor &color); 0264 void slotColorSimilarityChangedInternal (double similarity, int processedSimilarity); 0265 0266 protected Q_SLOTS: // TODO: there is no reason why these should be slots 0267 virtual void slotColorsSwapped (const kpColor & /*newForegroundColor*/, const kpColor & /*newBackgroundColor*/) {} 0268 virtual void slotForegroundColorChanged (const kpColor & /*color*/) {} 0269 virtual void slotBackgroundColorChanged (const kpColor & /*color*/) {} 0270 virtual void slotColorSimilarityChanged (double /*similarity*/, int /*processedSimilarity*/) {} 0271 0272 protected: 0273 // (only valid in slots connected to the respective signals above) 0274 kpColor oldForegroundColor () const; 0275 kpColor oldBackgroundColor () const; 0276 double oldColorSimilarity () const; 0277 0278 protected: 0279 // returns true if m_currentPoint <= 1 pixel away from m_lastPoint 0280 // or if there was no lastPoint 0281 bool currentPointNextToLast () const; // (includes diagonal adjacency) 0282 bool currentPointCardinallyNextToLast () const; // (only cardinally adjacent i.e. horiz & vert; no diag) 0283 0284 // TODO: We should rename these. 0285 // These are accessed from kpTool logic and our friends, kpCommandHistory, 0286 // kpMainWindow, kpToolToolBar and kpView. 0287 public: 0288 void beginInternal (); 0289 void endInternal (); 0290 0291 void beginDrawInternal (); 0292 void endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect, 0293 bool wantEndShape = false); 0294 void cancelShapeInternal (); 0295 // TODO: Who is actually calling endShapeInternal()? 0296 // Tools seem to call endShape() directly. 0297 void endShapeInternal (const QPoint &thisPoint = QPoint (), 0298 const QRect &normalizedRect = QRect ()); 0299 0300 0301 // 0302 // Mouse Events 0303 // 0304 0305 public: 0306 // Note: _All_ events are forwarded from a kpView. 0307 // The existence of a kpView implies the existence of a kpDocument. 0308 0309 // If you're reimplementing any of these, you probably don't know what 0310 // you're doing - reimplement begin(),beginDraw(),draw(),cancelShape(), 0311 // endDraw() etc. instead. 0312 virtual void mousePressEvent (QMouseEvent *e); 0313 virtual void mouseMoveEvent (QMouseEvent *e); 0314 virtual void mouseReleaseEvent (QMouseEvent *e); 0315 0316 virtual void wheelEvent (QWheelEvent *e); 0317 0318 0319 // 0320 // Keyboard Events 0321 // 0322 0323 protected: 0324 void seeIfAndHandleModifierKey (QKeyEvent *e); 0325 0326 void arrowKeyPressDirection (const QKeyEvent *e, int *dx, int *dy); 0327 void seeIfAndHandleArrowKeyPress (QKeyEvent *e); 0328 0329 bool isDrawKey (int key); 0330 void seeIfAndHandleBeginDrawKeyPress (QKeyEvent *e); 0331 void seeIfAndHandleEndDrawKeyPress (QKeyEvent *e); 0332 0333 public: 0334 virtual void keyPressEvent (QKeyEvent *e); 0335 virtual void keyReleaseEvent (QKeyEvent *e); 0336 0337 virtual void inputMethodEvent (QInputMethodEvent *) {} 0338 0339 private: 0340 void keyUpdateModifierState (QKeyEvent *e); 0341 void notifyModifierStateChanged (); 0342 0343 protected: 0344 virtual void setShiftPressed (bool pressed); 0345 virtual void setControlPressed (bool pressed); 0346 0347 virtual void setAltPressed (bool pressed); 0348 0349 0350 // 0351 // Other Events - 1. View Events 0352 // 0353 0354 public: 0355 // WARNING: Do not call this "event()" as our QObject parent has a 0356 // virtual function called that, that will pass us 0357 // QObject events. We only care about events forwarded by 0358 // kpView. 0359 // REFACTOR: rename mousePressEvent() -> viewMousePressEvent() etc. 0360 // to remind us that events are coming from the view - the tool 0361 // is not a visible object. 0362 virtual bool viewEvent (QEvent *e); 0363 0364 public: 0365 virtual void focusInEvent (QFocusEvent *e); 0366 virtual void focusOutEvent (QFocusEvent *e); 0367 0368 public: 0369 virtual void enterEvent (QEvent *e); 0370 virtual void leaveEvent (QEvent *e); 0371 0372 0373 // 0374 // Other Events - 2. Non-view Events 0375 // REFACTOR: Group methods under this. 0376 // 0377 0378 protected: 0379 // 0 = left, 1 = right, -1 = other (none, left+right, mid) 0380 static int mouseButton (Qt::MouseButtons mouseButtons); 0381 0382 public: 0383 static int calculateLength (int start, int end); 0384 0385 // 0386 // User Notifications (Status Bar) 0387 // 0388 0389 public: 0390 // Returns "(Left|Right) click to cancel." where Left or Right is chosen 0391 // depending on which one is the _opposite_ of <mouseButton> 0392 static QString cancelUserMessage (int mouseButton); 0393 QString cancelUserMessage () const; 0394 0395 QString userMessage () const; 0396 // WARNING: setUserMessage() will store a message different to <userMessage>, 0397 // in unspecified ways (e.g. the name of the tool, followed 0398 // by a colon and a space, will be prepended). userMessage() 0399 // will return this different string. 0400 void setUserMessage (const QString &userMessage = QString ()); 0401 0402 QPoint userShapeStartPoint () const; 0403 QPoint userShapeEndPoint () const; 0404 void setUserShapePoints (const QPoint &startPoint = KP_INVALID_POINT, 0405 const QPoint &endPoint = KP_INVALID_POINT, 0406 bool setSize = true); 0407 0408 QSize userShapeSize () const; 0409 int userShapeWidth () const; 0410 int userShapeHeight () const; 0411 void setUserShapeSize (const QSize &size = KP_INVALID_SIZE); 0412 void setUserShapeSize (int width, int height); 0413 0414 Q_SIGNALS: 0415 void userMessageChanged (const QString &userMessage); 0416 void userShapePointsChanged (const QPoint &startPoint = KP_INVALID_POINT, 0417 const QPoint &endPoint = KP_INVALID_POINT); 0418 void userShapeSizeChanged (const QSize &size); 0419 0420 0421 public: 0422 // Call this before the user tries to cause the document or selection 0423 // to resize from <oldWidth>x<oldHeight> to <newWidth>x<newHeight>. 0424 // If at least one dimension increases, the new dimensions will take a 0425 // large amount of memory (which causes thrashing, instability) and 0426 // the old dimensions did not take a large amount of memory, ask the 0427 // user if s/he really wants to perform the operation. 0428 // 0429 // Returns true if the operation should proceed, false otherwise. 0430 // 0431 // In order to make the translators' lives possible, this function cannot 0432 // generate the <text>,<caption> nor <continueButtonText> (without 0433 // concantenating sentences and words with tense). However, it is 0434 // recommended that you give them the following values: 0435 // 0436 // e.g.: 0437 // text = i18n ("<qt><p>(Rotating|Skewing) the (image|selection) to" 0438 // " %1x%2 may take a substantial amount of memory." 0439 // " This can reduce system" 0440 // " responsiveness and cause other application resource" 0441 // " problems.</p>").arg (newWidth, newHeight) 0442 // 0443 // "<p>Are you sure you want to (rotate|skew) the" 0444 // " (image|selection)?</p></qt>"); 0445 // caption = i18n ("Rotate (Image|Selection)?"); 0446 // continueButtonText = i18n ("Rotat&e (Image|Selection)"); 0447 static bool warnIfBigImageSize (int oldWidth, int oldHeight, 0448 int newWidth, int newHeight, 0449 const QString &text, 0450 const QString &caption, 0451 const QString &continueButtonText, 0452 QWidget *parent); 0453 0454 private: 0455 kpToolPrivate *d; 0456 }; 0457 0458 0459 #endif // KP_TOOL_H