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 &currentPoint_,
0138                                          const QPoint &currentViewPoint_);
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 &currentPoint, 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