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

0001 /*
0002    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0003    All rights reserved.
0004 
0005    Redistribution and use in source and binary forms, with or without
0006    modification, are permitted provided that the following conditions
0007    are met:
0008 
0009    1. Redistributions of source code must retain the above copyright
0010       notice, this list of conditions and the following disclaimer.
0011    2. Redistributions in binary form must reproduce the above copyright
0012       notice, this list of conditions and the following disclaimer in the
0013       documentation and/or other materials provided with the distribution.
0014 
0015    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0016    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0017    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0018    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0019    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0020    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0021    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0022    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0023    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0024    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0025 */
0026 
0027 
0028 #define DEBUG_KP_TOOL_ZOOM 0
0029 
0030 
0031 #include "kpToolZoom.h"
0032 
0033 #include "kpDefs.h"
0034 #include "document/kpDocument.h"
0035 #include "pixmapfx/kpPixmapFX.h"
0036 #include "generic/kpSetOverrideCursorSaver.h"
0037 #include "layers/tempImage/kpTempImage.h"
0038 #include "environments/tools/kpToolEnvironment.h"
0039 #include "views/manager/kpViewManager.h"
0040 #include "kpLogCategories.h"
0041 
0042 #include <KLocalizedString>
0043 #include <KToggleAction>
0044 
0045 #include <QIcon>
0046 #include <QWidget>
0047 
0048 //---------------------------------------------------------------------
0049 
0050 struct DrawZoomRectPackage
0051 {
0052     QRect normalizedRect;
0053 };
0054 
0055 static void DrawZoomRect (kpImage *destImage,
0056         const QPoint &topLeft,
0057         void *userData)
0058 {
0059     auto *pack = static_cast <DrawZoomRectPackage *> (userData);
0060 
0061     kpPixmapFX::drawStippleRect(destImage,
0062         topLeft.x (), topLeft.y (), pack->normalizedRect.width (), pack->normalizedRect.height (),
0063         kpColor::Yellow,
0064         kpColor::Green);
0065 }
0066 
0067 
0068 struct kpToolZoomPrivate
0069 {
0070     bool dragHasBegun{}, dragCompleted{};
0071     DrawZoomRectPackage drawPackage;
0072 };
0073 
0074 kpToolZoom::kpToolZoom (kpToolEnvironment *environ, QWidget *parent)
0075     : kpTool (i18n ("Zoom"), i18n ("Zooms in and out of the image"),
0076               Qt::Key_Z,
0077               environ, parent, QStringLiteral("tool_zoom")),
0078       d (new kpToolZoomPrivate ())
0079 {
0080   // different from objectName()
0081   action()->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original")));
0082 }
0083 
0084 //---------------------------------------------------------------------
0085 
0086 kpToolZoom::~kpToolZoom ()
0087 {
0088     delete d;
0089 }
0090 
0091 //---------------------------------------------------------------------
0092 // public virtual [base kpTool]
0093 
0094 bool kpToolZoom::returnToPreviousToolAfterEndDraw () const
0095 {
0096     // If the user clicks to zoom in or out, s/he generally wants to click
0097     // some more to get the exact zoom level wanted.
0098     //
0099     // However, if they drag out a rectangle to zoom into a particular area,
0100     // they probably don't need to do any further zooming so we can return
0101     // them to their previous tool.
0102     //
0103     // Note that if they cancel a drag (cancelShape()), we do _not_ return
0104     // them to their previous tool, unlike the Color Picker.  This is because
0105     // cancelling a drag generally means that the user got the top-left of
0106     // the drag wrong and wants to try a different top-left.  In contrast,
0107     // with the Color Picket, if you've made a mistake while pressing the
0108     // mouse, you can just keep holding down the mouse and drag to the intended
0109     // color -- a cancel with a Color Picker really means "I've decided not
0110     // to pick another color after all", not "I got the start of the drag wrong"
0111     // because you can correct that drag.
0112     return d->dragCompleted;
0113 }
0114 
0115 
0116 // private
0117 QString kpToolZoom::haventBegunDrawUserMessage () const
0118 {
0119     return i18n ("Click to zoom in/out or left drag to zoom into a specific area.");
0120 }
0121 
0122 
0123 // public virtual [base kpTool]
0124 void kpToolZoom::begin ()
0125 {
0126     viewManager ()->setCursor (Qt::CrossCursor);
0127 
0128     setUserMessage (haventBegunDrawUserMessage ());
0129 }
0130 
0131 // public virtual [base kpTool]
0132 void kpToolZoom::end ()
0133 {
0134     viewManager ()->unsetCursor ();
0135 }
0136 
0137 
0138 // public virtual [base kpTool]
0139 void kpToolZoom::globalDraw ()
0140 {
0141 #if DEBUG_KP_TOOL_ZOOM
0142     qCDebug(kpLogTools) << "CALL";
0143 #endif
0144     environ ()->fitToPage ();
0145 }
0146 
0147 
0148 // public virtual [base kpTool]
0149 void kpToolZoom::beginDraw ()
0150 {
0151     d->dragHasBegun = false;
0152     d->dragCompleted = false;
0153 
0154     setUserMessage (cancelUserMessage ());
0155 }
0156 
0157 // public virtual [base kpTool]
0158 void kpToolZoom::draw (const QPoint &thisPoint, const QPoint &, const QRect &normalizedRect)
0159 {
0160 #if DEBUG_KP_TOOL_ZOOM
0161     qCDebug(kpLogTools) << "kpToomZoom::draw() currentPoint=" << currentPoint ()
0162               << " lastPoint=" << lastPoint ()
0163               << endl;
0164 #endif
0165 
0166     // TODO: Need accidental drag detection from selection tool (when dragging
0167     //       out new selection)
0168 
0169     if (!d->dragHasBegun)
0170     {
0171         if (thisPoint == startPoint ()) {
0172             return;
0173         }
0174 
0175         // Left mouse drags select an area to zoom into.
0176         // However, it wouldn't make sense to select an area to "zoom out of"
0177         // (using the right mouse button).  Therefore, make RMB drags do the
0178         // same as RMB clicks i.e. a simple zoom out, with no "area" to worry
0179         // about.
0180         if (mouseButton () == 1/*RMB*/) {
0181             return;
0182         }
0183 
0184         d->dragHasBegun = true;
0185     }
0186 
0187 
0188     d->drawPackage.normalizedRect = normalizedRect;
0189 
0190     kpTempImage newTempImage (false/*always display*/,
0191         normalizedRect.topLeft (),
0192         &::DrawZoomRect, &d->drawPackage,
0193         normalizedRect.width (), normalizedRect.height ());
0194 
0195     viewManager ()->setFastUpdates ();
0196     {
0197         viewManager ()->setTempImage (newTempImage);
0198     }
0199     viewManager ()->restoreFastUpdates ();
0200 }
0201 
0202 // public virtual [base kpTool]
0203 void kpToolZoom::cancelShape ()
0204 {
0205     viewManager ()->invalidateTempImage ();
0206 
0207     // LOREFACTOR: A lot of tools use this - push up to kpTool?
0208     setUserMessage (i18n ("Let go of all the mouse buttons."));
0209 }
0210 
0211 // public virtual [base kpTool]
0212 void kpToolZoom::releasedAllButtons ()
0213 {
0214     setUserMessage (haventBegunDrawUserMessage ());
0215 }
0216 
0217 // public virtual [base kpTool]
0218 void kpToolZoom::endDraw (const QPoint &, const QRect &normalizedRect)
0219 {
0220 #if DEBUG_KP_TOOL_ZOOM
0221     qCDebug(kpLogTools) << "kpToolZoom::endDraw(rect=" << normalizedRect << ")"
0222         << " dragHasBegun=" << d->dragHasBegun << endl;
0223 #endif
0224 
0225     // TODO: This cursor doesn't stay on for long enough because zooming uses
0226     //       event loop tricks.
0227     kpSetOverrideCursorSaver cursorSaver (Qt::WaitCursor);
0228 
0229     viewManager ()->invalidateTempImage ();
0230 
0231     // Click?
0232     if (!d->dragHasBegun)
0233     {
0234         if (mouseButton () == 0/*LMB*/) {
0235             environ ()->zoomIn (true/*center under cursor*/);
0236         }
0237         else {
0238             environ ()->zoomOut (false/*don't center under cursor - as is
0239                                         confusing behaviour when zooming
0240                                         out*/);
0241         }
0242     }
0243     // Drag?
0244     else if (normalizedRect.isValid())
0245     {
0246         environ ()->zoomToRect (
0247             normalizedRect,
0248             false/*don't account for grips*/,
0249             true/*care about width*/, true/*care about height*/);
0250 
0251         d->dragCompleted = true;
0252     }
0253 }
0254 
0255 #include "moc_kpToolZoom.cpp"