1 /*
2  For general Scribus (>=1.3.2) copyright and licensing information please refer
3  to the COPYING file provided with the program. Following this notice may exist
4  a copyright and/or license notice that predates the release of Scribus 1.3.2
5  for which a new license (GPL+exception) is in place.
6  */
7 /***************************************************************************
8 *                                                                         *
9 *   This program is free software; you can redistribute it and/or modify  *
10 *   it under the terms of the GNU General Public License as published by  *
11 *   the Free Software Foundation; either version 2 of the License, or     *
12 *   (at your option) any later version.                                   *
13 *                                                                         *
14 ***************************************************************************/
15 /***************************************************************************
16                  canvasmode_editspiral.cpp  -  description
17                              -------------------
18     begin                : Wed Jan 27 2011
19     copyright            : (C) 2011 by Franz Schmid
20     email                : Franz.Schmid@altmuehlnet.de
21  ***************************************************************************/
22 
23 
24 #include "canvasmode_editspiral.h"
25 
26 #include <QApplication>
27 #include <QCursor>
28 #include <QEvent>
29 #include <QMouseEvent>
30 #include <QPainterPath>
31 #include <QPoint>
32 #include <QRect>
33 #include <QTimer>
34 #include <QWidgetAction>
35 
36 #include "appmodes.h"
37 #include "canvas.h"
38 #include "fpoint.h"
39 #include "pageitem_spiral.h"
40 #include "scribus.h"
41 #include "scribusdoc.h"
42 #include "scribusview.h"
43 #include "selection.h"
44 #include "ui/propertiespalette.h"
45 #include "undomanager.h"
46 #include "util.h"
47 #include "util_math.h"
48 
49 
CanvasMode_EditSpiral(ScribusView * view)50 CanvasMode_EditSpiral::CanvasMode_EditSpiral(ScribusView* view) : CanvasMode(view), m_ScMW(view->m_ScMW)
51 {
52 }
53 
GetItem(PageItem ** pi)54 inline bool CanvasMode_EditSpiral::GetItem(PageItem** pi)
55 {
56 	*pi = m_doc->m_Selection->itemAt(0);
57 	return (*pi) != nullptr;
58 }
59 
drawControls(QPainter * p)60 void CanvasMode_EditSpiral::drawControls(QPainter* p)
61 {
62 	p->save();
63 	if (m_canvas->m_viewMode.operItemMoving)
64 	{
65 		drawOutline(p);
66 	}
67 	else
68 	{
69 		drawSelection(p, false);
70 	}
71 	if (m_doc->appMode == modeEditSpiral)
72 	{
73 		drawControlsSpiral(p, m_doc->m_Selection->itemAt(0));
74 	}
75 	p->restore();
76 }
77 
drawControlsSpiral(QPainter * psx,PageItem * currItem)78 void CanvasMode_EditSpiral::drawControlsSpiral(QPainter* psx, PageItem* currItem)
79 {
80 	QPen p8b = QPen(Qt::blue, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
81 	QPen p8r = QPen(Qt::red, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
82 	psx->setTransform(currItem->getTransform(), true);
83 	psx->setBrush(Qt::NoBrush);
84 	psx->setPen(p8b);
85 	if (m_arcPoint == useControlStart)
86 		psx->setPen(p8r);
87 	else
88 		psx->setPen(p8b);
89 	psx->drawPoint(m_startPoint);
90 	if (m_arcPoint == useControlEnd)
91 		psx->setPen(p8r);
92 	else
93 		psx->setPen(p8b);
94 	psx->drawPoint(m_endPoint);
95 }
96 
enterEvent(QEvent * e)97 void CanvasMode_EditSpiral::enterEvent(QEvent *e)
98 {
99 	if (!m_canvas->m_viewMode.m_MouseButtonPressed)
100 	{
101 		setModeCursor();
102 	}
103 }
104 
leaveEvent(QEvent * e)105 void CanvasMode_EditSpiral::leaveEvent(QEvent *e)
106 {
107 }
108 
109 
activate(bool fromGesture)110 void CanvasMode_EditSpiral::activate(bool fromGesture)
111 {
112 	CanvasMode::activate(fromGesture);
113 
114 	m_VectorDialog = new SpiralVectorDialog(m_ScMW);
115 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
116 	m_canvas->resetRenderMode();
117 	m_doc->DragP = false;
118 	m_doc->leaveDrag = false;
119 	m_canvas->m_viewMode.operItemMoving = false;
120 	m_canvas->m_viewMode.operItemResizing = false;
121 	m_view->MidButt = false;
122 	m_Mxp = m_Myp = -1;
123 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
124 	PageItem_Spiral* item = currItem->asSpiral();
125 	m_startPoint = currItem->PoLine.pointQF(0);
126 	m_endPoint = currItem->PoLine.pointQF(currItem->PoLine.size() - 2);
127 	m_startAngle = item->spiralStartAngle;
128 	m_endAngle = item->spiralEndAngle;
129 	m_VectorDialog->setValues(computeRealAngle(m_startAngle, false), computeRealAngle(m_endAngle, false), item->spiralFactor);
130 	m_VectorDialog->show();
131 	setModeCursor();
132 	if (fromGesture)
133 	{
134 		m_view->update();
135 	}
136 	connect(m_VectorDialog, SIGNAL(NewVectors(double, double, double)), this, SLOT(applyValues(double, double, double)));
137 	connect(m_VectorDialog, SIGNAL(endEdit()), this, SLOT(endEditing()));
138 	connect(m_VectorDialog, SIGNAL(paletteShown(bool)), this, SLOT(endEditing(bool)));
139 	connect(m_doc, SIGNAL(docChanged()), this, SLOT(updateFromItem()));
140 }
141 
deactivate(bool forGesture)142 void CanvasMode_EditSpiral::deactivate(bool forGesture)
143 {
144 	disconnect(m_VectorDialog, SIGNAL(paletteShown(bool)), this, SLOT(endEditing(bool)));
145 	m_VectorDialog->close();
146 	m_VectorDialog->deleteLater();
147 	m_view->setRedrawMarkerShown(false);
148 	m_arcPoint = noPointDefined;
149 	disconnect(m_doc, SIGNAL(docChanged()), this, SLOT(updateFromItem()));
150 
151 	CanvasMode::deactivate(forGesture);
152 }
153 
updateFromItem()154 void CanvasMode_EditSpiral::updateFromItem()
155 {
156 	if (updateFromItemBlocked())
157 		return;
158 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
159 	PageItem_Spiral* item = currItem->asSpiral();
160 	m_startPoint = currItem->PoLine.pointQF(0);
161 	m_endPoint = currItem->PoLine.pointQF(currItem->PoLine.size() - 2);
162 	m_startAngle = item->spiralStartAngle;
163 	m_endAngle = item->spiralEndAngle;
164 	m_VectorDialog->setValues(computeRealAngle(m_startAngle, false), computeRealAngle(m_endAngle, false), item->spiralFactor);
165 	m_view->update();
166 }
167 
endEditing(bool active)168 void CanvasMode_EditSpiral::endEditing(bool active)
169 {
170 	if (!active)
171 		endEditing();
172 }
173 
endEditing()174 void CanvasMode_EditSpiral::endEditing()
175 {
176 	m_view->requestMode(modeNormal);
177 }
178 
getSegment(double angle)179 QPointF CanvasMode_EditSpiral::getSegment(double angle)
180 {
181 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
182 	PageItem_Spiral *item = currItem->asSpiral();
183 	double ww = item->width();
184 	double wws = 0.0;
185 	double wwn = ww;
186 	double hh = item->height() - (item->height() / (item->spiralFactor + 1.0));
187 	double segStart = 0.0;
188 	double segEnd = 180;
189 	bool segPart = true;
190 	QPointF ret = QPointF(item->width() / 2.0, item->height() / 2.0);
191 	if (angle < 0)
192 		return ret;
193 	while (true)
194 	{
195 		QLineF lin = QLineF(QPointF(wws, hh), QPointF(wwn, hh));
196 		if ((angle <= segEnd) && (angle >= segStart))
197 		{
198 			ret = lin.pointAt(0.5);
199 			break;
200 		}
201 		ww /= item->spiralFactor;
202 		wws = wwn;
203 		if (segPart)
204 			wwn -= ww;
205 		else
206 			wwn += ww;
207 		segPart = !segPart;
208 		segStart += 180.0;
209 		segEnd += 180.0;
210 	}
211 	return ret;
212 }
213 
computeRealAngle(double angle,bool fromDia)214 double CanvasMode_EditSpiral::computeRealAngle(double angle, bool fromDia)
215 {
216 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
217 	double ret = angle;
218 	int rev = static_cast<int>(angle / 360.0);
219 	double part = angle - (rev * 360);
220 	QTransform bb;
221 	bb.scale(currItem->width() / currItem->height(), 1.0);
222 	QLineF inp = QLineF(QPointF(currItem->width() / 2.0, currItem->height() / 2.0), QPointF(currItem->width(), currItem->height() / 2.0));
223 	inp.setAngle(part);
224 	if (fromDia)
225 	{
226 		QLineF res = bb.map(inp);
227 		ret = res.angle();
228 	}
229 	else
230 	{
231 		QTransform bt = bb.inverted();
232 		QLineF res = bt.map(inp);
233 		ret = res.angle();
234 	}
235 	ret += rev * 360;
236 	return ret;
237 }
238 
applyValues(double start,double end,double factor)239 void CanvasMode_EditSpiral::applyValues(double start, double end, double factor)
240 {
241 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
242 	PageItem_Spiral *item = currItem->asSpiral();
243 	SimpleState *ss = new SimpleState(Um::EditSpiral, "", Um::IPolygon);
244 	ss->set("SPIRAL");
245 	ss->set("OLD_START",item->spiralStartAngle);
246 	ss->set("OLD_END",item->spiralEndAngle);
247 	ss->set("OLD_FACTOR",item->spiralFactor);
248 	item->spiralStartAngle = computeRealAngle(start, true);
249 	item->spiralEndAngle = computeRealAngle(end, true);
250 	item->spiralFactor = factor;
251 	ss->set("NEW_START",item->spiralStartAngle);
252 	ss->set("NEW_END",item->spiralEndAngle);
253 	ss->set("NEW_FACTOR",item->spiralFactor);
254 	undoManager->action(item,ss);
255 	item->recalcPath();
256 	m_startPoint = currItem->PoLine.pointQF(0);
257 	m_endPoint = currItem->PoLine.pointQF(currItem->PoLine.size() - 2);
258 	m_startAngle = item->spiralStartAngle;
259 	m_endAngle = item->spiralEndAngle;
260 	QTransform itemMatrix = currItem->getTransform();
261 	m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, currItem->width(), currItem->height())).adjusted(-5, -5, 10, 10));
262 }
263 
keyPressEvent(QKeyEvent * e)264 void CanvasMode_EditSpiral::keyPressEvent(QKeyEvent *e)
265 {
266 	commonkeyPressEvent_Default(e);
267 }
268 
keyReleaseEvent(QKeyEvent * e)269 void CanvasMode_EditSpiral::keyReleaseEvent(QKeyEvent *e)
270 {
271 	commonkeyReleaseEvent(e);
272 }
273 
mouseDoubleClickEvent(QMouseEvent * m)274 void CanvasMode_EditSpiral::mouseDoubleClickEvent(QMouseEvent *m)
275 {
276 	m->accept();
277 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
278 	m_canvas->resetRenderMode();
279 	m_view->requestMode(modeNormal);
280 }
281 
mouseMoveEvent(QMouseEvent * m)282 void CanvasMode_EditSpiral::mouseMoveEvent(QMouseEvent *m)
283 {
284 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
285 	m->accept();
286 	double newX = mousePointDoc.x();
287 	double newY = mousePointDoc.y();
288 	if (m_canvas->m_viewMode.m_MouseButtonPressed && m_view->moveTimerElapsed() && (m_arcPoint != noPointDefined))
289 	{
290 		PageItem *currItem = m_doc->m_Selection->itemAt(0);
291 		QTransform itemMatrix = currItem->getTransform();
292 		PageItem_Spiral *item = currItem->asSpiral();
293 		QPointF sPoint;
294 		if (m_arcPoint == useControlStart)
295 			sPoint = getSegment(m_startAngle);
296 		else if (m_arcPoint == useControlEnd)
297 			sPoint = getSegment(m_endAngle);
298 		QPointF smPoint = itemMatrix.map(sPoint);
299 		QLineF stLinA = QLineF(smPoint, QPointF(m_Mxp, m_Myp));
300 		QLineF stLinM = QLineF(smPoint, QPointF(newX, newY));
301 		double deltaAngle = stLinM.angle() - stLinA.angle();
302 		if (deltaAngle < -180)
303 			deltaAngle = deltaAngle + 360;
304 		else if (deltaAngle > 180)
305 			deltaAngle = deltaAngle - 360;
306 		if (currItem->imageFlippedV())
307 			deltaAngle *= -1.0;
308 		if (currItem->imageFlippedH())
309 			deltaAngle *= -1.0;
310 		if (m_arcPoint == useControlStart)
311 		{
312 			if (m_startAngle + deltaAngle >= 0)
313 			{
314 				m_startAngle += deltaAngle;
315 				applyValues(m_startAngle,m_endAngle,item->spiralFactor);
316 				item->recalcPath();
317 				m_startPoint = currItem->PoLine.pointQF(0);
318 				m_canvas->displayRealRotHUD(m->globalPos(), m_startAngle);
319 			}
320 			m_VectorDialog->setValues(computeRealAngle(m_startAngle, false), computeRealAngle(m_endAngle, false), item->spiralFactor);
321 		}
322 		else if (m_arcPoint == useControlEnd)
323 		{
324 			if (m_endAngle + deltaAngle > m_startAngle)
325 			{
326 				m_endAngle += deltaAngle;
327 				applyValues(m_startAngle,m_endAngle,item->spiralFactor);
328 				item->recalcPath();
329 				m_endPoint = currItem->PoLine.pointQF(currItem->PoLine.size() - 2);
330 				m_canvas->displayRealRotHUD(m->globalPos(), m_endAngle);
331 			}
332 			m_VectorDialog->setValues(computeRealAngle(m_startAngle, false), computeRealAngle(m_endAngle, false), item->spiralFactor);
333 		}
334 		currItem->update();
335 		m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, currItem->width(), currItem->height())).adjusted(-5, -5, 10, 10));
336 	}
337 	m_Mxp = newX;
338 	m_Myp = newY;
339 }
340 
mousePressEvent(QMouseEvent * m)341 void CanvasMode_EditSpiral::mousePressEvent(QMouseEvent *m)
342 {
343 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
344 	m_canvas->PaintSizeRect(QRect());
345 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
346 	m_canvas->m_viewMode.operItemMoving = false;
347 	m_view->HaveSelRect = false;
348 	m_doc->DragP = false;
349 	m_doc->leaveDrag = false;
350 	m->accept();
351 	m_view->registerMousePress(m->globalPos());
352 	m_Mxp = mousePointDoc.x(); //m->x();
353 	m_Myp = mousePointDoc.y(); //m->y();
354 	if (m->button() == Qt::MidButton)
355 	{
356 		m_view->MidButt = true;
357 		if (m->modifiers() & Qt::ControlModifier)
358 			m_view->DrawNew();
359 		return;
360 	}
361 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
362 	QTransform itemMatrix = currItem->getTransform();
363 	QPointF stPoint = m_startPoint;
364 	stPoint = itemMatrix.map(stPoint);
365 	QPointF swPoint = m_endPoint;
366 	swPoint = itemMatrix.map(swPoint);
367 	if (m_canvas->hitsCanvasPoint(m->globalPos(), stPoint))
368 		m_arcPoint = useControlStart;
369 	else if (m_canvas->hitsCanvasPoint(m->globalPos(), swPoint))
370 		m_arcPoint = useControlEnd;
371 	else
372 		m_arcPoint = noPointDefined;
373 	if (m_arcPoint != noPointDefined)
374 		m_transaction = undoManager->beginTransaction(Um::Polygon, Um::IPolygon, Um::EditSpiral, "", Um::IPolygon);
375 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
376 	m_view->setCursor(QCursor(Qt::CrossCursor));
377 	m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, currItem->width(), currItem->height())).adjusted(-5, -5, 10, 10));
378 }
379 
mouseReleaseEvent(QMouseEvent * m)380 void CanvasMode_EditSpiral::mouseReleaseEvent(QMouseEvent *m)
381 {
382 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
383 	m_canvas->resetRenderMode();
384 	m->accept();
385 	PageItem *currItem = m_doc->m_Selection->itemAt(0);
386 	if (m_transaction)
387 	{
388 		m_transaction.commit();
389 		m_transaction.reset();
390 	}
391 	QTransform itemMatrix = currItem->getTransform();
392 	m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, currItem->width(), currItem->height())).adjusted(-5, -5, 10, 10));
393 }
394