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 #if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
17 #define _USE_MATH_DEFINES
18 #endif
19 #include <cmath>
20 
21 // #include <QDebug>
22 #include <QToolTip>
23 #include <QWidget>
24 
25 #include "appmodes.h"
26 #include "canvas.h"
27 #include "canvasmode.h"
28 #include "pageitem_textframe.h"
29 #include "pageitem_group.h"
30 #include "pageitemiterator.h"
31 #include "prefsmanager.h"
32 #include "scpage.h"
33 #include "scpainter.h"
34 #include "scribusdoc.h"
35 #include "scribusview.h"
36 #include "selection.h"
37 #include "ui/hruler.h"
38 #include "ui/vruler.h"
39 #include "util.h"
40 #include "util_math.h"
41 #include "units.h"
42 
43 #define DRAW_DEBUG_LINES 0
44 
contentsToViewport(QPoint p)45 static QPoint contentsToViewport(QPoint p)
46 {
47 	return p;
48 }
49 
operator <<(QDataStream & ds,const CanvasViewMode & vm)50 QDataStream &operator<< ( QDataStream & ds, const CanvasViewMode & vm )
51 {
52 	ds << vm.scale
53 	<< vm.previewMode
54 	<< vm.viewAsPreview
55 	<< vm.previewVisual
56 	<< vm.m_MouseButtonPressed
57 	<< vm.operItemMoving
58 	<< vm.operItemResizing
59 	<< vm.operItemSelecting
60 	<< vm.redrawPolygon
61 	<< vm.linkedFramesToShow
62 	<< vm.drawSelectedItemsWithControls
63 	<< vm.drawFramelinksWithContents
64 	<< vm.forceRedraw;
65 	return ds;
66 }
67 
operator >>(QDataStream & ds,CanvasViewMode & vm)68 QDataStream &operator>> ( QDataStream & ds, CanvasViewMode & vm )
69 {
70 	ds >> vm.scale
71 	>> vm.previewMode
72 	>> vm.viewAsPreview
73 	>> vm.previewVisual
74 	>> vm.m_MouseButtonPressed
75 	>> vm.operItemMoving
76 	>> vm.operItemResizing
77 	>> vm.operItemSelecting
78 	>> vm.redrawPolygon
79 	>> vm.linkedFramesToShow
80 	>> vm.drawSelectedItemsWithControls
81 	>> vm.drawFramelinksWithContents
82 	>> vm.forceRedraw;
83 	return ds;
84 }
85 
86 
Canvas(ScribusDoc * doc,ScribusView * parent)87 Canvas::Canvas(ScribusDoc* doc, ScribusView* parent) : QWidget(parent), m_doc(doc), m_view(parent)
88 {
89 	setAutoFillBackground(true);
90 	setAttribute(Qt::WA_OpaquePaintEvent, true);
91 	setAttribute(Qt::WA_NoSystemBackground, true);
92 	m_buffer = QPixmap();
93 	m_bufferRect = QRect();
94 	m_renderMode = RENDER_NORMAL;
95 }
96 
setPreviewVisual(int mode)97 void Canvas::setPreviewVisual(int mode)
98 {
99 	m_viewMode.previewVisual = qMax(0, mode);
100 	m_viewMode.viewAsPreview = (mode >= 0);
101 }
102 // ______________________________
103 // Coordinate Conversion Routines:
104 
105 
localToCanvas(QPoint p) const106 FPoint Canvas::localToCanvas(QPoint p) const
107 {
108 
109 /* Allow the user to select the exact coordinate represented by a ruler mark
110    when the mouse is lined up with the ruler, rather than returning the
111    coordinate represented by the mathematical centre of the pixel which
112    may not be exactly the same as the coordinate represented by the ruler.
113 */
114 
115 // (xmin, xmax) = canvas top-left
116 	double xmin = m_doc->minCanvasCoordinate.x();
117 	double ymin = m_doc->minCanvasCoordinate.y();
118 
119 // (xoff, yoff) = ruler origin relative to canvas top-left
120 	double xoff = m_doc->rulerXoffset - xmin;
121 	double yoff = m_doc->rulerYoffset - ymin;
122 	if (m_doc->guidesPrefs().rulerMode) {
123 		xoff += m_doc->currentPage()->xOffset();
124 		yoff += m_doc->currentPage()->yOffset();
125 	}
126 // (xsp, ysp) = spacing of ruler divisions
127 	double xsp = m_doc->view()->horizRuler->ruleSpacing();
128 	double ysp = m_doc->view()->vertRuler->ruleSpacing();
129 
130 	double sc = m_viewMode.scale;
131 
132 // number of ruler divisions from ruler origin to ruler mark closest to the
133 // selected mouse coordinate
134 	double xn = qRound((p.x()/sc - xoff)/xsp);
135 	double yn = qRound((p.y()/sc - yoff)/ysp);
136 
137 // xn*xsp + xoff, yn*ysp + yoff = distance in canvas coordinates
138 // from canvas top-left to ruler mark closest to selected mouse coordinate
139 
140 // If these round to the selected mouse coordinate, use these to define
141 // (x,y), the coordinates of the desired point relative to the canvas top-left.
142 // Otherwise, simply scale the mouse coordinates.
143 	double x = ( qRound(sc*(xn*xsp + xoff)) == p.x() ?
144 	             xn * xsp + xoff : p.x() / sc );
145 	double y = ( qRound(sc*(yn*ysp + yoff)) == p.y() ?
146 	             yn * ysp + yoff : p.y() / sc );
147 
148 // Finally, add xmin,ymin to get the absolute canvas coordinates of the
149 // desired point.
150 	return FPoint(x + xmin, y + ymin);
151 }
152 
153 
154 /*
155 FPoint Canvas::localToCanvas(QPointF p) const
156 {
157 	return FPoint(p.x() / m_viewMode.scale + m_doc->minCanvasCoordinate.x() ,
158 				  p.y() / m_viewMode.scale + m_doc->minCanvasCoordinate.y());
159 }
160 */
161 
162 
canvasToLocal(const FPoint & p) const163 QPoint Canvas::canvasToLocal(const FPoint& p) const
164 {
165 	return { qRound((p.x() - m_doc->minCanvasCoordinate.x()) * m_viewMode.scale),
166 	         qRound((p.y() - m_doc->minCanvasCoordinate.y()) * m_viewMode.scale) };
167 }
168 
169 
canvasToLocal(QPointF p) const170 QPoint Canvas::canvasToLocal(QPointF p) const
171 {
172 	return { qRound((p.x() - m_doc->minCanvasCoordinate.x()) * m_viewMode.scale),
173 	         qRound((p.y() - m_doc->minCanvasCoordinate.y()) * m_viewMode.scale) };
174 }
175 
176 
canvasToLocal(const QRectF & p) const177 QRect Canvas::canvasToLocal(const QRectF& p) const
178 {
179 	return { qRound((p.x() - m_doc->minCanvasCoordinate.x()) * m_viewMode.scale),
180 	         qRound((p.y() - m_doc->minCanvasCoordinate.y()) * m_viewMode.scale),
181 	         qRound(p.width() * m_viewMode.scale),
182 	         qRound(p.height() * m_viewMode.scale) };
183 }
184 
canvasToLocalF(const QRectF & p) const185 QRectF Canvas::canvasToLocalF(const QRectF& p) const
186 {
187 	return { (p.x() - m_doc->minCanvasCoordinate.x()) * m_viewMode.scale,
188 	         (p.y() - m_doc->minCanvasCoordinate.y()) * m_viewMode.scale,
189 	         p.width() * m_viewMode.scale,
190 	         p.height() * m_viewMode.scale };
191 }
192 
193 
canvasToGlobal(const FPoint & p) const194 QPoint Canvas::canvasToGlobal(const FPoint& p) const
195 {
196 	return mapToParent(QPoint(0,0)) + parentWidget()->mapToGlobal(QPoint(0, 0)) + canvasToLocal(p);
197 }
198 
199 
canvasToGlobal(QPointF p) const200 QPoint Canvas::canvasToGlobal(QPointF p) const
201 {
202 	return mapToParent(QPoint(0,0)) + parentWidget()->mapToGlobal(QPoint(0, 0)) + canvasToLocal(p);
203 }
204 
205 
canvasToGlobal(const QRectF & p) const206 QRect Canvas::canvasToGlobal(const QRectF& p) const
207 {
208 	return { mapToParent(QPoint(0,0) + canvasToLocal(p.topLeft())) + parentWidget()->mapToGlobal(QPoint(0, 0)),
209 	         QSize(qRound(p.width() * m_viewMode.scale), qRound(p.height() * m_viewMode.scale)) };
210 }
211 
212 
globalToCanvas(QPoint p) const213 FPoint Canvas::globalToCanvas(QPoint p) const
214 {
215 	return localToCanvas(p - (mapToParent(QPoint(0, 0)) + parentWidget()->mapToGlobal(QPoint(0, 0))));
216 }
217 
218 
219 /*
220 FPoint Canvas::globalToCanvas(QPointF p) const
221 {
222 	return localToCanvas(p - mapToGlobal(QPoint(0, 0)));
223 }
224 */
225 
226 
globalToCanvas(QRect p) const227 QRectF Canvas::globalToCanvas(QRect p) const
228 {
229 	FPoint org = globalToCanvas(p.topLeft());
230 	return { org.x(), org.y(), p.width() / m_viewMode.scale, p.height() / m_viewMode.scale };
231 }
232 
233 
234 /*
235 QRectF Canvas::globalToCanvas(QRectF p) const
236 {
237 	FPoint org = globalToCanvas(p.topLeft());
238 	return QRectF(org.x(), org.y(), p.width() / m_viewMode.scale, p.height() / m_viewMode.scale);
239 }
240 */
241 
242 
243 // ________________________
244 // Tests for Finding Things:
245 
246 
hitsCanvasPoint(QPoint globalPoint,const FPoint & canvasPoint) const247 bool Canvas::hitsCanvasPoint(QPoint globalPoint, const FPoint& canvasPoint) const
248 {
249 	QPoint localPoint1 = globalPoint - (mapToParent(QPoint(0,0)) + parentWidget()->mapToGlobal(QPoint(0, 0)));
250 	QPoint localPoint2 = canvasToLocal(canvasPoint);
251 	int radius = m_doc->guidesPrefs().grabRadius;
252 	return qAbs(localPoint1.x() - localPoint2.x()) < radius && qAbs(localPoint1.y() - localPoint2.y()) < radius;
253 }
254 
255 
hitsCanvasPoint(QPoint globalPoint,QPointF canvasPoint) const256 bool Canvas::hitsCanvasPoint(QPoint globalPoint, QPointF canvasPoint) const
257 {
258 	QPoint localPoint1 = globalPoint - (mapToParent(QPoint(0,0)) + parentWidget()->mapToGlobal(QPoint(0, 0)));
259 	QPoint localPoint2 = canvasToLocal(canvasPoint);
260 	int radius = m_doc->guidesPrefs().grabRadius;
261 	return qAbs(localPoint1.x() - localPoint2.x()) < radius && qAbs(localPoint1.y() - localPoint2.y()) < radius;
262 }
263 
hitsCanvasPoint(const FPoint & globalPoint,const QPointF & canvasPoint) const264 bool Canvas::hitsCanvasPoint(const FPoint& globalPoint, const QPointF& canvasPoint) const
265 {
266 	double radius = m_doc->guidesPrefs().grabRadius;
267 	return qAbs(globalPoint.x() - canvasPoint.x()) < radius && qAbs(globalPoint.y() - canvasPoint.y()) < radius;
268 }
269 
exposedRect() const270 QRect Canvas::exposedRect() const
271 {
272 	int ex( -(x() / m_viewMode.scale) + m_doc->minCanvasCoordinate.x());
273 	int ey( -(y() / m_viewMode.scale) + m_doc->minCanvasCoordinate.y());
274 	int ew( (m_view->visibleWidth() * 1.2) / m_viewMode.scale);
275 	int eh( (m_view->visibleHeight() * 1.2) / m_viewMode.scale);
276 
277 	return { ex, ey, ew, eh };
278 }
279 
280 
281 /// Little helper to calculate |p|^2
282 
length2(const QPointF & p)283 static double length2(const QPointF& p)
284 {
285 	return p.x()*p.x() + p.y()*p.y();
286 }
287 
288 
289 
290 /*!
291   returns -1 if canvasPoint is outside the frame + grabradius.
292   returns frameHandle if canvasPoint is near a framehandle
293   otherwise 0
294  */
frameHitTest(QPointF canvasPoint,PageItem * item) const295 Canvas::FrameHandle Canvas::frameHitTest(QPointF canvasPoint, PageItem* item) const
296 {
297 	// As item->getTransform() will translate to Pos, we need to adjust the rect passed
298 	// to frameHitTest in order to take line width, which in very *creative* design can
299 	// be huge, into account.
300 	// ### might be interesting to investigate if it would be painless to just change
301 	// PageItem::getTransform.
302 	double extraS = - item->visualLineWidth() / 2.0;
303 //	if (item->lineColor() != CommonStrings::None)
304 //		extraS = (item->lineWidth() / -2.0);
305 	if (item->isTextFrame() && (m_doc->appMode == modeEdit) && !item->asTextFrame()->availableRegion().contains(item->getTransform().inverted().map(canvasPoint.toPoint())))
306 		return OUTSIDE;
307 	QRectF visualRect = item->isLine() ? QRectF(0, extraS, item->visualWidth(), item->visualHeight())
308 		                               : QRectF(extraS, extraS, item->visualWidth(), item->visualHeight());
309 	Canvas::FrameHandle result = frameHitTest(item->getTransform().inverted().map(canvasPoint), visualRect);
310 //	qDebug() << "frameHitTest for item" << item->ItemNr
311 //		<< item->getTransform().inverted().map(canvasPoint)
312 //		<< item->getTransform().inverted()
313 //		<< QRectF(0, 0, item->width(), item->height());
314 	return result;
315 }
316 
frameHitTest(QPointF canvasPoint,const QRectF & frame) const317 Canvas::FrameHandle Canvas::frameHitTest(QPointF canvasPoint, const QRectF& frame) const
318 {
319 	FrameHandle result = INSIDE;
320 	const double radius = m_doc->guidesPrefs().grabRadius / m_viewMode.scale;
321 	const double radius2 = radius * radius;
322 	double resultDistance = radius2 * 10.0; // far off
323 
324 	const double frameWidth = frame.width();
325 	const double frameHeight = frame.height();
326 	const QPointF frameOrigin = frame.topLeft();
327 
328 	if (canvasPoint.x() < frameOrigin.x() - radius ||
329 		canvasPoint.x() > frameOrigin.x() + frameWidth + radius ||
330 		canvasPoint.y() < frameOrigin.y() - radius ||
331 		canvasPoint.y() > frameOrigin.y() + frameHeight + radius)
332 	{
333 //		qDebug() << "framehittest" << canvasPoint << frame << "-> OUTSIDE";
334 		return OUTSIDE;
335 	}
336 
337 	QPointF framePoint = frameOrigin;
338 	double distance = length2(canvasPoint - framePoint);
339 	if (distance < radius2 && distance < resultDistance)
340 	{
341 		result = NORTHWEST;
342 		resultDistance = distance;
343 	}
344 
345 	framePoint.setX(frameOrigin.x() + frameWidth/2);
346 	distance = length2(canvasPoint - framePoint);
347 	if (distance < radius2 && distance < resultDistance)
348 	{
349 		result = NORTH;
350 		resultDistance = distance;
351 	}
352 
353 	framePoint.setX(frameOrigin.x() + frameWidth);
354 	distance = length2(canvasPoint - framePoint);
355 	if (distance < radius2 && distance < resultDistance)
356 	{
357 		result = NORTHEAST;
358 		resultDistance = distance;
359 	}
360 
361 	framePoint.setY(frameOrigin.y() + frameHeight/2);
362 	distance = length2(canvasPoint - framePoint);
363 	if (distance < radius2 && distance < resultDistance)
364 	{
365 		result = EAST;
366 		resultDistance = distance;
367 	}
368 
369 	framePoint.setY(frameOrigin.y() + frameHeight);
370 	distance = length2(canvasPoint - framePoint);
371 	if (distance < radius2 && distance < resultDistance)
372 	{
373 		result = SOUTHEAST;
374 		resultDistance = distance;
375 	}
376 
377 	framePoint.setX(frameOrigin.x() + frameWidth/2);
378 	distance = length2(canvasPoint - framePoint);
379 	if (distance < radius2 && distance < resultDistance)
380 	{
381 		result = SOUTH;
382 		resultDistance = distance;
383 	}
384 
385 	framePoint.setX(frameOrigin.x());
386 	distance = length2(canvasPoint - framePoint);
387 	if (distance < radius2 && distance < resultDistance)
388 	{
389 		result = SOUTHWEST;
390 		resultDistance = distance;
391 	}
392 
393 	framePoint.setY(frameOrigin.y() + frameHeight/2);
394 	distance = length2(canvasPoint - framePoint);
395 	if (distance < radius2 && distance < resultDistance)
396 	{
397 		result = WEST;
398 		//resultDistance = distance;
399 	}
400 
401 //	qDebug() << "framehittest" << canvasPoint << frame << "->" << result;
402 	return result;
403 }
404 
405 
itemUnderCursor(QPoint globalPos,PageItem * itemAbove,bool allowInGroup,bool allowMasterItems) const406 PageItem* Canvas::itemUnderCursor(QPoint globalPos, PageItem* itemAbove, bool allowInGroup, bool allowMasterItems) const
407 {
408 	PageItem* currItem;
409 	QRectF mouseArea = globalToCanvas(QRect(globalPos, QSize(2*m_doc->guidesPrefs().grabRadius, 2*m_doc->guidesPrefs().grabRadius)));
410 	// look for masterpage items first
411 	if (allowMasterItems && !m_doc->masterPageMode() && m_doc->currentPage()->FromMaster.count() != 0)
412 	{
413 		ScPage* Mp = m_doc->MasterPages.at(m_doc->MasterNames[m_doc->currentPage()->masterPageName()]);
414 		// if itemAbove is given, we expect to find it among the masterpage items of this page
415 		int currNr = itemAbove? m_doc->currentPage()->FromMaster.indexOf(itemAbove)-1 : m_doc->currentPage()->FromMaster.count()-1;
416 		if (currNr < 0)
417 			return nullptr;
418 		while (currNr >= 0)
419 		{
420 			currItem = m_doc->currentPage()->FromMaster.at(currNr);
421 			QTransform itemPos;
422 			if (m_doc->canSelectItemOnLayer(currItem->m_layerID))
423 			{
424 				if (!currItem->ChangedMasterItem)
425 				{
426 					itemPos.translate(-Mp->xOffset() + m_doc->currentPage()->xOffset(), -Mp->yOffset() + m_doc->currentPage()->yOffset());
427 				}
428 				currItem->getTransform(itemPos);
429 				QPainterPath currPath;
430 				if (currItem->isLine())
431 				{
432 					double visualLineWidth = currItem->visualLineWidth();
433 					currPath.moveTo(itemPos.map(QPointF(0.0, -visualLineWidth / 2.0)));
434 					currPath.lineTo(itemPos.map(QPointF(currItem->width(), -visualLineWidth / 2.0)));
435 					currPath.lineTo(itemPos.map(QPointF(currItem->width(),  visualLineWidth / 2.0)));
436 					currPath.lineTo(itemPos.map(QPointF(0.0,  visualLineWidth / 2.0)));
437 				}
438 				else
439 				{
440 					currPath.moveTo(itemPos.map(QPointF(0, 0)));
441 					currPath.lineTo(itemPos.map(QPointF(currItem->width(), 0)));
442 					currPath.lineTo(itemPos.map(QPointF(currItem->width(), currItem->height())));
443 					currPath.lineTo(itemPos.map(QPointF(0, currItem->height())));
444 				}
445 				currPath.closeSubpath();
446 				QPainterPath currClip;
447 				currClip.addPolygon(itemPos.map(QPolygonF(currItem->Clip)));
448 				currClip.closeSubpath();
449 				if (currPath.intersects(mouseArea) || currClip.intersects(mouseArea))
450 				{
451 					if (currItem->isGroup() && allowInGroup)
452 					{
453 						currItem->asGroupFrame()->adjustXYPosition();
454 						PageItem* ret = itemInGroup(currItem, mouseArea);
455 						if (ret != nullptr)
456 							return ret;
457 					}
458 					return currItem;
459 				}
460 			}
461 			--currNr;
462 		}
463 	}
464 	// now look for normal items
465 	if (m_doc->Items->isEmpty())
466 		return nullptr;
467 
468 	QList<PageItem*> *itemList = (itemAbove && itemAbove->isGroupChild()) ? &itemAbove->parentGroup()->groupItemList : m_doc->Items;
469 	int currNr = itemAbove ? itemList->indexOf(itemAbove) - 1 : itemList->count() - 1;
470 	while (currNr >= 0)
471 	{
472 		currItem = itemList->at(currNr);
473 		if ((m_doc->masterPageMode())  && (!((currItem->OwnPage == -1) || (currItem->OwnPage == static_cast<int>(m_doc->currentPage()->pageNr())))))
474 		{
475 			--currNr;
476 			continue;
477 		}
478 		if ((m_doc->drawAsPreview && !m_doc->editOnPreview) && !(currItem->isAnnotation() || currItem->isGroup()))
479 		{
480 			--currNr;
481 			continue;
482 		}
483 		if (m_doc->canSelectItemOnLayer(currItem->m_layerID))
484 		{
485 			QTransform itemPos = currItem->getTransform();
486 			QPainterPath currPath;
487 			if (currItem->isLine())
488 			{
489 				double visualLineWidth = currItem->visualLineWidth();
490 				currPath.moveTo(itemPos.map(QPointF(0.0, -visualLineWidth / 2.0)));
491 				currPath.lineTo(itemPos.map(QPointF(currItem->width(), -visualLineWidth / 2.0)));
492 				currPath.lineTo(itemPos.map(QPointF(currItem->width(),  visualLineWidth / 2.0)));
493 				currPath.lineTo(itemPos.map(QPointF(0.0,  visualLineWidth / 2.0)));
494 			}
495 			else
496 			{
497 				currPath.moveTo(itemPos.map(QPointF(0, 0)));
498 				currPath.lineTo(itemPos.map(QPointF(currItem->width(), 0)));
499 				currPath.lineTo(itemPos.map(QPointF(currItem->width(), currItem->height())));
500 				currPath.lineTo(itemPos.map(QPointF(0, currItem->height())));
501 			}
502 			currPath.closeSubpath();
503 			QPainterPath currClip;
504 			currClip.addPolygon(itemPos.map(QPolygonF(currItem->Clip)));
505 			currClip.closeSubpath();
506 			if (currPath.intersects(mouseArea) || currClip.intersects(mouseArea))
507 			{
508 				if (currItem->isGroup() && allowInGroup)
509 				{
510 					currItem->asGroupFrame()->adjustXYPosition();
511 					PageItem* ret = itemInGroup(currItem, mouseArea);
512 					if (ret != nullptr)
513 					{
514 						if ((m_doc->drawAsPreview && !m_doc->editOnPreview) && !ret->isAnnotation())
515 							return nullptr;
516 						return ret;
517 					}
518 				}
519 				return currItem;
520 			}
521 		}
522 		--currNr;
523 	}
524 	return nullptr;
525 }
526 
cursorOverTextFrameControl(QPoint globalPos,PageItem * frame)527 bool Canvas::cursorOverTextFrameControl(QPoint globalPos, PageItem* frame)
528 {
529 	FPoint mp=globalToCanvas(globalPos);
530 	qreal sideLength = 10 / qMax(m_viewMode.scale, 1.0);
531 	qreal left  = frame->xPos() + frame->width() - sideLength;// / 2;
532 	qreal right = left + sideLength;
533 	qreal top   = frame->yPos() + frame->height() - sideLength;// * 1.5;
534 	qreal bottom = top + sideLength;
535 	return mp.x()>left && mp.x()<right && mp.y()>top && mp.y()<bottom;
536 }
537 
cursorOverFrameControl(QPoint globalPos,const QRectF & targetRect,PageItem * frame)538 bool Canvas::cursorOverFrameControl(QPoint globalPos, const QRectF& targetRect, PageItem* frame)
539 {
540 	FPoint mp = globalToCanvas(globalPos);
541 	QRectF tg = targetRect.translated(frame->xPos(), frame->yPos());
542 	return tg.contains(QPointF(mp.x(), mp.y()));
543 }
544 
itemInGroup(PageItem * group,const QRectF & mouseArea) const545 PageItem* Canvas::itemInGroup(PageItem* group, const QRectF& mouseArea) const
546 {
547 	int currNr = group->groupItemList.count() - 1;
548 	while (currNr >= 0)
549 	{
550 		PageItem* embedded = group->groupItemList.at(currNr);
551 		QTransform itemPosN = embedded->getTransform();
552 		QPainterPath currPath(itemPosN.map(QPointF(0, 0)));
553 		currPath.lineTo(itemPosN.map(QPointF(embedded->width(), 0)));
554 		currPath.lineTo(itemPosN.map(QPointF(embedded->width(), embedded->height())));
555 		currPath.lineTo(itemPosN.map(QPointF(0, embedded->height())));
556 		currPath.closeSubpath();
557 		QPainterPath currClip;
558 		currClip.addPolygon(itemPosN.map(QPolygonF(embedded->Clip)));
559 		currClip.closeSubpath();
560 		currClip.translate(embedded->gXpos, embedded->gYpos);
561 		if (currPath.intersects(mouseArea) || currClip.intersects(mouseArea))
562 		{
563 			if (embedded->isGroup())
564 			{
565 				PageItem* ret = itemInGroup(embedded, mouseArea);
566 				if (ret != nullptr)
567 					return ret;
568 			}
569 			else
570 				return embedded;
571 		}
572 		--currNr;
573 	}
574 	return nullptr;
575 }
576 
itemUnderItem(PageItem * item,int & index) const577 PageItem * Canvas::itemUnderItem(PageItem * item, int& index) const
578 {
579 	int indice = qMin(index, m_doc->Items->count());
580 	if (index < 0 || indice < 0)
581 		return nullptr;
582 
583 	int itemid = m_doc->Items->indexOf(item);
584 	QRectF baseRect(item->getBoundingRect());
585 	int itemLevel = m_doc->layerLevelFromID(item->m_layerID);
586 	if (itemLevel < 0)
587 		return nullptr;
588 
589 	for(index = indice - 1; index >= 0; --index)
590 	{
591 		PageItem* item1 = m_doc->Items->at(index);
592 		int item1id = m_doc->Items->indexOf(item1);
593 		int level = m_doc->layerLevelFromID(item1->m_layerID);
594 		if ((item != item1) && (level >= 0) && (level <= itemLevel))
595 		{
596 			if ((level == itemLevel) && (item1id > itemid))
597 				continue;
598 			QRectF uRect(item1->getBoundingRect());
599 			if (baseRect.intersects(uRect))
600 				return item1;
601 		}
602 	}
603 	return nullptr;
604 }
605 
606 // __________________
607 // Buffered rendering:
608 
609 /*
610  Rendermodes:
611 
612  m_buffer holds the current page(s)
613  m_bufferRect describes the contents in local coordinates:
614 
615  minCanvasCoordinate |-> local (0,0)
616 
617  (0,0) |-> local (scale*minCanvasCoordinate)
618 
619  local m_bufferRect.topLeft |-> buffer (0,0)
620 
621 
622  */
623 
setRenderMode(RenderMode mode)624 void Canvas::setRenderMode(RenderMode mode)
625 {
626 //	qDebug() << "setRenderMode" << m_renderMode << "-->" << mode;
627 	if ( (mode < RENDER_SELECTION_SEPARATE) != (m_renderMode < RENDER_SELECTION_SEPARATE) )
628 	{
629 		clearBuffers();
630 	}
631 	m_renderMode = mode;
632 }
633 
634 
clearBuffers()635 void Canvas::clearBuffers()
636 {
637 	m_buffer = QPixmap();
638 	m_bufferRect = QRect();
639 	m_selectionBuffer = QPixmap();
640 	m_selectionRect = QRect();
641 }
642 
setScale(double scale)643 void Canvas::setScale(double scale)
644 {
645 	if (m_viewMode.scale == scale)
646 		return;
647 	m_viewMode.scale = scale;
648 	clearBuffers();
649 	update();
650 }
651 
652 
adjustBuffer()653 bool Canvas::adjustBuffer()
654 {
655 	bool ret = false;
656 	QRect viewport(-x(), -y(), m_view->viewport()->width(), m_view->viewport()->height());
657 // 	qDebug()<<"Canvas::adjustBuffer"<<viewport<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
658 	QPoint minCanvasCoordinate = canvasToLocal(QPointF(0.0, 0.0));
659 	if (minCanvasCoordinate != m_oldMinCanvasCoordinate)
660 	{
661 		m_bufferRect.translate(minCanvasCoordinate.x() - m_oldMinCanvasCoordinate.x(),
662 							   minCanvasCoordinate.y() - m_oldMinCanvasCoordinate.y());
663 		m_oldMinCanvasCoordinate = minCanvasCoordinate;
664 	}
665 #if DRAW_DEBUG_LINES
666 //	qDebug() << "adjust buffer" << m_bufferRect << "for viewport" << viewport;
667 #endif
668 	if (!m_bufferRect.isValid())
669 	{
670 //		qDebug() << "adjust buffer: invalid buffer, viewport" << viewport;
671 		m_bufferRect = viewport;
672 		m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
673 		fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
674 		ret = true;
675 #if DRAW_DEBUG_LINES
676 		QPainter p(&m_buffer);
677 		p.setPen(Qt::blue);
678 		p.drawLine(0, 0, m_buffer.width(), m_buffer.height());
679 		p.drawLine(m_buffer.width(), 0, 0, m_buffer.height());
680 		p.end();
681 #endif
682 	}
683 	else if (!m_bufferRect.contains(viewport))
684 	{
685 		QRect newRect(m_bufferRect);
686 		if (m_bufferRect.left() > viewport.left())
687 			newRect.translate(viewport.left() - m_bufferRect.left(), 0);
688 		if (m_bufferRect.right() < viewport.right())
689 			newRect.translate(viewport.right() - m_bufferRect.right(), 0);
690 		if (m_bufferRect.top() > viewport.top())
691 			newRect.translate(0, viewport.top() - m_bufferRect.top());
692 		if (m_bufferRect.bottom() < viewport.bottom())
693 			newRect.translate(0, viewport.bottom() - m_bufferRect.bottom());
694 //		qDebug() << "adjust buffer: " << m_bufferRect << "outside viewport" << viewport << " new rect:" << newRect;
695 
696 		if (!m_bufferRect.intersects(newRect))
697 		{
698 //			qDebug() << "adjust buffer: fresh buffer" << m_bufferRect << "-->" << newRect;
699 			m_bufferRect = newRect;
700 			m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
701 			fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
702 			ret = true;
703 #if DRAW_DEBUG_LINES
704 			QPainter p(&m_buffer);
705 			p.setPen(Qt::blue);
706 			p.drawLine(0, 0, m_buffer.width(), m_buffer.height());
707 			p.drawLine(m_buffer.width(), 0, 0, m_buffer.height());
708 			p.end();
709 #endif
710 		}
711 		else
712 		{
713 			// copy buffer:
714 			QPixmap newBuffer = createPixmap(newRect.width(), newRect.height());
715 			QPainter p(&newBuffer);
716 			int xpos = m_bufferRect.x() - newRect.x();
717 			int ypos = m_bufferRect.y() - newRect.y();
718 			int x = 0;
719 			int y = 0;
720 			int width = m_bufferRect.width();
721 			int height = m_bufferRect.height();
722 			if (xpos < 0)
723 			{
724 				x = -xpos;
725 				width -= x;
726 				xpos = 0;
727 			}
728 			if (ypos < 0)
729 			{
730 				y = -ypos;
731 				height -= y;
732 				ypos = 0;
733 			}
734 			if (xpos + width > newRect.width())
735 			{
736 				width = newRect.width() - xpos;
737 			}
738 			if (ypos + height > newRect.height())
739 			{
740 				height = newRect.height() - ypos;
741 			}
742 
743 			drawPixmap(p, xpos, ypos, m_buffer, x, y, width + 1, height + 1);
744 #if DRAW_DEBUG_LINES
745 			p.setPen(Qt::blue);
746 			p.drawLine(xpos, ypos+height/2, xpos+width/2, ypos);
747 			p.drawLine(xpos+width, ypos+height/2, xpos+width/2, ypos);
748 			p.drawLine(xpos, ypos+height/2, xpos+width/2, ypos+height);
749 			p.drawLine(xpos+width, ypos+height/2, xpos+width/2, ypos+height);
750 //			qDebug() << "adjust buffer old" << m_bufferRect << "@" << xpos << ypos << "--> new" << newRect;
751 #endif
752 			p.end();
753 
754 			// #8548, #13470 do not return true in this case, we only partially update buffer content
755 			// and the redraw rect from paintEvent may not be included in the updated area if
756 			// canvas has just been resized, after an object has been put in scrap area for eg.
757 			if (newRect.top() < m_bufferRect.top())
758 			{
759 				fillBuffer(&newBuffer, newRect.topLeft(), QRect(newRect.left(), newRect.top(), newRect.width(), m_bufferRect.top() - newRect.top() + 2));
760 				//ret = true;
761 			}
762 			if (newRect.bottom() > m_bufferRect.bottom())
763 			{
764 				fillBuffer(&newBuffer, newRect.topLeft(), QRect(newRect.left(), m_bufferRect.bottom() - 1, newRect.width(), newRect.bottom() - m_bufferRect.bottom() + 2));
765 				//ret = true;
766 			}
767 			if (newRect.left() < m_bufferRect.left())
768 			{
769 				fillBuffer(&newBuffer, newRect.topLeft(), QRect(newRect.left(), m_bufferRect.top(), m_bufferRect.left() - newRect.left() + 2, m_bufferRect.height()));
770 				//ret = true;
771 			}
772 			if (newRect.right() > m_bufferRect.right())
773 			{
774 				fillBuffer(&newBuffer, newRect.topLeft(), QRect(m_bufferRect.right() - 1, m_bufferRect.top(), newRect.right() - m_bufferRect.right() + 2, m_bufferRect.height()));
775 				//ret = true;
776 			}
777 			m_buffer = newBuffer;
778 			m_bufferRect = newRect;
779 #if DRAW_DEBUG_LINES
780 			QPainter p2(&m_buffer);
781 			p2.setPen(Qt::blue);
782 			p2.drawRect(xpos, ypos, width, height);
783 			p2.end();
784 #endif
785 		}
786 	}
787 //	else
788 //		qDebug() << "adjustBuffer: reusing" << m_bufferRect;
789 // 	qDebug() << "Canvas::adjustBuffer"<<ret;
790 	return ret;
791 }
792 
fillBuffer(QPaintDevice * buffer,QPoint bufferOrigin,QRect clipRect)793 void Canvas::fillBuffer(QPaintDevice* buffer, QPoint bufferOrigin, QRect clipRect)
794 {
795 // 	qDebug()<<"Canvas::fillBuffer"<<clipRect<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
796 	QPainter painter(buffer);
797 	painter.translate(-bufferOrigin.x(), -bufferOrigin.y());
798 	drawContents(&painter, clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
799 	painter.end();
800 }
801 
802 /**
803   Actually we have at least three super-layers:
804   - background (page outlines, guides if below)
805   - content (master & page objects)
806   - controls (selection, mode specific mrks, guides if above)
807   For export we only need the contents.
808 */
paintEvent(QPaintEvent * p)809 void Canvas::paintEvent ( QPaintEvent * p )
810 {
811 //	qDebug()<<"Canvas::paintEvent"<<p->rect()<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
812 // 	printBacktrace(62);
813 	if (m_doc->isLoading() || !m_doc->DoDrawing)
814 		return;
815 // #define SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
816 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
817 	QTime t;
818 	QString dmode("");
819 	int t1,t2,t3,t4,t5,t6;
820 	t1 = t2=t3=t4=t5 =t6= 0;
821 	t.start();
822 #endif
823 	// fill buffer if necessary
824 	bool bufferFilled = adjustBuffer();
825 	QPainter qp(this);
826 	switch (m_renderMode)
827 	{
828 		case RENDER_NORMAL:
829 		{
830 #if DRAW_DEBUG_LINES
831 //			qDebug() << "update Buffer:" << m_bufferRect << p->rect() << m_viewMode.forceRedraw;
832 #endif
833 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
834 			dmode = "NORMAL";
835 			t1 = t.elapsed();
836 			t.start();
837 #endif
838 			if ((m_viewMode.forceRedraw || m_viewMode.operTextSelecting) && (!bufferFilled))
839 			{
840 //				qDebug() << "Canvas::paintEvent: forceRedraw=" << m_viewMode.forceRedraw << "bufferFilled=" << bufferFilled;
841 				fillBuffer(&m_buffer, m_bufferRect.topLeft(), p->rect());
842 			}
843 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
844 			t2 = t.elapsed();
845 			t.start();
846 #endif
847 			int xV = p->rect().x() - m_bufferRect.x();
848 			int yV = p->rect().y() - m_bufferRect.y();
849 			int wV = p->rect().width();
850 			int hV = p->rect().height();
851 			if (hV > 0 && wV > 0)
852 			{
853 				drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
854 #if DRAW_DEBUG_LINES
855 //				qDebug() << "normal rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
856 				qp.setPen(Qt::blue);
857 				qp.drawLine(p->rect().x(), p->rect().y(), p->rect().x() + p->rect().width(), p->rect().y() + p->rect().height());
858 				qp.drawLine(p->rect().x() + p->rect().width(), p->rect().y(), p->rect().x(), p->rect().y() + p->rect().height());
859 #endif
860 			}
861 		}
862 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
863 			t3 = t.elapsed();
864 			t.start();
865 #endif
866 			if (m_doc->appMode != modeNormal)
867 			{
868 				qp.save();
869 				qp.scale(m_viewMode.scale, m_viewMode.scale);
870 				qp.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
871 				drawControls( &qp );
872 				qp.restore();
873 			}
874 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
875 			t4 = t.elapsed();
876 			t.start();
877 #endif
878 			break;
879 		case RENDER_BUFFERED:
880 		{
881 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
882 			dmode = "BUFFER";
883 			t1 = t.elapsed();
884 			t.start();
885 #endif
886 				int xV = p->rect().x() - m_bufferRect.x();
887 				int yV = p->rect().y() - m_bufferRect.y();
888 				int wV = p->rect().width();
889 				int hV = p->rect().height();
890 				if (xV < 0)
891 				{
892 					wV += xV;
893 					xV = 0;
894 				}
895 				if (yV < 0)
896 				{
897 					hV += yV;
898 					yV = 0;
899 				}
900 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
901 				t2 = t.elapsed();
902 				t.start();
903 #endif
904 				if (hV > 0 && wV > 0)
905 				{
906 					drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
907 	#if DRAW_DEBUG_LINES
908 //					qDebug() << "buffered rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
909 					qp.setPen(Qt::green);
910 					qp.drawLine(p->rect().x(), p->rect().y(), p->rect().x() + p->rect().width(), p->rect().y() + p->rect().height());
911 					qp.drawLine(p->rect().x() + p->rect().width(), p->rect().y(), p->rect().x(), p->rect().y() + p->rect().height());
912 	#endif
913 				}
914 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
915 				t3 = t.elapsed();
916 				t.start();
917 #endif
918 				if (m_doc->appMode != modeNormal)
919 				{
920 					qp.save();
921 					qp.scale(m_viewMode.scale, m_viewMode.scale);
922 					qp.translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y());
923 					drawControls( &qp );
924 					qp.restore();
925 				}
926 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
927 				t4 = t.elapsed();
928 				t.start();
929 #endif
930 			}
931 			break;
932 		case RENDER_SELECTION_SEPARATE:
933 			break;
934 		case RENDER_SELECTION_BUFFERED:
935 			break;
936 		case RENDER_LEGACY:
937 		default:
938 			assert (false);
939 	}
940 
941 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
942 	t5 = t.elapsed();
943 	t.start();
944 #endif
945 	// does mode specific rendering, currently selection in legacymode and nodes in nodeedit
946 	m_view->m_canvasMode->drawControls(&qp);
947 	m_view->m_canvasMode->drawSnapLine(&qp);
948 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
949 	t6 = t.elapsed();
950 	qDebug()<<dmode<<t1<<t2<<t3<<t4<<t5<<t6<<"-" <<t1+t2+t3+t4+t5+t6;
951 #endif
952 	m_viewMode.forceRedraw = false;
953 	m_viewMode.operItemSelecting = false;
954 	m_viewMode.operTextSelecting = false;
955 }
956 
957 
drawContents(QPainter * psx,int clipx,int clipy,int clipw,int cliph)958 void Canvas::drawContents(QPainter *psx, int clipx, int clipy, int clipw, int cliph)
959 {
960 //	int Tsetup, Toutlines , Tbackground, Tcontents;
961 //	Toutlines=0;
962 //	QTime tim;
963 //	tim.start();
964 // 	qDebug() << "Canvas::drawContents" << clipx << clipy << clipw << cliph<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
965 	int docPagesCount = m_doc->Pages->count();
966 	ScPainter *painter = nullptr;
967 	QImage img = QImage(clipw * devicePixelRatioF(), cliph * devicePixelRatioF(), QImage::Format_ARGB32_Premultiplied);
968 	img.setDevicePixelRatio(devicePixelRatioF());
969 	painter = new ScPainter(&img, img.width(), img.height(), 1.0, 0);
970 	painter->clear(palette().color(QPalette::Window));
971 	painter->newPath();
972 	painter->moveTo(0, 0);
973 	painter->lineTo(clipw, 0);
974 	painter->lineTo(clipw, cliph);
975 	painter->lineTo(0, cliph);
976 	painter->closePath();
977 	painter->setClipPath();
978 	painter->translate(-clipx, -clipy);
979 	painter->setZoomFactor(m_viewMode.scale);
980 	painter->translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y());
981 	painter->setLineWidth(1);
982 	painter->setFillMode(ScPainter::Solid);
983 
984 	ScLayer layer;
985 	layer.isViewable = false;
986 	layer.ID = 0;
987 
988 	if (!m_doc->masterPageMode())
989 	{
990 		drawBackgroundPageOutlines(painter, clipx, clipy, clipw, cliph);
991 		m_viewMode.linkedFramesToShow.clear();
992 		QRectF clip = QRectF(clipx, clipy, clipw, cliph);
993 		DrawPageBorder(painter, clip);
994 		if (m_viewMode.viewAsPreview)
995 		{
996 			FPointArray PoLine;
997 			getClipPathForPages(&PoLine);
998 			painter->beginLayer(1.0, 0, &PoLine);
999 		}
1000 		else
1001 			painter->beginLayer(1.0, 0);
1002 		int renderStackCount = m_doc->guidesPrefs().renderStackOrder.count();
1003 		for (int r = 0; r < renderStackCount; r++)
1004 		{
1005 			int ri = m_doc->guidesPrefs().renderStackOrder[r];
1006 			if (ri == 0)
1007 			{
1008 				if (!m_viewMode.viewAsPreview)
1009 					DrawPageMargins(painter, clip);			// drawing stack id = 0
1010 			}
1011 			else if (ri == 1)
1012 			{
1013 				if (!m_viewMode.viewAsPreview)
1014 					DrawPageBaselineGrid(painter, clip);	// drawing stack id = 1
1015 			}
1016 			else if (ri == 2)
1017 			{
1018 				if (!m_viewMode.viewAsPreview)
1019 					DrawPageGrid(painter, clip);			// drawing stack id = 2
1020 			}
1021 			else if (ri == 3)
1022 			{
1023 				if (!m_viewMode.viewAsPreview)
1024 					DrawPageGuides(painter, clip);			// drawing stack id = 3
1025 			}
1026 			else if (ri == 4)
1027 			{
1028 				int layerCount = m_doc->layerCount();	// drawing stack id = 4
1029 				for (int layerLevel = 0; layerLevel < layerCount; ++layerLevel)
1030 				{
1031 					m_doc->Layers.levelToLayer(layer, layerLevel);
1032 					for (int a = 0; a < docPagesCount; ++a)
1033 					{
1034 						DrawMasterItems(painter, m_doc->Pages->at(a), layer, QRect(clipx, clipy, clipw, cliph));
1035 					}
1036 					//first pass draws all except notes frames
1037 					DrawPageItems(painter, layer, QRect(clipx, clipy, clipw, cliph), false);
1038 					//seconf only for notes frames
1039 					DrawPageItems(painter, layer, QRect(clipx, clipy, clipw, cliph), true);
1040 				}
1041 			}
1042 		}
1043 		if (!m_viewMode.viewAsPreview)
1044 			DrawPageIndicator(painter, clip);
1045 		painter->endLayer();
1046 	}
1047 	else // masterPageMode
1048 	{
1049 		m_viewMode.linkedFramesToShow.clear();
1050 		drawBackgroundMasterpage(painter, clipx, clipy, clipw, cliph);
1051 		painter->beginLayer(1.0, 0);
1052 		QRectF clip = QRectF(clipx, clipy, clipw, cliph);
1053 		DrawPageBorder(painter, clip, true);
1054 		int renderStackCount = m_doc->guidesPrefs().renderStackOrder.count();
1055 		for (int r = 0; r < renderStackCount; r++)
1056 		{
1057 			int ri = m_doc->guidesPrefs().renderStackOrder[r];
1058 			if (ri == 0)
1059 			{
1060 				DrawPageMargins(painter, clip, true);			// drawing stack id = 0
1061 			}
1062 			else if (ri == 1)
1063 			{
1064 				DrawPageBaselineGrid(painter, clip, true);	// drawing stack id = 1
1065 			}
1066 			else if (ri == 2)
1067 			{
1068 				DrawPageGrid(painter, clip, true);			// drawing stack id = 2
1069 			}
1070 			else if (ri == 3)
1071 			{
1072 				DrawPageGuides(painter, clip, true);			// drawing stack id = 3
1073 			}
1074 			else if (ri == 4)
1075 			{
1076 				int layerCount = m_doc->layerCount();	// drawing stack id = 4
1077 				for (int layerLevel = 0; layerLevel < layerCount; ++layerLevel)
1078 				{
1079 					m_doc->Layers.levelToLayer(layer, layerLevel);
1080 					//first pass draws all except notes frames
1081 					DrawPageItems(painter, layer, QRect(clipx, clipy, clipw, cliph), false);
1082 					//second pass draw only notes frames
1083 					DrawPageItems(painter, layer, QRect(clipx, clipy, clipw, cliph), true);
1084 				}
1085 			}
1086 		}
1087 		DrawPageIndicator(painter, clip, true);
1088 		painter->endLayer();
1089 	}
1090 	if (((m_doc->m_Selection->count() != 0) || (m_viewMode.linkedFramesToShow.count() != 0))  && (!m_viewMode.viewAsPreview))
1091 	{
1092 		drawFrameLinks(painter);
1093 	}
1094 	painter->end();
1095 	psx->drawImage(clipx, clipy, img);
1096 	delete painter;
1097 	painter=nullptr;
1098 // 	qDebug( "Time elapsed: %d ms, setup=%d, outlines=%d, background=%d, contents=%d, rest=%d", tim.elapsed(), Tsetup,Toutlines -Tsetup, Tbackground-Toutlines, Tcontents-Tbackground, tim.elapsed() - Tcontents );
1099 }
1100 
drawControls(QPainter * psx)1101 void Canvas::drawControls(QPainter *psx)
1102 {
1103 	psx->save();
1104 	if ((m_doc->appMode == modeDrawBezierLine) && (!m_viewMode.redrawPolygon.isEmpty()) && (m_doc->m_Selection->count() != 0))
1105 	{
1106 		drawControlsBezierCurve(psx, m_doc->m_Selection->itemAt(0));
1107 	}
1108 	if (m_viewMode.m_MouseButtonPressed && (m_doc->appMode == modeMeasurementTool))
1109 	{
1110 		drawControlsMeasurementLine(psx);
1111 	}
1112 	if (m_viewMode.m_MouseButtonPressed && (m_doc->appMode == modeDrawLine))
1113 	{
1114 		drawControlsDrawLine(psx);
1115 	}
1116 	if (m_viewMode.operItemMoving || m_viewMode.operItemResizing)
1117 	{
1118 		if (m_viewMode.operItemResizing)
1119 		{
1120 			if (!m_viewMode.redrawPolygon.isEmpty())
1121 			{
1122 				if (m_viewMode.m_MouseButtonPressed && ((m_doc->appMode == modeDrawFreehandLine) || (m_doc->appMode == modeDrawCalligraphicLine)))
1123 				{
1124 					drawControlsFreehandLine(psx);
1125 				}
1126 				else if (m_doc->appMode != modeDrawFreehandLine)
1127 				{
1128 //					qDebug() << "XXX drawControls - operItemResizing";
1129 					assert(false);
1130 //					drawControlsHighlightRect(psx);
1131 				}
1132 			}
1133 		}
1134 		else
1135 		{
1136 			drawControlsMovingItemsRect(psx);
1137 		}
1138 	}
1139 	else
1140 	{
1141 		if ((m_doc->m_Selection->count() != 0) && (m_doc->appMode != modeDrawBezierLine))
1142 		{
1143 //			drawControlsSelection(psx, m_doc->m_Selection->itemAt(0));
1144 			/*
1145 			 PageItem *currItem = m_doc->m_Selection->itemAt(0);
1146 			 if ((m_doc->appMode == modeEditClip) && (currItem->isSelected()))
1147 			 {
1148 				 drawControlsNodeEditPoints(psx, currItem);
1149 			 }
1150 			 else
1151 			 {
1152 				 drawControlsSelectionSpecial(psx, currItem);
1153 			 }*/
1154 		}
1155 	}
1156 	psx->restore();
1157 }
1158 
1159 
1160 
1161 /**
1162 
1163 */
drawControlsMovingItemsRect(QPainter * pp)1164 void Canvas::drawControlsMovingItemsRect(QPainter* pp)
1165 {
1166 	int selectedItemCount = m_doc->m_Selection->count();
1167 	if (selectedItemCount <= 0)
1168 		return;
1169 
1170 	PageItem *currItem = nullptr;
1171 	if (selectedItemCount >= moveWithBoxesOnlyThreshold)
1172 	{
1173 		double gx, gy, gw, gh;
1174 		m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
1175 		pp->translate(gx, gy);
1176 		pp->drawRect(QRectF(0.0, 0.0, gw, gh));
1177 		return;
1178 	}
1179 
1180 	for (int cu = 0; cu < selectedItemCount; cu++)
1181 	{
1182 		currItem = m_doc->m_Selection->itemAt(cu);
1183 		pp->save();
1184 		pp->translate(currItem->xPos(), currItem->yPos());
1185 		pp->rotate(currItem->rotation());
1186 		pp->setBrush(Qt::NoBrush);
1187 		pp->setPen(QPen(Qt::black, 1.0 / m_viewMode.scale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
1188 		if (currItem->isGroup())
1189 		{
1190 			PageItem_Group* gItem = currItem->asGroupFrame();
1191 			pp->scale(gItem->width() / gItem->groupWidth, gItem->height() / gItem->groupHeight);
1192 			int itemCountG = gItem->groupItemList.count();
1193 			if (itemCountG < moveWithFullOutlinesThreshold)
1194 			{
1195 				for (int cg = 0; cg < itemCountG; cg++)
1196 				{
1197 					currItem = gItem->groupItemList.at(cg);
1198 					if (!(currItem->isLine()))
1199 						currItem->DrawPolyL(pp, currItem->Clip);
1200 					else
1201 					{
1202 						if (currItem->isLine())
1203 						{
1204 							int lw2 = 1;
1205 							int lw = 1;
1206 							Qt::PenCapStyle le = Qt::FlatCap;
1207 							if (currItem->NamedLStyle.isEmpty())
1208 							{
1209 								if (currItem->lineColor() != CommonStrings::None)
1210 								{
1211 									lw2 = qRound(currItem->lineWidth()  / 2.0);
1212 									lw = qRound(qMax(currItem->lineWidth(), 1.0));
1213 								}
1214 								le = currItem->PLineEnd;
1215 							}
1216 							else
1217 							{
1218 								multiLine ml = m_doc->docLineStyles[currItem->NamedLStyle];
1219 								lw2 = qRound(ml[ml.size()-1].Width  / 2.0);
1220 								lw = qRound(qMax(ml[ml.size()-1].Width, 1.0));
1221 								le = static_cast<Qt::PenCapStyle>(ml[ml.size()-1].LineEnd);
1222 							}
1223 							if (le != Qt::FlatCap)
1224 								pp->drawRect(-lw2, -lw2, qRound(currItem->width())+lw, lw);
1225 							else
1226 								pp->drawRect(-1, -lw2, qRound(currItem->width()), lw);
1227 						}
1228 					}
1229 				}
1230 			}
1231 		}
1232 		else if (selectedItemCount < moveWithFullOutlinesThreshold)
1233 		{
1234 			if (!currItem->asLine())
1235 				currItem->DrawPolyL(pp, currItem->Clip);
1236 			else
1237 			{
1238 				int lw2 = 1;
1239 				int lw = 1;
1240 				Qt::PenCapStyle le = Qt::FlatCap;
1241 				if (currItem->NamedLStyle.isEmpty())
1242 				{
1243 					if (currItem->lineColor() != CommonStrings::None)
1244 					{
1245 						lw2 = qRound(currItem->lineWidth()  / 2.0);
1246 						lw = qRound(qMax(currItem->lineWidth(), 1.0));
1247 					}
1248 					le = currItem->PLineEnd;
1249 				}
1250 				else
1251 				{
1252 					multiLine ml = m_doc->docLineStyles[currItem->NamedLStyle];
1253 					lw2 = qRound(ml[ml.size()-1].Width  / 2.0);
1254 					lw = qRound(qMax(ml[ml.size()-1].Width, 1.0));
1255 					le = static_cast<Qt::PenCapStyle>(ml[ml.size()-1].LineEnd);
1256 				}
1257 				if (le != Qt::FlatCap)
1258 					pp->drawRect(-lw2, -lw2, qRound(currItem->width())+lw, lw);
1259 				else
1260 					pp->drawRect(-1, -lw2, qRound(currItem->width()), lw);
1261 			}
1262 		}
1263 		else
1264 			pp->drawRect(0, 0, static_cast<int>(currItem->width())+1, static_cast<int>(currItem->height())+1);
1265 		pp->restore();
1266 	}
1267 }
1268 
1269 /**
1270   draws the bezier curve in edit bezier mode
1271   */
drawControlsBezierCurve(QPainter * pp,PageItem * currItem)1272 void Canvas::drawControlsBezierCurve(QPainter* pp, PageItem* currItem)
1273 {
1274 	pp->setBrush(Qt::NoBrush);
1275 	pp->setPen(QPen(Qt::black, 1.0 / m_viewMode.scale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
1276 	pp->translate(static_cast<int>(currItem->xPos()), static_cast<int>(currItem->yPos()));
1277 	pp->rotate(currItem->rotation());
1278 	QPainterPath Bez;
1279 	if (currItem->PoLine.size() > 1)
1280 	{
1281 		QPoint nXY = m_viewMode.redrawPolygon.point(0);
1282 		if (!m_viewMode.m_MouseButtonPressed)
1283 		{
1284 			FPoint a1 = currItem->PoLine.point(currItem->PoLine.size()-2);
1285 			FPoint a2 = currItem->PoLine.point(currItem->PoLine.size()-1);
1286 			Bez.moveTo(a1.x(), a1.y());
1287 			Bez.cubicTo(a2.x(), a2.y(), nXY.x(), nXY.y(), nXY.x(), nXY.y());
1288 			pp->drawPath(Bez);
1289 		}
1290 		else
1291 		{
1292 			FPoint a2 = currItem->PoLine.point(currItem->PoLine.size()-1);
1293 			if (currItem->PoLine.size() > 2)
1294 			{
1295 				FPoint a1 = currItem->PoLine.point(currItem->PoLine.size()-2);
1296 				FPoint a3 = currItem->PoLine.point(currItem->PoLine.size()-3);
1297 				Bez.moveTo(a3.x(), a3.y());
1298 				Bez.cubicTo(a1.x(), a1.y(), nXY.x(), nXY.y(), a2.x(), a2.y());
1299 				pp->drawPath(Bez);
1300 			}
1301 			pp->drawLine(QPoint(qRound(a2.x()), qRound(a2.y())), nXY);
1302 		}
1303 	}
1304 	else
1305 	{
1306 		QPoint a2 = currItem->PoLine.pointQ(currItem->PoLine.size()-1);
1307 		QPoint nXY = m_viewMode.redrawPolygon.point(0);
1308 		pp->drawLine(a2, nXY);
1309 	}
1310 	m_viewMode.redrawPolygon.clear();
1311 }
1312 
1313 
1314 
1315 
1316 /**
1317   draws the measurement line in measure mode
1318  */
drawControlsMeasurementLine(QPainter * pp)1319 void Canvas::drawControlsMeasurementLine(QPainter* pp)
1320 {
1321 	pp->setBrush(Qt::NoBrush);
1322 	pp->setPen(QPen(Qt::black, 1.0, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
1323 	pp->drawPolyline(m_viewMode.redrawPolygon);
1324 	m_viewMode.redrawPolygon.clear();
1325 }
1326 
1327 
1328 /**
1329   draws the line in drawline mode
1330  */
drawControlsDrawLine(QPainter * pp)1331 void Canvas::drawControlsDrawLine(QPainter* pp)
1332 {
1333 	pp->setBrush(Qt::NoBrush);
1334 	pp->setPen(QPen(Qt::black, 1.0 / m_viewMode.scale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
1335 	pp->drawPolyline(m_viewMode.redrawPolygon);
1336 	m_viewMode.redrawPolygon.clear();
1337 }
1338 
1339 
1340 /**
1341   draws the freehand curve in freehand mode
1342  */
drawControlsFreehandLine(QPainter * pp)1343 void Canvas::drawControlsFreehandLine(QPainter* pp)
1344 {
1345 	pp->setBrush(Qt::NoBrush);
1346 	pp->setPen(QPen(Qt::black, 1.0 / m_viewMode.scale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
1347 	pp->drawPolyline(m_viewMode.redrawPolygon);
1348 	m_viewMode.redrawPolygon.clear();
1349 }
1350 
1351 
1352 /**
1353   draws masterpage items of a specific layer
1354  */
DrawMasterItems(ScPainter * painter,ScPage * page,ScLayer & layer,QRect clip)1355 void Canvas::DrawMasterItems(ScPainter *painter, ScPage *page, ScLayer& layer, QRect clip)
1356 {
1357 	if ((m_viewMode.previewMode) && (!layer.isPrintable))
1358 		return;
1359 	if ((m_viewMode.viewAsPreview) && (!layer.isPrintable))
1360 		return;
1361 	if (!layer.isViewable)
1362 		return;
1363 	if (page->masterPageNameEmpty())
1364 		return;
1365 	if (page->FromMaster.count() <= 0)
1366 		return;
1367 
1368 	FPoint orig = localToCanvas(clip.topLeft());
1369 	QRectF cullingArea = QRectF(static_cast<int>(orig.x()), static_cast<int>(orig.y()),
1370 							  qRound(clip.width() / m_viewMode.scale + 0.5), qRound(clip.height() / m_viewMode.scale + 0.5));
1371 
1372 	PageItem *currItem;
1373 	ScPage* Mp = m_doc->MasterPages.at(m_doc->MasterNames[page->masterPageName()]);
1374 	int layerCount = m_doc->layerCount();
1375 	if ((layerCount > 1) && ((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
1376 		painter->beginLayer(layer.transparency, layer.blendMode);
1377 	int pageFromMasterCount = page->FromMaster.count();
1378 	for (int a = 0; a < pageFromMasterCount; ++a)
1379 	{
1380 		currItem = page->FromMaster.at(a);
1381 		if (currItem->m_layerID != layer.ID)
1382 			continue;
1383 		if ((currItem->OwnPage != -1) && (currItem->OwnPage != static_cast<int>(Mp->pageNr())))
1384 			continue;
1385 		if ((m_viewMode.previewMode) && (!currItem->printEnabled()))
1386 			continue;
1387 		if ((m_viewMode.viewAsPreview) && (!currItem->printEnabled()))
1388 			continue;
1389 		double oldX = currItem->xPos();
1390 		double oldY = currItem->yPos();
1391 		double oldBX = currItem->BoundingX;
1392 		double oldBY = currItem->BoundingY;
1393 		if (!currItem->ChangedMasterItem)
1394 		{
1395 			//Hack to not check for undo changes, indicate drawing only
1396 			currItem->moveBy(-Mp->xOffset() + page->xOffset(), -Mp->yOffset() + page->yOffset(), true);
1397 			currItem->BoundingX = oldBX - Mp->xOffset() + page->xOffset();
1398 			currItem->BoundingY = oldBY - Mp->yOffset() + page->yOffset();
1399 		}
1400 		// Save PageItem's OwnPage and set its value to page number
1401 		// so that page number placed in text frames can work, also modify
1402 		// OwnPage of items embeded inside groups for same reason
1403 		currItem->savedOwnPage = currItem->OwnPage;
1404 		currItem->OwnPage = page->pageNr();
1405 		if (currItem->isGroup())
1406 		{
1407 			PageItem_Group *groupItem = currItem->asGroupFrame();
1408 			PageItemIterator itemIt(groupItem->groupItemList, PageItemIterator::IterateInGroups);
1409 			for ( ; *itemIt; ++itemIt)
1410 			{
1411 				PageItem* item = *itemIt;
1412 				item->savedOwnPage = currItem->OwnPage;
1413 				item->OwnPage = page->pageNr();
1414 			}
1415 		}
1416 		if (cullingArea.intersects(currItem->getBoundingRect().adjusted(0.0, 0.0, 1.0, 1.0)))
1417 		{
1418 			if (!((m_viewMode.operItemMoving) && (currItem->isSelected())))
1419 			{
1420 				if (m_viewMode.forceRedraw)
1421 					currItem->invalidateLayout();
1422 				currItem->DrawObj(painter, cullingArea);
1423 				currItem->DrawObj_Decoration(painter);
1424 			}
1425 //			else
1426 //				qDebug() << "skip masterpage item (move/resizeEdit/selected)" << m_viewMode.operItemMoving << currItem->isSelected();
1427 		}
1428 		// Restore items' OwnPage including those of item embedded inside groups
1429 		if (currItem->isGroup())
1430 		{
1431 			PageItem_Group *groupItem = currItem->asGroupFrame();
1432 			PageItemIterator itemIt(groupItem->groupItemList, PageItemIterator::IterateInGroups);
1433 			for ( ; *itemIt; ++itemIt)
1434 			{
1435 				PageItem* item = *itemIt;
1436 				item->OwnPage = item->savedOwnPage;
1437 			}
1438 		}
1439 		currItem->OwnPage = currItem->savedOwnPage;
1440 		if (!currItem->ChangedMasterItem)
1441 		{
1442 			//Hack to not check for undo changes, indicate drawing only
1443 			currItem->setXYPos(oldX, oldY, true);
1444 			currItem->BoundingX = oldBX;
1445 			currItem->BoundingY = oldBY;
1446 		}
1447 	}
1448 	if ((layerCount > 1) && ((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
1449 		painter->endLayer();
1450 }
1451 
1452 
1453 /**
1454   draws page items contained in a specific Layer
1455  */
DrawPageItems(ScPainter * painter,ScLayer & layer,QRect clip,bool notesFramesPass)1456 void Canvas::DrawPageItems(ScPainter *painter, ScLayer& layer, QRect clip, bool notesFramesPass)
1457 {
1458 	if ((m_viewMode.previewMode) && (!layer.isPrintable))
1459 		return;
1460 	if ((m_viewMode.viewAsPreview) && (!layer.isPrintable))
1461 		return;
1462 	if (!layer.isViewable)
1463 		return;
1464 	if (m_doc->Items->count() <= 0)
1465 		return;
1466 
1467 // 	qDebug()<<"Canvas::DrawPageItems"<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
1468 	FPoint orig = localToCanvas(clip.topLeft());
1469 	QRectF cullingArea = QRectF(static_cast<int>(orig.x()), static_cast<int>(orig.y()),
1470 							  qRound(clip.width() / m_viewMode.scale + 0.5), qRound(clip.height() / m_viewMode.scale + 0.5));
1471 
1472 	PageItem *currItem;
1473 	int layerCount = m_doc->layerCount();
1474 	int docCurrPageNo=static_cast<int>(m_doc->currentPageNumber());
1475 	if ((layerCount > 1) && ((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
1476 		painter->beginLayer(layer.transparency, layer.blendMode);
1477 
1478 	//if notes are used
1479 	//then we must be sure that text frames are valid and all notes frames are created before we start drawing
1480 	if (!notesFramesPass && !m_doc->notesList().isEmpty())
1481 	{
1482 		for (auto it = m_doc->Items->begin(); it != m_doc->Items->end(); ++it)
1483 		{
1484 			PageItem* currItem = *it;
1485 			if ( !currItem->isTextFrame()
1486 				|| currItem->isNoteFrame()
1487 				|| !currItem->invalid
1488 				|| (currItem->m_layerID != layer.ID)
1489 				|| (m_viewMode.previewMode && !currItem->printEnabled())
1490 				|| (m_viewMode.viewAsPreview && (!currItem->printEnabled()))
1491 				|| (m_doc->masterPageMode() && ((currItem->OwnPage != -1) && (currItem->OwnPage != docCurrPageNo)))
1492 				|| ((!m_doc->masterPageMode() && !currItem->OnMasterPage.isEmpty()) && (currItem->OnMasterPage != m_doc->currentPage()->pageName())))
1493 				continue;
1494 			if (cullingArea.intersects(currItem->getBoundingRect().adjusted(0.0, 0.0, 1.0, 1.0)))
1495 				currItem->layout();
1496 		}
1497 	}
1498 	for (int it = 0; it < m_doc->Items->count(); ++it)
1499 	{
1500 		currItem = m_doc->Items->at(it);
1501 		if (notesFramesPass && !currItem->isNoteFrame())
1502 			continue;
1503 		if (!notesFramesPass && currItem->isNoteFrame())
1504 			continue;
1505 		if (currItem->m_layerID != layer.ID)
1506 			continue;
1507 		if ((m_viewMode.previewMode) && (!currItem->printEnabled()))
1508 			continue;
1509 		if ((m_viewMode.viewAsPreview) && (!currItem->printEnabled()))
1510 			continue;
1511 		if ((m_doc->masterPageMode()) && ((currItem->OwnPage != -1) && (currItem->OwnPage != docCurrPageNo)))
1512 			continue;
1513 		if (!m_doc->masterPageMode() && !currItem->OnMasterPage.isEmpty())
1514 		{
1515 			if (currItem->OnMasterPage != m_doc->currentPage()->pageName())
1516 				continue;
1517 		}
1518 		if (cullingArea.intersects(currItem->getBoundingRect().adjusted(0.0, 0.0, 1.0, 1.0)))
1519 		{
1520 //FIXME		if (!evSpon || forceRedraw)
1521 //				currItem->invalid = true;
1522 //			if ((!m_MouseButtonPressed) || (m_doc->appMode == modeEditClip))
1523 			if (((m_viewMode.operItemMoving || m_viewMode.drawSelectedItemsWithControls) && currItem->isSelected()))
1524 			{
1525 //					qDebug() << "skipping pageitem (move/resizeEdit/selected)" << m_viewMode.operItemMoving << currItem->isSelected();
1526 			}
1527 			else if (m_viewMode.operItemSelecting)
1528 			{
1529 				currItem->invalid = false;
1530 				currItem->DrawObj(painter, cullingArea);
1531 				currItem->DrawObj_Decoration(painter);
1532 			}
1533 			else
1534 			{
1535 				// I comment it because the "view" should not
1536 				// alter the "data". And it really prevents optimisation - pm
1537 // 				if (m_viewMode.forceRedraw)
1538 // 					currItem->invalidateLayout();
1539 				currItem->DrawObj(painter, cullingArea);
1540 				currItem->DrawObj_Decoration(painter);
1541 			}
1542 			getLinkedFrames(currItem);
1543 /*			if ((currItem->isTextFrame()) && ((currItem->nextInChain() != 0) || (currItem->prevInChain() != 0)))
1544 			{
1545 				PageItem *nextItem = currItem;
1546 				while (nextItem != 0)
1547 				{
1548 					if (nextItem->prevInChain() != 0)
1549 						nextItem = nextItem->prevInChain();
1550 					else
1551 						break;
1552 				}
1553 				if (!m_viewMode.linkedFramesToShow.contains(nextItem))
1554 					m_viewMode.linkedFramesToShow.append(nextItem);
1555 			}*/
1556 			/* FIXME:av -
1557 			what to fix exactly? - pm
1558 			*/
1559 			if ((m_doc->appMode == modeEdit) && (currItem->isSelected()) && (currItem->itemType() == PageItem::TextFrame))
1560 			{
1561 				setupEditHRuler(currItem);
1562 			}
1563 		}
1564 	}
1565 	if ((layerCount > 1) && ((layer.blendMode != 0) || (layer.transparency != 1.0)) && (!layer.outlineMode))
1566 		painter->endLayer();
1567 }
1568 
1569 /**
1570   Draws the canvas background for masterpages, incl. bleeds
1571  */
drawBackgroundMasterpage(ScPainter * painter,int clipx,int clipy,int clipw,int cliph)1572 void Canvas::drawBackgroundMasterpage(ScPainter* painter, int clipx, int clipy, int clipw, int cliph)
1573 {
1574 	const ScPage* currentPage = m_doc->currentPage();
1575 	double x = currentPage->xOffset() * m_viewMode.scale;
1576 	double y = currentPage->yOffset() * m_viewMode.scale;
1577 	double w = currentPage->width() * m_viewMode.scale;
1578 	double h = currentPage->height() * m_viewMode.scale;
1579 	QRectF drawRect = QRectF(x, y, w+5, h+5);
1580 	drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1581 	if (!drawRect.intersects(QRectF(clipx, clipy, clipw, cliph)))
1582 		return;
1583 
1584 	painter->setFillMode(ScPainter::Solid);
1585 	painter->setBrush(QColor(128,128,128));
1586 	MarginStruct pageBleeds;
1587 	if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
1588 		m_doc->getBleeds(currentPage, pageBleeds);
1589 	double px = currentPage->xOffset() - pageBleeds.left();
1590 	double py = currentPage->yOffset() - pageBleeds.top();
1591 	double pw = currentPage->width() + pageBleeds.left() + pageBleeds.right();
1592 	double ph = currentPage->height() + pageBleeds.bottom() + pageBleeds.top();
1593 	painter->setAntialiasing(false);
1594 	painter->setPen(Qt::black, 1 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1595 	if (PrefsManager::instance().appPrefs.displayPrefs.showPageShadow)
1596 		painter->drawRect(px + 5, py + 5, pw, ph);
1597 	painter->setBrush(m_doc->paperColor());
1598 	painter->drawRect(px, py, pw, ph);
1599 	painter->setAntialiasing(true);
1600 }
1601 
1602 
1603 
1604 /**
1605   draws the page outlines on canvas, including bleed area
1606  */
drawBackgroundPageOutlines(ScPainter * painter,int clipx,int clipy,int clipw,int cliph)1607 void Canvas::drawBackgroundPageOutlines(ScPainter* painter, int clipx, int clipy, int clipw, int cliph)
1608 {
1609 	int docPagesCount=m_doc->Pages->count();
1610 	if (PrefsManager::instance().appPrefs.displayPrefs.showPageShadow)
1611 	{
1612 		painter->setBrush(QColor(128,128,128));
1613 		painter->setAntialiasing(false);
1614 		painter->setPen(Qt::black, 1.0 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1615 		ScPage *actPg;
1616 		MarginStruct pageBleeds;
1617 		for (int a = 0; a < static_cast<int>(docPagesCount); ++a)
1618 		{
1619 			actPg = m_doc->Pages->at(a);
1620 			m_doc->getBleeds(actPg, pageBleeds);
1621 			if (m_viewMode.viewAsPreview)
1622 				pageBleeds.resetToZero();
1623 			double blx = (actPg->xOffset() - pageBleeds.left()) * m_viewMode.scale;
1624 			double bly = (actPg->yOffset() - pageBleeds.top()) * m_viewMode.scale;
1625 			double blw = (actPg->width() + pageBleeds.left() + pageBleeds.right()) * m_viewMode.scale;
1626 			double blh = (actPg->height() + pageBleeds.bottom() + pageBleeds.top()) * m_viewMode.scale;
1627 
1628 			QRectF drawRect = QRectF(blx-1, bly-1, blw+6, blh+6);
1629 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1630 			if (drawRect.intersects(QRectF(clipx, clipy, clipw, cliph)))
1631 			{
1632 				painter->setFillMode(ScPainter::Solid);
1633 				double blx2 = actPg->xOffset();
1634 				double bly2 = actPg->yOffset();
1635 				double blw2 = actPg->width();
1636 				double blh2 = actPg->height();
1637 				if (m_doc->guidesPrefs().showBleed)
1638 				{
1639 					blx2 -= pageBleeds.left();
1640 					bly2 -= pageBleeds.top();
1641 					blw2 += pageBleeds.left() + pageBleeds.right();
1642 					blh2 += pageBleeds.bottom() + pageBleeds.top();
1643 				}
1644 				painter->drawRect(blx2 + 5, bly2 + 5, blw2, blh2);
1645 				if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
1646 				{
1647 					painter->setFillMode(ScPainter::None);
1648 					painter->setPen(Qt::black, 1.0 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1649 					painter->drawRect(blx2 - 1 / m_viewMode.scale, bly2 - 1 / m_viewMode.scale, blw2 + 2 / m_viewMode.scale, blh2 + 2 / m_viewMode.scale);
1650 				}
1651 			}
1652 		}
1653 		painter->setAntialiasing(true);
1654 	}
1655 	painter->setFillMode(ScPainter::Solid);
1656 	ScPage *actPg;
1657 	MarginStruct pageBleeds;
1658 	for (int a = 0; a < static_cast<int>(docPagesCount); ++a)
1659 	{
1660 		actPg = m_doc->Pages->at(a);
1661 		double x = actPg->xOffset();
1662 		double y = actPg->yOffset();
1663 		double w = actPg->width();
1664 		double h = actPg->height();
1665 		bool drawBleed = false;
1666 		if (!m_doc->bleeds()->isNull() && m_doc->guidesPrefs().showBleed)
1667 		{
1668 			drawBleed = true;
1669 			m_doc->getBleeds(a, pageBleeds);
1670 		}
1671 		else
1672 			pageBleeds.resetToZero();
1673 		double blx = (actPg->xOffset() - pageBleeds.left()) * m_viewMode.scale;
1674 		double bly = (actPg->yOffset() - pageBleeds.top()) * m_viewMode.scale;
1675 		double blw = (actPg->width() + pageBleeds.left() + pageBleeds.right()) * m_viewMode.scale;
1676 		double blh = (actPg->height() + pageBleeds.bottom() + pageBleeds.top()) * m_viewMode.scale;
1677 
1678 		QRectF drawRect = QRectF(blx, bly, blw+5, blh+5);
1679 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1680 		if (drawRect.intersects(QRectF(clipx, clipy, clipw, cliph)))
1681 		{
1682 			painter->setFillMode(ScPainter::Solid);
1683 			painter->setPen(Qt::black, 0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1684 			painter->setAntialiasing(false);
1685 			painter->setLineWidth(0.0);
1686 			painter->setBrush(m_doc->paperColor());
1687 			if (!m_viewMode.viewAsPreview)
1688 			{
1689 				double blx2 = actPg->xOffset() - pageBleeds.left();
1690 				double bly2 = actPg->yOffset() - pageBleeds.top();
1691 				double blw2 = actPg->width() + pageBleeds.left() + pageBleeds.right();
1692 				double blh2 = actPg->height() + pageBleeds.bottom() + pageBleeds.top();
1693 				painter->drawRect(blx2, bly2, blw2, blh2);
1694 				if (drawBleed)
1695 					painter->drawRect(x, y, w, h);
1696 			}
1697 			else
1698 				painter->drawRect(x, y, w, h);
1699 			painter->setAntialiasing(true);
1700 		}
1701 	}
1702 }
1703 
getLinkedFrames(PageItem * currItem)1704 void Canvas::getLinkedFrames(PageItem* currItem)
1705 {
1706 	if (currItem->isGroup())
1707 	{
1708 		for (int em = 0; em < currItem->groupItemList.count(); ++em)
1709 		{
1710 			PageItem* embedded = currItem->groupItemList.at(em);
1711 			getLinkedFrames(embedded);
1712 		}
1713 
1714 	}
1715 	else if ((currItem->isTextFrame()) && ((currItem->nextInChain() != nullptr) || (currItem->prevInChain() != nullptr)))
1716 	{
1717 		PageItem *nextItem = currItem;
1718 		while (nextItem != nullptr)
1719 		{
1720 			if (nextItem->prevInChain() != nullptr)
1721 				nextItem = nextItem->prevInChain();
1722 			else
1723 				break;
1724 		}
1725 		if (!m_viewMode.linkedFramesToShow.contains(nextItem))
1726 			m_viewMode.linkedFramesToShow.append(nextItem);
1727 	}
1728 }
1729 
1730 /**
1731  fills PoLine with a clippath for the doc pages
1732  */
getClipPathForPages(FPointArray * PoLine)1733 void Canvas::getClipPathForPages(FPointArray* PoLine)
1734 {
1735 	PoLine->resize(0);
1736 	bool first = true;
1737 	ScPage *actPg;
1738 
1739 	int firstPage = 0;
1740 	int lastPage  = m_doc->Pages->count();
1741 	if (m_doc->Pages == &m_doc->MasterPages)
1742 	{
1743 		firstPage = m_doc->currentPage()->pageNr();
1744 		lastPage  = firstPage + 1;
1745 	}
1746 
1747 	for (int i = firstPage; i < lastPage; ++i)
1748 	{
1749 		if (!first)
1750 			PoLine->setMarker();
1751 		first = false;
1752 		actPg = m_doc->Pages->at(i);
1753 		double x = actPg->xOffset();
1754 		double y = actPg->yOffset();
1755 		double w = actPg->width();
1756 		double h = actPg->height();
1757 		static double rect[] = {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
1758 			1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
1759 			0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0};
1760 		for (int j = 0; j < 29; j += 4)
1761 		{
1762 			PoLine->addPoint(x + w * rect[j], y + h * rect[j+1]);
1763 			PoLine->addPoint(x + w * rect[j+2], y + h * rect[j+3]);
1764 		}
1765 	}
1766 }
1767 
1768 /**
1769   draws page border
1770   */
DrawPageBorderSub(ScPainter * p,ScPage * page)1771 void Canvas::DrawPageBorderSub(ScPainter *p, ScPage *page)
1772 {
1773 	p->save();
1774 	p->setAntialiasing(false);
1775 	p->translate(page->xOffset(), page->yOffset());
1776 	double lineWidth = 1.0 / m_viewMode.scale;
1777 	double pageHeight = page->height();
1778 	double pageWidth = page->width();
1779 	p->setFillMode(ScPainter::None);
1780 	p->setStrokeMode(ScPainter::Solid);
1781 	p->setPen(Qt::black, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1782 	p->drawRect(0, 0, pageWidth, pageHeight);
1783 	p->setAntialiasing(true);
1784 	p->restore();
1785 }
1786 
DrawPageBorder(ScPainter * p,const QRectF & clip,bool master)1787 void Canvas::DrawPageBorder(ScPainter *p, const QRectF& clip, bool master)
1788 {
1789 	if (master)
1790 	{
1791 		ScPage *page = m_doc->currentPage();
1792 		double x = m_doc->scratch()->left() * m_viewMode.scale;
1793 		double y = m_doc->scratch()->top() * m_viewMode.scale;
1794 		double w = page->width() * m_viewMode.scale;
1795 		double h = page->height() * m_viewMode.scale;
1796 		QRectF drawRect = QRectF(x, y, w+5, h+5);
1797 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1798 		if (drawRect.intersects(clip))
1799 			DrawPageBorderSub(p, page);
1800 	}
1801 	else
1802 	{
1803 		int docPagesCount = m_doc->Pages->count();
1804 		for (int a = 0; a < docPagesCount; ++a)
1805 		{
1806 			ScPage *page = m_doc->Pages->at(a);
1807 			QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
1808 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1809 			if (drawRect.intersects(clip))
1810 				DrawPageBorderSub(p, page);
1811 		}
1812 	}
1813 }
1814 
1815 /**
1816   draws margins
1817  */
DrawPageMarginsGridSub(ScPainter * p,ScPage * page)1818 void Canvas::DrawPageMarginsGridSub(ScPainter *p, ScPage *page)
1819 {
1820 	p->save();
1821 	p->setAntialiasing(false);
1822 	p->translate(page->xOffset(), page->yOffset());
1823 	double lineWidth = 1.0 / m_viewMode.scale;
1824 	double pageHeight = page->height();
1825 	double pageWidth = page->width();
1826 	p->setFillMode(ScPainter::None);
1827 	p->setStrokeMode(ScPainter::Solid);
1828 	p->setPen(Qt::black, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1829 	if (m_doc->guidesPrefs().marginsShown)
1830 	{
1831 		p->setPen(m_doc->guidesPrefs().marginColor);
1832 		if (m_doc->marginColored())
1833 		{
1834 			p->setFillMode(ScPainter::Solid);
1835 			p->setBrush(m_doc->guidesPrefs().marginColor);
1836 			p->drawRect(0, 0, pageWidth, page->Margins.top());
1837 			p->drawRect(0, page->Margins.top(), page->Margins.left(), pageHeight - page->Margins.top());
1838 			p->drawRect(page->Margins.left(), pageHeight - page->Margins.bottom(), pageWidth - page->Margins.right() - page->Margins.left(), page->Margins.bottom());
1839 			p->drawRect(pageWidth - page->Margins.right(), page->Margins.top(), page->Margins.right(), pageHeight-page->Margins.top());
1840 			p->setFillMode(ScPainter::None);
1841 		}
1842 		p->setFillMode(ScPainter::None);
1843 		p->drawRect(page->Margins.left(), page->Margins.top(), pageWidth - page->Margins.left() - page->Margins.right(), pageHeight - page->Margins.top() - page->Margins.bottom());
1844 	}
1845 	p->setAntialiasing(true);
1846 	p->restore();
1847 }
1848 
DrawPageMargins(ScPainter * p,const QRectF & clip,bool master)1849 void Canvas::DrawPageMargins(ScPainter *p, const QRectF& clip, bool master)
1850 {
1851 	if (master)
1852 	{
1853 		ScPage *page = m_doc->currentPage();
1854 		double x = m_doc->scratch()->left() * m_viewMode.scale;
1855 		double y = m_doc->scratch()->top() * m_viewMode.scale;
1856 		double w = page->width() * m_viewMode.scale;
1857 		double h = page->height() * m_viewMode.scale;
1858 		QRectF drawRect = QRectF(x, y, w+5, h+5);
1859 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1860 		if (drawRect.intersects(clip))
1861 			DrawPageMarginsGridSub(p, page);
1862 	}
1863 	else
1864 	{
1865 		int docPagesCount = m_doc->Pages->count();
1866 		for (int a = 0; a < docPagesCount; ++a)
1867 		{
1868 			ScPage *page = m_doc->Pages->at(a);
1869 			QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
1870 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1871 			if (drawRect.intersects(clip))
1872 				DrawPageMarginsGridSub(p, page);
1873 		}
1874 	}
1875 }
1876 
1877 /**
1878   draws baseline grid
1879  */
DrawPageBaselineGridSub(ScPainter * p,ScPage * page)1880 void Canvas::DrawPageBaselineGridSub(ScPainter *p, ScPage *page)
1881 {
1882 	if (!m_doc->guidesPrefs().baselineGridShown)
1883 		return;
1884 
1885 	p->save();
1886 	p->setAntialiasing(false);
1887 	p->translate(page->xOffset(), page->yOffset());
1888 	double lineWidth = 1.0 / m_viewMode.scale;
1889 	double pageHeight = page->height();
1890 	double pageWidth = page->width();
1891 	p->setFillMode(ScPainter::None);
1892 	p->setStrokeMode(ScPainter::Solid);
1893 	p->setPen(m_doc->guidesPrefs().baselineGridColor, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1894 	for (double yg = m_doc->guidesPrefs().offsetBaselineGrid; yg < pageHeight; yg += m_doc->guidesPrefs().valueBaselineGrid)
1895 		p->drawLine(FPoint(0, yg), FPoint(pageWidth, yg));
1896 	p->setAntialiasing(true);
1897 	p->restore();
1898 }
1899 
DrawPageBaselineGrid(ScPainter * p,const QRectF & clip,bool master)1900 void Canvas::DrawPageBaselineGrid(ScPainter *p, const QRectF& clip, bool master)
1901 {
1902 	if (!m_doc->guidesPrefs().baselineGridShown)
1903 		return;
1904 
1905 	if (master)
1906 	{
1907 		ScPage *page = m_doc->currentPage();
1908 		double x = m_doc->scratch()->left() * m_viewMode.scale;
1909 		double y = m_doc->scratch()->top() * m_viewMode.scale;
1910 		double w = page->width() * m_viewMode.scale;
1911 		double h = page->height() * m_viewMode.scale;
1912 		QRectF drawRect = QRectF(x, y, w+5, h+5);
1913 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1914 		if (drawRect.intersects(clip))
1915 			DrawPageBaselineGridSub(p, page);
1916 	}
1917 	else
1918 	{
1919 		int docPagesCount = m_doc->Pages->count();
1920 		for (int a = 0; a < docPagesCount; ++a)
1921 		{
1922 			ScPage *page = m_doc->Pages->at(a);
1923 			QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
1924 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
1925 			if (drawRect.intersects(clip))
1926 				DrawPageBaselineGridSub(p, page);
1927 		}
1928 	}
1929 }
1930 
1931 /**
1932   draws grid
1933  */
DrawPageGridSub(ScPainter * p,ScPage * page,const QRectF & clip)1934 void Canvas::DrawPageGridSub(ScPainter *p, ScPage *page, const QRectF& clip)
1935 {
1936 	if (!m_doc->guidesPrefs().gridShown)
1937 		return;
1938 
1939 	p->save();
1940 	FPointArray PoLine;
1941 	getClipPathForPages(&PoLine);
1942 	p->beginLayer(1.0, 0, &PoLine);
1943 	p->setAntialiasing(false);
1944 	p->translate(page->xOffset(), page->yOffset());
1945 	double lineWidth = 1.0 / m_viewMode.scale;
1946 	double pageHeight = page->height();
1947 	double pageWidth = page->width();
1948 	p->setFillMode(ScPainter::None);
1949 	p->setStrokeMode(ScPainter::Solid);
1950 	p->setPen(Qt::black, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1951 
1952 	double lowerBx = qMax(clip.x() / m_viewMode.scale + m_doc->minCanvasCoordinate.x() - page->xOffset(), 0.0);
1953 	double lowerBy = qMax(clip.y() / m_viewMode.scale + m_doc->minCanvasCoordinate.y() - page->yOffset(), 0.0);
1954 	double highBx = qMin(lowerBx + clip.width() / m_viewMode.scale, pageWidth);
1955 	double highBy = qMin(lowerBy + clip.height() / m_viewMode.scale, pageHeight);
1956 	if (m_viewMode.scale > 0.49)
1957 	{
1958 		if (m_doc->guidesPrefs().gridType == 0)
1959 		{
1960 			double i,start;
1961 			i = m_doc->guidesPrefs().majorGridSpacing;
1962 			p->setPen(m_doc->guidesPrefs().majorGridColor, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
1963 			start = floor(lowerBy / i);
1964 			start *= i;
1965 			for (double b = start; b <= highBy; b+=i)
1966 			{
1967 				p->drawLine(FPoint(qMax(lowerBx, 0.0), b), FPoint(qMin(pageWidth, highBx), b));
1968 			}
1969 			start=floor(lowerBx/i);
1970 			start*=i;
1971 			for (double b = start; b <= highBx; b+=i)
1972 			{
1973 				p->drawLine(FPoint(b, qMax(lowerBy, 0.0)), FPoint(b, qMin(pageHeight, highBy)));
1974 			}
1975 			i = m_doc->guidesPrefs().minorGridSpacing;
1976 			p->setPen(m_doc->guidesPrefs().minorGridColor, lineWidth, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin);
1977 			start = floor(lowerBy / i);
1978 			start *= i;
1979 			for (double b = start; b <= highBy; b+=i)
1980 			{
1981 				p->drawLine(FPoint(qMax(lowerBx, 0.0), b), FPoint(qMin(pageWidth, highBx), b));
1982 			}
1983 			start=floor(lowerBx/i);
1984 			start*=i;
1985 			for (double b = start; b <= highBx; b+=i)
1986 			{
1987 				p->drawLine(FPoint(b, qMax(lowerBy, 0.0)), FPoint(b, qMin(pageHeight, highBy)));
1988 			}
1989 		}
1990 		else if (m_doc->guidesPrefs().gridType == 1)
1991 		{
1992 			double i, startX, startY;
1993 			i = m_doc->guidesPrefs().minorGridSpacing;
1994 			p->setPen(m_doc->guidesPrefs().minorGridColor, 3.0 / m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
1995 			startY = floor(lowerBy / i);
1996 			startY *= i;
1997 			startX = floor(lowerBx / i);
1998 			startX *= i;
1999 			for (double b = startY; b <= highBy; b += i)
2000 			{
2001 				for (double bb = startX; bb <= highBx; bb += i)
2002 				{
2003 					p->drawLine(FPoint(bb, b), FPoint(bb, b));
2004 				}
2005 			}
2006 			i = m_doc->guidesPrefs().majorGridSpacing;
2007 			p->setPen(m_doc->guidesPrefs().majorGridColor, lineWidth * 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
2008 			startY = floor(lowerBy / i);
2009 			startY *= i;
2010 			startX = floor(lowerBx / i);
2011 			startX *= i;
2012 			for (double b = startY; b <= highBy; b += i)
2013 			{
2014 				for (double bb = startX; bb <= highBx; bb += i)
2015 				{
2016 					p->drawLine(FPoint(bb - 4, b), FPoint(bb + 4, b));
2017 					p->drawLine(FPoint(bb, b - 4), FPoint(bb, b + 4));
2018 				}
2019 			}
2020 		}
2021 	}
2022 
2023 	p->setAntialiasing(true);
2024 	p->endLayer();
2025 	p->restore();
2026 }
2027 
DrawPageGrid(ScPainter * p,const QRectF & clip,bool master)2028 void Canvas::DrawPageGrid(ScPainter *p, const QRectF& clip, bool master)
2029 {
2030 	if (!m_doc->guidesPrefs().gridShown)
2031 		return;
2032 
2033 	if (master)
2034 	{
2035 		ScPage *page = m_doc->currentPage();
2036 		double x = m_doc->scratch()->left() * m_viewMode.scale;
2037 		double y = m_doc->scratch()->top() * m_viewMode.scale;
2038 		double w = page->width() * m_viewMode.scale;
2039 		double h = page->height() * m_viewMode.scale;
2040 		QRectF drawRect = QRectF(x, y, w+5, h+5);
2041 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2042 		if (drawRect.intersects(clip))
2043 			DrawPageGridSub(p, page, clip);
2044 	}
2045 	else
2046 	{
2047 		int docPagesCount = m_doc->Pages->count();
2048 		for (int a = 0; a < docPagesCount; ++a)
2049 		{
2050 			ScPage *page = m_doc->Pages->at(a);
2051 			QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
2052 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2053 			if (drawRect.intersects(clip))
2054 				DrawPageGridSub(p, page, clip);
2055 		}
2056 	}
2057 }
2058 
2059 /**
2060   draws guides
2061  */
DrawPageGuidesSub(ScPainter * p,ScPage * page)2062 void Canvas::DrawPageGuidesSub(ScPainter *p, ScPage *page)
2063 {
2064 	if (!m_doc->guidesPrefs().guidesShown)
2065 		return;
2066 
2067 	p->save();
2068 	p->setAntialiasing(false);
2069 	p->translate(page->xOffset(), page->yOffset());
2070 	double lineWidth = 1.0 / m_viewMode.scale;
2071 	p->setFillMode(ScPainter::None);
2072 	p->setStrokeMode(ScPainter::Solid);
2073 	p->setPen(Qt::black, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
2074 	page->guides.drawPage(p, m_doc, lineWidth);
2075 	p->setAntialiasing(true);
2076 	p->restore();
2077 }
2078 
DrawPageGuides(ScPainter * p,const QRectF & clip,bool master)2079 void Canvas::DrawPageGuides(ScPainter *p, const QRectF& clip, bool master)
2080 {
2081 	if (!m_doc->guidesPrefs().guidesShown)
2082 		return;
2083 
2084 	if (master)
2085 	{
2086 		ScPage *page = m_doc->currentPage();
2087 		double x = m_doc->scratch()->left() * m_viewMode.scale;
2088 		double y = m_doc->scratch()->top() * m_viewMode.scale;
2089 		double w = page->width() * m_viewMode.scale;
2090 		double h = page->height() * m_viewMode.scale;
2091 		QRectF drawRect = QRectF(x, y, w+5, h+5);
2092 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2093 		if (drawRect.intersects(clip))
2094 			DrawPageGuidesSub(p, page);
2095 	}
2096 	else
2097 	{
2098 		int docPagesCount = m_doc->Pages->count();
2099 		for (int a = 0; a < docPagesCount; ++a)
2100 		{
2101 			ScPage *page = m_doc->Pages->at(a);
2102 			QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
2103 			drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2104 			if (drawRect.intersects(clip))
2105 				DrawPageGuidesSub(p, page);
2106 		}
2107 	}
2108 }
2109 
2110 /**
2111   draws actual page indicator frame
2112  */
DrawPageIndicatorSub(ScPainter * p,ScPage * page)2113 void Canvas::DrawPageIndicatorSub(ScPainter *p, ScPage *page)
2114 {
2115 	p->save();
2116 	int fm = p->fillMode();
2117 	p->setAntialiasing(false);
2118 	p->translate(page->xOffset(), page->yOffset());
2119 	double lineWidth = 1.0 / m_viewMode.scale;
2120 	double pageHeight = page->height();
2121 	double pageWidth = page->width();
2122 	p->setFillMode(ScPainter::None);
2123 	p->setStrokeMode(ScPainter::Solid);
2124 	p->setPen(Qt::black, lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
2125 	p->setPen(PrefsManager::instance().appPrefs.displayPrefs.pageBorderColor, 1 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
2126 	p->drawRect(0, 0, pageWidth, pageHeight);
2127 	p->setAntialiasing(true);
2128 	p->setFillMode(fm);
2129 	p->restore();
2130 }
2131 
DrawPageIndicator(ScPainter * p,const QRectF & clip,bool master)2132 void Canvas::DrawPageIndicator(ScPainter *p, const QRectF& clip, bool master)
2133 {
2134 	if (master)
2135 	{
2136 		ScPage *page = m_doc->currentPage();
2137 		double x = m_doc->scratch()->left() * m_viewMode.scale;
2138 		double y = m_doc->scratch()->top() * m_viewMode.scale;
2139 		double w = page->width() * m_viewMode.scale;
2140 		double h = page->height() * m_viewMode.scale;
2141 		QRectF drawRect = QRectF(x, y, w+5, h+5);
2142 		drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2143 		if (drawRect.intersects(clip))
2144 			DrawPageIndicatorSub(p, page);
2145 	}
2146 	else
2147 	{
2148 		int docPagesCount = m_doc->Pages->count();
2149 		for (int a = 0; a < docPagesCount; ++a)
2150 		{
2151 			ScPage *page = m_doc->Pages->at(a);
2152 			if (page == m_doc->currentPage())
2153 			{
2154 				QRectF drawRect = QRectF(page->xOffset() * m_viewMode.scale, page->yOffset() * m_viewMode.scale, page->width() * m_viewMode.scale + 5, page->height() * m_viewMode.scale + 5);
2155 				drawRect.translate(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale, -m_doc->minCanvasCoordinate.y() * m_viewMode.scale);
2156 				if (drawRect.intersects(clip))
2157 					DrawPageIndicatorSub(p, page);
2158 			}
2159 		}
2160 	}
2161 }
2162 
2163 /**
2164   draws the links between textframe chains.
2165   needs the list of visible textframes in m_viewMode.linkedFramesToShow
2166  */
drawFrameLinks(ScPainter * painter)2167 void Canvas::drawFrameLinks(ScPainter* painter)
2168 {
2169 	PageItem *currItem = nullptr;
2170 	if ((m_doc->appMode == modeLinkFrames) || (m_doc->appMode == modeUnlinkFrames))
2171 	{
2172 		if (m_doc->m_Selection->count() > 0)
2173 			currItem = m_doc->m_Selection->itemAt(0);
2174 		else if (m_viewMode.linkedFramesToShow.count() > 0)
2175 			currItem = m_viewMode.linkedFramesToShow.at(0);
2176 		if (currItem && (currItem->itemType() != PageItem::TextFrame))
2177 			currItem = nullptr;
2178 	}
2179 
2180 	//Draw the frame links
2181 	painter->save();
2182 	if (m_doc->guidesPrefs().linkShown || m_viewMode.drawFramelinksWithContents)
2183 	{
2184 		for (int i = 0; i < m_viewMode.linkedFramesToShow.count(); ++i)
2185 		{
2186 			PageItem* nextItem = m_viewMode.linkedFramesToShow.at(i);
2187 			while (nextItem != nullptr)
2188 			{
2189 				if (nextItem->nextInChain() != nullptr)
2190 				{
2191 					FPoint start, end;
2192 					calculateFrameLinkPoints(nextItem, nextItem->nextInChain(), start, end);
2193 					drawLinkFrameLine(painter, start, end);
2194 				}
2195 				nextItem = nextItem->nextInChain();
2196 			}
2197 		}
2198 	}
2199 	else if ((((m_doc->appMode == modeLinkFrames) || (m_doc->appMode == modeUnlinkFrames)) && (currItem != nullptr)))
2200 	{
2201 		PageItem *nextItem = currItem->firstInChain();
2202 		while (nextItem != nullptr)
2203 		{
2204 			if (nextItem->nextInChain() != nullptr)
2205 			{
2206 				FPoint start, end;
2207 				calculateFrameLinkPoints(nextItem, nextItem->nextInChain(), start, end);
2208 				drawLinkFrameLine(painter, start, end);
2209 			}
2210 			nextItem = nextItem->nextInChain();
2211 		}
2212 	}
2213 	painter->setLineWidth(1);
2214 	painter->setPenOpacity(1.0);
2215 	painter->restore();
2216 }
2217 
2218 
2219 /**
2220   draws one linkline between textframes
2221   */
drawLinkFrameLine(ScPainter * painter,FPoint & start,FPoint & end)2222 void Canvas::drawLinkFrameLine(ScPainter* painter, FPoint &start, FPoint &end)
2223 {
2224 	//CB FIXME Add some checking that the painter is setup?
2225 	Q_ASSERT(painter!=nullptr);
2226 	painter->setPen(Qt::black, 1.0 / m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
2227 	painter->setPenOpacity(1.0);
2228 	painter->drawLine(start, end);
2229 	QTransform arrowTrans;
2230 	arrowTrans.translate(end.x(), end.y());
2231 	double r = atan2(end.y()-start.y(), end.x()-start.x())*(180.0/M_PI);
2232 	arrowTrans.rotate(r);
2233 	double sc = 0.8 / m_viewMode.scale;
2234 	arrowTrans.scale(sc, sc);
2235 	FPointArray arrow;
2236 	arrow.addQuadPoint(-12, 0, -12, 0, -12, 0, -12, 0);
2237 	arrow.addQuadPoint(-15, -5, -15, -5, -15, -5, -15, -5);
2238 	arrow.addQuadPoint(0, 0, 0, 0, 0, 0, 0, 0);
2239 	arrow.addQuadPoint(-15, 5, -15, 5, -15, 5, -15, 5);
2240 	arrow.addQuadPoint(-12, 0, -12, 0, -12, 0, -12, 0);
2241 	arrow.map(arrowTrans);
2242 	painter->setBrush(painter->pen());
2243 	painter->setBrushOpacity(1.0);
2244 	painter->setLineWidth(0);
2245 	painter->setFillMode(ScPainter::Solid);
2246 	painter->setupPolygon(&arrow);
2247 	painter->fillPath();
2248 }
2249 
2250 
2251 
2252 /**
2253   this is a wrapper around repaint()
2254  */
PaintSizeRect(QRect newRect)2255 void Canvas::PaintSizeRect(QRect newRect)
2256 {
2257 	static QRect oldRect;
2258 	if (!newRect.isNull())
2259 	{
2260 		if (!oldRect.isNull())
2261 			newRect = newRect.united(oldRect);
2262 		repaint(newRect.adjusted(-10, -10, 20, 20));
2263 	}
2264 	oldRect = newRect;
2265 }
2266 
2267 
2268 /// ???
PaintSizeRect(QPolygon newRect)2269 void Canvas::PaintSizeRect(QPolygon newRect)
2270 {
2271 	static QRect oldRect;
2272 	QRect newR = newRect.boundingRect();
2273 	if (!newR.isNull())
2274 	{
2275 		if (!oldRect.isNull())
2276 			newRect = newRect.united(oldRect);
2277 //		newR.moveBy(qRound(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale), qRound(-m_doc->minCanvasCoordinate.y() * m_viewMode.scale));
2278 		m_viewMode.redrawPolygon = newRect;
2279 //		m_viewMode.redrawPolygon.translate(qRound(-m_doc->minCanvasCoordinate.x() * m_viewMode.scale), qRound(-m_doc->minCanvasCoordinate.y() * m_viewMode.scale));
2280 		repaint(newR.adjusted(-20, -20, 40, 40));
2281 	}
2282 	oldRect = newR;
2283 }
2284 
getGroupRectScreen(double * x,double * y,double * w,double * h)2285 void Canvas::getGroupRectScreen(double *x, double *y, double *w, double *h)
2286 {
2287 	double gx, gy, gh, gw;
2288 	m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
2289 	QPoint in(qRound(gx* m_viewMode.scale), qRound(gy* m_viewMode.scale));
2290 //	in -= QPoint(qRound(m_doc->minCanvasCoordinate.x() * m_viewMode.scale), qRound(m_doc->minCanvasCoordinate.y() * m_viewMode.scale));
2291 	QPoint out = contentsToViewport(in);
2292 	*x = static_cast<double>(out.x());
2293 	*y = static_cast<double>(out.y());
2294 	*w = gw* m_viewMode.scale;
2295 	*h = gh* m_viewMode.scale;
2296 }
2297 
2298 
Transform(PageItem * currItem,QPainter * p)2299 void Canvas::Transform(PageItem *currItem, QPainter *p)
2300 {
2301 	p->translate(currItem->xPos()*m_viewMode.scale, currItem->yPos()*m_viewMode.scale);
2302 	p->scale(m_viewMode.scale, m_viewMode.scale);
2303 	p->rotate(currItem->rotation());
2304 }
2305 
Transform(PageItem * currItem,QTransform & m)2306 void Canvas::Transform(PageItem *currItem, QTransform& m)
2307 {
2308 	m.translate(currItem->xPos()*m_viewMode.scale, currItem->yPos()*m_viewMode.scale);
2309 	m.scale(m_viewMode.scale, m_viewMode.scale);
2310 	m.rotate(currItem->rotation());
2311 }
2312 
TransformM(PageItem * currItem,QPainter * p)2313 void Canvas::TransformM(PageItem *currItem, QPainter *p)
2314 {
2315 	if (currItem->imageFlippedH())
2316 	{
2317 		p->translate(currItem->width(), 0);
2318 		p->scale(-1, 1);
2319 	}
2320 	if (currItem->imageFlippedV())
2321 	{
2322 		p->translate(0, currItem->height());
2323 		p->scale(1, -1);
2324 	}
2325 }
2326 
calculateFrameLinkPoints(PageItem * pi1,PageItem * pi2,FPoint & start,FPoint & end)2327 void Canvas::calculateFrameLinkPoints(PageItem *pi1, PageItem *pi2, FPoint & start, FPoint & end)
2328 {
2329 	if (pi1==nullptr || pi2==nullptr)
2330 		return;
2331 	//Calculate the link points of the frames
2332 	double x11 = pi1->xPos();
2333 	double y11 = pi1->yPos();
2334 	double x12 = x11 + pi1->width();
2335 	double y12 = y11 + pi1->height();
2336 	if (pi1->isGroupChild())
2337 	{
2338 		QTransform itemTrans = pi1->getTransform();
2339 		QPointF itPos = itemTrans.map(QPointF(0, 0));
2340 		x11 = itPos.x();
2341 		y11 = itPos.y();
2342 		double grScXi = 1.0;
2343 		double grScYi = 1.0;
2344 		getScaleFromMatrix(itemTrans, grScXi, grScYi);
2345 		if (itemTrans.m11() < 0)
2346 			x11 -= pi1->width() * grScXi;
2347 		if (itemTrans.m22() < 0)
2348 			y11 -= pi1->height() * grScYi;
2349 		x12 = x11 + pi1->width() * grScXi;
2350 		y12 = y11 + pi1->height() * grScYi;
2351 	}
2352 	double x1mid = x11 + (x12 - x11) / 2.0;
2353 	double y1mid = y11 + (y12 - y11) / 2.0;
2354 
2355 	if (pi1->rotation()!=0.000)
2356 	{
2357 		FPoint tempPoint(0,0, x11, y11, pi1->rotation(), 1, 1);
2358 		x11=tempPoint.x();
2359 		y11=tempPoint.y();
2360 		FPoint tempPoint2(0,0, x12, y12, pi1->rotation(), 1, 1);
2361 		x12=tempPoint2.x();
2362 		y12=tempPoint2.y();
2363 		FPoint tempPoint3(0,0, x1mid, y1mid, pi1->rotation(), 1, 1);
2364 		x1mid=tempPoint3.x();
2365 		y1mid=tempPoint3.y();
2366 	}
2367 
2368 
2369 	double a1, b1, a2, b2;
2370 	a1 = a2 = b1 = b2 = 0;
2371 	double x21 = pi2->xPos();
2372 	double y21 = pi2->yPos();
2373 	double x22 = x21 + pi2->width();
2374 	double y22 = y21 + pi2->height();
2375 	if (pi2->isGroupChild())
2376 	{
2377 		QTransform itemTrans = pi2->getTransform();
2378 		QPointF itPos = itemTrans.map(QPointF(0, 0));
2379 		x21 = itPos.x();
2380 		y21 = itPos.y();
2381 		double grScXi = 1.0;
2382 		double grScYi = 1.0;
2383 		getScaleFromMatrix(itemTrans, grScXi, grScYi);
2384 		if (itemTrans.m11() < 0)
2385 			x21 -= pi2->width() * grScXi;
2386 		if (itemTrans.m22() < 0)
2387 			y11 -= pi2->height() * grScYi;
2388 		x22 = x21 + pi2->width() * grScXi;
2389 		y22 = y21 + pi2->height() * grScYi;
2390 	}
2391 
2392 	double x2mid = x21 + (x22 - x21) / 2.0;
2393 	double y2mid = y21 + (y22 - y21) / 2.0;
2394 
2395 	if (pi2->rotation()!=0.000)
2396 	{
2397 		FPoint tempPoint(0,0, x21, y21, pi2->rotation(), 1, 1);
2398 		x21=tempPoint.x();
2399 		y21=tempPoint.y();
2400 		FPoint tempPoint2(0,0, x22, y22, pi2->rotation(), 1, 1);
2401 		x22=tempPoint2.x();
2402 		y22=tempPoint2.y();
2403 		FPoint tempPoint3(0,0, x2mid, y2mid, pi2->rotation(), 1, 1);
2404 		x2mid=tempPoint3.x();
2405 		y2mid=tempPoint3.y();
2406 	}
2407 
2408 	if (x22<x11) { a1 = x11; a2 = x22; }
2409 	if (x21>x12) { a1 = x12; a2 = x21; }
2410 	if (y22<y11) { b1 = y11; b2 = y22; }
2411 	if (y21>y12) { b1 = y12; b2 = y21; }
2412 
2413 	if (x21<x12 && x21>x11) { a1 = x1mid; a2 = x2mid; }
2414 	if (x21<x11 && x22>x11) { a1 = x1mid; a2 = x2mid; }
2415 
2416 	if (y21<y12 && y21>y11) { b1 = y1mid; b2 = y2mid; }
2417 	if (y21<y11 && y22>y11) { b1 = y1mid; b2 = y2mid; }
2418 
2419 	//When our points (in pt) are exactly the same, cover this too. #3634
2420 	if (x11==x21) { a1 = x1mid; a2 = x2mid; }
2421 	if (y11==y21) { b1 = y1mid; b2 = y2mid; }
2422 
2423 	//Set the link frame lines' endpoints
2424 	start.setXY(a1-pi1->xPos(), b1-pi1->yPos());
2425 	start.transform(pi1->xPos(), pi1->yPos(), pi1->rotation(), 1, 1, false);
2426 	end.setXY(a2-pi2->xPos(), b2-pi2->yPos());
2427 	end.transform(pi2->xPos(), pi2->yPos(), pi2->rotation(), 1, 1, false);
2428 }
2429 
createPixmap(double w,double h)2430 QPixmap Canvas::createPixmap(double w, double h)
2431 {
2432 	QPixmap p(w * devicePixelRatioF(), h * devicePixelRatioF());
2433 	p.setDevicePixelRatio(devicePixelRatioF());
2434 	return p;
2435 }
2436 
drawPixmap(QPainter & painter,double x,double y,const QPixmap & pixmap,double sx,double sy,double sw,double sh)2437 void Canvas::drawPixmap(QPainter& painter, double x, double y, const QPixmap& pixmap, double sx, double sy, double sw, double sh)
2438 {
2439 	sx *= devicePixelRatioF();
2440 	sy *= devicePixelRatioF();
2441 	sw *= devicePixelRatioF();
2442 	sh *= devicePixelRatioF();
2443 	painter.drawPixmap(x, y, pixmap, sx, sy, sw, sh);
2444 }
2445 
displayXYHUD(QPoint m)2446 void Canvas::displayXYHUD(QPoint m)
2447 {
2448 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2449 		return;
2450 	double gx, gy, gh, gw, r;
2451 	if (m_doc->m_Selection->isMultipleSelection())
2452 	{
2453 		m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
2454 		r = 0.0;
2455 	}
2456 	else
2457 	{
2458 		PageItem* currItem = m_doc->m_Selection->itemAt(0);
2459 		gx = currItem->xPos();
2460 		gy = currItem->yPos();
2461 		gw = currItem->width();
2462 		gh = currItem->height();
2463 		r = currItem->rotation();
2464 	}
2465 	QTransform ma;
2466 	ma.translate(gx, gy);
2467 	ma.rotate(r);
2468 	FPoint n;
2469 	if (m_doc->rotationMode() == 0)
2470 		n = FPoint(0.0, 0.0);
2471 	else if (m_doc->rotationMode() == 1)
2472 		n = FPoint(gw, 0.0);
2473 	else if (m_doc->rotationMode() == 2)
2474 		n = FPoint(gw / 2.0, gh / 2.0);
2475 	else if (m_doc->rotationMode() == 3)
2476 		n = FPoint(0.0, gh);
2477 	else if (m_doc->rotationMode() == 4)
2478 		n = FPoint(gw, gh);
2479 	gx = ma.m11() * n.x() + ma.m21() * n.y() + ma.dx();
2480 	gy = ma.m22() * n.y() + ma.m12() * n.x() + ma.dy();
2481 	if (m_doc->guidesPrefs().rulerMode)
2482 	{
2483 		gx -= m_doc->currentPage()->xOffset();
2484 		gy -= m_doc->currentPage()->yOffset();
2485 	}
2486 	gx -= m_doc->rulerXoffset;
2487 	gy -= m_doc->rulerYoffset;
2488 	displayXYHUD(m, gx, gy);
2489 }
2490 
displayCorrectedXYHUD(QPoint m,double x,double y)2491 void Canvas::displayCorrectedXYHUD(QPoint m, double x, double y)
2492 {
2493 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2494 		return;
2495 	double gx = x;
2496 	double gy = y;
2497 	if (m_doc->guidesPrefs().rulerMode)
2498 	{
2499 		gx -= m_doc->currentPage()->xOffset();
2500 		gy -= m_doc->currentPage()->yOffset();
2501 	}
2502 	gx -= m_doc->rulerXoffset;
2503 	gy -= m_doc->rulerYoffset;
2504 	QToolTip::showText(m + QPoint(5, 5), tr("X: %1\nY: %2").arg(value2String(gx, m_doc->unitIndex(), true, true), value2String(gy, m_doc->unitIndex(), true, true)), this);
2505 }
2506 
displayCorrectedSingleHUD(QPoint m,double val,bool isX)2507 void Canvas::displayCorrectedSingleHUD(QPoint m, double val, bool isX)
2508 {
2509 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2510 		return;
2511 	double gx = val;
2512 	if (isX)
2513 	{
2514 		if (m_doc->guidesPrefs().rulerMode)
2515 			gx -= m_doc->currentPage()->xOffset();
2516 		gx -= m_doc->rulerXoffset;
2517 		QToolTip::showText(m + QPoint(5, 5), tr("X: %1").arg(value2String(gx, m_doc->unitIndex(), true, true)), this);
2518 	}
2519 	else
2520 	{
2521 		if (m_doc->guidesPrefs().rulerMode)
2522 			gx -= m_doc->currentPage()->yOffset();
2523 		gx -= m_doc->rulerYoffset;
2524 		QToolTip::showText(m + QPoint(5, 5), tr("Y: %1").arg(value2String(gx, m_doc->unitIndex(), true, true)), this);
2525 	}
2526 }
2527 
displayXYHUD(QPoint m,double x,double y)2528 void Canvas::displayXYHUD(QPoint m, double x, double y)
2529 {
2530 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2531 		return;
2532 	QToolTip::showText(m + QPoint(5, 5), tr("X: %1\nY: %2").arg(value2String(x, m_doc->unitIndex(), true, true), value2String(y, m_doc->unitIndex(), true, true)), this);
2533 }
2534 
displaySizeHUD(QPoint m,double x,double y,bool isLine)2535 void Canvas::displaySizeHUD(QPoint m, double x, double y, bool isLine)
2536 {
2537 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2538 		return;
2539 	if (isLine)
2540 		QToolTip::showText(m + QPoint(5, 5), tr("Length: %1\nAngle: %2").arg(value2String(x, m_doc->unitIndex(), true, true), value2String(y, SC_DEGREES, true, true)), this);
2541 	else
2542 		QToolTip::showText(m + QPoint(5, 5), tr("Width: %1\nHeight: %2").arg(value2String(x, m_doc->unitIndex(), true, true), value2String(y, m_doc->unitIndex(), true, true)), this);
2543 }
2544 
displayRotHUD(QPoint m,double rot)2545 void Canvas::displayRotHUD(QPoint m, double rot)
2546 {
2547 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2548 		return;
2549 	double r;
2550 	if (rot < 0.0)
2551 		r = rot * -1.0;
2552 	else
2553 		r = 360.0 - rot;
2554 	QToolTip::showText(m + QPoint(5, 5), tr("Angle: %1").arg(value2String(r, SC_DEGREES, true, true)), this);
2555 }
2556 
displayRealRotHUD(QPoint m,double rot)2557 void Canvas::displayRealRotHUD(QPoint m, double rot)
2558 {
2559 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2560 		return;
2561 	QToolTip::showText(m + QPoint(5, 5), tr("Angle: %1").arg(value2String(rot, SC_DEGREES, true, true)), this);
2562 }
2563 
displayDoubleHUD(QPoint point,const QString & label,double value)2564 void Canvas::displayDoubleHUD(QPoint point, const QString& label, double value)
2565 {
2566 	if (!PrefsManager::instance().appPrefs.displayPrefs.showMouseCoordinates)
2567 		return;
2568 	QToolTip::showText(point + QPoint(5, 5), QString("%1: %2").arg(label, value2String(value, m_doc->unitIndex(), true, true)), this);
2569 }
2570 
setupEditHRuler(PageItem * item,bool forceAndReset)2571 void Canvas::setupEditHRuler(PageItem * item, bool forceAndReset)
2572 {
2573 	static QString rulerItemRef;
2574 	static double rulerDumbHash(0.0);
2575 
2576 	if ((rulerItemRef != item->itemName())
2577 		   || forceAndReset )
2578 	{
2579 		rulerItemRef = item->itemName();
2580 		rulerDumbHash = 0.0;
2581 	}
2582 
2583 	double controlHash(0.0);
2584 	controlHash = item->xPos()
2585 			+ item->yPos()				* 1.0
2586 			+ item->m_columnGap 				* 2.0
2587 			+ item->m_columns 				* 3.0
2588 			+ item->textToFrameDistLeft()		* 4.0
2589 			+ item->textToFrameDistRight()		* 5.0
2590 			+ item->currentStyle().firstIndent()	* 6.0
2591 			+ item->currentStyle().leftMargin()	* 7.0
2592 			+ item->width()				* 8.0
2593 			+ item->currentStyle().rightMargin()	* 9.0
2594 			+ (item->imageFlippedH() ? 32.32 : 13.13);
2595 
2596 	const ParagraphStyle& currParaStyle = item->currentStyle();
2597 	for (const ParagraphStyle::TabRecord& tabrec : currParaStyle.tabValues())
2598 	{
2599 		controlHash += tabrec.tabPosition;
2600 	}
2601 // 	qDebug()<<"Canvas::setupEditHRuler"<<rulerItemRef<<controlHash<<rulerDumbHash;
2602 	if (controlHash == rulerDumbHash)
2603 		return;
2604 
2605 	rulerDumbHash = controlHash;
2606 	m_view->horizRuler->setItem(item);
2607 	m_view->horizRuler->update();
2608 }
2609