File indexing completed on 2024-05-12 04:21:28

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 #define DEBUG_KP_TOOL_SELECTION 0
0030 
0031 
0032 #include "kpAbstractSelectionTool.h"
0033 #include "kpAbstractSelectionToolPrivate.h"
0034 
0035 #include <QCursor>
0036 #include <QPixmap>
0037 #include <QTimer>
0038 
0039 #include <KLocalizedString>
0040 
0041 #include "kpLogCategories.h"
0042 #include "layers/selections/image/kpAbstractImageSelection.h"
0043 #include "layers/selections/kpAbstractSelection.h"
0044 #include "commands/kpCommandHistory.h"
0045 #include "kpDefs.h"
0046 #include "document/kpDocument.h"
0047 #include "commands/kpMacroCommand.h"
0048 #include "commands/tools/selection/kpToolSelectionCreateCommand.h"
0049 #include "commands/tools/selection/kpToolSelectionDestroyCommand.h"
0050 #include "environments/tools/selection/kpToolSelectionEnvironment.h"
0051 #include "commands/tools/selection/kpToolSelectionMoveCommand.h"
0052 #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h"
0053 #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h"
0054 #include "widgets/toolbars/kpToolToolBar.h"
0055 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h"
0056 #include "views/kpView.h"
0057 #include "views/manager/kpViewManager.h"
0058 
0059 
0060 // private
0061 void kpAbstractSelectionTool::initCreate ()
0062 {
0063     d->createNOPTimer = new QTimer (this);
0064     d->createNOPTimer->setSingleShot (true);
0065     connect (d->createNOPTimer, &QTimer::timeout,
0066              this, &kpAbstractSelectionTool::delayedDrawCreate);
0067 }
0068 
0069 // private
0070 void kpAbstractSelectionTool::uninitCreate ()
0071 {
0072     // d->createNOPTimer (deleted by QObject mechanism)
0073 }
0074 
0075 
0076 // private
0077 void kpAbstractSelectionTool::beginCreate ()
0078 {
0079     // d->createNOPTimer
0080 }
0081 
0082 // private
0083 void kpAbstractSelectionTool::endCreate ()
0084 {
0085     // d->createNOPTimer
0086 }
0087 
0088 //---------------------------------------------------------------------
0089 // use a crosshair cursor which is really always exactly 1 pixel wide
0090 // to the contrary of the "themed" crosshair cursors which might look nice
0091 // but does not allow to exactly position the hot-spot.
0092 /* XPM */
0093 static const char *crosshair[]={
0094 "17 17 3 1",
0095 ". c None",
0096 "x c #FFFFFF",
0097 "# c #000000",
0098 ".......xxx.......",
0099 ".......x#x.......",
0100 ".......x#x.......",
0101 ".......x#x.......",
0102 ".......x#x.......",
0103 ".......x#x.......",
0104 ".......x#x.......",
0105 "xxxxxxxx#xxxxxxxx",
0106 "x#######.#######x",
0107 "xxxxxxxx#xxxxxxxx",
0108 ".......x#x.......",
0109 ".......x#x.......",
0110 ".......x#x.......",
0111 ".......x#x.......",
0112 ".......x#x.......",
0113 ".......x#x.......",
0114 ".......xxx......."};
0115 
0116 // private
0117 void kpAbstractSelectionTool::setCursorCreate ()
0118 {
0119     viewManager()->setCursor(QCursor(QPixmap(crosshair), 8, 8));
0120 }
0121 
0122 //---------------------------------------------------------------------
0123 
0124 // protected virtual
0125 void kpAbstractSelectionTool::setSelectionBorderForBeginDrawCreate ()
0126 {
0127     viewManager ()->setQueueUpdates ();
0128     {
0129         // LOREFACTOR: I suspect some calls to viewManager() in this
0130         //             file (including this) are redundant since any
0131         //             code that tweaks such settings, returns them to
0132         //             their original state, after the code is complete.
0133         viewManager ()->setSelectionBorderVisible (true);
0134 
0135         viewManager ()->setSelectionBorderFinished (false);
0136     }
0137     viewManager ()->restoreQueueUpdates ();
0138 }
0139 
0140 // private
0141 void kpAbstractSelectionTool::beginDrawCreate ()
0142 {
0143     if (document ()->selection ()) {
0144         pushOntoDocument ();
0145     }
0146 
0147     /*virtual*/setSelectionBorderForBeginDrawCreate ();
0148 
0149     // (single shot)
0150     d->createNOPTimer->start (200/*ms*/);
0151 
0152     setUserMessage (cancelUserMessage ());
0153 }
0154 
0155 
0156 // private
0157 void kpAbstractSelectionTool::drawCreate (const QPoint &thisPoint,
0158         const QRect &normalizedRect)
0159 {
0160 #if DEBUG_KP_TOOL_SELECTION && 1
0161     qCDebug(kpLogTools) << "\tnot moving - resizing rect to" << normalizedRect;
0162     qCDebug(kpLogTools) << "\t\tcreateNOPTimer->isActive()="
0163                 << d->createNOPTimer->isActive ()
0164                 << " viewManhattanLength from startPoint="
0165                 << viewUnderStartPoint ()->transformDocToViewX ((thisPoint - startPoint ()).manhattanLength ());
0166 #endif
0167 
0168     QPoint accidentalDragAdjustedPoint = thisPoint;
0169     if (d->createNOPTimer->isActive ())
0170     {
0171         // See below "d->createNOPTimer->stop()".
0172         Q_ASSERT (!d->dragAccepted);
0173 
0174         if (viewUnderStartPoint ()->transformDocToViewX (
0175                 (accidentalDragAdjustedPoint - startPoint ()).manhattanLength ()) <= 6)
0176         {
0177         #if DEBUG_KP_TOOL_SELECTION && 1
0178             qCDebug(kpLogTools) << "\t\tsuppress accidental movement";
0179         #endif
0180             accidentalDragAdjustedPoint = startPoint ();
0181         }
0182         else
0183         {
0184         #if DEBUG_KP_TOOL_SELECTION && 1
0185             qCDebug(kpLogTools) << "\t\tit's a \"big\" intended move - stop timer";
0186         #endif
0187             d->createNOPTimer->stop ();
0188         }
0189     }
0190 
0191 
0192     const bool hadSelection = document ()->selection ();
0193 
0194     const bool oldDrawAcceptedAsDrag = d->dragAccepted;
0195     d->dragAccepted = /*virtual*/drawCreateMoreSelectionAndUpdateStatusBar (
0196         d->dragAccepted,
0197         accidentalDragAdjustedPoint,
0198         normalizedRect);
0199     if (oldDrawAcceptedAsDrag) {
0200         Q_ASSERT (d->dragAccepted);
0201     }
0202     if (d->dragAccepted)
0203     {
0204     #if DEBUG_KP_TOOL_SELECTION && 1
0205         qCDebug(kpLogTools) << "\t\tdrawHasDoneSomething - kill create timer";
0206     #endif
0207         // No longer a NOP.
0208         d->createNOPTimer->stop ();
0209     }
0210 
0211     // Did we just create a selection?
0212     if (!hadSelection && document ()->selection ()) {
0213         viewManager ()->setSelectionBorderVisible (true);
0214     }
0215 }
0216 
0217 // private slot
0218 void kpAbstractSelectionTool::delayedDrawCreate ()
0219 {
0220 #if DEBUG_KP_TOOL_SELECTION && 1
0221     qCDebug(kpLogTools) << "kpAbstractSelectionTool::delayedDrawCreate() hasBegunDraw="
0222                << hasBegunDraw ()
0223                << " currentPoint=" << currentPoint ()
0224                << " lastPoint=" << lastPoint ()
0225                << " startPoint=" << startPoint ();
0226 #endif
0227 
0228     // (just in case not called from single shot)
0229     d->createNOPTimer->stop ();
0230 
0231     if (hasBegunDraw ())
0232     {
0233         draw (currentPoint (), lastPoint (), normalizedRect ());
0234     }
0235 }
0236 
0237 
0238 // private
0239 void kpAbstractSelectionTool::cancelCreate ()
0240 {
0241 #if DEBUG_KP_TOOL_SELECTION
0242     qCDebug(kpLogTools) << "\twas creating sel - kill";
0243 #endif
0244 
0245     d->createNOPTimer->stop ();
0246 
0247     // TODO: should we give the user back the selection s/he had before (if any)?
0248     if (document ()->selection ()) {
0249         document ()->selectionDelete ();
0250     }
0251 }
0252 
0253 // private
0254 void kpAbstractSelectionTool::endDrawCreate ()
0255 {
0256     d->createNOPTimer->stop ();
0257 }
0258 
0259 
0260 // private
0261 QVariant kpAbstractSelectionTool::operationCreate (Operation op,
0262         const QVariant &data1, const QVariant &data2)
0263 {
0264     (void) data1;
0265     (void) data2;
0266 
0267 
0268     switch (op)
0269     {
0270     case HaventBegunDrawUserMessage:
0271         return /*virtual*/haventBegunDrawUserMessageCreate ();
0272 
0273     case SetCursor:
0274         setCursorCreate ();
0275         break;
0276 
0277     case BeginDraw:
0278         beginDrawCreate ();
0279         break;
0280 
0281     case Draw:
0282         drawCreate (currentPoint (), normalizedRect ());
0283         break;
0284 
0285     case Cancel:
0286         cancelCreate ();
0287         break;
0288 
0289     case EndDraw:
0290         endDrawCreate ();
0291         break;
0292 
0293     default:
0294         Q_ASSERT (!"Unhandled operation");
0295         break;
0296     }
0297 
0298 
0299     return {};
0300 }