1 
2 /*
3    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
4    All rights reserved.
5 
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9 
10    1. Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15 
16    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 
29 #define DEBUG_KP_TOOL_SELECTION 0
30 
31 
32 #include "kpAbstractSelectionTool.h"
33 #include "kpAbstractSelectionToolPrivate.h"
34 #include "kpLogCategories.h"
35 #include "layers/selections/image/kpAbstractImageSelection.h"
36 #include "layers/selections/kpAbstractSelection.h"
37 #include "commands/kpCommandHistory.h"
38 #include "kpDefs.h"
39 #include "document/kpDocument.h"
40 #include "commands/kpMacroCommand.h"
41 #include "commands/tools/selection/kpToolSelectionCreateCommand.h"
42 #include "commands/tools/selection/kpToolSelectionDestroyCommand.h"
43 #include "environments/tools/selection/kpToolSelectionEnvironment.h"
44 #include "commands/tools/selection/kpToolSelectionMoveCommand.h"
45 #include "commands/tools/selection/kpToolSelectionResizeScaleCommand.h"
46 #include "commands/tools/selection/kpToolImageSelectionTransparencyCommand.h"
47 #include "widgets/toolbars/kpToolToolBar.h"
48 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h"
49 #include "views/kpView.h"
50 #include "views/manager/kpViewManager.h"
51 
52 #include <QTimer>
53 
54 #include <KLocalizedString>
55 
56 //---------------------------------------------------------------------
57 
58 // private
initMove()59 void kpAbstractSelectionTool::initMove ()
60 {
61     d->currentMoveCommand = nullptr;
62 
63     // d->currentMoveCommandIsSmear
64 
65     // d->startMoveDragFromSelectionTopLeft
66 
67     d->RMBMoveUpdateGUITimer = new QTimer (this);
68     d->RMBMoveUpdateGUITimer->setSingleShot (true);
69     connect (d->RMBMoveUpdateGUITimer, &QTimer::timeout,
70              this, &kpAbstractSelectionTool::slotRMBMoveUpdateGUI);
71 }
72 
73 //---------------------------------------------------------------------
74 
75 // private
uninitMove()76 void kpAbstractSelectionTool::uninitMove ()
77 {
78     // (state must be after construction, or after some time after endMove())
79     Q_ASSERT (!d->currentMoveCommand);
80 
81     // d->currentMoveCommandIsSmear
82 
83     // d->startMoveDragFromSelectionTopLeft
84 
85     // d->RMBMoveUpdateGUITimer (deleted by QObject mechanism)
86 }
87 
88 //---------------------------------------------------------------------
89 
90 // private
beginMove()91 void kpAbstractSelectionTool::beginMove ()
92 {
93     // (state must be after construction, or after some time after endMove())
94     Q_ASSERT (!d->currentMoveCommand);
95 
96     // d->currentMoveCommandIsSmear
97 
98     // d->startMoveDragFromSelectionTopLeft;
99 
100     // d->RMBMoveUpdateGUITimer
101 }
102 
103 //---------------------------------------------------------------------
104 
105 // private
endMove()106 void kpAbstractSelectionTool::endMove ()
107 {
108     // (should have been killed by cancelMove() or endDrawMove())
109     Q_ASSERT (!d->currentMoveCommand);
110 
111     // d->currentMoveCommandIsSmear
112 
113     // d->startMoveDragFromSelectionTopLeft
114 
115     // d->RMBMoveUpdateGUITimer
116 }
117 
118 //---------------------------------------------------------------------
119 
120 // private
setCursorMove()121 void kpAbstractSelectionTool::setCursorMove ()
122 {
123     viewManager ()->setCursor (Qt::SizeAllCursor);
124 }
125 
126 //---------------------------------------------------------------------
127 
128 // protected virtual
setSelectionBorderForBeginDrawMove()129 void kpAbstractSelectionTool::setSelectionBorderForBeginDrawMove ()
130 {
131     // don't show border while moving
132     viewManager ()->setQueueUpdates ();
133     {
134         viewManager ()->setSelectionBorderVisible (false);
135         viewManager ()->setSelectionBorderFinished (true);
136     }
137     viewManager ()->restoreQueueUpdates ();
138 }
139 
140 //---------------------------------------------------------------------
141 
142 // private
beginDrawMove()143 void kpAbstractSelectionTool::beginDrawMove ()
144 {
145     d->startMoveDragFromSelectionTopLeft =
146         currentPoint () - document ()->selection ()->topLeft ();
147 
148     if (mouseButton () == 0)
149     {
150         /*virtual*/setSelectionBorderForBeginDrawMove ();
151     }
152     else
153     {
154         // Don't hide sel border momentarily if user is just
155         // right _clicking_ selection.
156         // (single shot timer)
157         d->RMBMoveUpdateGUITimer->start (100/*ms*/);
158     }
159 
160     setUserMessage (cancelUserMessage ());
161 }
162 
163 //---------------------------------------------------------------------
164 
165 // private slot
slotRMBMoveUpdateGUI()166 void kpAbstractSelectionTool::slotRMBMoveUpdateGUI ()
167 {
168     // (just in case not called from single shot)
169     d->RMBMoveUpdateGUITimer->stop ();
170 
171     /*virtual*/setSelectionBorderForBeginDrawMove ();
172 
173     kpAbstractSelection * const sel = document ()->selection ();
174     if (sel) {
175         setUserShapePoints (sel->topLeft ());
176     }
177 }
178 
179 //---------------------------------------------------------------------
180 
181 // private
drawMove(const QPoint & thisPoint,const QRect &)182 void kpAbstractSelectionTool::drawMove (const QPoint &thisPoint, const QRect &/*normalizedRect*/)
183 {
184 #if DEBUG_KP_TOOL_SELECTION && 1
185     qCDebug(kpLogTools) << "\tmoving selection";
186 #endif
187 
188     kpAbstractSelection *sel = document ()->selection ();
189 
190     QRect targetSelRect (thisPoint.x () - d->startMoveDragFromSelectionTopLeft.x (),
191         thisPoint.y () - d->startMoveDragFromSelectionTopLeft.y (),
192         sel->width (),
193         sel->height ());
194 
195 #if DEBUG_KP_TOOL_SELECTION && 1
196     qCDebug(kpLogTools) << "\t\tstartPoint=" << startPoint ()
197                 << " thisPoint=" << thisPoint
198                 << " startDragFromSel=" << d->startMoveDragFromSelectionTopLeft
199                 << " targetSelRect=" << targetSelRect;
200 #endif
201 
202     // Try to make sure selection still intersects document so that it's
203     // reachable.
204 
205     if (targetSelRect.right () < 0) {
206         targetSelRect.translate (-targetSelRect.right (), 0);
207     }
208     else if (targetSelRect.left () >= document ()->width ()) {
209         targetSelRect.translate (document ()->width () - targetSelRect.left () - 1, 0);
210     }
211 
212     if (targetSelRect.bottom () < 0) {
213         targetSelRect.translate (0, -targetSelRect.bottom ());
214     }
215     else if (targetSelRect.top () >= document ()->height ()) {
216         targetSelRect.translate (0, document ()->height () - targetSelRect.top () - 1);
217     }
218 
219 #if DEBUG_KP_TOOL_SELECTION && 1
220     qCDebug(kpLogTools) << "\t\t\tafter ensure sel rect clickable=" << targetSelRect;
221 #endif
222 
223 
224     if (!d->dragAccepted &&
225         targetSelRect.topLeft () + d->startMoveDragFromSelectionTopLeft == startPoint ())
226     {
227     #if DEBUG_KP_TOOL_SELECTION && 1
228         qCDebug(kpLogTools) << "\t\t\t\tnop";
229     #endif
230 
231 
232         if (!d->RMBMoveUpdateGUITimer->isActive ())
233         {
234             // (slotRMBMoveUpdateGUI() calls similar line)
235             setUserShapePoints (sel->topLeft ());
236         }
237 
238         // Prevent both NOP drag-moves
239         return;
240     }
241 
242 
243     if (d->RMBMoveUpdateGUITimer->isActive ())
244     {
245         d->RMBMoveUpdateGUITimer->stop ();
246         slotRMBMoveUpdateGUI ();
247     }
248 
249 
250     giveContentIfNeeded ();
251 
252 
253     if (!d->currentMoveCommand)
254     {
255         d->currentMoveCommand = new kpToolSelectionMoveCommand (
256             QString()/*uninteresting child of macro cmd*/,
257             environ ()->commandEnvironment ());
258         d->currentMoveCommandIsSmear = false;
259     }
260 
261 
262     //viewManager ()->setQueueUpdates ();
263     //viewManager ()->setFastUpdates ();
264 
265     if (shiftPressed ()) {
266         d->currentMoveCommandIsSmear = true;
267     }
268 
269     if (!d->dragAccepted && (controlPressed () || shiftPressed ())) {
270         d->currentMoveCommand->copyOntoDocument ();
271     }
272 
273     d->currentMoveCommand->moveTo (targetSelRect.topLeft ());
274 
275     if (shiftPressed ()) {
276         d->currentMoveCommand->copyOntoDocument ();
277     }
278 
279     //viewManager ()->restoreFastUpdates ();
280     //viewManager ()->restoreQueueUpdates ();
281 
282     // REFACTOR: yuck, yuck
283     kpAbstractSelection *orgSel = d->currentMoveCommand->originalSelectionClone ();
284     QPoint start = orgSel->topLeft ();
285     delete orgSel;
286     QPoint end = targetSelRect.topLeft ();
287     setUserShapePoints (start, end, false/*don't set size*/);
288     setUserShapeSize (end.x () - start.x (), end.y () - start.y ());
289 
290 
291     d->dragAccepted = true;
292 }
293 
294 //---------------------------------------------------------------------
295 
296 // private
cancelMove()297 void kpAbstractSelectionTool::cancelMove ()
298 {
299 #if DEBUG_KP_TOOL_SELECTION
300     qCDebug(kpLogTools) << "\twas drag moving - undo drag and undo acquire";
301 #endif
302 
303     d->RMBMoveUpdateGUITimer->stop ();
304 
305     // NOP drag?
306     if (!d->currentMoveCommand) {
307         return;
308     }
309 
310 #if DEBUG_KP_TOOL_SELECTION
311     qCDebug(kpLogTools) << "\t\tundo currentMoveCommand";
312 #endif
313     d->currentMoveCommand->finalize ();
314     d->currentMoveCommand->unexecute ();
315     delete d->currentMoveCommand;
316     d->currentMoveCommand = nullptr;
317 }
318 
319 //---------------------------------------------------------------------
320 
321 // protected virtual
nonSmearMoveCommandName() const322 QString kpAbstractSelectionTool::nonSmearMoveCommandName () const
323 {
324     return i18n ("Selection: Move");
325 }
326 
327 //---------------------------------------------------------------------
328 
329 // private
endDrawMove()330 void kpAbstractSelectionTool::endDrawMove ()
331 {
332     d->RMBMoveUpdateGUITimer->stop ();
333 
334     // NOP drag?
335     if (!d->currentMoveCommand) {
336         return;
337     }
338 
339     d->currentMoveCommand->finalize ();
340 
341     kpMacroCommand *renamedCmd = nullptr;
342 #if DEBUG_KP_TOOL_SELECTION
343     qCDebug(kpLogTools) << "\thave moveCommand";
344 #endif
345     if (d->currentMoveCommandIsSmear)
346     {
347         renamedCmd = new kpMacroCommand (i18n ("%1: Smear",
348             document ()->selection ()->name ()),
349             environ ()->commandEnvironment ());
350     }
351     else
352     {
353         renamedCmd = new kpMacroCommand (
354             /*virtual*/nonSmearMoveCommandName (),
355             environ ()->commandEnvironment ());
356     }
357 
358     renamedCmd->addCommand (d->currentMoveCommand);
359     d->currentMoveCommand = nullptr;
360 
361     addNeedingContentCommand (renamedCmd);
362 }
363 
364 //---------------------------------------------------------------------
365 
366 // private
operationMove(Operation op,const QVariant & data1,const QVariant & data2)367 QVariant kpAbstractSelectionTool::operationMove (Operation op,
368         const QVariant &data1, const QVariant &data2)
369 {
370     (void) data1;
371     (void) data2;
372 
373 
374     switch (op)
375     {
376     case HaventBegunDrawUserMessage:
377         return /*virtual*/haventBegunDrawUserMessageMove ();
378 
379     case SetCursor:
380         setCursorMove ();
381         break;
382 
383     case BeginDraw:
384         beginDrawMove ();
385         break;
386 
387     case Draw:
388         drawMove (currentPoint (), normalizedRect ());
389         break;
390 
391     case Cancel:
392         cancelMove ();
393         break;
394 
395     case EndDraw:
396         endDrawMove ();
397         break;
398 
399     default:
400         Q_ASSERT (!"Unhandled operation");
401         break;
402     }
403 
404     return {};
405 }
406 
407 //---------------------------------------------------------------------
408