1 /****************************************************************************
2 ** Copyright (c) 2019, Adel Kara Slimane <adel.ks@zegrapher.com>
3 **
4 ** This file is part of ZeGrapher's source code.
5 **
6 ** ZeGrapher is free software: you may copy, redistribute and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation, either version 3 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This file is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **
19 ****************************************************************************/
20
21 #include "GraphDraw/mainview.h"
22
MainView(Information * info)23 MainView::MainView(Information *info): BaseGraphDraw(info)
24 {
25 orientation = QPageLayout::Landscape;
26 moveType = NOTHING;
27 setMouseTracking(true);
28 sizeSettings.scalingFactor = 1;
29
30 minRelSize = RELATIVE_MIN_SIZE;
31
32 screenDPI = qGuiApp->primaryScreen()->physicalDotsPerInch();
33
34 relFigRect.setHeight(1);
35 relFigRect.setWidth(1);
36 relFigRect.moveTopLeft(QPointF(0, 0));
37
38 connect(information, SIGNAL(graphSizeSettingsChanged()), this, SLOT(onSizeSettingsChange()));
39 connect(information, SIGNAL(graphZoomSettingsChanged()), this, SLOT(onZoomSettingsChange()));
40 }
41
onSizeUnitChange()42 void MainView::onSizeUnitChange()
43 {
44 updateTargetSupportSizePx();
45 }
46
updateWidgetSize()47 void MainView::updateWidgetSize()
48 {
49 sizeSettings = information->getGraphSizeSettings();
50 zoomSettings = information->getGraphZoomSettings();
51
52 if(sizeSettings.sizingType == ZeSizeSettings::FITWINDOW or zoomSettings.zoomingType == ZeZoomSettings::FITSHEET)
53 {
54 resize(parentWidget()->size());
55 }
56 else
57 {
58 if(zoomSettings.zoom > 1)
59 resize((QSizeF(sizeSettings.pxSheetSize) * zoomSettings.zoom).toSize());
60 else resize(sizeSettings.pxSheetSize);
61 }
62
63 emit widgetResized();
64 }
65
updateTargetSupportSizePx()66 void MainView::updateTargetSupportSizePx()
67 {
68 sizeSettings = information->getGraphSizeSettings();
69
70 if(sizeSettings.sizingType == ZeSizeSettings::FITWINDOW)
71 {
72 sizeSettings.pxSheetSize = size();
73 sizeSettings.cmSheetSize = sizeSettings.pxSheetSize / screenDPI * CM_PER_INCH;
74
75 information->setGraphSizeSettings(sizeSettings);
76 }
77
78 if(sizeSettings.sizeUnit == ZeSizeSettings::CENTIMETER)
79 {
80 // TODO: determine orientation from the sheet size: whether or not sizeSettings.cmSheetSize height > width
81 QSizeF sheetSizeMm(sizeSettings.cmSheetSize.width() * 10, sizeSettings.cmSheetSize.height() * 10);
82 QPageLayout layout(QPageSize(sheetSizeMm, QPageSize::Millimeter), orientation, QMarginsF(), QPageLayout::Millimeter);
83 layout.setOrientation(orientation);
84 targetSupportSizePixels = layout.fullRectPixels(int(screenDPI)).size();
85
86 if(fabs(layout.fullRect().width() / layout.fullRect().height() - sheetSizeMm.width() / sheetSizeMm.height()) > 0.01)
87 targetSupportSizePixels.transpose();
88 }
89 else
90 {
91 targetSupportSizePixels = sizeSettings.pxSheetSize;
92 }
93 }
94
getTargetSupportSizePixels()95 QSize MainView::getTargetSupportSizePixels()
96 {
97 return targetSupportSizePixels;
98 }
99
getMinFigureRelativeSize()100 double MainView::getMinFigureRelativeSize()
101 {
102 return minRelSize;
103 }
104
exportPDF(QString fileName,SheetSizeType sizeType)105 void MainView::exportPDF(QString fileName, SheetSizeType sizeType)
106 {
107 QPdfWriter *pdfWriter = new QPdfWriter(fileName);
108
109 pdfWriter->setCreator(QString("ZeGrapher ") + SOFTWARE_VERSION_STR);
110 pdfWriter->setTitle(tr("Exported graph"));
111
112 int targetResolution = int(screenDPI / sizeSettings.scalingFactor);
113
114 pdfWriter->setResolution(targetResolution);
115
116 QPageLayout layout;
117 layout.setUnits(QPageLayout::Millimeter);
118
119 QSizeF sheetSizeMm(sizeSettings.cmSheetSize.width() * 10, sizeSettings.cmSheetSize.height() * 10);
120 layout.setPageSize(QPageSize(sheetSizeMm, QPageSize::Millimeter, "", QPageSize::FuzzyOrientationMatch));
121
122 if(sizeType == SheetSizeType::NORMALISED)
123 layout.setOrientation(orientation);
124 else layout.setOrientation(QPageLayout::Portrait);
125
126 pdfWriter->setPageLayout(layout);
127
128 painter.begin(pdfWriter);
129
130 if(information->getGraphSettings().estheticSettings.backgroundColor != QColor(Qt::white))
131 {
132 painter.setBrush(QBrush(information->getGraphSettings().estheticSettings.backgroundColor));
133 painter.drawRect(painter.viewport());
134 }
135
136 figureRectScaled = getFigureRect(painter.viewport());
137
138 painter.translate(figureRectScaled.topLeft());
139
140 paint();
141
142 painter.end();
143
144 delete pdfWriter;
145 }
146
exportSVG(QString fileName)147 void MainView::exportSVG(QString fileName)
148 {
149 QSvgGenerator svgGenerator;
150 svgGenerator.setFileName(fileName);
151
152 svgGenerator.setTitle(tr("Exported graph"));
153 svgGenerator.setDescription(tr("Created with ZeGrapher ") + SOFTWARE_VERSION_STR);
154
155 double targetResolution = screenDPI / sizeSettings.scalingFactor;
156
157 svgGenerator.setResolution(int(targetResolution));
158
159 QSize sizePx(int(sizeSettings.cmSheetSize.width() * 0.393701 * targetResolution), int(sizeSettings.cmSheetSize.height() * 0.393701 * targetResolution));
160
161 svgGenerator.setSize(sizePx);
162 svgGenerator.setViewBox(QRect(QPoint(0, 0), sizePx));
163
164 painter.begin(&svgGenerator);
165
166 if(information->getGraphSettings().estheticSettings.backgroundColor != QColor(Qt::white))
167 {
168 painter.setBrush(QBrush(information->getGraphSettings().estheticSettings.backgroundColor));
169 painter.drawRect(painter.viewport());
170 }
171
172 figureRectScaled = getFigureRect(painter.viewport());
173
174 painter.translate(figureRectScaled.topLeft());
175
176 paint();
177
178 painter.end();
179 }
180
181
paintEvent(QPaintEvent * event)182 void MainView::paintEvent(QPaintEvent *event)
183 {
184 Q_UNUSED(event);
185
186 if(currentSize != size())
187 {
188 currentSize = size();
189 updateWidgetSize();
190 onSizeSettingsChange();
191 }
192
193 painter.begin(this);
194
195 drawSupport();
196 drawFigureRect();
197
198 assignMouseRects();
199
200 drawGraph();
201
202 painter.end();
203 }
204
assignMouseRects()205 void MainView::assignMouseRects()
206 {
207 QPoint topLeftTranslation;
208 topLeftTranslation.setX(-8);
209 topLeftTranslation.setY(-8);
210
211 QPoint bottomRightTranslation;
212 bottomRightTranslation.setX(8);
213 bottomRightTranslation.setY(8);
214
215
216 topLeft.setTopLeft(figureRect.topLeft() + topLeftTranslation);
217 topLeft.setBottomRight(figureRect.topLeft() + bottomRightTranslation);
218
219 topRight.setTopLeft(figureRect.topRight() + topLeftTranslation);
220 topRight.setBottomRight(figureRect.topRight() + bottomRightTranslation);
221
222 bottomLeft.setTopLeft(figureRect.bottomLeft() + topLeftTranslation);
223 bottomLeft.setBottomRight(figureRect.bottomLeft() + bottomRightTranslation);
224
225 bottomRight.setTopLeft(figureRect.bottomRight() + topLeftTranslation);
226 bottomRight.setBottomRight(figureRect.bottomRight() + bottomRightTranslation);
227
228 top.setTopLeft(topLeft.topRight());
229 top.setBottomRight(topRight.bottomLeft());
230
231 bottom.setTopLeft(bottomLeft.topRight());
232 bottom.setBottomRight(bottomRight.bottomLeft());
233
234 left.setTopLeft(topLeft.bottomLeft());
235 left.setBottomRight(bottomLeft.topRight());
236
237 right.setTopLeft(topRight.bottomLeft());
238 right.setBottomRight(bottomRight.topRight());
239 }
240
getDrawableRect(const QRect & refSupportRect)241 QRect MainView::getDrawableRect(const QRect &refSupportRect)
242 { // gives the drawable rect in the given support, in the support's coordinates
243 // the drawable rect is the support's rect minus the margins
244
245 int pxMargins = 0;
246
247 if(information->getGraphSizeSettings().sizeUnit == ZeSizeSettings::CENTIMETER)
248 {
249 pxMargins = int(sizeSettings.cmMargins / CM_PER_INCH * screenDPI);
250 }
251 else
252 {
253 pxMargins = sizeSettings.pxMargins;
254 }
255
256 QRect drawableRect;
257 drawableRect.setWidth(refSupportRect.width() - 2 * pxMargins);
258 drawableRect.setHeight(refSupportRect.height() - 2 * pxMargins);
259 drawableRect.moveTopLeft(QPoint(pxMargins, pxMargins));
260
261 return drawableRect;
262 }
263
getFigureRect(const QRect & refSupportRect)264 QRect MainView::getFigureRect(const QRect &refSupportRect)
265 {
266 QRect rect;
267 QPoint graphRectTopLeft;
268
269 graphRectTopLeft.setX(int(relFigRect.topLeft().x() * double(refSupportRect.width())));
270 graphRectTopLeft.setY(int(relFigRect.topLeft().y() * double(refSupportRect.height())));
271
272 rect.setWidth(int(relFigRect.width() * refSupportRect.width()));
273 rect.setHeight(int(relFigRect.height() * refSupportRect.height()));
274 rect.moveTopLeft(refSupportRect.topLeft() + graphRectTopLeft);
275
276 return rect;
277 }
278
supportRectFromViewRect(QRect viewRect)279 QRect MainView::supportRectFromViewRect(QRect viewRect)
280 {
281 QRect rect;
282 zoomSettings = information->getGraphZoomSettings();
283 sizeSettings = information->getGraphSizeSettings();
284
285 if(sizeSettings.sizingType == ZeSizeSettings::FITWINDOW)
286 {
287 rect = viewRect;
288 }
289 else if(zoomSettings.zoomingType == ZeZoomSettings::FITSHEET)
290 {
291 double ratio, targetRatio;
292 ratio = double(viewRect.height()) / double(viewRect.width());
293
294 if(sizeSettings.sizeUnit == ZeSizeSettings::CENTIMETER)
295 targetRatio = sizeSettings.cmSheetSize.height() / sizeSettings.cmSheetSize.width();
296 else targetRatio = double(sizeSettings.pxSheetSize.height()) / double(sizeSettings.pxSheetSize.width());
297
298 if(ratio <= targetRatio)
299 {
300 rect.setHeight(viewRect.height());
301 rect.setWidth(int(double(viewRect.height()) / targetRatio));
302
303 rect.moveTopLeft(QPoint((viewRect.width() - rect.width())/2, 0));
304 }
305 else
306 {
307 rect.setHeight(int(double(viewRect.width()) * targetRatio));
308 rect.setWidth(viewRect.width());
309
310 rect.moveTopLeft(QPoint(0, (viewRect.height() - rect.height())/2));
311 }
312 }
313 else
314 {
315 rect.setSize(sizeSettings.pxSheetSize);
316 rect.translate(viewRect.center() - rect.center());
317 }
318
319 return rect;
320 }
321
drawSupport()322 void MainView::drawSupport()
323 { // draws the sheet on an untransformed view
324 painter.setBrush(QBrush(information->getGraphSettings().estheticSettings.backgroundColor));
325
326 supportRect = supportRectFromViewRect(painter.viewport());
327
328 painter.drawRect(supportRect);
329 }
330
drawFigureRect()331 void MainView::drawFigureRect()
332 {
333 figureRect = getFigureRect(supportRect);
334
335 painter.setBrush(Qt::NoBrush);
336 pen.setStyle(Qt::DashLine);
337 pen.setWidth(1);
338 pen.setColor(information->getAxesSettings().x.color);
339 painter.setPen(pen);
340 painter.drawRect(figureRect);
341
342 pen.setStyle(Qt::SolidLine);
343 painter.setPen(pen);
344 }
345
setGraphRange(GraphRange range)346 void MainView::setGraphRange(GraphRange range)
347 {
348
349 }
350
scaleView(const QRect & refSheetRect)351 void MainView::scaleView(const QRect &refSheetRect)
352 {
353 zoomSettings = information->getGraphZoomSettings();
354
355 if(zoomSettings.zoomingType == ZeZoomSettings::FITSHEET)
356 {
357 double newZoom;
358
359 if(information->getGraphSizeSettings().sizeUnit == ZeSizeSettings::CENTIMETER)
360 {
361 newZoom = double(refSheetRect.width()) / double(targetSupportSizePixels.width());
362 }
363 else
364 {
365 newZoom = double(refSheetRect.width()) / double(sizeSettings.pxSheetSize.width());
366 }
367
368 if(fabs(newZoom - zoomSettings.zoom) > 0.001)
369 {
370 zoomSettings.zoom = newZoom;
371
372 information->setGraphZoomSettings(zoomSettings);
373 }
374 }
375
376 double totalScaleFactor = zoomSettings.zoom * sizeSettings.scalingFactor;
377
378 painter.scale(totalScaleFactor, totalScaleFactor);
379 }
380
drawGraph()381 void MainView::drawGraph()
382 {
383 scaleView(supportRect);
384
385 sheetRectScaled = painter.worldTransform().inverted().mapRect(supportRect);
386
387 figureRectScaled = getFigureRect(sheetRectScaled);
388
389 painter.translate(figureRectScaled.topLeft());
390
391 paint();
392 }
393
mousePressEvent(QMouseEvent * event)394 void MainView::mousePressEvent(QMouseEvent *event)
395 {
396 if(topLeft.contains(event->pos()))
397 moveType = TOPLEFT_CORNER;
398 else if(topRight.contains(event->pos()))
399 moveType = TOPRIGHT_CORNER;
400 else if(top.contains(event->pos()))
401 moveType = TOP_SIDE;
402 else if(bottomLeft.contains(event->pos()))
403 moveType = BOTTOMLEFT_CORNER;
404 else if(bottomRight.contains(event->pos()))
405 moveType = BOTTOMRIGHT_CORNER;
406 else if(bottom.contains(event->pos()))
407 moveType = BOTTOM_SIDE;
408 else if(left.contains(event->pos()))
409 moveType = LEFT_SIDE;
410 else if(right.contains(event->pos()))
411 moveType = RIGHT_SIDE;
412 else if(figureRect.contains(event->pos()))
413 moveType = ALL;
414 else moveType = NOTHING;
415
416 if(moveType != NOTHING)
417 lastMousePos = event->pos();
418 }
419
mouseMoveEvent(QMouseEvent * event)420 void MainView::mouseMoveEvent(QMouseEvent *event)
421 {
422 if(moveType == NOTHING)
423 {
424 if(topLeft.contains(event->pos()) || bottomRight.contains(event->pos()))
425 setCursor(Qt::SizeFDiagCursor);
426 else if(topRight.contains(event->pos()) || bottomLeft.contains(event->pos()))
427 setCursor(Qt::SizeBDiagCursor);
428 else if(top.contains(event->pos()) || bottom.contains(event->pos()))
429 setCursor(Qt::SizeVerCursor);
430 else if(left.contains(event->pos()) || right.contains(event->pos()))
431 setCursor(Qt::SizeHorCursor);
432 else if(figureRect.contains(event->pos()))
433 setCursor(Qt::SizeAllCursor);
434 else setCursor(Qt::ArrowCursor);
435
436 lastMousePos = event->pos();
437 }
438 else
439 {
440 QPoint dr = event->pos() - lastMousePos;
441 lastMousePos = event->pos();
442 auto zoomSettings = information->getGraphZoomSettings();
443 switch(moveType)
444 {
445 case TOPLEFT_CORNER:
446 figureRect.setTopLeft(figureRect.topLeft() + dr);
447 break;
448 case TOPRIGHT_CORNER:
449 figureRect.setTopRight(figureRect.topRight() + dr);
450 break;
451 case BOTTOMLEFT_CORNER:
452 figureRect.setBottomLeft(figureRect.bottomLeft() + dr);
453 break;
454 case BOTTOMRIGHT_CORNER:
455 figureRect.setBottomRight(figureRect.bottomRight() + dr);
456 break;
457 case LEFT_SIDE:
458 figureRect.setLeft(figureRect.left() + dr.x());
459 break;
460 case TOP_SIDE:
461 figureRect.setTop(figureRect.top() + dr.y());
462 break;
463 case RIGHT_SIDE:
464 figureRect.setRight(figureRect.right() + dr.x());
465 break;
466 case BOTTOM_SIDE:
467 figureRect.setBottom(figureRect.bottom() + dr.y());
468 break;
469 case ALL:
470 figureRect.translate(dr);
471 break;
472 case NOTHING:
473 break;
474 }
475
476
477 QPointF pt = figureRect.topLeft() - supportRect.topLeft();
478 pt.setX(pt.x() / double(supportRect.width()));
479 pt.setY(pt.y() / double(supportRect.height()));
480
481 relFigRect.setWidth(double(figureRect.width()) / double(supportRect.width()));
482 relFigRect.setHeight(double(figureRect.height()) / double(supportRect.height()));
483 relFigRect.moveTopLeft(pt);
484
485 constrainFigureRectRel();
486 updateFigureSize();
487 update();
488 }
489
490 }
491
onSizeSettingsChange()492 void MainView::onSizeSettingsChange()
493 {
494
495 updateTargetSupportSizePx();
496
497 // Add function here that calcualtes the needed widget size
498
499 sizeSettings = information->getGraphSizeSettings();
500
501 if(sizeSettings.sizeUnit == ZeSizeSettings::CENTIMETER)
502 {
503 relFigRect.setWidth(sizeSettings.cmFigureSize.width() / (sizeSettings.cmSheetSize.width()));
504 relFigRect.setHeight(sizeSettings.cmFigureSize.height() / (sizeSettings.cmSheetSize.height()));
505 }
506 else
507 {
508 relFigRect.setWidth(double(sizeSettings.pxFigureSize.width()) / double(sizeSettings.pxSheetSize.width()));
509 relFigRect.setHeight(double(sizeSettings.pxFigureSize.height()) / (sizeSettings.pxSheetSize.height() ));
510 }
511
512 constrainFigureRectRel();
513 updateFigureSize();
514
515 update();
516 }
517
onZoomSettingsChange()518 void MainView::onZoomSettingsChange()
519 {
520 update();
521 }
522
updateFigureSize()523 void MainView::updateFigureSize()
524 {
525 sizeSettings.cmFigureSize.setWidth(relFigRect.width() * sizeSettings.cmSheetSize.width());
526 sizeSettings.cmFigureSize.setHeight(relFigRect.height() * sizeSettings.cmSheetSize.height());
527
528 sizeSettings.pxFigureSize.setWidth(int(relFigRect.width() * double(sizeSettings.pxSheetSize.width())));
529 sizeSettings.pxFigureSize.setHeight(int(relFigRect.height() * double(sizeSettings.pxSheetSize.height())));
530
531 disconnect(information, SIGNAL(graphSizeSettingsChanged()), this, SLOT(onSizeSettingsChange()));
532 information->setGraphSizeSettings(sizeSettings);
533 connect(information, SIGNAL(graphSizeSettingsChanged()), this, SLOT(onSizeSettingsChange()));
534 }
535
constrainFigureRectRel()536 void MainView::constrainFigureRectRel()
537 {
538 if(sizeSettings.sizeUnit == ZeSizeSettings::CENTIMETER)
539 {
540 relMargins.setWidth(sizeSettings.cmMargins / sizeSettings.cmSheetSize.width());
541 relMargins.setHeight(sizeSettings.cmMargins / sizeSettings.cmSheetSize.height());
542 }
543 else
544 {
545 relMargins.setWidth(double(sizeSettings.pxMargins) / double(sizeSettings.pxSheetSize.width()));
546 relMargins.setHeight(double(sizeSettings.pxMargins) / double(sizeSettings.pxSheetSize.height()));
547 }
548
549 if(relFigRect.width() > 1 - 2*relMargins.width())
550 relFigRect.setWidth(1 - 2*relMargins.width());
551
552 if(relFigRect.height() > 1 - 2*relMargins.height())
553 relFigRect.setHeight(1 - 2*relMargins.height());
554 //------------------------------
555
556 if(relFigRect.width() < minRelSize)
557 relFigRect.setWidth(minRelSize);
558
559 if(relFigRect.height() < minRelSize)
560 relFigRect.setHeight(minRelSize);
561 //------------------------------
562
563 if(relFigRect.left() < relMargins.width())
564 relFigRect.moveLeft(relMargins.width());
565
566 if(relFigRect.right() > 1 - relMargins.width())
567 relFigRect.moveRight(1 - relMargins.width());
568 //------------------------------
569
570 if(relFigRect.bottom() > 1 - relMargins.height())
571 relFigRect.moveBottom(1 - relMargins.height());
572
573 if(relFigRect.top() < relMargins.height())
574 relFigRect.moveTop(relMargins.height());
575 }
576
mouseReleaseEvent(QMouseEvent * event)577 void MainView::mouseReleaseEvent(QMouseEvent *event)
578 {
579 Q_UNUSED(event);
580 setCursor(Qt::ArrowCursor);
581 moveType = NOTHING;
582 }
583
wheelEvent(QWheelEvent * event)584 void MainView::wheelEvent(QWheelEvent *event)
585 {
586 Q_UNUSED(event);
587 }
588