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 #include "kpLogCategories.h"
0035 #include "layers/selections/image/kpAbstractImageSelection.h"
0036 #include "layers/selections/kpAbstractSelection.h"
0037 #include "commands/kpCommandHistory.h"
0038 #include "kpDefs.h"
0039 #include "document/kpDocument.h"
0040 #include "commands/kpMacroCommand.h"
0041 #include "commands/tools/selection/kpToolSelectionCreateCommand.h"
0042 #include "commands/tools/selection/kpToolSelectionDestroyCommand.h"
0043 #include "environments/tools/selection/kpToolSelectionEnvironment.h"
0044 #include "commands/tools/selection/kpToolSelectionMoveCommand.h"
0045 #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h"
0046 #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h"
0047 #include "widgets/toolbars/kpToolToolBar.h"
0048 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h"
0049 #include "views/kpView.h"
0050 #include "views/manager/kpViewManager.h"
0051 
0052 #include <QTimer>
0053 
0054 #include <KLocalizedString>
0055 
0056 //---------------------------------------------------------------------
0057 
0058 // private
0059 void kpAbstractSelectionTool::initMove ()
0060 {
0061     d->currentMoveCommand = nullptr;
0062 
0063     // d->currentMoveCommandIsSmear
0064 
0065     // d->startMoveDragFromSelectionTopLeft
0066 
0067     d->RMBMoveUpdateGUITimer = new QTimer (this);
0068     d->RMBMoveUpdateGUITimer->setSingleShot (true);
0069     connect (d->RMBMoveUpdateGUITimer, &QTimer::timeout,
0070              this, &kpAbstractSelectionTool::slotRMBMoveUpdateGUI);
0071 }
0072 
0073 //---------------------------------------------------------------------
0074 
0075 // private
0076 void kpAbstractSelectionTool::uninitMove ()
0077 {
0078     // (state must be after construction, or after some time after endMove())
0079     Q_ASSERT (!d->currentMoveCommand);
0080 
0081     // d->currentMoveCommandIsSmear
0082 
0083     // d->startMoveDragFromSelectionTopLeft
0084 
0085     // d->RMBMoveUpdateGUITimer (deleted by QObject mechanism)
0086 }
0087 
0088 //---------------------------------------------------------------------
0089 
0090 // private
0091 void kpAbstractSelectionTool::beginMove ()
0092 {
0093     // (state must be after construction, or after some time after endMove())
0094     Q_ASSERT (!d->currentMoveCommand);
0095 
0096     // d->currentMoveCommandIsSmear
0097 
0098     // d->startMoveDragFromSelectionTopLeft;
0099 
0100     // d->RMBMoveUpdateGUITimer
0101 }
0102 
0103 //---------------------------------------------------------------------
0104 
0105 // private
0106 void kpAbstractSelectionTool::endMove ()
0107 {
0108     // (should have been killed by cancelMove() or endDrawMove())
0109     Q_ASSERT (!d->currentMoveCommand);
0110 
0111     // d->currentMoveCommandIsSmear
0112 
0113     // d->startMoveDragFromSelectionTopLeft
0114 
0115     // d->RMBMoveUpdateGUITimer
0116 }
0117 
0118 //---------------------------------------------------------------------
0119 
0120 // private
0121 void kpAbstractSelectionTool::setCursorMove ()
0122 {
0123     viewManager ()->setCursor (Qt::SizeAllCursor);
0124 }
0125 
0126 //---------------------------------------------------------------------
0127 
0128 // protected virtual
0129 void kpAbstractSelectionTool::setSelectionBorderForBeginDrawMove ()
0130 {
0131     // don't show border while moving
0132     viewManager ()->setQueueUpdates ();
0133     {
0134         viewManager ()->setSelectionBorderVisible (false);
0135         viewManager ()->setSelectionBorderFinished (true);
0136     }
0137     viewManager ()->restoreQueueUpdates ();
0138 }
0139 
0140 //---------------------------------------------------------------------
0141 
0142 // private
0143 void kpAbstractSelectionTool::beginDrawMove ()
0144 {
0145     d->startMoveDragFromSelectionTopLeft =
0146         currentPoint () - document ()->selection ()->topLeft ();
0147 
0148     if (mouseButton () == 0)
0149     {
0150         /*virtual*/setSelectionBorderForBeginDrawMove ();
0151     }
0152     else
0153     {
0154         // Don't hide sel border momentarily if user is just
0155         // right _clicking_ selection.
0156         // (single shot timer)
0157         d->RMBMoveUpdateGUITimer->start (100/*ms*/);
0158     }
0159 
0160     setUserMessage (cancelUserMessage ());
0161 }
0162 
0163 //---------------------------------------------------------------------
0164 
0165 // private slot
0166 void kpAbstractSelectionTool::slotRMBMoveUpdateGUI ()
0167 {
0168     // (just in case not called from single shot)
0169     d->RMBMoveUpdateGUITimer->stop ();
0170 
0171     /*virtual*/setSelectionBorderForBeginDrawMove ();
0172 
0173     kpAbstractSelection * const sel = document ()->selection ();
0174     if (sel) {
0175         setUserShapePoints (sel->topLeft ());
0176     }
0177 }
0178 
0179 //---------------------------------------------------------------------
0180 
0181 // private
0182 void kpAbstractSelectionTool::drawMove (const QPoint &thisPoint, const QRect &/*normalizedRect*/)
0183 {
0184 #if DEBUG_KP_TOOL_SELECTION && 1
0185     qCDebug(kpLogTools) << "\tmoving selection";
0186 #endif
0187 
0188     kpAbstractSelection *sel = document ()->selection ();
0189 
0190     QRect targetSelRect (thisPoint.x () - d->startMoveDragFromSelectionTopLeft.x (),
0191         thisPoint.y () - d->startMoveDragFromSelectionTopLeft.y (),
0192         sel->width (),
0193         sel->height ());
0194 
0195 #if DEBUG_KP_TOOL_SELECTION && 1
0196     qCDebug(kpLogTools) << "\t\tstartPoint=" << startPoint ()
0197                 << " thisPoint=" << thisPoint
0198                 << " startDragFromSel=" << d->startMoveDragFromSelectionTopLeft
0199                 << " targetSelRect=" << targetSelRect;
0200 #endif
0201 
0202     // Try to make sure selection still intersects document so that it's
0203     // reachable.
0204 
0205     if (targetSelRect.right () < 0) {
0206         targetSelRect.translate (-targetSelRect.right (), 0);
0207     }
0208     else if (targetSelRect.left () >= document ()->width ()) {
0209         targetSelRect.translate (document ()->width () - targetSelRect.left () - 1, 0);
0210     }
0211 
0212     if (targetSelRect.bottom () < 0) {
0213         targetSelRect.translate (0, -targetSelRect.bottom ());
0214     }
0215     else if (targetSelRect.top () >= document ()->height ()) {
0216         targetSelRect.translate (0, document ()->height () - targetSelRect.top () - 1);
0217     }
0218 
0219 #if DEBUG_KP_TOOL_SELECTION && 1
0220     qCDebug(kpLogTools) << "\t\t\tafter ensure sel rect clickable=" << targetSelRect;
0221 #endif
0222 
0223 
0224     if (!d->dragAccepted &&
0225         targetSelRect.topLeft () + d->startMoveDragFromSelectionTopLeft == startPoint ())
0226     {
0227     #if DEBUG_KP_TOOL_SELECTION && 1
0228         qCDebug(kpLogTools) << "\t\t\t\tnop";
0229     #endif
0230 
0231 
0232         if (!d->RMBMoveUpdateGUITimer->isActive ())
0233         {
0234             // (slotRMBMoveUpdateGUI() calls similar line)
0235             setUserShapePoints (sel->topLeft ());
0236         }
0237 
0238         // Prevent both NOP drag-moves
0239         return;
0240     }
0241 
0242 
0243     if (d->RMBMoveUpdateGUITimer->isActive ())
0244     {
0245         d->RMBMoveUpdateGUITimer->stop ();
0246         slotRMBMoveUpdateGUI ();
0247     }
0248 
0249 
0250     giveContentIfNeeded ();
0251 
0252 
0253     if (!d->currentMoveCommand)
0254     {
0255         d->currentMoveCommand = new kpToolSelectionMoveCommand (
0256             QString()/*uninteresting child of macro cmd*/,
0257             environ ()->commandEnvironment ());
0258         d->currentMoveCommandIsSmear = false;
0259     }
0260 
0261 
0262     //viewManager ()->setQueueUpdates ();
0263     //viewManager ()->setFastUpdates ();
0264 
0265     if (shiftPressed ()) {
0266         d->currentMoveCommandIsSmear = true;
0267     }
0268 
0269     if (!d->dragAccepted && (controlPressed () || shiftPressed ())) {
0270         d->currentMoveCommand->copyOntoDocument ();
0271     }
0272 
0273     d->currentMoveCommand->moveTo (targetSelRect.topLeft ());
0274 
0275     if (shiftPressed ()) {
0276         d->currentMoveCommand->copyOntoDocument ();
0277     }
0278 
0279     //viewManager ()->restoreFastUpdates ();
0280     //viewManager ()->restoreQueueUpdates ();
0281 
0282     // REFACTOR: yuck, yuck
0283     kpAbstractSelection *orgSel = d->currentMoveCommand->originalSelectionClone ();
0284     QPoint start = orgSel->topLeft ();
0285     delete orgSel;
0286     QPoint end = targetSelRect.topLeft ();
0287     setUserShapePoints (start, end, false/*don't set size*/);
0288     setUserShapeSize (end.x () - start.x (), end.y () - start.y ());
0289 
0290 
0291     d->dragAccepted = true;
0292 }
0293 
0294 //---------------------------------------------------------------------
0295 
0296 // private
0297 void kpAbstractSelectionTool::cancelMove ()
0298 {
0299 #if DEBUG_KP_TOOL_SELECTION
0300     qCDebug(kpLogTools) << "\twas drag moving - undo drag and undo acquire";
0301 #endif
0302 
0303     d->RMBMoveUpdateGUITimer->stop ();
0304 
0305     // NOP drag?
0306     if (!d->currentMoveCommand) {
0307         return;
0308     }
0309 
0310 #if DEBUG_KP_TOOL_SELECTION
0311     qCDebug(kpLogTools) << "\t\tundo currentMoveCommand";
0312 #endif
0313     d->currentMoveCommand->finalize ();
0314     d->currentMoveCommand->unexecute ();
0315     delete d->currentMoveCommand;
0316     d->currentMoveCommand = nullptr;
0317 }
0318 
0319 //---------------------------------------------------------------------
0320 
0321 // protected virtual
0322 QString kpAbstractSelectionTool::nonSmearMoveCommandName () const
0323 {
0324     return i18n ("Selection: Move");
0325 }
0326 
0327 //---------------------------------------------------------------------
0328 
0329 // private
0330 void kpAbstractSelectionTool::endDrawMove ()
0331 {
0332     d->RMBMoveUpdateGUITimer->stop ();
0333 
0334     // NOP drag?
0335     if (!d->currentMoveCommand) {
0336         return;
0337     }
0338 
0339     d->currentMoveCommand->finalize ();
0340 
0341     kpMacroCommand *renamedCmd = nullptr;
0342 #if DEBUG_KP_TOOL_SELECTION
0343     qCDebug(kpLogTools) << "\thave moveCommand";
0344 #endif
0345     if (d->currentMoveCommandIsSmear)
0346     {
0347         renamedCmd = new kpMacroCommand (i18n ("%1: Smear",
0348             document ()->selection ()->name ()),
0349             environ ()->commandEnvironment ());
0350     }
0351     else
0352     {
0353         renamedCmd = new kpMacroCommand (
0354             /*virtual*/nonSmearMoveCommandName (),
0355             environ ()->commandEnvironment ());
0356     }
0357 
0358     renamedCmd->addCommand (d->currentMoveCommand);
0359     d->currentMoveCommand = nullptr;
0360 
0361     addNeedingContentCommand (renamedCmd);
0362 }
0363 
0364 //---------------------------------------------------------------------
0365 
0366 // private
0367 QVariant kpAbstractSelectionTool::operationMove (Operation op,
0368         const QVariant &data1, const QVariant &data2)
0369 {
0370     (void) data1;
0371     (void) data2;
0372 
0373 
0374     switch (op)
0375     {
0376     case HaventBegunDrawUserMessage:
0377         return /*virtual*/haventBegunDrawUserMessageMove ();
0378 
0379     case SetCursor:
0380         setCursorMove ();
0381         break;
0382 
0383     case BeginDraw:
0384         beginDrawMove ();
0385         break;
0386 
0387     case Draw:
0388         drawMove (currentPoint (), normalizedRect ());
0389         break;
0390 
0391     case Cancel:
0392         cancelMove ();
0393         break;
0394 
0395     case EndDraw:
0396         endDrawMove ();
0397         break;
0398 
0399     default:
0400         Q_ASSERT (!"Unhandled operation");
0401         break;
0402     }
0403 
0404     return {};
0405 }
0406 
0407 //---------------------------------------------------------------------