Seamly2D
Code documentation
vmaingraphicsview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017 Seamly, LLC *
4  * *
5  * https://github.com/fashionfreedom/seamly2d *
6  * *
7  ***************************************************************************
8  **
9  ** Seamly2D 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 3 of the License, or
12  ** (at your option) any later version.
13  **
14  ** Seamly2D is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  ** GNU General Public License for more details.
18  **
19  ** You should have received a copy of the GNU General Public License
20  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
21  **
22  **************************************************************************
23 
24  ************************************************************************
25  **
26  ** @file vmaingraphicsview.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date November 15, 2013
29  **
30  ** @brief
31  ** @copyright
32  ** This source code is part of the Valentine project, a pattern making
33  ** program, whose allow create and modeling patterns of clothing.
34  ** Copyright (C) 2013-2015 Seamly2D project
35  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
36  **
37  ** Seamly2D is free software: you can redistribute it and/or modify
38  ** it under the terms of the GNU General Public License as published by
39  ** the Free Software Foundation, either version 3 of the License, or
40  ** (at your option) any later version.
41  **
42  ** Seamly2D is distributed in the hope that it will be useful,
43  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
44  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45  ** GNU General Public License for more details.
46  **
47  ** You should have received a copy of the GNU General Public License
48  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
49  **
50  *************************************************************************/
51 
52 #include "vmaingraphicsview.h"
53 
54 #include <QApplication>
55 #include <QCursor>
56 #include <QEvent>
57 #include <QFlags>
58 #include <QGraphicsItem>
59 #include <QGraphicsScene>
60 #include <QLineF>
61 #include <QList>
62 #include <QMessageLogger>
63 #include <QMouseEvent>
64 #include <QGestureEvent>
65 #include <QPainter>
66 #include <QPoint>
67 #include <QScrollBar>
68 #include <QTimeLine>
69 #include <QTransform>
70 #include <QWheelEvent>
71 #include <QGesture>
72 #include <QWidget>
73 #include <QGuiApplication>
74 #include <QScreen>
75 #include <QAbstractScrollArea>
76 #include <QScreen>
77 
78 #include "../vmisc/logging.h"
79 #include "../vmisc/def.h"
80 #include "../vmisc/vmath.h"
81 #include "../vmisc/vsettings.h"
82 #include "../vmisc/vcommonsettings.h"
83 #include "../vmisc/vabstractapplication.h"
84 #include "../ifc/ifcdef.h"
85 #include "vabstractmainwindow.h"
86 #include "vmaingraphicsscene.h"
87 #include "vsimplecurve.h"
88 
89 Q_LOGGING_CATEGORY(vGraphicsViewZoom, "vgraphicsviewzoom")
90 
91 const qreal maxSceneSize = ((20.0 * 1000.0) / 25.4) * PrintDPI; // 20 meters in pixels
92 
93 //---------------------------------------------------------------------------------------------------------------------
94 GraphicsViewZoom::GraphicsViewZoom(QGraphicsView* view)
95  : QObject(view)
96  , m_view(view)
97  , m_modifiers(Qt::ControlModifier)
98  , m_zoomSpeedFactor(1.0015)
99  , targetScenePos(QPointF())
100  , targetViewPos(QPointF())
101  , m_duration()
102  , m_updateInterval()
103  , verticalScrollAnim(new QTimeLine(300, this))
104  , m_numScheduledVerticalScrollings(0)
105  , horizontalScrollAnim(new QTimeLine(300, this))
106  , m_numScheduledHorizontalScrollings(0)
107  , pan(nullptr)
108  , pinch(nullptr)
109  , horizontalOffset(0.0)
110  , verticalOffset(0.0)
111  , scaleFactor(0.0)
112  , currentScaleFactor(0.0)
113 {
114  m_view->viewport()->installEventFilter(this);
115 
116  //Enable gestures for the view widget
117  m_view->viewport()->grabGesture(Qt::PinchGesture);
118  m_view->viewport()->grabGesture(Qt::PanGesture);
119  m_view->setMouseTracking(true);
120 
121  initScrollAnimations();
122  connect(verticalScrollAnim, &QTimeLine::valueChanged, this, &GraphicsViewZoom::verticalScrollingTime);
123  connect(verticalScrollAnim, &QTimeLine::finished, this, &GraphicsViewZoom::animFinished);
124  connect(horizontalScrollAnim, &QTimeLine::valueChanged, this, &GraphicsViewZoom::horizontalScrollingTime);
125  connect(horizontalScrollAnim, &QTimeLine::finished, this, &GraphicsViewZoom::animFinished);
126 }
127 
128 //---------------------------------------------------------------------------------------------------------------------
130 {
131  // We need to check current scale factor because in Windows we have an error when we zoom in or zoom out to much.
132  // See issue #532: Unexpected error occurs when zoom out image.
133  // factor > 1 for zoomIn and factor < 1 for zoomOut.
134  const qreal m11 = m_view->transform().m11();
135 
136  if ((factor > 1 && m11 <= VMainGraphicsView::MaxScale()) || (factor < 1 && m11 >= VMainGraphicsView::MinScale()))
137  {
138  m_view->scale(factor, factor);
139  if (factor < 1)
140  {
141  // Because QGraphicsView centers the picture when it's smaller than the view. And QGraphicsView's scrolls
142  // boundaries don't allow to put any picture point at any viewport position we will provide fictive scene
143  // size. Temporary and bigger than view, scene size will help position an image under cursor.
144  fictiveSceneRect(m_view->scene(), m_view);
145  }
146  m_view->centerOn(targetScenePos);
147  QPointF deltaViewPos = targetViewPos - QPointF(m_view->viewport()->width() / 2.0,
148  m_view->viewport()->height() / 2.0);
149  QPointF viewCenter = m_view->mapFromScene(targetScenePos) - deltaViewPos;
150  m_view->centerOn(m_view->mapToScene(viewCenter.toPoint()));
151  // In the end we just set correct scene size
152  VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(m_view->scene());
153  SCASSERT(currentScene)
154  currentScene->setCurrentTransform(m_view->transform());
156  emit zoomed();
157  }
158 }
159 
160 //---------------------------------------------------------------------------------------------------------------------
161 // cppcheck-suppress unusedFunction
162 void GraphicsViewZoom::setModifiers(Qt::KeyboardModifiers modifiers)
163 {
164  m_modifiers = modifiers;
165 }
166 
167 //---------------------------------------------------------------------------------------------------------------------
168 // cppcheck-suppress unusedFunction
170 {
171  m_zoomSpeedFactor = value;
172 }
173 
175 {
176  m_duration = qApp->Settings()->getScrollDuration();
177  m_updateInterval = qApp->Settings()->getScrollUpdateInterval();
178  verticalScrollAnim->setDuration(m_duration);
179  verticalScrollAnim->setUpdateInterval(m_updateInterval);
180 
181  horizontalScrollAnim->setDuration(m_duration);
182  horizontalScrollAnim->setUpdateInterval(m_updateInterval);
183 }
184 
185 //---------------------------------------------------------------------------------------------------------------------
187 {
188  Q_UNUSED(x)
189  // Try to adapt scrolling to speed of rotating mouse wheel and scale factor
190  // Value of _numScheduledScrollings is too short, so we scale the value
191 
192  qreal scroll = static_cast<qreal>(qAbs(m_numScheduledVerticalScrollings))*(10. + 10./m_view->transform().m22())
193  /(static_cast<qreal>(m_duration)/static_cast<qreal>(m_updateInterval));
194 
195  if (qAbs(scroll) < 1)
196  {
197  scroll = 1;
198  }
199 
201  {
202  scroll = scroll * -1;
203  }
204  m_view->verticalScrollBar()->setValue(qRound(m_view->verticalScrollBar()->value() + scroll));
205 }
206 
207 //---------------------------------------------------------------------------------------------------------------------
209 {
210  Q_UNUSED(x)
211  // Try to adapt scrolling to speed of rotating mouse wheel and scale factor
212  // Value of _numScheduledScrollings is too short, so we scale the value
213 
214  qreal scroll = static_cast<qreal>(qAbs(m_numScheduledHorizontalScrollings))*(10. + 10./m_view->transform().m11())
215  /(static_cast<qreal>(m_duration)/static_cast<qreal>(m_updateInterval));
216 
217  if (qAbs(scroll) < 1)
218  {
219  scroll = 1;
220  }
221 
223  {
224  scroll = scroll * -1;
225  }
226  m_view->horizontalScrollBar()->setValue(qRound(m_view->horizontalScrollBar()->value() + scroll));
227 }
228 
229 //---------------------------------------------------------------------------------------------------------------------
231 {
233  verticalScrollAnim->stop();
234 
235  /*
236  * In moust cases cursor position on view doesn't change, but for scene after scrolling position will be different.
237  * We are goint to check changes and save new value.
238  * If don't do that we will zoom using old value cursor position on scene. It is not what we expect.
239  * Almoust the same we do in method GraphicsViewZoom::eventFilter.
240  */
241  const QPoint pos = m_view->mapFromGlobal(QCursor::pos());
242  const QPointF delta = targetScenePos - m_view->mapToScene(pos);
243  if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
244  {
245  targetViewPos = pos;
246  targetScenePos = m_view->mapToScene(pos);
247  }
248 }
249 
250 //---------------------------------------------------------------------------------------------------------------------
251 bool GraphicsViewZoom::eventFilter(QObject *object, QEvent *event)
252 {
253  m_modifiers = (qApp->Settings()->getZoomModKey()) ? Qt::ControlModifier : Qt::NoModifier;
254  const qreal m_zoomSpeedFactor = (qreal(qApp->Settings()->getZoomSpeedFactor())/10000) + 1.0004;
255 
256  if (event->type() == QEvent::MouseMove)
257  {
258  /*
259  * Here we are saving cursor position on view and scene.
260  * This data need for gentleZoom().
261  * Almoust the same we do in method GraphicsViewZoom::animFinished.
262  */
263  QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
264  QPointF delta = targetViewPos - mouse_event->pos();
265  if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5)
266  {
267  targetViewPos = mouse_event->pos();
268  targetScenePos = m_view->mapToScene(mouse_event->pos());
269  }
270  return false;
271  }
272  else if (event->type() == QEvent::Wheel)
273  {
274  QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
275  SCASSERT(wheel_event != nullptr)
276  if (QApplication::keyboardModifiers() == m_modifiers)
277  {
278  if (wheel_event->angleDelta().y() != 0)
279  {
280  const double angle = wheel_event->angleDelta().y();
281  const double factor = qPow(m_zoomSpeedFactor, angle);
282  qCDebug(vGraphicsViewZoom, "zoom Factor =%f \n", factor);
283  gentleZoom(factor);
284  return true;
285  }
286  }
287  else
288  {
289  if (QApplication::keyboardModifiers() == Qt::ShiftModifier)
290  {
291  return startHorizontalScrollings(wheel_event);
292  }
293  else
294  {
295  return startVerticalScrollings(wheel_event);
296  }
297  }
298  }
299  else if (event->type() == QEvent::Gesture)
300  {
301  return gestureEvent(static_cast<QGestureEvent*>(event));
302  }
303 
304  return QObject::eventFilter(object, event);
305 }
306 
307 //---------------------------------------------------------------------------------------------------------------------
308 bool GraphicsViewZoom::gestureEvent(QGestureEvent *event)
309 {
310  if (QGesture *pinch = event->gesture(Qt::PinchGesture))
311  {
312  qCDebug(vGraphicsViewZoom, "pinch gestureEvent");
313  pinchTriggered(static_cast<QPinchGesture *>(pinch));
314  return true;
315  }
316  if (QGesture *pan = event->gesture(Qt::PanGesture))
317  {
318  qCDebug(vGraphicsViewZoom, "pan gestureEvent");
319  panTriggered(static_cast<QPanGesture *>(pan));
320  return true;
321  }
322 
323  return false;
324 }
325 
326 void GraphicsViewZoom::panTriggered(QPanGesture *gesture)
327 {
328 #ifndef QT_NO_CURSOR
329  switch (gesture->state())
330  {
331  case Qt::GestureStarted:
332  case Qt::GestureUpdated:
333  m_view->viewport()->setCursor(Qt::SizeAllCursor);
334  break;
335  default:
336  m_view->viewport()->setCursor(Qt::ArrowCursor);
337  }
338 #endif
339  QPointF delta = gesture->delta();
340  qCDebug(vGraphicsViewZoom) << "panTriggered():" << gesture;
341  horizontalOffset += delta.x();
342  verticalOffset += delta.y();
343  //m_view->scrollContentsBy(horizontalOffset, verticalOffset);
344 }
345 
346 void GraphicsViewZoom::pinchTriggered(QPinchGesture *gesture)
347 {
348  QPinchGesture::ChangeFlags flags = gesture->changeFlags();
349  if (flags & QPinchGesture::ScaleFactorChanged)
350  {
351  qreal currentScaleFactor = gesture->lastScaleFactor();
353  }
354 }
355 
356 //---------------------------------------------------------------------------------------------------------------------
357 void GraphicsViewZoom::fictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view)
358 {
359  SCASSERT(sc != nullptr)
360  SCASSERT(view != nullptr)
361 
362  //Calculate view rect
363  //to receive the currently visible area, map the widgets bounds to the scene
364  const QPointF a = view->mapToScene(0, 0 );
365  const QPointF b = view->mapToScene(view->viewport()->width(), view->viewport()->height());
366  QRectF viewRect = QRectF( a, b );
367 
368  //Scale view
369  QLineF topLeftRay(viewRect.center(), viewRect.topLeft());
370  topLeftRay.setLength(topLeftRay.length()*2);
371 
372  QLineF bottomRightRay(viewRect.center(), viewRect.bottomRight());
373  bottomRightRay.setLength(bottomRightRay.length()*2);
374 
375  viewRect = QRectF(topLeftRay.p2(), bottomRightRay.p2());
376 
377  //Calculate scene rect
378  const QRectF sceneRect = sc->sceneRect();
379 
380  //Unite two rects
381  const QRectF newRect = sceneRect.united(viewRect);
382 
383  sc->setSceneRect(newRect);
384 }
385 
386 //---------------------------------------------------------------------------------------------------------------------
387 bool GraphicsViewZoom::startVerticalScrollings(QWheelEvent *wheel_event)
388 {
389  SCASSERT(wheel_event != nullptr)
390 
391  const QPoint numPixels = wheel_event->pixelDelta();
392  const QPoint numDegrees = wheel_event->angleDelta() / 8;
393  int numSteps;
394 
395  if (not numPixels.isNull())
396  {
397  numSteps = numPixels.y();
398  }
399  else if (not numDegrees.isNull())
400  {
401  numSteps = numDegrees.y() / 15;
402  }
403  else
404  {
405  return true;//Just ignore
406  }
407 
409  if (m_numScheduledVerticalScrollings * numSteps < 0)
410  { // if user moved the wheel in another direction, we reset previously scheduled scalings
412  }
413 
414  m_numScheduledVerticalScrollings *= qint32(qApp->Settings()->getScrollSpeedFactor()/10.0);
415 
416  if (verticalScrollAnim->state() != QTimeLine::Running)
417  {
418  verticalScrollAnim->start();
419  }
420  return true;
421 }
422 
423 //---------------------------------------------------------------------------------------------------------------------
424 bool GraphicsViewZoom::startHorizontalScrollings(QWheelEvent *wheel_event)
425 {
426  SCASSERT(wheel_event != nullptr)
427 
428  const QPoint numPixels = wheel_event->pixelDelta();
429  const QPoint numDegrees = wheel_event->angleDelta() / 8;
430  int numSteps;
431 
432  if (not numPixels.isNull())
433  {
434  numSteps = numPixels.y();
435  }
436  else if (not numDegrees.isNull())
437  {
438  numSteps = numDegrees.y() / 15;
439  }
440  else
441  {
442  return true;//Just ignore
443  }
444 
446  if (m_numScheduledHorizontalScrollings * numSteps < 0)
447  { // if user moved the wheel in another direction, we reset previously scheduled scalings
449  }
450 
451  m_numScheduledHorizontalScrollings *= qint32(qApp->Settings()->getScrollSpeedFactor()/10.0);
452 
453  if (horizontalScrollAnim->state() != QTimeLine::Running)
454  {
455  horizontalScrollAnim->start();
456  }
457  return true;
458 }
459 
460 Q_LOGGING_CATEGORY(vMainGraphicsView, "vmaingraphicsview")
461 
462 //---------------------------------------------------------------------------------------------------------------------
463 /**
464  * @brief VMainGraphicsView constructor.
465  * @param parent parent object.
466  */
468  : QGraphicsView(parent)
469  , curMagnifier(new QCursor(QPixmap(":/cursor/magnifier_cursor.png"), 2, 2))
470  , zoom(new GraphicsViewZoom(this))
471  , showToolProperties(true)
472  , showScrollBars()
473  , isallowRubberBand(true)
474  , isZoomToAreaActive(false)
475  , isRubberBandActive(false)
476  , isRubberBandColorSet(false)
477  , isZoomPanActive(false)
478  , isPanDragActive(false)
479  , rubberBand(nullptr)
480  , rubberBandRect(nullptr)
481  , startPoint(QPoint())
482  , endPoint(QPoint())
483  , m_ptStartPos(QPoint())
484  , cursorPos(QPoint())
485 {
486  initScrollBars();
487 
488  this->setResizeAnchor(QGraphicsView::AnchorUnderMouse);
489  this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
490  this->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
491  this->setInteractive(true);
492 
493  connect(zoom, &GraphicsViewZoom::zoomed, this, [this](){emit signalZoomScaleChanged(transform().m11());});
494 }
495 
496 //---------------------------------------------------------------------------------------------------------------------
498 {
499  qreal factor = qBound(MinScale(), scale, MaxScale());
500  QTransform transform = this->transform();
501  transform.setMatrix(factor, transform.m12(), transform.m13(),
502  transform.m21(), factor, transform.m23(),
503  transform.m31(), transform.m32(), transform.m33());
504  this->setTransform(transform);
505  updateView(transform);
506 }
507 
508 //---------------------------------------------------------------------------------------------------------------------
510 {
511  // We need to check current scale factor because in Windows we get an error when we zoom in or out too much.
512  // See issue #532: Unexpected error occurs when zoom out image.
513  if (this->transform().m11() <= MaxScale())
514  {
515  scale(1.1, 1.1);
516  updateView(this->transform());
517  }
518 }
519 
520 //---------------------------------------------------------------------------------------------------------------------
522 {
523  // We need to check current scale factor because in Windows we have an error when we zoom in or zoom out to much.
524  // See issue #532: Unexpected error occurs when zoom out image.
525  if (this->transform().m11() >= MinScale())
526  {
527  scale(1.0/1.1, 1.0/1.1);
528  updateView(this->transform());
529  }
530 }
531 
532 //---------------------------------------------------------------------------------------------------------------------
534 {
535  QTransform transform = this->transform();
536  transform.setMatrix(1.0, transform.m12(), transform.m13(),
537  transform.m21(), 1.0, transform.m23(),
538  transform.m31(), transform.m32(), transform.m33());
539  this->setTransform(transform);
540  updateView(transform);
541 }
542 
543 //---------------------------------------------------------------------------------------------------------------------
545 {
546  VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene());
547  SCASSERT(currentScene)
548  currentScene->setOriginsVisible(false);
549  const QRectF rect = currentScene->visibleItemsBoundingRect();
550  currentScene->setOriginsVisible(true);
551 
552  zoomToRect(rect);
553 }
554 
555 void VMainGraphicsView::zoomToRect(const QRectF &rect)
556 {
557  if (rect.isEmpty())
558  {
559  return;
560  }
561 
562  this->fitInView(rect, Qt::KeepAspectRatio);
563  QTransform transform = this->transform();
564 
565  qreal factor = transform.m11();
566  factor = qMax(factor, MinScale());
567  factor = qMin(factor, MaxScale());
568 
569  transform.setMatrix(factor, transform.m12(), transform.m13(),
570  transform.m21(), factor, transform.m23(),
571  transform.m31(), transform.m32(), transform.m33());
572  this->setTransform(transform);
573  updateView(transform);
574 }
575 
576 void VMainGraphicsView::updateView(const QTransform &transform)
577 {
578  VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(scene());
579  SCASSERT(currentScene)
580  currentScene->setCurrentTransform(transform);
581  VMainGraphicsView::NewSceneRect(this->scene(), this);
582  emit signalZoomScaleChanged(transform.m11());
583 }
584 //---------------------------------------------------------------------------------------------------------------------
586 {
587  isZoomToAreaActive = value;
588  if (isZoomToAreaActive)
589  {
590  qCDebug(vMainGraphicsView, "View->Zoom to Selected Area Mode active\n");
591  isZoomPanActive = false;
592  viewport()->setCursor(*curMagnifier);
593  }
594  else
595  {
596  qCDebug(vMainGraphicsView, "View->Zoom to Selected Area Mode not active\n");
597  viewport()->setCursor(Qt::ArrowCursor);
598  }
599 }
600 
601 //---------------------------------------------------------------------------------------------------------------------
603 {
604  isZoomPanActive = value;
605  if (isZoomPanActive)
606  {
607  qCDebug(vMainGraphicsView, "View->Pan Zoom Mode active\n");
608  isZoomToAreaActive = false;
609  viewport()->setCursor(Qt::OpenHandCursor);
610  }
611  else
612  {
613  qCDebug(vMainGraphicsView, "View->Pan Zoom Mode not active\n");
614  viewport()->setCursor(Qt::ArrowCursor);
615  }
616 }
617 
618 void VMainGraphicsView::setRubberBandColor(QRubberBand *band, const QColor &color)
619 {
620  QPalette palette;
621  palette.setColor(QPalette::Active, QPalette::Highlight, color);
622  band->setPalette(palette);
623  isRubberBandColorSet = true;
624 }
625 
626 //---------------------------------------------------------------------------------------------------------------------
627 /**
628  * @brief mousePressEvent handle mouse press events.
629  * @param event mouse press event.
630  */
631 void VMainGraphicsView::mousePressEvent(QMouseEvent *event)
632 {
633  switch (event->button())
634  {
635  case Qt::LeftButton:
636  {
637  if ( isZoomToAreaActive )
638  {
639  if (!rubberBand)
640  {
641  rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
642  }
643  isRubberBandActive = true;
644  startPoint = event->pos();
645  rubberBand->setGeometry(QRect(startPoint,QSize()));
646  rubberBand->show();
647  qCDebug(vMainGraphicsView, "Select Area...\nstart point X=%d Y=%d\n", startPoint.x(), startPoint.y());
648  break;
649  }
650  else if ( isZoomPanActive )
651  {
652  isPanDragActive = true;
653  qCDebug(vMainGraphicsView, "Start Pan\n");
654 
655  const QList<QGraphicsItem *> list = items(event->pos());
656  if (list.size() == 0)
657  {// Only when the user clicks on the scene background
658  m_ptStartPos = event->pos();
659  QGraphicsView::setDragMode(QGraphicsView::ScrollHandDrag);
660  event->accept();
661  viewport()->setCursor(Qt::ClosedHandCursor);
662  }
663  break;
664  }
665  else
666  {
667  if ( isallowRubberBand )
668  {
669  QGraphicsView::setDragMode(QGraphicsView::RubberBandDrag);
670  }
671  if ( showToolProperties )
672  {
673  QList<QGraphicsItem *> list = items(event->pos());
674  if (list.size() == 0)
675  {
676  emit itemClicked(nullptr);
677  break;
678  }
679  for (int i = 0; i < list.size(); ++i)
680  {
681  if (this->scene()->items().contains(list.at(i)))
682  {
683  if (list.at(i)->type() > QGraphicsItem::UserType && list.at(i)->type() <= VSimpleCurve::Type)
684  {
685  emit itemClicked(list.at(i));
686  break;
687  }
688  else
689  {
690  emit itemClicked(nullptr);
691  }
692  }
693  }
694  }
695  }
696  break;
697  }
698  case Qt::MiddleButton:
699  {
700  const QList<QGraphicsItem *> list = items(event->pos());
701  if (list.size() == 0)
702  {// Only when the user clicks on the scene background
703  m_ptStartPos = event->pos();
704  QGraphicsView::setDragMode(QGraphicsView::ScrollHandDrag);
705  event->accept();
706  viewport()->setCursor(Qt::ClosedHandCursor);
707  }
708  break;
709  }
710  default:
711  break;
712  }
713  QGraphicsView::mousePressEvent(event);
714 }
715 
716 //---------------------------------------------------------------------------------------------------------------------
717 void VMainGraphicsView::mouseMoveEvent(QMouseEvent *event)
718 {
719  if ( (dragMode() == QGraphicsView::ScrollHandDrag) || isPanDragActive )
720  {
721  QScrollBar *hBar = horizontalScrollBar();
722  QScrollBar *vBar = verticalScrollBar();
723  const QPoint delta = event->pos() - m_ptStartPos;
724  hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
725  vBar->setValue(vBar->value() - delta.y());
726  m_ptStartPos = event->pos();
727  }
728  else if ( isRubberBandActive )
729  {
730  endPoint = event->pos();
732  {
733  if ( (endPoint.x() < startPoint.x()) | (endPoint.y() < startPoint.y()) )
734  {
735  setRubberBandColor(rubberBand, qApp->Settings()->getZoomRBNegativeColor());
736  }
737  else
738  {
739  setRubberBandColor(rubberBand, qApp->Settings()->getZoomRBPositiveColor());
740  }
741  isRubberBandColorSet = true;
742  }
743  rubberBand->setGeometry(QRect(startPoint,endPoint).normalized());
744  qCDebug(vMainGraphicsView, "End point X=%d Y=%d", endPoint.x(), endPoint.y());
745  }
746  else
747  {
748  QGraphicsView::mouseMoveEvent(event);
749  }
750 }
751 
752 //---------------------------------------------------------------------------------------------------------------------
753 /**
754  * @brief mouseReleaseEvent handle mouse release events.
755  * @param event mouse release event.
756  */
757 void VMainGraphicsView::mouseReleaseEvent(QMouseEvent *event)
758 {
759  QGraphicsView::mouseReleaseEvent ( event ); // First because need to hide a rubber band
760  QGraphicsView::setDragMode( QGraphicsView::NoDrag );
761  if ( isPanDragActive )
762  {
763  isPanDragActive = false;
764  viewport()->setCursor(Qt::OpenHandCursor);
765  qCDebug(vMainGraphicsView, "Stop Pan\n");
766  }
767  else if ( isRubberBandActive )
768  {
769  rubberBand->hide();
770  endPoint = event->pos();
771  qCDebug( vMainGraphicsView, "End point X=%d Y=%d", endPoint.x(), endPoint.y() );
772 
773  QRect rubberBandRect = rubberBand->geometry().normalized();
774  if (rubberBandRect.width() > 5 && rubberBandRect.height() > 5)
775  {
776  this->fitInView(QRectF(mapToScene(rubberBandRect.topLeft()),
777  mapToScene(rubberBandRect.bottomRight())), Qt::KeepAspectRatio);
778  updateView(this->transform());
779  }
780  isRubberBandActive = false;
781  isRubberBandColorSet = false;
782  }
783  else if (event->button() == Qt::LeftButton)
784  {
785  emit mouseRelease();
786  }
787 }
788 
789 //---------------------------------------------------------------------------------------------------------------------
791 {
792  if (event->button() == Qt::LeftButton && qApp->Settings()->isZoomDoubleClick())
793  {
794  if (VAbstractMainWindow *window = qobject_cast<VAbstractMainWindow *>(qApp->getMainWindow()))
795  {
796  window->zoomToSelected();
797  }
798  }
799  QGraphicsView::mouseDoubleClickEvent(event);
800 }
801 
802 //---------------------------------------------------------------------------------------------------------------------
804 {
805  const QRect screenRect(QGuiApplication::primaryScreen()->availableGeometry());
806  const qreal screenSize = qMin(screenRect.width(), screenRect.height());
807 
808  return screenSize / maxSceneSize;
809 }
810 
811 //---------------------------------------------------------------------------------------------------------------------
813 {
814  const QRect screenRect(QGuiApplication::primaryScreen()->availableGeometry());
815  const qreal screenSize = qMin(screenRect.width(), screenRect.height());
816 
817  return maxSceneSize / screenSize;
818 }
819 
820 //---------------------------------------------------------------------------------------------------------------------
822 {
823  showToolProperties = value;
824 }
825 
826 //---------------------------------------------------------------------------------------------------------------------
828 {
829  isallowRubberBand = value;
830 }
831 
832 //---------------------------------------------------------------------------------------------------------------------
833 /**
834  * @brief NewSceneRect calculate scene rect what contains all items and doesn't less that size of scene view.
835  * @param sc scene.
836  * @param view view.
837  */
838  void VMainGraphicsView::NewSceneRect(QGraphicsScene *sc, QGraphicsView *view, QGraphicsItem *item)
839  {
840  SCASSERT(sc != nullptr)
841  SCASSERT(view != nullptr)
842 
843  if (item == nullptr)
844  {
845  //Calculate view rect
846  const QRectF viewRect = SceneVisibleArea(view);
847 
848  //Calculate scene rect
849  VMainGraphicsScene *currentScene = qobject_cast<VMainGraphicsScene *>(sc);
850  SCASSERT(currentScene)
851  const QRectF itemsRect = currentScene->visibleItemsBoundingRect();
852 
853  //Unite two rects
854  sc->setSceneRect(itemsRect.united(viewRect));
855  }
856  else if (not sc->sceneRect().contains(item->sceneBoundingRect()))
857  {
858  sc->setSceneRect(sc->sceneRect().united(item->sceneBoundingRect()));
859  }
860 }
861 
862 //---------------------------------------------------------------------------------------------------------------------
863 QRectF VMainGraphicsView::SceneVisibleArea(QGraphicsView *view)
864 {
865  SCASSERT(view != nullptr)
866  //to receive the currently visible area, map the widgets bounds to the scene
867  return QRectF(view->mapToScene(0, 0), view->mapToScene(view->width(), view->height()));
868 }
869 
871 {
872  showScrollBars = qApp->Settings()->getShowScrollBars();
873  if (showScrollBars == true)
874  {
875  QString horizontal_styleSheet = QString("QScrollBar {height: ");
876  horizontal_styleSheet += QString().number(qApp->Settings()->getScrollBarWidth());
877  horizontal_styleSheet += QString("px;}");
878 
879  QString vertical_styleSheet = QString("QScrollBar {width: ");
880  vertical_styleSheet += QString().number(qApp->Settings()->getScrollBarWidth());
881  vertical_styleSheet += QString("px;}");
882 
883  this->horizontalScrollBar()->setStyleSheet(horizontal_styleSheet);
884  this->verticalScrollBar()->setStyleSheet(vertical_styleSheet);
885  }
886  else
887  {
888  this->horizontalScrollBar()->setStyleSheet("QScrollBar {height: 0px;}");
889  this->verticalScrollBar()->setStyleSheet("QScrollBar {width: 0px;}");
890  }
891 
892  this->horizontalScrollBar()->setSingleStep(1);
893  this->horizontalScrollBar()->update();
894 
895  this->verticalScrollBar()->setSingleStep(1);
896  this->verticalScrollBar()->update();
897 
898 }
899 
901 {
902  initScrollBars();
903 }
904 
905 //---------------------------------------------------------------------------------------------------------------------
907 {
909 }
QTimeLine * verticalScrollAnim
void panTriggered(QPanGesture *gesture)
void horizontalScrollingTime(qreal x)
Qt::KeyboardModifiers m_modifiers
bool startHorizontalScrollings(QWheelEvent *wheel_event)
qint32 m_numScheduledVerticalScrollings
_numScheduledVerticalScrollings keep number scheduled vertical scrollings.
virtual bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE
bool gestureEvent(QGestureEvent *event)
void setModifiers(Qt::KeyboardModifiers modifiers)
void pinchTriggered(QPinchGesture *gesture)
QGraphicsView * m_view
void setZoomSpeedFactor(qreal value)
void verticalScrollingTime(qreal x)
void fictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view)
bool startVerticalScrollings(QWheelEvent *wheel_event)
void gentleZoom(qreal factor)
QTimeLine * horizontalScrollAnim
qint32 m_numScheduledHorizontalScrollings
_numScheduledHorizontalScrollings keep number scheduled horizontal scrollings.
The VMainGraphicsScene class main scene.
QRectF visibleItemsBoundingRect() const
void setOriginsVisible(bool visible)
void setCurrentTransform(const QTransform &transform)
setCurrentTransform set view transformation.
The VMainGraphicsView class main scene view.
void itemClicked(QGraphicsItem *item)
void signalZoomScaleChanged(qreal scale)
static qreal MinScale()
virtual void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE
mouseReleaseEvent handle mouse release events.
QRubberBand * rubberBand
QSharedPointer< QCursor > curMagnifier
virtual void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE
static QRectF SceneVisibleArea(QGraphicsView *view)
virtual void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE
void zoomPanEnabled(bool value)
void zoomToRect(const QRectF &rect)
void mouseRelease()
mouseRelease help catch mouse release event.
GraphicsViewZoom * zoom
void updateView(const QTransform &transform)
void setShowToolOptions(bool value)
void zoomByScale(qreal scale)
virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE
mousePressEvent handle mouse press events.
static void NewSceneRect(QGraphicsScene *sc, QGraphicsView *view, QGraphicsItem *item=nullptr)
NewSceneRect calculate scene rect what contains all items and doesn't less that size of scene view.
void zoomToAreaEnabled(bool value)
static qreal MaxScale()
void setRubberBandColor(QRubberBand *band, const QColor &color)
void allowRubberBand(bool value)
const qreal PrintDPI
Definition: def.cpp:228
#define SCASSERT(cond)
Definition: def.h:317
#define qApp
Definition: vapplication.h:67
const qreal maxSceneSize