ATLAS Offline Software
Loading...
Searching...
No Matches
VP1GraphicsView.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6// //
7// Implementation of class VP1GraphicsView //
8// //
9// Author: Thomas Kittelmann <Thomas.Kittelmann@cern.ch> //
10// //
11// Initial version: April 2007 //
12// //
14
15//Todo: Mouse zoom mode (updown...).
16// left+middle:zoom. left+middle+right: keep.
17// left+right:drag keep mode until click.
18// Zoom by rubberband mode.
19// Add zoom in/out slots to be like Key_Plus/Key_Minus?
20// A changeview drag does not abort a zoom!
21// Adjust zoom nsteps based on number of items in view.
22
23
26
30
31#include "VP1Base/VP1Settings.h"
32#include "VP1Base/VP1Msg.h"
33
34// QtCore
35#include <QTimer>
36#include <QQueue>
37#include <QSet>
38#include <QDir>
39
40// QtGui
41#include <QWheelEvent>
42#include <QMouseEvent>
43#include <QGraphicsScene>
44#include <QScrollBar>
45#include <QGraphicsPathItem>
46#include <QPrinter>
47#include <QPrintDialog>
48#include <QPixmap>
49#include <QFileDialog>
50#include <QTextDocument>
51#include <QAbstractTextDocumentLayout>
52
53// Qt OpenGL
54#include <QGLWidget>
55#include <QGLFormat>
56
57#include<iostream>//fixme
58#include <cassert>
59
60//____________________________________________________________________
62public:
63
64 void init(VP1GraphicsView*);
65 QGraphicsScene * scene;
67
69 Mode lastmajormode;//To go back to the previous major mode when exiting a seek.
70
71 QList<VP1GraphicsItemCollection*> cols_act;//All item collections not inherently INERT
72 QList<VP1GraphicsItemCollection*> cols_all;//Needed since event inactive collections might have movable items.
73
74 //The following two lists may contain pointers to ic's not presently
75 //attached to the view since we need to remember settings:
76 QSet<VP1GraphicsItemCollection*> cols_override_inactive;
77 QSet<VP1GraphicsItemCollection*> cols_override_unmovable;
78
79 QRectF home;
80
85 QQueue<QRectF> zoomanim_queue;
86 QPainter::RenderHints savedrenderhints;
87
89
90 void setNewSelected(QGraphicsItem*,const bool& multimode=false);
91 QMap<QGraphicsItem*,HighLightItem*> selecteditems;
92
93// QList<QGraphicsItem*> selecteditems;//Fixme more than one item!!
94// QList<QGraphicsPathItem*> selectionoutlines;
95 VP1GraphicsItemCollection * ic_multiselection;//Holds the ic when a multiselection is taking place.
96 void locateActiveItemAtPoint(QGraphicsItem*&,VP1GraphicsItemCollection*& ic,
97 const QPoint& pos,
98 VP1GraphicsItemCollection * searchic=0);
99 void select(QGraphicsItem*item);
100 void deselect(QGraphicsItem*item);
103 QList<QGraphicsItem*> lastemittedselecteditems;
104
105
107 void paintDescription(QPainter *painter);
108 QTextDocument helptext;
110 void createNewHelptextImage(const QRect& imrect);
112
113 //transformation:
116};
117
118//We make a slightly modified pathitem for highlight item - because we
119//need to know when it is killed (which it will be when the user
120//removes an item):
121//____________________________________________________________________
122class VP1GraphicsView::HighLightItem : public QGraphicsPathItem {
123public:
124 HighLightItem ( const QPainterPath & path, QGraphicsItem * parent, VP1GraphicsView*v)
125 : QGraphicsPathItem(path,parent),view(v),sendsignalondelete(true) {}
126 virtual ~HighLightItem() {
128 view->m_d->HighLightItemBeingDeleted(this);
129 }
132};
133
134//____________________________________________________________________
136 :QGraphicsView(parent), m_d(new Imp)
137{
138 m_d->init(this);
139}
140
141//____________________________________________________________________
142VP1GraphicsView::VP1GraphicsView ( QGraphicsScene * scene, QWidget * parent )
143 : QGraphicsView(scene,parent), m_d(new Imp)
144{
145 m_d->init(this);
146}
147
148//____________________________________________________________________
150{
151 view=v;
152 view->setTransformationAnchor(AnchorUnderMouse);
153 view->setResizeAnchor(AnchorViewCenter);
154 if (QGLFormat::hasOpenGL())//It turns out that when doing x-forward (at least from lxplus) GLX, and thus OpenGL support is not present.
155 view->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers),view));
156 view->setRenderHint(QPainter::Antialiasing);//QPainter::SmoothPixmapTransform
157 view->setBackgroundBrush(Qt::black);
158 if (!view->scene())
159 view->setScene(new QGraphicsScene());
160 scene=view->scene();
162 view->setMode(PICK);
163
164 view->setFrameStyle(QFrame::NoFrame);
165
166 zoomanim_timer = new QTimer();
167 QObject::connect(zoomanim_timer, SIGNAL(timeout()), view, SLOT(updateZoomAnimation()));
168 zoomfactoronseek = 10.0;
169 //Like this to set the correct timer interval:
170 zoomanim_nsteps = 24;
171 view->setAnimatedZoomTime(1500.0);//ms
172
173 // Due to a bug in Qt 4.3.0 (not present in 4.2.3 and supposedly
174 // fixed in 4.3.1), we have to show the scrollbars if we want to
175 // have proper scrollhanddrag and seek modes. Therefore we uncomment
176 // the next two lines - and we should reenable them for Qt4.3.1 (fixme).
177 // view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
178 // view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
179
180 //Make sure that animation aborts if user moves a scrollbar (in case someone turns them on):
181 QObject::connect(view->horizontalScrollBar(),SIGNAL(sliderMoved(int)),view,SLOT(abortZoomAnimation()));
182 QObject::connect(view->verticalScrollBar(),SIGNAL(sliderMoved(int)),view,SLOT(abortZoomAnimation()));
185// selecteditem=0;
186// selectionoutline=0;
188 showhelptext=false;
189
190 transform = 0;
191 transformactive = false;
192 //fixme:
193 if (false) {
194 transformactive = true;
195 // transform = new VP12DViewRZFishEyeTransformation();
197 view->setInteractive ( false );
198 }
199
200}
201
202//____________________________________________________________________
204{
205 delete m_d->transform;
206 delete m_d; m_d=0;
207}
208
209//____________________________________________________________________
210void VP1GraphicsView::scaleView(qreal scaleFactor)
211{
213 qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
214 if (factor < 1e-5 || factor > 1e5)//Fixme:Set as options!
215 return;
216 scale(scaleFactor, scaleFactor);
217}
218
219//____________________________________________________________________
221{
222 if (m_d->transform&&m_d->transformactive)
223 fitInView( m_d->transform->transform(scene()->sceneRect()), Qt::KeepAspectRatio );
224 else
225 fitInView( scene()->sceneRect(), Qt::KeepAspectRatio );
226}
227
228//____________________________________________________________________
229void VP1GraphicsView::wheelEvent(QWheelEvent *event)
230{
231 if (m_d->showhelptext) {
232 m_d->showhelptext=false;
233 viewport()->update();
234 };
235 double ratefact = 0.8;
236 if (event->modifiers() & Qt::ControlModifier)
237 ratefact = 0.1;
238 if (event->modifiers() & Qt::ShiftModifier)
239 ratefact = 0.01;
240 scaleView(pow((double)2, -event->angleDelta().y() / (240.0/ratefact)));
241}
242
243//____________________________________________________________________
244void VP1GraphicsView::keyPressEvent(QKeyEvent *event)
245{
246// VP1Msg::messageDebug("VP1GraphicsView::keyPressEvent");
247
248// std::string keyText = (event->text()).toStdString();
249// VP1Msg::messageDebug(keyText.c_str());
250
251 if (m_d->showhelptext&&!(event->key()==Qt::Key_F1||event->key()==Qt::Key_H)) {
252 m_d->showhelptext=false;
253 viewport()->update();
254 };
255
256 switch (event->key()) {
257 case Qt::Key_Home:
258 if (event->modifiers() & Qt::ControlModifier)
259 setHome();
260 else
261 viewHome();
262 break;
263 case Qt::Key_F1:
264 case Qt::Key_H:
265 m_d->showhelptext=!m_d->showhelptext;
266 viewport()->update();
267 break;
268 case Qt::Key_1:
270 break;
271 case Qt::Key_Escape:
272 if (m_d->mode==SEEK)
273 setMode(m_d->lastmajormode);
274 else if (m_d->mode==PICK)
276 else
277 setMode(PICK);
278 break;
279 case Qt::Key_S:
280 if (m_d->mode!=SEEK)
281 setMode(SEEK);
282 else
283 setMode(m_d->lastmajormode);
284 break;
285 case Qt::Key_Plus:
286 case Qt::Key_Equal:
287 scaleView(1.2);
288 break;
289 case Qt::Key_Minus:
290 scaleView(1 / 1.2);
291 break;
292 case Qt::Key_P:
293 if (event->modifiers() & Qt::ControlModifier)
294 saveImage();
295 else
296 print();
297 break;
298 default:
299 // QGraphicsView::keyPressEvent(event);
300 break;
301 }
302
303// if (m_d->mode==PICK) {
304// for (QGraphicsItem*item : items(event->pos())) {
305// for (VP1GraphicsItemCollection* ic : m_d->cols_act) {
306// if (ic->itemBelongsAndIsPresentlyActive(item)) {
307// event->accept();
308// //EMIT [event] SIGNALS.
309// }
310// }
311// }
312// }
313
314
315 QGraphicsView::keyPressEvent(event);
316}
317
318//____________________________________________________________________
320{
321 if (m_d->mode==m)
322 return;
323 m_d->mode=m;
324 if (m==PICK||m==CHANGEVIEW)
325 m_d->lastmajormode=m;
326
327 if (m!=DRAGZOOM&&m!=DRAGZOOMHOLD)
328 m_d->dragzoom_startpoint=QPoint();
329
330 //Dragmode:
331 if (m==CHANGEVIEW) {
332 setDragMode(QGraphicsView::ScrollHandDrag);
333 } else {
334 setDragMode(QGraphicsView::NoDrag);
335 }
336
337 //Cursor:
338 switch (m) {
339 case PICK:
340 setCursor(Qt::ArrowCursor);
341 break;
342 case CHANGEVIEW:
343 setCursor(Qt::OpenHandCursor);
344 break;
345 case DRAGZOOM:
346 case DRAGZOOMHOLD:
347 setCursor(Qt::SizeVerCursor);
348 break;
349 case SEEK:
350 setCursor(Qt::CrossCursor);
351 break;
352 default:
353 assert(0);
354 break;
355 }
356
357 //Interactions/movable:
358 if (m==PICK) {
359 for (VP1GraphicsItemCollection*ic : m_d->cols_act)
360 if (!m_d->cols_override_inactive.contains(ic))
361 ic->setTemporaryIgnoreInteractions(false);
362 for (VP1GraphicsItemCollection*ic : m_d->cols_all)
363 if (!m_d->cols_override_unmovable.contains(ic))
364 ic->setTemporaryIgnoreMovable(false);
365 } else {
366 for (VP1GraphicsItemCollection*ic : m_d->cols_all)
367 ic->setTemporaryIgnoreMovable(true);
368 for (VP1GraphicsItemCollection*ic : m_d->cols_act)
369 ic->setTemporaryIgnoreInteractions(true);
370 }
371}
372
373//____________________________________________________________________
375{
376 return m_d->mode;
377}
378
379//____________________________________________________________________
381 assert(!m_d->cols_all.contains(ic));
382 assert(!m_d->cols_act.contains(ic));
383 m_d->cols_all << ic;
384 if (ic->interactionMode()!=VP1GraphicsItemCollection::INERT) {
385 m_d->cols_act << ic;
386 ic->setTemporaryIgnoreInteractions( m_d->mode!=PICK || m_d->cols_override_inactive.contains(ic) );
387 ic->setTemporaryIgnoreMovable( m_d->mode!=PICK || m_d->cols_override_unmovable.contains(ic) );
388 }
389 ic->attachToView(this);
390}
391
392//____________________________________________________________________
394 assert(m_d->cols_all.contains(ic));
395 m_d->cols_all.removeAll(ic);
396 if (m_d->cols_act.contains(ic))
397 m_d->cols_act.removeAll(ic);
398 ic->setTemporaryIgnoreInteractions(false);
399 ic->setTemporaryIgnoreMovable(false);
400 ic->real_detachFromView();
401 //Fixme: When user calls the detach/attach/... methods on the ic, these methods must also be invoked!
402 //Fixme: use groupnode in each ic. This also allows an easy hide/unhide action as well as z values... (ic have external setZValue() method).
403}
404
405//____________________________________________________________________
406void VP1GraphicsView::mouseDoubleClickEvent(QMouseEvent * event) {
407
408 if (m_d->showhelptext) {
409 m_d->showhelptext=false;
410 viewport()->update();
411 };
412
413 if (m_d->mode!=PICK) {
414 QGraphicsView::mouseDoubleClickEvent(event);
415 return;
416 }
417 //Fixme: transformed pos
418 for (QGraphicsItem*item : items(event->pos())) {
419 for (VP1GraphicsItemCollection* ic : m_d->cols_act) {
420 if (ic->itemBelongsAndIsPresentlyActive(item)) {
421 event->accept();
422 //EMIT SIGNALS. CHANGE SELECTION.
423 }
424 }
425 }
426 QGraphicsView::mouseDoubleClickEvent(event);
427 return;
428}
429
430
431//____________________________________________________________________
432void VP1GraphicsView::mouseMoveEvent(QMouseEvent *event)
433{
434
435 //Fixme: transformed pos
436
437 if ((m_d->mode==DRAGZOOM||m_d->mode==DRAGZOOMHOLD) && m_d->dragzoom_startpoint!=QPoint() ) {
438 double delta = event->pos().y()-m_d->dragzoom_startpoint.y();
439 m_d->dragzoom_startpoint=event->pos();
440 ViewportAnchor save = transformationAnchor();
441 setTransformationAnchor(AnchorViewCenter);
442 scaleView(pow((double)2, -delta / (240.0/0.8)));//FIXME!! Dont have this equation more than once!
443 setTransformationAnchor(save);
444 event->accept();
445 return;
446 }
447 if (m_d->mode==PICK) {
448 for (QGraphicsItem*item : items(event->pos())) {
449 for (VP1GraphicsItemCollection* ic : m_d->cols_act) {
450 if (ic->itemBelongsAndIsPresentlyActive(item)) {
451 event->accept();
452 //EMIT [event] SIGNALS.
453 }
454 }
455 }
456 }
457 QGraphicsView::mouseMoveEvent(event);
458 return;
459}
460
461//____________________________________________________________________
462void VP1GraphicsView::mousePressEvent(QMouseEvent *event)
463{
464 setFocus(Qt::MouseFocusReason);//Fixme: also doubleclick event!
465
466 if (m_d->showhelptext) {
467 m_d->showhelptext=false;
468 viewport()->update();
469 };
470
471 if (m_d->mode==SEEK) {
472 event->accept();
473 setMode(m_d->lastmajormode);
474 seekToPoint(mapToScene(event->pos()));
475 return;
476 }
477
478 if (m_d->mode==CHANGEVIEW&&event->buttons()==(Qt::LeftButton|Qt::MiddleButton)) {
479 event->accept();
480 m_d->dragzoom_startpoint=event->pos();
482 return;
483 }
484
485 if (m_d->mode==DRAGZOOM&&event->buttons()!=(Qt::LeftButton|Qt::MiddleButton)) {
486 if (event->buttons()==(Qt::LeftButton|Qt::MiddleButton|Qt::RightButton)) {
488 } else {
490 }
491 event->accept();
492 return;
493 }
494
495 if (m_d->mode==DRAGZOOMHOLD) {//Fixme: also doubleclick event!
497 event->accept();
498 return;
499 }
500
501
502 if (m_d->mode==PICK) {
503 if (event->buttons()!=Qt::LeftButton) {
504 QGraphicsView::mousePressEvent(event);
505 return;
506 }
507 //If we have previous selections already, and the mult select key
508 //is down, then we will only consider items in the same collection
509 //as active.
510 bool continueselection = m_d->ic_multiselection && (event->modifiers() & Qt::ShiftModifier);
511 QGraphicsItem*item(0);VP1GraphicsItemCollection*ic(0);
512
513// QPoint pickpoint = m_d->transform ?
514// mapFromScene(m_d->transform->inverseTransform( mapToScene(event->pos())))
515// : event->pos();
516 QPoint pickpoint = event->pos();
517 if (continueselection) {
518 assert(m_d->ic_multiselection);
519 m_d->locateActiveItemAtPoint(item,ic,pickpoint,m_d->ic_multiselection);
520 if (!item) {
521 //shift was down, and the user did not hit anything
522 QGraphicsView::mousePressEvent(event);
523 return;
524 }
525 } else {
526 m_d->locateActiveItemAtPoint(item,ic,pickpoint);
527 }
528
529 if (item) {
530 assert(ic);
531 if (ic->interactionMode()==VP1GraphicsItemCollection::SINGLEPICKS) {
533 m_d->setNewSelected(item);
534 ic->itemPickedPrivate(item);
535 } else if (ic->interactionMode()==VP1GraphicsItemCollection::EVENTS) {
537 event->accept();
538 ic->itemGotEventPrivate(item,event);
539 return;
540 } else if (ic->interactionMode()==VP1GraphicsItemCollection::SELECTIONS) {
541 assert(ic);
542 VP1GraphicsItemCollection * tmpic = ic;
543 m_d->ic_multiselection=ic;
544 m_d->setNewSelected(item,continueselection);
546 } else {
547 assert(0);
548 }
549 } else {
551 }
552 }
553
554 QGraphicsView::mousePressEvent(event);
555 return;
556}
557
558//____________________________________________________________________
560{
561
562 //Fixme: transformed pos
563 if (m_d->mode==CHANGEVIEW&&event->buttons()==(Qt::LeftButton|Qt::MiddleButton)) {
564 event->accept();
565 m_d->dragzoom_startpoint=event->pos();
567 return;
568 }
569
570 if (m_d->mode==DRAGZOOM&&event->buttons()!=(Qt::LeftButton|Qt::MiddleButton)) {
571 event->accept();
573 return;
574 }
575
576 if (m_d->mode==PICK) {
577// for (QGraphicsItem*item : items(event->pos())) {
578// if (item==static_cast<QGraphicsItem*>(m_d->selectionoutline))//Fixme: Dont do the cast here.
579// continue;
580// for(VP1GraphicsItemCollection* ic : m_d->cols_act) {
581// if (ic->itemBelongsAndIsPresentlyActive(item)) {
582// event->accept();
583// if (ic->interactionMode()==VP1GraphicsItemCollection::EVENTS) {
584// //EMIT EVENT SIGNAL!
585// return;
586// }
587// if (m_d->selecteditem==item) {
588// QGraphicsView::mouseReleaseEvent(event);
589// return;
590// }
591// m_d->setNewSelected(item);
592// //EMIT pick/selection signals.
593// }
594// }
595// }
596 }
597 QGraphicsView::mouseReleaseEvent(event);
598 return;
599
600}
601
602//____________________________________________________________________
605 const QPoint& pos,
606 VP1GraphicsItemCollection * searchic) {
607
608 //We turn the point into a small circle - to get some chance of picking lines, degenerate rectangles, etc.
609 const double tol = 2.0;
610 QRectF tolrect( pos.x()-tol, pos.y()-tol, 2*tol, 2*tol );
611
612 QPainterPath p;
614 QPainterPath ptmp;
615 ptmp.addEllipse(tolrect);
616 QPainterPath ptmp2;
617 transform->inverseTransformPath(view->mapToScene(ptmp),ptmp2);
618 QPainterPath p = view->mapFromScene(ptmp2);
619 } else {
620 p.addEllipse(tolrect);
621 }
622
623 //Fixme: use faster stl style iterators.
624 for (QGraphicsItem* item2 : view->items(p)) {
625 if (searchic) {
626 if (searchic->itemBelongsAndIsPresentlyActive(item2)) {
627 item=item2;
628 ic=searchic;
629 return;
630 }
631 } else {
633 if (ic2->itemBelongsAndIsPresentlyActive(item2)) {
634 item=item2;
635 ic=ic2;
636 return;
637 }
638 }
639 }
640 }
641 assert(!item&&!ic);
642 return;
643}
644
645//____________________________________________________________________
647{
648
649#ifndef NDEBUG
650 QMapIterator<QGraphicsItem*,HighLightItem*> ittest(selecteditems);
651 assert(ittest.findNext(hlitem));
652#endif
653
654 QMap<QGraphicsItem*,HighLightItem*>::iterator
655 it = selecteditems.begin(), itE = selecteditems.end();
656 for (;it!=itE;++it) {
657 if (it.value()==hlitem) {
658 selecteditems.erase(it);
659 break;
660 }
661 }
662
663 if (ic_multiselection) {
664 view->emitSelectionChanged(ic_multiselection);
665 }
666#ifndef NDEBUG
667 QMapIterator<QGraphicsItem*,HighLightItem*> ittest2(selecteditems);
668 assert(!ittest2.findNext(hlitem));
669#endif
670}
671
672//____________________________________________________________________
673void VP1GraphicsView::clearSelections() {//Fixme: only clear
674 //selections of certain
675 //collections? (so the
676 //permanent items stay
677 //selected?)
678
679 bool haditemsinselection = m_d->ic_multiselection && !m_d->selecteditems.empty();
680
681 //Remove highlight items:
682 QMapIterator<QGraphicsItem*,HighLightItem*> it(m_d->selecteditems);
683 while (it.hasNext()) {
684 it.next();
685 it.value()->sendsignalondelete = false;
686 //assert(!m_d->scene->items().contains(it.key()));
687 if (m_d->scene->items().contains(it.value())) {
688 m_d->scene->removeItem(it.value());
689 // delete it.value();
690 }
691 }
692
693 //Clear lists - possibly emit a signal:
694 m_d->selecteditems.clear();
695 if (m_d->clearselectionsemitsignals&&haditemsinselection) {
696 emitSelectionChanged(m_d->ic_multiselection);
697 m_d->ic_multiselection = 0;//TEST
698 }
699 m_d->clearselectionsemitsignals=true;
700}
701
702//____________________________________________________________________
703void VP1GraphicsView::Imp::deselect(QGraphicsItem*item)
704{
705 if (selecteditems.count()==1) {
706 view->clearSelections();
707 return;
708 }
709
710 assert(selecteditems.contains(item));
711 QMap<QGraphicsItem*,HighLightItem*>::iterator it = selecteditems.find(item);
712 if (scene->items().contains(it.value())) {
713 assert(scene->items().contains(it.value()));
714 scene->removeItem(it.value());
715 it.value()->sendsignalondelete = false;
716 delete it.value();
717 }
718 assert(selecteditems.contains(item));
719 selecteditems.erase(it);
720 assert(!selecteditems.contains(item));
721}
722
723//____________________________________________________________________
724void VP1GraphicsView::Imp::select(QGraphicsItem*item)
725{
726 assert(!selecteditems.contains(item));
727
728 QPainterPath path = item->shape();
729
730 HighLightItem* outline = new HighLightItem(path,item,view);
731 outline->setBrush(QColor(250,0,250,100));
732 outline->setPen(QPen(Qt::red,0,Qt::SolidLine,Qt::SquareCap,Qt::RoundJoin));
733 scene->addItem(outline);
734
735 selecteditems.insert(item,outline);
736
737}
738
739//____________________________________________________________________
740void VP1GraphicsView::Imp::setNewSelected(QGraphicsItem*item,const bool& continueselection) {
741
742 assert(item);
743
744 if (continueselection) {
745 if (selecteditems.contains(item))
746 deselect(item);
747 else
748 select(item);
749 return;
750 } else {
751 if (!selecteditems.empty()) {
753 view->clearSelections();
754 }
755 select(item);
756 }
757
758// if (selecteditems.contains(item))
759// view->addselect(item);
760// view->removeselect(item);
761
762// if (!continueselection&&!selecteditems.empty()) {
763// view->clearSelections();
764// }
765
766
767}
768
769//____________________________________________________________________
770void VP1GraphicsView::seekToPoint(QPointF targetpoint) {
771 abortZoomAnimation();//In case there is already an animation running we abort it.
772 QRectF currentview = mapToScene(viewport()->rect()).boundingRect();
773 double w1= currentview.width(), h1= currentview.height();
774 double w2 = w1/m_d->zoomfactoronseek, h2 = h1/m_d->zoomfactoronseek;
775 double x2 = targetpoint.x()-0.5*w2, y2 = targetpoint.y()-0.5*h2;
776 initiateAnimatedZoomTo( QRectF(x2,y2,w2,h2) );
777}
778
779//____________________________________________________________________
781{
783 if (m_d->zoomanim_nsteps==1) {
784 fitInView(goal);
785 return;
786 }
787
788 QRectF currentview = mapToScene(viewport()->rect()).boundingRect();
789
790 double w1 = currentview.width(), h1 = currentview.height();
791 double x1 = currentview.x(), y1 = currentview.y();
792
793 double w2 = goal.width(), h2 = goal.height();
794 double x2 = goal.x(), y2 = goal.y();
795
796 const double eps = 1.0/m_d->zoomanim_nsteps;
797 for (double f = eps; f < 1.0+0.5*eps; f+=eps ) {
798 //f values are spaced linearly between eps and 1.0. Let us
799 //construct something which has values packed closer near 1.0 (for
800 //that nice smooth slow-down feel):
801 double f2 = sqrt(f);
802 m_d->zoomanim_queue.enqueue(QRectF( x1*(1.0-f2)+x2*f2, y1*(1.0-f2)+y2*f2,
803 w1*(1.0-f2)+w2*f2, h1*(1.0-f2)+h2*f2 ));
804 }
805
806 m_d->savedrenderhints=renderHints();
807 setRenderHints(QPainter::RenderHints());
808 m_d->zoomanim_timer->start();
809}
810
811//____________________________________________________________________
813{
814 assert(!m_d->zoomanim_queue.empty());
815 //For testing:
816 // QGraphicsRectItem * item = new QGraphicsRectItem(m_d->zoomanim_queue.dequeue());
817 // item->setPen(QPen(Qt::blue,0,Qt::SolidLine,Qt::SquareCap,Qt::RoundJoin));
818 // scene()->addItem(item);
819 fitInView( m_d->zoomanim_queue.dequeue(), Qt::KeepAspectRatio );
820 if (m_d->zoomanim_queue.empty())
821 m_d->zoomanim_timer->stop();
822}
823
824//____________________________________________________________________
826{
827 if (m_d->zoomanim_timer->isActive())
828 m_d->zoomanim_timer->stop();
829 if (!m_d->zoomanim_queue.empty())
830 m_d->zoomanim_queue.clear();
831 if (m_d->savedrenderhints)
832 setRenderHints(m_d->savedrenderhints);
833 m_d->savedrenderhints=QPainter::RenderHints();
834 //Fixme: renderhints changed during an
835 //animation cycle might not be saved... Should
836 //override the renderhints methods to avoid
837 //this.
838}
839
840
841//____________________________________________________________________
843{
844 assert(n>=1);
845 m_d->zoomanim_nsteps = n;
846 m_d->zoomanim_timer->setInterval(std::max(1,static_cast<int>(m_d->zoomanim_totaltime/m_d->zoomanim_nsteps+0.5)));
847 //Same as just below.
848}
849
850//____________________________________________________________________
852{
853 m_d->zoomanim_totaltime = t;
854 m_d->zoomanim_timer->setInterval(std::max(1,static_cast<int>(m_d->zoomanim_totaltime/m_d->zoomanim_nsteps+0.5)));
855 //Same as just above.
856}
857
858//____________________________________________________________________
860{
861 m_d->zoomfactoronseek = zf;
862}
863
864//____________________________________________________________________
866
867 const bool animatedhome = true;//Fixme: option?
868 if (m_d->home == QRect()) {
869 if (animatedhome) {
870 if (m_d->transform&&m_d->transformactive)
871 initiateAnimatedZoomTo(m_d->transform->transform(scene()->sceneRect()));
872 else
873 initiateAnimatedZoomTo(scene()->sceneRect());
874 } else {
876 }
877 } else {
878 if (animatedhome) {
880 } else {
881 fitInView( m_d->home, Qt::KeepAspectRatio );
882 }
883 }
884}
885
886//____________________________________________________________________
888 m_d->home=mapToScene(viewport()->rect()).boundingRect();
889}
890
891//____________________________________________________________________
893 QList<QGraphicsItem*> emitlist = m_d->selecteditems.keys();
894 if (emitlist==m_d->lastemittedselecteditems)
895 return;
896 m_d->lastemittedselecteditems=emitlist;
897 ic->selectionChangedPrivate(emitlist);
898}
899
900//____________________________________________________________________
902{
903 if (m_d->cols_override_inactive.contains(ic)==disallow)
904 return;
905
906 if ( disallow ) {
907 m_d->cols_override_inactive.insert(ic);
908 if ( m_d->cols_all.contains(ic) )
909 ic->setTemporaryIgnoreInteractions(true);
910 } else {
911 m_d->cols_override_inactive.remove(ic);
912 if ( m_d->cols_all.contains(ic) && m_d->mode != PICK )
913 ic->setTemporaryIgnoreInteractions(false);
914 }
915}
916
917//____________________________________________________________________
919{
920 if (m_d->cols_override_unmovable.contains(ic)==disallow)
921 return;
922
923 if (disallow) {
924 m_d->cols_override_unmovable.insert(ic);
925 if (m_d->cols_all.contains(ic))
926 ic->setTemporaryIgnoreMovable(true);
927 } else {
928 m_d->cols_override_unmovable.remove(ic);
929 if ( m_d->cols_all.contains(ic) && m_d->mode != PICK )
930 ic->setTemporaryIgnoreMovable(false);
931 }
932}
933
934//____________________________________________________________________
936{
937 //Fixme: This does not really work well... Check again in QT 4.3?
938 QPrinter printer;
939 QPrintDialog dialog(&printer, this);
940 if (dialog.exec() == QDialog::Accepted) {
941 QPainter painter(&printer);
942 render(&painter);
943 }
944}
945
946//____________________________________________________________________
948{
949 QString guess;
950 if (m_d->currentsaveimagefile.isEmpty()) {
951 QString base=VP1Settings::defaultFileSelectDirectory()+QDir::separator()+"vp1_capture";
952 guess=base;
953 int i(2);
954 while (QFile::exists(guess+".png"))
955 guess=base+"_"+QString::number(i++);
956 guess+=".png";
957 } else {
958 guess=m_d->currentsaveimagefile;
959 }
960
961 QString filename = QFileDialog::getSaveFileName(0, "Select target image file", guess,
962 "Image (*.png *.bmp)",
963 0,QFileDialog::DontResolveSymlinks);
964 if(filename.isEmpty())
965 return;
966
967 QPixmap pm = viewport()->grab();
968 if (!(filename.endsWith(".png",Qt::CaseInsensitive)||filename.endsWith(".bmp",Qt::CaseInsensitive)))
969 filename += ".png";
970
971 pm.save(filename);
972 m_d->currentsaveimagefile = std::move(filename);
973}
974
975// //____________________________________________________________________
976// void VP1GraphicsView::paintEvent ( QPaintEvent * event )
977// {
978// //Fixme: Reimplementing the paintEvent like this is supposedly
979// //helpful in some circumstances... I have not really benchmarked
980// //whether it actually helps though...
981// // QPaintEvent * newEvent = new QPaintEvent(event->region().boundingRect());
982// // QGraphicsView::paintEvent(newEvent);
983// // delete newEvent;
984// }
985
986//____________________________________________________________________
987void VP1GraphicsView::drawForeground ( QPainter * painter, const QRectF & /*rect*/ ) {
988
989 //Fixme: use rect?
990 if (!m_d->showhelptext)
991 return;
992 QRect imgrect = viewport()->rect();
993 imgrect.setWidth(imgrect.width()*3);
994 imgrect.setHeight(imgrect.height()*3);
995 if (!m_d->helptextimage||m_d->helptextimage->size()!=imgrect.size())
996 m_d->createNewHelptextImage(imgrect);//viewport()->rect());
997 painter->setRenderHint(QPainter::Antialiasing, false);
998 painter->drawImage(mapToScene(viewport()->rect()).boundingRect(),*(m_d->helptextimage),
999 imgrect);
1000}
1001
1002//____________________________________________________________________
1004{
1005 if(helptext.isEmpty()) {
1006 helptext.setHtml ("<html>\n"
1007 "\n"
1008 "<h2>How to navigate a VP1GraphicsView</h2>\n"
1009 "\n"
1010 " <p>\n <b>H/F1</b> Show this help."
1011 " \n <b>S</b> Seek mode.\n"
1012 " \n <b>+/-</b> Zoom.\n"
1013 " \n <b>CTRL+HOME</b> Set home.\n"
1014 " \n <b>HOME</b> View home.\n"
1015 " \n <b>1</b> View all.\n"
1016 " \n <b>ESC</b> Switch between view and pick mode.\n"
1017 " \n <b>P</b> Print view.\n"
1018 " \n <b>CTRL+P</b> Save snapshot to image file.</p>\n"
1019 " <p>\n <b>Mouse wheel</b> zoom. Use <b>CTRL</b> and <b>SHIFT</b> for finegrained control.</p>\n"
1020 " <p>\n To select items (in pick mode), click on them. Selected multiple by holding down <b>SHIFT</b>.</p>\n"
1021 "\n"
1022 "<p>\n"
1023 " Please report any bugs to <i>Thomas.Kittelmann@cern.ch</i>.\n"
1024 "</p>\n"
1025 "\n"
1026 "\n"
1027 "</html>" );
1028 QFont myfont("Helvetica",36);
1029 // myfont.setPointSize(400);
1030 helptext.setDefaultFont ( myfont );
1031 // helptext.defaultFont().setPointSize(400);
1032 }
1033
1034 delete helptextimage;
1035 helptextimage = new QImage(imrect.size(), QImage::Format_ARGB32);//Fixme delete in destructor!!
1036
1037 QPainter painter;
1038 painter.begin(helptextimage);
1039
1040 int pageWidth = qMax(imrect.width() - 100, 100);
1041 int pageHeight = qMax(imrect.height() - 100, 100);
1042 if (pageWidth != helptext.pageSize().width()) {
1043 helptext.setPageSize(QSize(pageWidth, pageHeight));
1044 }
1045
1046 QRect textRect(imrect.width() / 2 - pageWidth / 2,
1047 imrect.height() / 2 - pageHeight / 2,
1048 pageWidth,
1049 pageHeight);
1050 int pad = 10;
1051 QRect clearRect = textRect.adjusted(-pad, -pad, pad, pad);
1052 painter.setPen(Qt::NoPen);
1053 painter.setBrush(QColor(0, 0, 0, 63));
1054 int shade = 10;
1055 painter.drawRect(clearRect.x() + clearRect.width() + 1,
1056 clearRect.y() + shade,
1057 shade,
1058 clearRect.height() + 1);
1059 painter.drawRect(clearRect.x() + shade,
1060 clearRect.y() + clearRect.height() + 1,
1061 clearRect.width() - shade + 1,
1062 shade);
1063
1064 painter.setRenderHint(QPainter::Antialiasing, false);
1065 painter.setBrush(QColor(255, 255, 255, 220));
1066 painter.setPen(Qt::black);
1067 painter.drawRect(clearRect);
1068
1069 painter.setClipRegion(textRect, Qt::IntersectClip);
1070 painter.translate(textRect.topLeft());
1071
1072 QAbstractTextDocumentLayout::PaintContext ctx;
1073
1074 QLinearGradient g(0, 0, 0, textRect.height());
1075 g.setColorAt(0, Qt::black);
1076 g.setColorAt(0.9, Qt::black);
1077 g.setColorAt(1, Qt::transparent);
1078
1079 QPalette pal = view->viewport()->palette();
1080 pal.setBrush(QPalette::Text, g);
1081
1082 ctx.palette = std::move(pal);
1083 ctx.clip = QRect(0, 0, textRect.width(), textRect.height());
1084 helptext.documentLayout()->draw(&painter, ctx);
1085
1086 painter.end();
1087
1088}
1089
1090//____________________________________________________________________
1091void VP1GraphicsView::drawItems(QPainter *painter, int numItems,
1092 QGraphicsItem *items[],
1093 const QStyleOptionGraphicsItem options[])
1094{
1095
1096 if (!(m_d->transform&&m_d->transformactive)) {
1097 QGraphicsView::drawItems(painter,numItems,items,options);
1098 //Fixme: implement own drawing here also - to make sure inbuilt selection stuff is never shown?
1099 return;
1100 }
1101
1102 for (int i = 0; i < numItems; ++i) {
1103 QGraphicsItem *item = items[i];
1104 painter->save();
1105 painter->setTransform(item->sceneTransform(), true);//??
1106 // std::cout<< item->sceneMatrix().isIdentity()<<std::endl;
1107 // std::cout<< item->sceneMatrix().dx()<<" : "<<item->sceneMatrix().dy()<<std::endl;
1108 m_d->transform->paintItem(painter, item);
1109 painter->restore();
1110 }
1111}
constexpr int pow(int base, int exp) noexcept
bool itemBelongsAndIsPresentlyActive(QGraphicsItem *) const
HighLightItem(const QPainterPath &path, QGraphicsItem *parent, VP1GraphicsView *v)
void setNewSelected(QGraphicsItem *, const bool &multimode=false)
void locateActiveItemAtPoint(QGraphicsItem *&, VP1GraphicsItemCollection *&ic, const QPoint &pos, VP1GraphicsItemCollection *searchic=0)
void init(VP1GraphicsView *)
void select(QGraphicsItem *item)
QQueue< QRectF > zoomanim_queue
void HighLightItemBeingDeleted(HighLightItem *)
QSet< VP1GraphicsItemCollection * > cols_override_inactive
QList< VP1GraphicsItemCollection * > cols_act
VP1GraphicsItemCollection * ic_multiselection
IVP12DViewTransformation * transform
QPainter::RenderHints savedrenderhints
void deselect(QGraphicsItem *item)
QGraphicsScene * scene
QList< VP1GraphicsItemCollection * > cols_all
void paintDescription(QPainter *painter)
void createNewHelptextImage(const QRect &imrect)
QSet< VP1GraphicsItemCollection * > cols_override_unmovable
QMap< QGraphicsItem *, HighLightItem * > selecteditems
VP1GraphicsView * view
QList< QGraphicsItem * > lastemittedselecteditems
void setMode(const Mode &)
void keyPressEvent(QKeyEvent *)
VP1GraphicsView(QWidget *parent=0)
void mouseReleaseEvent(QMouseEvent *)
void setAnimatedZoomSteps(int)
void setZoomFactorOnSeek(double)
void addItemCollection(VP1GraphicsItemCollection *)
void setDisallowMovable(VP1GraphicsItemCollection *, const bool &disallow=true)
void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[])
void mouseMoveEvent(QMouseEvent *)
void initiateAnimatedZoomTo(QRectF)
void drawForeground(QPainter *painter, const QRectF &rect)
void removeItemCollection(VP1GraphicsItemCollection *)
void mousePressEvent(QMouseEvent *)
friend class HighLightItem
void mouseDoubleClickEvent(QMouseEvent *event)
void seekToPoint(QPointF)
void emitSelectionChanged(VP1GraphicsItemCollection *)
void scaleView(qreal scaleFactor)
void setDisallowInteractions(VP1GraphicsItemCollection *, const bool &disallow=true)
void wheelEvent(QWheelEvent *)
void setAnimatedZoomTime(double)
static QString defaultFileSelectDirectory()
std::string base
Definition hcg.cxx:81