Vuo 2.4.4
Loading...
Searching...
No Matches
VuoEditorGraphicsView.cc
Go to the documentation of this file.
1
11#include "VuoEditor.hh"
12#include "VuoEditorCocoa.hh"
14#include "VuoEditorWindow.hh"
15
20 : QGraphicsView(parent)
21{
22 setOptimizationFlags(QGraphicsView::DontSavePainterState | QGraphicsView::DontAdjustForAntialiasing);
23
24 // For large compositions, it's faster to redraw the entire viewport
25 // than to check hundreds of objects to determine whether we should render them.
26 setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
27
28 framesRenderedSinceProfileLogged = 0;
29 renderDurationSinceProfileLogged = 0;
30 lastProfileLoggedTime = VuoLogGetElapsedTime();
31
32 viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
33 accumulatedScale = 1;
34 gestureDetected = false;
35
36 QSettings settings;
37 ignorePinchesSmallerThanX = settings.value("canvas/ignorePinchesSmallerThanX", 0.25).toDouble();
38 ignorePinchesStartedLessThanXSecondsAfterDrag = settings.value("canvas/ignorePinchesStartedLessThanXSecondsAfterDrag", 0.5).toDouble();
39 ignorePinchesStartedMoreThanXSecondsAfterTouch = settings.value("canvas/ignorePinchesStartedMoreThanXSecondsAfterTouch", 0.25).toDouble();
40
41 VuoEditor *editor = (VuoEditor *)qApp;
42 connect(editor, &VuoEditor::darkInterfaceToggled, this, &VuoEditorGraphicsView::updateColor);
43}
44
49{
50 return gestureDetected;
51}
52
56bool VuoEditorGraphicsView::event(QEvent * event)
57{
58 if (event->type() == QEvent::KeyPress)
59 {
60 QKeyEvent *keyEvent = (QKeyEvent *)(event);
61 if (keyEvent->key() == Qt::Key_Return && (keyEvent->modifiers() & Qt::ControlModifier))
62 {
63 VuoEditor *e = (VuoEditor *)QCoreApplication::instance();
64 e->showNodeLibrary();
65 return true;
66 }
67
68 if (keyEvent->key() == Qt::Key_Escape)
69 qApp->sendEvent(parentWidget(), keyEvent);
70 }
71
72 else if (event->type() == QEvent::Resize)
73 emit viewResized();
74
75 return QGraphicsView::event(event);
76}
77
81void VuoEditorGraphicsView::paintEvent(QPaintEvent *event)
82{
83 double t0 = VuoLogGetElapsedTime();
84 QGraphicsView::paintEvent(event);
85 double renderDuration = VuoLogGetElapsedTime() - t0;
86
88 {
89 ++framesRenderedSinceProfileLogged;
90 renderDurationSinceProfileLogged += renderDuration;
91 const double profileSeconds = 5;
92 if (t0 > lastProfileLoggedTime + profileSeconds)
93 {
94 VUserLog("%4d items, average draw time %6.4f s (%6.1f fps), %6.1f draws per second, %4d MB cached, bspDepth %2d",
95 scene()->items().count(),
96 renderDurationSinceProfileLogged/framesRenderedSinceProfileLogged,
97 framesRenderedSinceProfileLogged/renderDurationSinceProfileLogged,
98 framesRenderedSinceProfileLogged/profileSeconds,
99 QPixmapCache::totalUsed()/1024,
100 scene()->bspTreeDepth());
101#if 0
102 foreach (QGraphicsItem *i, scene()->items())
103 {
104 VuoRendererNode *node = dynamic_cast<VuoRendererNode *>(i);
105 VuoRendererPort *port = dynamic_cast<VuoRendererPort *>(i);
106 if (node)
107 VUserLog("\t%p node '%s'", i, node->getBase()->getTitle().c_str());
108 else if (port)
109 VUserLog("\t%p port '%s'", i, port->getBase()->getClass()->getName().c_str());
110 else
111 VUserLog("\t%p %s", i, typeid(*i).name());
112 }
113#endif
114
115 lastProfileLoggedTime = t0;
116 framesRenderedSinceProfileLogged = 0;
117 renderDurationSinceProfileLogged = 0;
118 }
119 }
120}
121
125bool VuoEditorGraphicsView::viewportEvent(QEvent *event)
126{
127 QEvent::Type eventType = event->type();
128 VuoEditorComposition *composition = static_cast<VuoEditorComposition *>(scene());
129
130
131 // See VuoEditorWindow::eventFilter.
132 // https://b33p.net/kosada/vuo/vuo/-/issues/16688
133 if (eventType == QEvent::MouseButtonPress)
134 {
135 auto mbp = static_cast<QMouseEvent *>(event);
136 if (mbp->button() == Qt::RightButton)
137 {
138 QGraphicsSceneContextMenuEvent contextMenuEvent(QEvent::GraphicsSceneContextMenu);
139 contextMenuEvent.setScreenPos(mbp->globalPos());
140 contextMenuEvent.setScenePos(mapToScene(mbp->pos()));
141 contextMenuEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
142 QApplication::sendEvent(scene(), &contextMenuEvent);
143 event->accept();
144 return true;
145 }
146 }
147
148
149 if (eventType == QEvent::TouchBegin
150 || eventType == QEvent::TouchUpdate
151 || eventType == QEvent::TouchEnd)
152 {
153 QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
154 const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent->touchPoints();
155 const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
156 const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
157
158 static double latestTouchBeganTime = 0;
159 if (touchPoint0.state() & Qt::TouchPointPressed
160 || touchPoint1.state() & Qt::TouchPointPressed)
161 latestTouchBeganTime = ((double)touchEvent->timestamp()) / 1000.;
162
163 // System Settings > Trackpad > Scroll & Zoom > Zoom in or out
164 Boolean pinchPreference = CFPreferencesGetAppBooleanValue(CFSTR("TrackpadPinch"), CFSTR("com.apple.driver.AppleBluetoothMultitouch.trackpad"), nullptr);
165 if (!pinchPreference)
166 return false;
167
168 if (static_cast<VuoEditorWindow *>(window())->isScrollInProgress())
169 {
170 VDebugLog("ignoring pinch while scroll in progress");
171 return false;
172 }
173
174 double secondsSinceLastDrag = VuoLogGetElapsedTime() - static_cast<VuoEditorWindow *>(window())->getLatestDragTime();
175 if (secondsSinceLastDrag < ignorePinchesStartedLessThanXSecondsAfterDrag)
176 {
177 VDebugLog("ignoring pinch that occurred just %.2fs (less than %gs) after the latest drag", secondsSinceLastDrag, ignorePinchesStartedLessThanXSecondsAfterDrag);
178 return false;
179 }
180
181 if (static_cast<VuoEditorWindow *>(window())->isItemDragInProgress())
182 {
183 VDebugLog("ignoring pinch while item drag in progress");
184 return false;
185 }
186
187 if (composition && composition->getCableInProgress())
188 {
189 VDebugLog("ignoring pinch while cable drag in progress");
190 return false;
191 }
192
193 if (!rubberBandRect().isNull())
194 {
195 VDebugLog("ignoring pinch while rubberband in progress");
196 return false;
197 }
198
199 if (touchPoints.count() == 2)
200 {
201 double currentLength = QLineF(touchPoint0.pos(), touchPoint1.pos()).length();
202
203 static double detectedLength = 0;
204 if (!gestureDetected)
205 {
206 // Ignore tiny gestures (which probably aren't intended to be pinch gestures anyway).
207 double startLength = QLineF(touchPoint0.startPos(), touchPoint1.startPos()).length();
208 double scale = currentLength / startLength;
209 if (fabs(scale - 1) < ignorePinchesSmallerThanX)
210 {
211 VDebugLog("ignoring small pinch (%.2f < %g)", fabs(scale-1), ignorePinchesSmallerThanX);
212 return false;
213 }
214
215 // Ignore pinch gestures that start long after both fingers are down
216 // (which probably aren't intended to be pinch gestures anyway).
217 double secondsSinceTouch = ((double)touchEvent->timestamp())/1000. - latestTouchBeganTime;
218 if (secondsSinceTouch > ignorePinchesStartedMoreThanXSecondsAfterTouch)
219 {
220 VDebugLog("ignoring pinch that started %.2fs (more than %gs) after touch", secondsSinceTouch, ignorePinchesStartedMoreThanXSecondsAfterTouch);
221 return false;
222 }
223
224 detectedLength = QLineF(touchPoint0.pos(), touchPoint1.pos()).length();
225
226 // At the start of each pinch gesture, use the view's current scale.
227 accumulatedScale = transform().m11();
228
229 setInteractive(false);
230 gestureDetected = true;
231 }
232
233 double scale = currentLength / detectedLength;
234
235 if (touchEvent->touchPointStates() & Qt::TouchPointReleased)
236 {
237 accumulatedScale *= scale;
238 scale = 1;
239 setInteractive(true);
240 gestureDetected = false;
241 }
242
243 else
244 {
245 // Skip rendering if we aren't keeping up.
246 double lag = VuoEditorCocoa_systemUptime() - touchEvent->timestamp()/1000.;
247 const double lagLimit = .1;
248 if (lag > lagLimit)
249 return true;
250 }
251
252 VDebugLog("pinch zoomed to scale %g", accumulatedScale * scale);
253 setTransform(QTransform::fromScale(accumulatedScale * scale, accumulatedScale * scale));
254
255 // After zooming, scroll the scene to the view's center.
256 centerOn(mapToScene(rect().center()));
257
258 static_cast<VuoEditorWindow *>(window())->updateUI();
259 }
260 return true;
261 }
262
263 return QGraphicsView::viewportEvent(event);
264}
265
269void VuoEditorGraphicsView::updateColor(bool isDark)
270{
271 VuoEditorComposition *composition = static_cast<VuoEditorComposition *>(scene());
272 composition->setColor(isDark);
273}