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 }