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_editweldpoint.cpp  -  description
17 							 -------------------
18 	begin                : Sun Oct 23 2011
19 	copyright            : (C) 2011 by Franz Schmid
20 	email                : Franz.Schmid@altmuehlnet.de
21  ***************************************************************************/
22 
23 
24 #include "canvasmode_editweldpoint.h"
25 
26 #include <QApplication>
27 #include <QButtonGroup>
28 #include <QCheckBox>
29 #include <QCursor>
30 #include <QEvent>
31 #include <QMessageBox>
32 #include <QMouseEvent>
33 #include <QPainterPath>
34 #include <QPoint>
35 #include <QRect>
36 #include <QTimer>
37 #include <QWidgetAction>
38 #include <QDebug>
39 
40 #include "appmodes.h"
41 #include "canvas.h"
42 #include "fpoint.h"
43 #include "fpointarray.h"
44 #include "hyphenator.h"
45 #include "pageitem_textframe.h"
46 #include "prefscontext.h"
47 #include "prefsfile.h"
48 #include "prefsmanager.h"
49 #include "sccolorengine.h"
50 #include "sclimits.h"
51 #include "scribus.h"
52 #include "scribusXml.h"
53 #include "scribusdoc.h"
54 #include "scribusview.h"
55 #include "selection.h"
56 #include "ui/aligndistribute.h"
57 #include "ui/contextmenu.h"
58 #include "ui/pageselector.h"
59 #include "ui/propertiespalette.h"
60 #include "undomanager.h"
61 #include "units.h"
62 #include "util.h"
63 #include "util_math.h"
64 
65 
CanvasMode_EditWeldPoint(ScribusView * view)66 CanvasMode_EditWeldPoint::CanvasMode_EditWeldPoint(ScribusView* view) : CanvasMode(view),
67 	m_ScMW(view->m_ScMW)
68 {
69 }
70 
GetItem(PageItem ** pi)71 inline bool CanvasMode_EditWeldPoint::GetItem(PageItem** pi)
72 {
73 	*pi = m_doc->m_Selection->itemAt(0);
74 	return (*pi) != nullptr;
75 }
76 
drawControls(QPainter * p)77 void CanvasMode_EditWeldPoint::drawControls(QPainter* p)
78 {
79 	p->save();
80 	if (m_canvas->m_viewMode.operItemMoving)
81 	{
82 		drawOutline(p);
83 	}
84 	else
85 	{
86 		drawSelection(p, false);
87 	}
88 	if (m_doc->appMode == modeEditWeldPoint)
89 	{
90 		drawControlsWeldPoint(p, m_doc->m_Selection->itemAt(0));
91 	}
92 	p->restore();
93 }
94 
drawControlsWeldPoint(QPainter * psx,PageItem * currItem)95 void CanvasMode_EditWeldPoint::drawControlsWeldPoint(QPainter* psx, PageItem* currItem)
96 {
97 	psx->translate(static_cast<int>(currItem->xPos()), static_cast<int>(currItem->yPos()));
98 	psx->rotate(currItem->rotation());
99 	psx->setBrush(Qt::NoBrush);
100 	for (int i = 0 ; i <  currItem->weldList.count(); i++)
101 	{
102 		PageItem::WeldingInfo wInf =  currItem->weldList.at(i);
103 		if (i == m_selectedPoint)
104 			psx->setPen(QPen(Qt::red, 8.0 / m_canvas->scale(), Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
105 		else
106 			psx->setPen(QPen(Qt::yellow, 8.0 / m_canvas->scale(), Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
107 		psx->drawPoint(QPointF(wInf.weldPoint.x(), wInf.weldPoint.y()));
108 	}
109 }
110 
enterEvent(QEvent * e)111 void CanvasMode_EditWeldPoint::enterEvent(QEvent *e)
112 {
113 	if (!m_canvas->m_viewMode.m_MouseButtonPressed)
114 	{
115 		setModeCursor();
116 	}
117 }
118 
leaveEvent(QEvent * e)119 void CanvasMode_EditWeldPoint::leaveEvent(QEvent *e)
120 {
121 }
122 
123 
activate(bool fromGesture)124 void CanvasMode_EditWeldPoint::activate(bool fromGesture)
125 {
126 	CanvasMode::activate(fromGesture);
127 
128 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
129 	m_canvas->resetRenderMode();
130 	m_doc->DragP = false;
131 	m_doc->leaveDrag = false;
132 	m_canvas->m_viewMode.operItemMoving = false;
133 	m_canvas->m_viewMode.operItemResizing = false;
134 	m_view->MidButt = false;
135 	m_keyRepeat = false;
136 	m_currItem = m_doc->m_Selection->itemAt(0);
137 	m_weldToList = m_currItem->itemsWeldedTo();
138 	m_weldToList.append(m_currItem);
139 	m_Mxp = m_Myp = -1;
140 	m_selectedPoint = -1;
141 	setModeCursor();
142 	if (fromGesture)
143 	{
144 		m_view->update();
145 	}
146 	m_ModeDialog = new WeldEditDialog(m_ScMW);
147 	m_ModeDialog->show();
148 	connect(m_ModeDialog, SIGNAL(endEdit()), this, SLOT(endEditing()));
149 	connect(m_ModeDialog, SIGNAL(paletteShown(bool)), this, SLOT(endEditing(bool)));
150 	connect(m_ModeDialog, SIGNAL(modeMoveWeld()), this, SLOT(setWeldMode()));
151 	connect(m_ModeDialog, SIGNAL(modeMoveObject()), this, SLOT(setObjectMode()));
152 }
153 
deactivate(bool forGesture)154 void CanvasMode_EditWeldPoint::deactivate(bool forGesture)
155 {
156 	m_view->setRedrawMarkerShown(false);
157 	m_selectedPoint = -1;
158 	m_weldToList.clear();
159 	disconnect(m_ModeDialog, SIGNAL(paletteShown(bool)), this, SLOT(endEditing(bool)));
160 	m_ModeDialog->close();
161 	delete m_ModeDialog;
162 
163 	CanvasMode::deactivate(forGesture);
164 }
165 
endEditing(bool active)166 void CanvasMode_EditWeldPoint::endEditing(bool active)
167 {
168 	if (!active)
169 		endEditing();
170 }
171 
endEditing()172 void CanvasMode_EditWeldPoint::endEditing()
173 {
174 	m_view->requestMode(modeNormal);
175 }
176 
setWeldMode()177 void CanvasMode_EditWeldPoint::setWeldMode()
178 {
179 	m_editWeldMode = true;
180 }
181 
setObjectMode()182 void CanvasMode_EditWeldPoint::setObjectMode()
183 {
184 	m_editWeldMode = false;
185 }
186 
keyPressEvent(QKeyEvent * e)187 void CanvasMode_EditWeldPoint::keyPressEvent(QKeyEvent *e)
188 {
189 	if (m_selectedPoint < 0)
190 		return;
191 	int kk = e->key();
192 	if (m_keyRepeat)
193 		return;
194 	m_keyRepeat = true;
195 	e->accept();
196 
197 	if (e->key() == Qt::Key_Escape)
198 	{
199 		// Go back to normal mode.
200 		m_view->requestMode(modeNormal);
201 		return;
202 	}
203 
204 	Qt::KeyboardModifiers buttonModifiers = e->modifiers();
205 	if ((!m_view->m_ScMW->zoomSpinBox->hasFocus()) && (!m_view->m_ScMW->pageSelector->hasFocus()))
206 	{
207 		if (m_doc->m_Selection->count() != 0)
208 		{
209 			double moveBy = 1.0;
210 			double moveX = 0.0;
211 			double moveY = 0.0;
212 			bool isMoving = false;
213 			bool doUpdate = false;
214 			if (m_doc->unitIndex()!=SC_INCHES)
215 			{
216 				if ((buttonModifiers & Qt::ShiftModifier) && !(buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
217 					moveBy = 0.1;
218 				else if (!(buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
219 					moveBy = 10.0;
220 				else if ((buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
221 					moveBy = 0.01;
222 				moveBy /= m_doc->unitRatio();//Lets allow movement by the current doc ratio, not only points
223 			}
224 			else
225 			{
226 				if ((buttonModifiers & Qt::ShiftModifier) && !(buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
227 					moveBy = 0.1 / m_doc->unitRatio();
228 				else if (!(buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
229 					moveBy = 1.0 / m_doc->unitRatio();
230 				else if ((buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
231 					moveBy = 0.01 /m_doc->unitRatio();
232 			}
233 			moveBy /= m_canvas->m_viewMode.scale;
234 			PageItem *currItem = m_doc->m_Selection->itemAt(0);
235 			switch (kk)
236 			{
237 				case Qt::Key_7:
238 					moveX = -moveBy;
239 					moveY = -moveBy;
240 					isMoving = true;
241 					doUpdate = true;
242 					break;
243 				case Qt::Key_9:
244 					moveX = moveBy;
245 					moveY = -moveBy;
246 					isMoving = true;
247 					doUpdate = true;
248 					break;
249 				case Qt::Key_3:
250 					moveX = moveBy;
251 					moveY = moveBy;
252 					isMoving = true;
253 					doUpdate = true;
254 					break;
255 				case Qt::Key_1:
256 					moveX = -moveBy;
257 					moveY = moveBy;
258 					isMoving = true;
259 					doUpdate = true;
260 					break;
261 				case Qt::Key_Left:
262 				case Qt::Key_4:
263 					moveX = -moveBy;
264 					isMoving = true;
265 					doUpdate = true;
266 					break;
267 				case Qt::Key_Right:
268 				case Qt::Key_6:
269 					moveX = moveBy;
270 					isMoving = true;
271 					doUpdate = true;
272 					break;
273 				case Qt::Key_Up:
274 				case Qt::Key_8:
275 					moveY = -moveBy;
276 					isMoving = true;
277 					doUpdate = true;
278 					break;
279 				case Qt::Key_Down:
280 				case Qt::Key_2:
281 					moveY = moveBy;
282 					isMoving = true;
283 					doUpdate = true;
284 					break;
285 			}
286 			if (isMoving)
287 			{
288 				if (m_editWeldMode)
289 				{
290 					currItem->weldList[m_selectedPoint].weldPoint += FPoint(moveX, moveY);
291 				}
292 				else
293 				{
294 					currItem->setXYPos(currItem->xPos() + moveX, currItem->yPos() + moveY, true);
295 					currItem->setRedrawBounding();
296 					currItem->OwnPage = m_doc->OnPage(currItem);
297 				}
298 			}
299 			if (doUpdate)
300 			{
301 				currItem->update();
302 				m_doc->regionsChanged()->update(getUpdateRect());
303 			}
304 		}
305 	}
306 	m_keyRepeat = false;
307 }
308 
mouseDoubleClickEvent(QMouseEvent * m)309 void CanvasMode_EditWeldPoint::mouseDoubleClickEvent(QMouseEvent *m)
310 {
311 	m->accept();
312 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
313 	m_canvas->resetRenderMode();
314 	if ((m_doc->m_Selection->isMultipleSelection()) || (m_doc->appMode != modeNormal))
315 	{
316 		if ((m_doc->m_Selection->isMultipleSelection()) && (m_doc->appMode == modeNormal))
317 		{
318 			if (GetItem(&m_currItem))
319 			{
320 				/* CB: old code, removing this as shift-alt select on an unselected table selects a cell now.
321 				//#6789 is closed by sorting this.
322 				if (currItem->isTableItem)
323 				{
324 					m_view->Deselect(false);
325 					m_doc->m_Selection->addItem(currItem);
326 					currItem->isSingleSel = true;
327 					//CB FIXME don't call this if the added item is item 0
328 					if (!m_doc->m_Selection->primarySelectionIs(currItem))
329 						currItem->emitAllToGUI();
330 					m_view->updateContents(currItem->getRedrawBounding(m_canvas->scale()));
331 				}*/
332 			}
333 			return;
334 		}
335 		if (!(GetItem(&m_currItem) && (m_doc->appMode == modeEdit) && m_currItem->isTextFrame()))
336 		{
337 			mousePressEvent(m);
338 			return;
339 		}
340 	}
341 }
342 
mouseMoveEvent(QMouseEvent * m)343 void CanvasMode_EditWeldPoint::mouseMoveEvent(QMouseEvent *m)
344 {
345 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
346 	m->accept();
347 	FPoint npfN;
348 	double nx = mousePointDoc.x();
349 	double ny = mousePointDoc.y();
350 	if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
351 		npfN = m_doc->ApplyGridF(FPoint(nx, ny));
352 	else
353 		npfN = FPoint(nx, ny);
354 	m_currItem = m_doc->m_Selection->itemAt(0);
355 	FPoint npf = FPoint(npfN.x(), npfN.y(), m_currItem->xPos(), m_currItem->yPos(), m_currItem->rotation(), 1, 1, true);
356 	FPoint npx(m_Mxp - npfN.x(), m_Myp - npfN.y(), 0, 0, m_currItem->rotation(), 1, 1, true);
357 	m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
358 	if (m_canvas->m_viewMode.m_MouseButtonPressed && m_view->moveTimerElapsed())
359 	{
360 		if (m_editWeldMode)
361 		{
362 			if (m_selectedPoint != -1)
363 			{
364 				m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
365 				FPoint mp_orig = m_currItem->weldList[m_selectedPoint].weldPoint;
366 				FPoint mp = mp_orig - npx;
367 				double xx = mp.x();
368 				double yy = mp.y();
369 				snapToEdgePoints(xx, yy);
370 				m_currItem->weldList[m_selectedPoint].weldPoint = FPoint(xx, yy);
371 			}
372 		}
373 		else
374 		{
375 			m_currItem->setXYPos(m_currItem->xPos() - npx.x(), m_currItem->yPos() - npx.y(), true);
376 			m_currItem->setRedrawBounding();
377 			m_currItem->OwnPage = m_doc->OnPage(m_currItem);
378 		}
379 		m_doc->regionsChanged()->update(getUpdateRect());
380 	}
381 	m_Mxp = npfN.x();
382 	m_Myp = npfN.y();
383 }
384 
mousePressEvent(QMouseEvent * m)385 void CanvasMode_EditWeldPoint::mousePressEvent(QMouseEvent *m)
386 {
387 	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
388 
389 	m_canvas->PaintSizeRect(QRect());
390 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
391 	m_canvas->m_viewMode.operItemMoving = false;
392 	m_view->HaveSelRect = false;
393 	m_doc->DragP = false;
394 	m_doc->leaveDrag = false;
395 	m->accept();
396 	m_view->registerMousePress(m->globalPos());
397 	m_Mxp = mousePointDoc.x(); //m->x();
398 	m_Myp = mousePointDoc.y(); //m->y();
399 	if (m->button() == Qt::MidButton)
400 	{
401 		m_view->MidButt = true;
402 		if (m->modifiers() & Qt::ControlModifier)
403 			m_view->DrawNew();
404 		return;
405 	}
406 	QTransform itemMatrix;
407 	m_currItem = m_doc->m_Selection->itemAt(0);
408 	itemMatrix.translate(m_currItem->xPos(), m_currItem->yPos());
409 	itemMatrix.rotate(m_currItem->rotation());
410 	m_selectedPoint = -1;
411 	for (int i = 0 ; i <  m_currItem->weldList.count(); i++)
412 	{
413 		PageItem::WeldingInfo wInf = m_currItem->weldList.at(i);
414 		if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(wInf.weldPoint.x(), wInf.weldPoint.y()))))
415 		{
416 			m_selectedPoint = i;
417 			break;
418 		}
419 	}
420 	m_canvas->m_viewMode.m_MouseButtonPressed = true;
421 	m_view->setCursor(QCursor(Qt::CrossCursor));
422 	m_doc->regionsChanged()->update(getUpdateRect());
423 }
424 
mouseReleaseEvent(QMouseEvent * m)425 void CanvasMode_EditWeldPoint::mouseReleaseEvent(QMouseEvent *m)
426 {
427 	m_canvas->m_viewMode.m_MouseButtonPressed = false;
428 	m_canvas->resetRenderMode();
429 	m->accept();
430 	m_currItem = m_doc->m_Selection->itemAt(0);
431 	m_currItem->update();
432 	m_doc->regionsChanged()->update(getUpdateRect());
433 }
434 
snapToEdgePoints(double & x,double & y)435 void CanvasMode_EditWeldPoint::snapToEdgePoints(double &x, double &y)
436 {
437 	int radius = m_doc->guidesPrefs().grabRadius;
438 	if (qAbs(0.0 - x) < radius && qAbs(0.0 - y) < radius)
439 	{
440 		x = 0.0;
441 		y = 0.0;
442 		return;
443 	}
444 	if ((qAbs((m_currItem->width() / 2.0) - x) < radius) && (qAbs(0.0 - y) < radius))
445 	{
446 		x = m_currItem->width() / 2.0;
447 		y = 0.0;
448 		return;
449 	}
450 	if ((qAbs(m_currItem->width() - x) < radius) && (qAbs(0.0 - y) < radius))
451 	{
452 		x = m_currItem->width();
453 		y = 0.0;
454 		return;
455 	}
456 	if ((qAbs(0.0 - x) < radius) && (qAbs((m_currItem->height() / 2.0) - y) < radius))
457 	{
458 		x = 0.0;
459 		y = m_currItem->height() / 2.0;
460 		return;
461 	}
462 	if ((qAbs((m_currItem->width() / 2.0) - x) < radius) && (qAbs((m_currItem->height() / 2.0) - y) < radius))
463 	{
464 		x = m_currItem->width() / 2.0;
465 		y = m_currItem->height() / 2.0;
466 		return;
467 	}
468 	if ((qAbs(m_currItem->width() - x) < radius) && (qAbs((m_currItem->height() / 2.0) - y) < radius))
469 	{
470 		x = m_currItem->width();
471 		y = m_currItem->height() / 2.0;
472 		return;
473 	}
474 	if ((qAbs(0.0 - x) < radius) && (qAbs(m_currItem->height() - y) < radius))
475 	{
476 		x = 0.0;
477 		y = m_currItem->height();
478 		return;
479 	}
480 	if ((qAbs((m_currItem->width() / 2.0) - x) < radius) && (qAbs(m_currItem->height() - y) < radius))
481 	{
482 		x = m_currItem->width() / 2.0;
483 		y = m_currItem->height();
484 		return;
485 	}
486 	if ((qAbs(m_currItem->width() - x) < radius) && (qAbs(m_currItem->height() - y) < radius))
487 	{
488 		x = m_currItem->width();
489 		y = m_currItem->height();
490 		return;
491 	}
492 }
493 
getUpdateRect()494 QRectF CanvasMode_EditWeldPoint::getUpdateRect()
495 {
496 	PageItem *item;
497 	uint selectedItemCount = m_weldToList.count();
498 	if (selectedItemCount == 0)
499 		return QRectF();
500 	double vminx =  std::numeric_limits<double>::max();
501 	double vminy =  std::numeric_limits<double>::max();
502 	double vmaxx = -std::numeric_limits<double>::max();
503 	double vmaxy = -std::numeric_limits<double>::max();
504 
505 	for (uint gc = 0; gc < selectedItemCount; ++gc)
506 	{
507 		item = m_weldToList.at(gc);
508 		if (item->rotation() != 0)
509 		{
510 			QRectF itRect(item->getVisualBoundingRect());
511 			vminx = qMin(vminx, itRect.x());
512 			vminy = qMin(vminy, itRect.y());
513 			vmaxx = qMax(vmaxx, itRect.right());
514 			vmaxy = qMax(vmaxy, itRect.bottom());
515 		}
516 		else
517 		{
518 			vminx = qMin(vminx, item->visualXPos());
519 			vminy = qMin(vminy, item->visualYPos());
520 			vmaxx = qMax(vmaxx, item->visualXPos() + item->visualWidth());
521 			vmaxy = qMax(vmaxy, item->visualYPos() + item->visualHeight());
522 		}
523 	}
524 	return QRectF(vminx, vminy, vmaxx - vminx, vmaxy - vminy).adjusted(-20, -20, 40, 40);
525 }
526