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