1 #include "nodeeditcontext.h"
2 #include "pageitem.h"
3 #include "scribusdoc.h"
4 #include "undomanager.h"
5 #include "util_math.h"
6
NodeEditContext()7 NodeEditContext::NodeEditContext() :
8 nodeTransaction(nullptr)
9 {
10 }
11
hasNodeSelected() const12 bool NodeEditContext::hasNodeSelected() const
13 {
14 return m_ClRe != -1;
15 }
16
deselect()17 void NodeEditContext::deselect()
18 {
19 m_ClRe = -1;
20 m_SelNode.clear();
21 }
22
selectNode(int i)23 void NodeEditContext::selectNode(int i)
24 {
25 m_ClRe = i;
26 m_SelNode.append(i);
27 }
28
selectionCount() const29 int NodeEditContext::selectionCount() const
30 {
31 return m_SelNode.count();
32 }
33
reset()34 void NodeEditContext::reset()
35 {
36 m_submode = MOVE_POINT;
37 m_isContourLine = false;
38 m_ClRe = -1;
39 m_ClRe2 = -1;
40 m_SegP1 = -1;
41 m_SegP2 = -1;
42 delete oldClip;
43 oldClip = nullptr;
44 nodeTransaction.reset();
45 m_MoveSym = false;
46 m_SelNode.clear();
47 m_preview = false;
48 }
49
setPreviewMode(bool mode)50 void NodeEditContext::setPreviewMode(bool mode)
51 {
52 m_preview = mode;
53 }
54
beginTransaction(PageItem * currItem)55 FPointArray NodeEditContext::beginTransaction(PageItem* currItem)
56 {
57 ScribusDoc* Doc = currItem->doc();
58 UndoManager* undoManager = UndoManager::instance();
59
60 FPointArray Clip;
61 QString uAction;
62 if (Doc->nodeEdit.m_isContourLine)
63 {
64 Clip = currItem->ContourLine;
65 uAction = Um::EditContour;
66 }
67 else
68 {
69 Clip = currItem->PoLine;
70 uAction = Um::EditShape;
71 }
72
73 if (nodeTransaction)
74 return (oldClip ? FPointArray(*oldClip) : Clip);
75
76 delete oldClip;
77 oldClip = new FPointArray(Clip);
78
79 m_oldItemX = currItem->xPos();
80 m_oldItemY = currItem->yPos();
81 if (UndoManager::undoEnabled())
82 nodeTransaction = undoManager->beginTransaction(currItem->getUName(), currItem->getUPixmap(), uAction);
83 return Clip;
84 }
85
86
87
finishTransaction(PageItem * currItem)88 void NodeEditContext::finishTransaction(PageItem* currItem)
89 {
90 ScribusDoc* Doc = currItem->doc();
91 UndoManager* undoManager = UndoManager::instance();
92 ScItemState<QPair<FPointArray, FPointArray> >* state = nullptr;
93
94 if (nodeTransaction.isNull()) // is there the old clip stored for the undo action
95 return;
96
97 FPointArray newClip(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine : currItem->PoLine);
98 if (UndoManager::undoEnabled() && oldClip && (*oldClip != newClip))
99 {
100 QString name = Doc->nodeEdit.m_isContourLine ? Um::EditContour : Um::EditShape;
101 state = new ScItemState<QPair<FPointArray, FPointArray> >(name);
102 state->set("EDIT_SHAPE_OR_CONTOUR");
103 state->set("IS_CONTOUR", Doc->nodeEdit.m_isContourLine);
104 state->setItem(qMakePair(*oldClip, newClip));
105 state->set("OLD_X", m_oldItemX);
106 state->set("OLD_Y", m_oldItemY);
107 state->set("NEW_X", currItem->xPos());
108 state->set("NEW_Y", currItem->yPos());
109 undoManager->action(currItem, state);
110 nodeTransaction.commit();
111 }
112 else
113 nodeTransaction.cancel();
114
115 nodeTransaction.reset();
116 delete oldClip;
117 oldClip = nullptr;
118 }
119
120
121 /**
122 first part: create a new UndoState or cancel the current transaction
123 */
finishTransaction1(PageItem * currItem)124 ScItemState<QPair<FPointArray, FPointArray> >* NodeEditContext::finishTransaction1(PageItem* currItem)
125 {
126 ScribusDoc* Doc = currItem->doc();
127 UndoManager* undoManager = UndoManager::instance();
128 ScItemState<QPair<FPointArray, FPointArray> >* state = nullptr;
129
130 if (nodeTransaction.isNull()) // is there the old clip stored for the undo action
131 return nullptr;
132
133 FPointArray newClip(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine : currItem->PoLine);
134 if (UndoManager::undoEnabled() && oldClip && (*oldClip != newClip))
135 {
136 QString name = Doc->nodeEdit.m_isContourLine ? Um::EditContour : Um::EditShape;
137 state = new ScItemState<QPair<FPointArray, FPointArray> >(name);
138 state->set("EDIT_SHAPE_OR_CONTOUR");
139 state->set("IS_CONTOUR", Doc->nodeEdit.m_isContourLine);
140 state->setItem(qMakePair(*oldClip, newClip));
141 undoManager->setUndoEnabled(false);
142 }
143 else
144 {
145 delete oldClip;
146 oldClip = nullptr;
147 nodeTransaction.cancel();
148 nodeTransaction.reset();
149 }
150 return state;
151 }
152
153 /**
154 second part: take the UndoState returned from finishTransaction1() and commit it
155 */
finishTransaction2(PageItem * currItem,ScItemState<QPair<FPointArray,FPointArray>> * state)156 void NodeEditContext::finishTransaction2(PageItem* currItem, ScItemState<QPair<FPointArray, FPointArray> >* state)
157 {
158 UndoManager* undoManager = UndoManager::instance();
159
160 state->set("OLD_X", m_oldItemX);
161 state->set("OLD_Y", m_oldItemY);
162 state->set("NEW_X", currItem->xPos());
163 state->set("NEW_Y", currItem->yPos());
164 undoManager->setUndoEnabled(true);
165 undoManager->action(currItem, state);
166 nodeTransaction.commit();
167 nodeTransaction.reset();
168 delete oldClip;
169 oldClip = nullptr;
170 }
171
172
173 //CB-->Doc
moveClipPoint(PageItem * currItem,const FPoint & ip)174 void NodeEditContext::moveClipPoint(PageItem *currItem, const FPoint& ip)
175 {
176 ScribusDoc* Doc = currItem->doc();
177 if (((m_EdPoints) && (m_ClRe % 2 != 0)) || ((!m_EdPoints) && (m_ClRe % 2 == 0)))
178 return;
179 double xposOrig = currItem->xPos();
180 double yposOrig = currItem->yPos();
181 currItem->ClipEdited = true;
182 FPointArray Clip;
183 if (m_isContourLine)
184 Clip = currItem->ContourLine.copy();
185 else
186 Clip = currItem->PoLine.copy();
187 currItem->FrameType = 3;
188 uint EndInd = Clip.size();
189 uint StartInd = 0;
190 for (int n = m_ClRe; n < Clip.size(); ++n)
191 {
192 if (Clip.isMarker(n))
193 {
194 EndInd = n;
195 break;
196 }
197 }
198 if (m_ClRe > 0)
199 {
200 for (int n2 = m_ClRe; n2 > 0; n2--)
201 {
202 if (Clip.isMarker(n2))
203 {
204 StartInd = n2 + 1;
205 break;
206 }
207 }
208 }
209 FPoint np(ip);
210 if (hasNodeSelected())
211 {
212 if ((np.x() < 0) && (!m_isContourLine) && (!(currItem->isGroup() || currItem->isSymbol())))
213 {
214 Doc->sizeItem(currItem->width() - np.x(), currItem->height(), currItem, false, false, false);
215 if (currItem->rotation() != 0)
216 {
217 FPoint npv(np.x(), 0);
218 Doc->moveRotated(currItem, npv);
219 }
220 else
221 Doc->moveItem(np.x(), 0, currItem);
222 Clip.translate(-np.x(), 0);
223 if (!currItem->imageFlippedH())
224 currItem->moveImageInFrame(-np.x()/currItem->imageXScale(), 0);
225 np.setX(0);
226 }
227 if ((np.y() < 0) && (!m_isContourLine) && (!(currItem->isGroup() || currItem->isSymbol())))
228 {
229 Doc->sizeItem(currItem->width(), currItem->height() - np.y(), currItem, false, false, false);
230 if (currItem->rotation() != 0)
231 {
232 FPoint npv(0, np.y());
233 Doc->moveRotated(currItem, npv);
234 }
235 else
236 Doc->moveItem(0, np.y(), currItem);
237 Clip.translate(0, -np.y());
238 if (!currItem->imageFlippedV())
239 currItem->moveImageInFrame(0, -np.y()/currItem->imageYScale());
240 np.setY(0);
241 }
242 update(QPointF(np.x(), np.y()));
243 if ((m_ClRe + 1 < static_cast<int>(EndInd)) && (m_ClRe % 2 == 0))
244 {
245 FPoint ap(Clip.point(m_ClRe));
246 FPoint ap2(Clip.point(m_ClRe + 1));
247 ap2.setX(ap2.x() - (ap.x() - np.x()));
248 ap2.setY(ap2.y() - (ap.y() - np.y()));
249 Clip.setPoint(m_ClRe + 1, ap2);
250 }
251 Clip.setPoint(m_ClRe, np);
252 if (((m_ClRe % 4 != 0) && (m_ClRe % 2 == 0)) && (m_ClRe + 3 < static_cast<int>(EndInd)) && (m_ClRe != static_cast<int>(StartInd)))
253 {
254 FPoint ap(Clip.point(m_ClRe + 2));
255 FPoint ap2(Clip.point(m_ClRe + 3));
256 ap2.setX(ap2.x() - (ap.x() - np.x()));
257 ap2.setY(ap2.y() - (ap.y() - np.y()));
258 Clip.setPoint(m_ClRe + 3, ap2);
259 Clip.setPoint(m_ClRe + 2, np);
260 }
261 if ((m_ClRe % 4 == 0) && (m_ClRe + 3 < static_cast<int>(EndInd)) && (m_ClRe != static_cast<int>(StartInd)))
262 {
263 FPoint ap(Clip.point(m_ClRe - 2));
264 FPoint ap2(Clip.point(m_ClRe - 1));
265 ap2.setX(ap2.x() - (ap.x() - np.x()));
266 ap2.setY(ap2.y() - (ap.y() - np.y()));
267 Clip.setPoint(m_ClRe - 1, ap2);
268 Clip.setPoint(m_ClRe - 2, np);
269 }
270 if (((m_ClRe == static_cast<int>(StartInd)) || (m_ClRe == static_cast<int>(EndInd - 2))) &&
271 ((currItem->itemType() == PageItem::Polygon)
272 || (currItem->itemType() == PageItem::Group)
273 || (currItem->itemType() == PageItem::Symbol)
274 || (currItem->itemType() == PageItem::TextFrame)
275 || (currItem->itemType() == PageItem::ImageFrame)))
276 {
277 if (m_ClRe == static_cast<int>(StartInd))
278 {
279 FPoint ap(Clip.point(EndInd- 2));
280 FPoint ap2(Clip.point(EndInd - 1));
281 ap2.setX(ap2.x() - (ap.x() - np.x()));
282 ap2.setY(ap2.y() - (ap.y() - np.y()));
283 Clip.setPoint(EndInd - 2, Clip.point(StartInd));
284 Clip.setPoint(EndInd - 1, ap2);
285 }
286 else
287 {
288 FPoint ap(Clip.point(StartInd));
289 FPoint ap2(Clip.point(StartInd + 1));
290 ap2.setX(ap2.x() - (ap.x() - np.x()));
291 ap2.setY(ap2.y() - (ap.y() - np.y()));
292 Clip.setPoint(StartInd, Clip.point(EndInd - 2));
293 Clip.setPoint(StartInd + 1, ap2);
294 }
295 }
296 if (((m_ClRe == static_cast<int>(StartInd + 1)) || (m_ClRe == static_cast<int>(EndInd - 1))) &&
297 ((currItem->itemType() == PageItem::Polygon)
298 || (currItem->itemType() == PageItem::Group)
299 || (currItem->itemType() == PageItem::Symbol)
300 || (currItem->itemType() == PageItem::TextFrame)
301 || (currItem->itemType() == PageItem::ImageFrame)) &&
302 (m_MoveSym))
303 {
304 uint kon = 0;
305 if (m_ClRe == static_cast<int>(StartInd + 1))
306 kon = EndInd - 1;
307 else
308 kon = StartInd + 1;
309 FPoint lxy(Clip.point(m_ClRe - 1));
310 FPoint lk(Clip.point(m_ClRe));
311 double dx = lxy.x() - lk.x();
312 double dy = lxy.y() - lk.y();
313 lk.setX(lk.x() + dx * 2);
314 lk.setY(lk.y() + dy * 2);
315 Clip.setPoint(kon, lk);
316 }
317 if ((m_ClRe % 2 != 0) && (m_MoveSym) && (m_ClRe != static_cast<int>(StartInd + 1)) && (m_ClRe != static_cast<int>(EndInd - 1)))
318 {
319 uint kon = 0;
320 if ((m_ClRe + 1) % 4 == 0)
321 kon = m_ClRe + 2;
322 else
323 kon = m_ClRe - 2;
324 FPoint lxy(Clip.point(m_ClRe - 1));
325 FPoint lk(Clip.point(m_ClRe));
326 double dx = lxy.x() - lk.x();
327 double dy = lxy.y() - lk.y();
328 lk.setX(lk.x() + dx * 2);
329 lk.setY(lk.y() + dy * 2);
330 Clip.setPoint(kon, lk);
331 }
332 if (Doc->nodeEdit.m_isContourLine)
333 currItem->ContourLine = Clip.copy();
334 else
335 currItem->PoLine = Clip.copy();
336 currItem->Clip = flattenPath(currItem->PoLine, currItem->Segments);
337 }
338 if (!m_isContourLine)
339 {
340 // Move the contour accordingly in the item's coordinate space
341 QTransform m = QTransform().rotate(-currItem->rotation());
342 QPointF delta = m.map(QPointF(xposOrig, yposOrig)) - m.map(QPointF(currItem->xPos(), currItem->yPos()));
343 currItem->ContourLine.translate(delta.x(), delta.y());
344 }
345 }
346
347
reset1Control(PageItem * currItem)348 void NodeEditContext::reset1Control(PageItem* currItem)
349 {
350 ScribusDoc* Doc = currItem->doc();
351 if ((m_ClRe < 0) || (m_ClRe % 2 == 0))
352 return;
353 UndoManager* undoManager = UndoManager::instance();
354
355 // do no record anything else but the core reset points action
356 undoManager->setUndoEnabled(false);
357
358 oldClip = new FPointArray(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine.copy() : currItem->PoLine.copy());
359 m_oldItemX = currItem->xPos();
360 m_oldItemY = currItem->yPos();
361 currItem->ClipEdited = true;
362 FPoint np;
363 if (Doc->nodeEdit.m_isContourLine)
364 np = currItem->ContourLine.point(Doc->nodeEdit.m_ClRe - 1);
365 else
366 np = currItem->PoLine.point(Doc->nodeEdit.m_ClRe - 1);
367 currItem->OldB2 = currItem->width();
368 currItem->OldH2 = currItem->height();
369 if (Doc->nodeEdit.m_isContourLine)
370 {
371 currItem->ContourLine.setPoint(Doc->nodeEdit.m_ClRe, np);
372 Doc->regionsChanged()->update(QRectF());
373 currItem->FrameOnly = true;
374 currItem->update();
375 }
376 else
377 {
378 currItem->PoLine.setPoint(Doc->nodeEdit.m_ClRe, np);
379 // if (!(currItem->isGroup() || currItem->isSymbol()))
380 Doc->adjustItemSize(currItem, true);
381 Doc->regionsChanged()->update(QRectF());
382 }
383 undoManager->setUndoEnabled(true);
384 FPointArray newClip(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine : currItem->PoLine);
385 if (*oldClip != newClip && UndoManager::undoEnabled())
386 {
387 ScItemState<QPair<FPointArray, FPointArray> > *state =
388 new ScItemState<QPair<FPointArray, FPointArray> >(Um::ResetControlPoint, "",
389 currItem->getUPixmap());
390 state->set("EDIT_SHAPE_OR_CONTOUR");
391 state->set("IS_CONTOUR", Doc->nodeEdit.m_isContourLine);
392 state->setItem(qMakePair(*oldClip, newClip));
393 state->set("OLD_X", m_oldItemX);
394 state->set("OLD_Y", m_oldItemY);
395 state->set("NEW_X", currItem->xPos());
396 state->set("NEW_Y", currItem->yPos());
397 undoManager->action(currItem, state);
398 }
399 delete oldClip;
400 oldClip = nullptr;
401 }
402
403
resetControl(PageItem * currItem)404 void NodeEditContext::resetControl(PageItem* currItem)
405 {
406 ScribusDoc* Doc = currItem->doc();
407 if (m_ClRe < 0)
408 return;
409 UndoManager* undoManager = UndoManager::instance();
410
411 // do no record anything else but the core reset points action
412 undoManager->setUndoEnabled(false);
413
414 oldClip = new FPointArray(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine.copy() : currItem->PoLine.copy());
415 m_oldItemX = currItem->xPos();
416 m_oldItemY = currItem->yPos();
417 currItem->ClipEdited = true;
418 FPointArray Clip;
419 if (Doc->nodeEdit.m_isContourLine)
420 Clip = currItem->ContourLine.copy();
421 else
422 Clip = currItem->PoLine.copy();
423 int EndInd = Clip.size();
424 int StartInd = 0;
425 for (int n = m_ClRe; n < Clip.size(); ++n)
426 {
427 if (Clip.isMarker(n))
428 {
429 EndInd = n;
430 break;
431 }
432 }
433 if (m_ClRe > 0)
434 {
435 for (int n2 = m_ClRe; n2 > 0; n2--)
436 {
437 if (Clip.isMarker(n2))
438 {
439 StartInd = n2 + 1;
440 break;
441 }
442 }
443 }
444 FPoint np = Clip.point(Doc->nodeEdit.clre());
445 currItem->OldB2 = currItem->width();
446 currItem->OldH2 = currItem->height();
447 if ((Doc->nodeEdit.clre() == StartInd) || (Doc->nodeEdit.clre() == EndInd - 2))
448 {
449 if (currItem->isPolyLine())
450 {
451 if (Doc->nodeEdit.clre() == StartInd)
452 Clip.setPoint(StartInd + 1, np);
453 else
454 Clip.setPoint(EndInd - 1, np);
455 }
456 else
457 {
458 Clip.setPoint(StartInd + 1, np);
459 Clip.setPoint(EndInd - 1, np);
460 }
461 }
462 else
463 {
464 Clip.setPoint(Doc->nodeEdit.m_ClRe + 1, np);
465 Clip.setPoint((Doc->nodeEdit.m_ClRe % 4 != 0 ? Doc->nodeEdit.m_ClRe + 3 : Doc->nodeEdit.m_ClRe - 1), np);
466 }
467 if (!Doc->nodeEdit.m_isContourLine)
468 {
469 currItem->PoLine = Clip.copy();
470 // if (!(currItem->isGroup() || currItem->isSymbol()))
471 Doc->adjustItemSize(currItem, true);
472 Doc->regionsChanged()->update(QRectF());
473 }
474 else
475 {
476 currItem->ContourLine = Clip.copy();
477 Doc->regionsChanged()->update(QRectF());
478 }
479 Doc->update();
480
481 undoManager->setUndoEnabled(true);
482 FPointArray newClip(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine : currItem->PoLine);
483 if (*oldClip != newClip && UndoManager::undoEnabled())
484 {
485 ScItemState<QPair<FPointArray, FPointArray> > *state =
486 new ScItemState<QPair<FPointArray, FPointArray> >(Um::ResetControlPoints, "",
487 currItem->getUPixmap());
488 state->set("EDIT_SHAPE_OR_CONTOUR");
489 state->set("IS_CONTOUR", Doc->nodeEdit.m_isContourLine);
490 state->setItem(qMakePair(*oldClip, newClip));
491 state->set("OLD_X", m_oldItemX);
492 state->set("OLD_Y", m_oldItemY);
493 state->set("NEW_X", currItem->xPos());
494 state->set("NEW_Y", currItem->yPos());
495 undoManager->action(currItem, state);
496 }
497 delete oldClip;
498 oldClip = nullptr;
499 }
500
501