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