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 
0036 #include <KLocalizedString>
0037 
0038 #include "layers/selections/image/kpAbstractImageSelection.h"
0039 #include "layers/selections/kpAbstractSelection.h"
0040 #include "commands/kpCommandHistory.h"
0041 #include "kpDefs.h"
0042 #include "document/kpDocument.h"
0043 #include "commands/kpMacroCommand.h"
0044 #include "commands/tools/selection/kpToolSelectionCreateCommand.h"
0045 #include "commands/tools/selection/kpToolSelectionDestroyCommand.h"
0046 #include "environments/tools/selection/kpToolSelectionEnvironment.h"
0047 #include "commands/tools/selection/kpToolSelectionMoveCommand.h"
0048 #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h"
0049 #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h"
0050 #include "widgets/toolbars/kpToolToolBar.h"
0051 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h"
0052 #include "views/kpView.h"
0053 #include "views/manager/kpViewManager.h"
0054 
0055 
0056 // private
0057 int kpAbstractSelectionTool::onSelectionResizeHandle () const
0058 {
0059     kpView *v = viewManager ()->viewUnderCursor ();
0060     if (!v) {
0061         return 0;
0062     }
0063 
0064     return v->mouseOnSelectionResizeHandle (currentViewPoint ());
0065 }
0066 
0067 //---------------------------------------------------------------------
0068 
0069 // private
0070 void kpAbstractSelectionTool::initResizeScale ()
0071 {
0072     d->currentResizeScaleCommand = nullptr;
0073 
0074    // d->resizeScaleType
0075 }
0076 
0077 // private
0078 void kpAbstractSelectionTool::uninitResizeScale ()
0079 {
0080     // (state must be after construction, or after some time after endResizeScale())
0081     Q_ASSERT (!d->currentResizeScaleCommand);
0082 
0083     // d->resizeScaleType
0084 }
0085 
0086 
0087 // private
0088 void kpAbstractSelectionTool::beginResizeScale ()
0089 {
0090     // (state must be after construction, or after some time after endResizeScale())
0091     Q_ASSERT (!d->currentResizeScaleCommand);
0092 
0093     // d->resizeScaleType
0094 }
0095 
0096 // private
0097 void kpAbstractSelectionTool::endResizeScale ()
0098 {
0099     // (should have been killed by cancelResizeScale() or endResizeScale())
0100     Q_ASSERT (!d->currentResizeScaleCommand);
0101 
0102     // d->resizeScaleType
0103 }
0104 
0105 //---------------------------------------------------------------------
0106 
0107 // private
0108 void kpAbstractSelectionTool::setCursorResizeScale ()
0109 {
0110 #if DEBUG_KP_TOOL_SELECTION && 0
0111     qCDebug(kpLogTools) << "\tonSelectionResizeHandle="
0112                 << onSelectionResizeHandle ();
0113 #endif
0114     Qt::CursorShape shape = Qt::ArrowCursor;
0115 
0116     switch (onSelectionResizeHandle ())
0117     {
0118     case (kpView::Top | kpView::Left):
0119     case (kpView::Bottom | kpView::Right):
0120         shape = Qt::SizeFDiagCursor;
0121         break;
0122 
0123     case (kpView::Bottom | kpView::Left):
0124     case (kpView::Top | kpView::Right):
0125         shape = Qt::SizeBDiagCursor;
0126         break;
0127 
0128     case kpView::Top:
0129     case kpView::Bottom:
0130         shape = Qt::SizeVerCursor;
0131         break;
0132 
0133     case kpView::Left:
0134     case kpView::Right:
0135         shape = Qt::SizeHorCursor;
0136         break;
0137     }
0138 
0139     viewManager ()->setCursor (shape);
0140 }
0141 
0142 //---------------------------------------------------------------------
0143 
0144 // protected virtual
0145 void kpAbstractSelectionTool::setSelectionBorderForBeginDrawResizeScale ()
0146 {
0147     viewManager ()->setQueueUpdates ();
0148     {
0149         viewManager ()->setSelectionBorderVisible (true);
0150         viewManager ()->setSelectionBorderFinished (true);
0151     }
0152     viewManager ()->restoreQueueUpdates ();
0153 }
0154 
0155 //---------------------------------------------------------------------
0156 
0157 // private
0158 void kpAbstractSelectionTool::beginDrawResizeScale ()
0159 {
0160     d->resizeScaleType = onSelectionResizeHandle ();
0161 
0162     /*virtual*/setSelectionBorderForBeginDrawResizeScale ();
0163 
0164     setUserMessage (cancelUserMessage ());
0165 }
0166 
0167 //---------------------------------------------------------------------
0168 
0169 
0170 // private
0171 void kpAbstractSelectionTool::drawResizeScaleTryKeepAspect (
0172         int newWidth, int newHeight,
0173         bool horizontalGripDragged, bool verticalGripDragged,
0174         const kpAbstractSelection &originalSelection,
0175         int *newWidthOut, int *newHeightOut)
0176 {
0177     const int oldWidth = originalSelection.width (),
0178         oldHeight = originalSelection.height ();
0179 
0180     // Width changed more than height?  At equality, favor width.
0181     // Fix width, change height.
0182     //
0183     // We use <horizontalGripDragged> and <verticalGripDragged> to prevent
0184     // e.g. the situation where we've dragged such that newWidth < oldWidth but
0185     // we're not dragging a vertical grip.  We certainly don't want this
0186     // code to modify the width - we want to fix the width and change the
0187     // height.
0188     if ((horizontalGripDragged ? double (newWidth) / oldWidth : 0) >=
0189         (verticalGripDragged ? double (newHeight) / oldHeight : 0))
0190     {
0191         *newHeightOut = newWidth * oldHeight / oldWidth;
0192         *newHeightOut = qMax (originalSelection.minimumHeight (), *newHeightOut);
0193     }
0194     // Height changed more than width?
0195     // Fix height, change width.
0196     else
0197     {
0198         *newWidthOut = newHeight * oldWidth / oldHeight;
0199         *newWidthOut = qMax (originalSelection.minimumWidth (), *newWidthOut);
0200     }
0201 }
0202 
0203 //---------------------------------------------------------------------
0204 
0205 // private
0206 void kpAbstractSelectionTool::drawResizeScaleCalculateNewSelectionPosSize (
0207         const kpAbstractSelection &originalSelection,
0208         int *newX, int *newY,
0209         int *newWidth, int *newHeight)
0210 {
0211     //
0212     // Determine new width.
0213     //
0214 
0215     // Dragging left or right grip?
0216     // If left, positive X drags decrease width.
0217     // If right, positive X drags increase width.
0218     int userXSign = 0;
0219     if (d->resizeScaleType & kpView::Left) {
0220         userXSign = -1;
0221     }
0222     else if (d->resizeScaleType & kpView::Right) {
0223         userXSign = +1;
0224     }
0225 
0226     // Calculate new width.
0227     *newWidth = originalSelection.width () +
0228         userXSign * (currentPoint ().x () - startPoint ().x ());
0229 
0230     // Don't allow new width to be less than that kind of selection type's
0231     // minimum.
0232     *newWidth = qMax (originalSelection.minimumWidth (), *newWidth);
0233 
0234 
0235     //
0236     // Determine new height.
0237     //
0238 
0239     // Dragging top or bottom grip?
0240     // If top, positive Y drags decrease height.
0241     // If bottom, positive Y drags increase height.
0242     int userYSign = 0;
0243     if (d->resizeScaleType & kpView::Top) {
0244         userYSign = -1;
0245     }
0246     else if (d->resizeScaleType & kpView::Bottom) {
0247         userYSign = +1;
0248     }
0249 
0250     // Calculate new height.
0251     *newHeight = originalSelection.height () +
0252         userYSign * (currentPoint ().y () - startPoint ().y ());
0253 
0254     // Don't allow new height to be less than that kind of selection type's
0255     // minimum.
0256     *newHeight = qMax (originalSelection.minimumHeight (), *newHeight);
0257 
0258 
0259     // Keep aspect ratio?
0260     if (shiftPressed ())
0261     {
0262         drawResizeScaleTryKeepAspect (*newWidth, *newHeight,
0263             (userXSign != 0)/*X or XY grip dragged*/,
0264                 (userYSign != 0)/*Y or XY grip dragged*/,
0265             originalSelection,
0266             newWidth/*ptr*/, newHeight/*ptr*/);
0267     }
0268 
0269 
0270     *newX = originalSelection.x ();
0271     *newY = originalSelection.y ();
0272 
0273 
0274     //
0275     // Adjust x/y to new width/height for left/top resizes.
0276     //
0277 
0278     if (d->resizeScaleType & kpView::Left)
0279     {
0280         *newX -= (*newWidth - originalSelection.width ());
0281     }
0282 
0283     if (d->resizeScaleType & kpView::Top)
0284     {
0285         *newY -= (*newHeight - originalSelection.height ());
0286     }
0287 
0288 #if DEBUG_KP_TOOL_SELECTION && 1
0289     qCDebug(kpLogTools) << "\t\tnewX=" << *newX
0290                 << " newY=" << *newY
0291                 << " newWidth=" << *newWidth
0292                 << " newHeight=" << *newHeight;
0293 #endif
0294 }
0295 
0296 //---------------------------------------------------------------------
0297 
0298 // private
0299 void kpAbstractSelectionTool::drawResizeScale (
0300         const QPoint &thisPoint,
0301         const QRect &/*normalizedRect*/)
0302 {
0303 #if DEBUG_KP_TOOL_SELECTION && 1
0304     qCDebug(kpLogTools) << "\tresize/scale";
0305 #endif
0306 
0307     kpAbstractSelection *sel = document ()->selection ();
0308 
0309     if (!d->dragAccepted && thisPoint == startPoint ())
0310     {
0311     #if DEBUG_KP_TOOL_SELECTION && 1
0312         qCDebug(kpLogTools) << "\t\tnop";
0313     #endif
0314 
0315         setUserShapePoints (QPoint (sel->width (), sel->height ()));
0316         return;
0317     }
0318 
0319 
0320     giveContentIfNeeded ();
0321 
0322 
0323     if (!d->currentResizeScaleCommand)
0324     {
0325         d->currentResizeScaleCommand
0326             = new kpToolSelectionResizeScaleCommand (environ ()->commandEnvironment ());
0327     }
0328 
0329 
0330     const kpAbstractSelection *originalSelection =
0331         d->currentResizeScaleCommand->originalSelection ();
0332 
0333 
0334     // There is nothing illegal about position (-1,-1) but why not.
0335     int newX = -1, newY = -1,
0336         newWidth = 0, newHeight = 0;
0337 
0338     // This should change all of the above values.
0339     drawResizeScaleCalculateNewSelectionPosSize (
0340         *originalSelection,
0341         &newX, &newY,
0342         &newWidth, &newHeight);
0343 
0344 
0345     viewManager ()->setFastUpdates ();
0346     {
0347         d->currentResizeScaleCommand->resizeAndMoveTo (
0348             newWidth, newHeight,
0349             QPoint (newX, newY),
0350             true/*smooth scale delayed*/);
0351     }
0352     viewManager ()->restoreFastUpdates ();
0353 
0354     setUserShapePoints (QPoint (originalSelection->width (),
0355                                 originalSelection->height ()),
0356                         QPoint (newWidth,
0357                                 newHeight),
0358                         false/*don't set size*/);
0359     setUserShapeSize (newWidth - originalSelection->width (),
0360                         newHeight - originalSelection->height ());
0361 
0362 
0363     d->dragAccepted = true;
0364 }
0365 
0366 //---------------------------------------------------------------------
0367 
0368 
0369 // private
0370 void kpAbstractSelectionTool::cancelResizeScale ()
0371 {
0372 #if DEBUG_KP_TOOL_SELECTION
0373     qCDebug(kpLogTools) << "\twas resize/scale sel - kill";
0374 #endif
0375 
0376     // NOP drag?
0377     if (!d->currentResizeScaleCommand) {
0378         return;
0379     }
0380 
0381 #if DEBUG_KP_TOOL_SELECTION
0382     qCDebug(kpLogTools) << "\t\tundo currentResizeScaleCommand";
0383 #endif
0384     d->currentResizeScaleCommand->finalize ();  // (unneeded but let's be safe)
0385     d->currentResizeScaleCommand->unexecute ();
0386     delete d->currentResizeScaleCommand;
0387     d->currentResizeScaleCommand = nullptr;
0388 }
0389 
0390 //---------------------------------------------------------------------
0391 
0392 // private
0393 void kpAbstractSelectionTool::endDrawResizeScale ()
0394 {
0395     // NOP drag?
0396     if (!d->currentResizeScaleCommand) {
0397         return;
0398     }
0399 
0400     d->currentResizeScaleCommand->finalize ();
0401 
0402     addNeedingContentCommand (d->currentResizeScaleCommand);
0403     d->currentResizeScaleCommand = nullptr;
0404 }
0405 
0406 //---------------------------------------------------------------------
0407 
0408 // private
0409 QVariant kpAbstractSelectionTool::operationResizeScale (Operation op,
0410         const QVariant &data1, const QVariant &data2)
0411 {
0412     (void) data1;
0413     (void) data2;
0414 
0415 
0416     switch (op)
0417     {
0418     case HaventBegunDrawUserMessage:
0419         return /*virtual*/haventBegunDrawUserMessageResizeScale ();
0420 
0421     case SetCursor:
0422         setCursorResizeScale ();
0423         break;
0424 
0425     case BeginDraw:
0426         beginDrawResizeScale ();
0427         break;
0428 
0429     case Draw:
0430         drawResizeScale (currentPoint (), normalizedRect ());
0431         break;
0432 
0433     case Cancel:
0434         cancelResizeScale ();
0435         break;
0436 
0437     case EndDraw:
0438         endDrawResizeScale ();
0439         break;
0440 
0441     default:
0442         Q_ASSERT (!"Unhandled operation");
0443         break;
0444     }
0445 
0446 
0447     return {};
0448 }
0449 
0450 //---------------------------------------------------------------------