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