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 #include "canvasgesture_linemove.h"
17 
18 //#include <QDebug>
19 #include <QMouseEvent>
20 #include <QPainter>
21 #include <QPen>
22 
23 #include "canvas.h"
24 #include "pageitem_line.h"
25 #include "scribusview.h"
26 #include "selection.h"
27 #include "undomanager.h"
28 #include "util_math.h"
29 
clear()30 void LineMove::clear()
31 {
32 	m_haveLineItem = false;
33 	if (m_transaction.isStarted())
34 	{
35 		m_transaction.cancel();
36 		m_transaction.reset();
37 	}
38 }
39 
40 
prepare(QPointF start,QPointF end)41 void LineMove::prepare(QPointF start, QPointF end)
42 {
43 	m_haveLineItem = false;
44 	setStartPoint(start);
45 	setStartPoint(end);
46 }
47 
48 
prepare(PageItem_Line * line,bool useOriginAsEndpoint)49 void LineMove::prepare(PageItem_Line* line, bool useOriginAsEndpoint)
50 {
51 	m_haveLineItem = (line != nullptr);
52 	if (!m_haveLineItem)
53 		return;
54 	m_useOriginAsEndpoint = useOriginAsEndpoint;
55 	m_line = line;
56 	setStartPoint(QPointF(m_line->xPos(), m_line->yPos()));
57 	setEndPoint(QPointF(m_line->xPos() + m_line->width(), m_line->yPos()));
58 	setRotation(m_line->rotation());
59 	if (m_useOriginAsEndpoint)
60 	{
61 		QPointF tmp = startPoint();
62 		setStartPoint(endPoint());
63 		setEndPoint(tmp);
64 	}
65 }
66 
67 
rotation() const68 double LineMove::rotation() const
69 {
70 	double rot = xy2Deg(m_bounds.width(), m_bounds.height());
71 	if (rot < 0.0)
72 		return 360 + rot;
73 	return rot;
74 }
75 
76 
setRotation(double rot)77 void LineMove::setRotation(double rot)
78 {
79 	m_bounds.setSize(length() * QSizeF(cosd(rot), sind(rot)));
80 }
81 
82 
length() const83 double LineMove::length() const
84 {
85 	return qMax(0.01, distance(m_bounds.width(), m_bounds.height()));
86 }
87 
88 
setStartPoint(QPointF p)89 void LineMove::setStartPoint(QPointF p)
90 {
91 	m_bounds.setTopLeft(p);
92 }
93 
94 
setEndPoint(QPointF p)95 void LineMove::setEndPoint(QPointF p)
96 {
97 	m_bounds.setBottomRight(p);
98 }
99 
100 
activate(bool forGesture)101 void LineMove::activate(bool forGesture)
102 {
103 	CanvasGesture::activate(forGesture);
104 }
105 
106 
107 
deactivate(bool forGesture)108 void LineMove::deactivate(bool forGesture)
109 {
110 //	qDebug() << "LineMove::deactivate" << flag;
111 	if (!forGesture)
112 		clear();
113 	CanvasGesture::deactivate(forGesture);
114 }
115 
116 
117 
drawControls(QPainter * p)118 void LineMove::drawControls(QPainter* p)
119 {
120 	p->save();
121 	p->scale(m_canvas->scale(), m_canvas->scale());
122 	p->translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y());
123 	p->setBrush(Qt::NoBrush);
124 	p->setPen(QPen(Qt::black, 1.0 / m_canvas->scale(), Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
125 	p->drawLine(m_bounds.topLeft(), m_bounds.bottomRight());
126 	p->restore();
127 }
128 
mousePressEvent(QMouseEvent * m)129 void LineMove::mousePressEvent(QMouseEvent *m)
130 {
131 	PageItem_Line* line = m_doc->m_Selection->count() == 1 ? m_doc->m_Selection->itemAt(0)->asLine() : nullptr;
132 	if (line)
133 	{
134 		bool hitsOrigin = m_canvas->hitsCanvasPoint(m->globalPos(), line->xyPos());
135 		prepare(line, hitsOrigin);
136 		// now we also know the line's endpoint:
137 		bool hitsEnd = m_canvas->hitsCanvasPoint(m->globalPos(), endPoint());
138 		m_haveLineItem = hitsOrigin || hitsEnd;
139 	}
140 	else
141 	{
142 		FPoint point = m_canvas->globalToCanvas(m->globalPos());
143 		setStartPoint(QPointF(point.x(), point.y()));
144 		setEndPoint(QPointF(point.x(), point.y()));
145 		m_haveLineItem = false;
146 	}
147 	if (m_haveLineItem)
148 	{
149 		if (!m_transaction)
150 		{
151 			QString targetName = line->getUName();
152 			QPixmap* targetIcon = line->getUPixmap();
153 			m_transaction = Um::instance()->beginTransaction(targetName, targetIcon, Um::Resize, "", Um::IResize);
154 		}
155 		adjustBounds(m, false);
156 		m_initialBounds = m_bounds;
157 		m->accept();
158 	}
159 }
160 
mouseMoveEvent(QMouseEvent * m)161 void LineMove::mouseMoveEvent(QMouseEvent *m)
162 {
163 	adjustBounds(m);
164 	if (m_haveLineItem)
165 	{
166 		doResize();
167 		double angle = rotation();
168 		if (angle > 0)
169 			angle = 360 - angle;
170 		m_canvas->displaySizeHUD(m->globalPos(), length(), fabs(angle), true);
171 	}
172 	m->accept();
173 	m_canvas->repaint();
174 }
175 
mouseReleaseEvent(QMouseEvent * m)176 void LineMove::mouseReleaseEvent(QMouseEvent *m)
177 {
178 	adjustBounds(m);
179 	if (m_haveLineItem)
180 	{
181 		if (m_bounds != m_initialBounds)
182 			doResize();
183 		m_doc->setRedrawBounding(m_line);
184 		m_view->resetMousePressed();
185 		m_line->checkChanges();
186 		m_line->update();
187 	}
188 	if (m_transaction.isStarted())
189 	{
190 		m_transaction.commit();
191 		m_transaction.reset();
192 	}
193 	m->accept();
194 	m_canvas->update();
195 //	qDebug() << "LineMove::mouseRelease" << m_line->xPos() << "," << m_line->yPos() << "@" << m_line->rotation() << m_line->width() << "x" << m_line->height();
196 	m_view->stopGesture();
197 }
198 
199 
doResize()200 void LineMove::doResize()
201 {
202 	if (m_useOriginAsEndpoint)
203 	{
204 		m_line->setXYPos(m_bounds.right(), m_bounds.bottom());
205 		double rot = rotation();
206 		m_line->setRotation(rot < 180? rot + 180 : rot - 180);
207 	}
208 	else
209 	{
210 		m_line->setXYPos(m_bounds.x(), m_bounds.y());
211 		m_line->setRotation(rotation());
212 	}
213 	m_line->setWidth(length());
214 	m_line->setHeight(1.0);
215 	m_line->updateClip();
216 //	qDebug() << "LineMove::doresize" << m_line->xPos() << "," << m_line->yPos() << "@" << m_line->rotation() << m_line->width() << "x" << m_line->height();
217 }
218 
adjustBounds(QMouseEvent * m,bool updateCanvas)219 void LineMove::adjustBounds(QMouseEvent *m, bool updateCanvas)
220 {
221 	FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
222 	bool constrainRatio = ((m->modifiers() & Qt::ControlModifier) != Qt::NoModifier);
223 
224 	double newX = mousePointDoc.x();
225 	double newY = mousePointDoc.y();
226 
227 	if (m_doc->SnapGrid)
228 	{
229 		newX = qRound(newX / m_doc->guidesPrefs().minorGridSpacing) * m_doc->guidesPrefs().minorGridSpacing;
230 		newY = qRound(newY / m_doc->guidesPrefs().minorGridSpacing) * m_doc->guidesPrefs().minorGridSpacing;
231 	}
232 	//<<#8099
233 	FPoint np2 = m_doc->ApplyGridF(FPoint(newX, newY));
234 	double nx = np2.x();
235 	double ny = np2.y();
236 	m_doc->ApplyGuides(&nx, &ny);
237 	m_doc->ApplyGuides(&nx, &ny,true);
238 	newX = nx;
239 	newY = ny;
240 	//>>#8099
241 
242 	m_bounds.setBottomRight(QPointF(newX, newY));
243 	//Constrain rotation angle, when the mouse is being dragged around for a new line
244 	if (constrainRatio)
245 	{
246 		double newRot = rotation();
247 		newRot = constrainAngle(newRot, m_doc->opToolPrefs().constrain);
248 		setRotation(newRot);
249 	}
250 	if (updateCanvas)
251 	{
252 		m_view->updateCanvas(m_bounds.normalized().adjusted(-10, -10, 20, 20));
253 	}
254 }
255