Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
zoomwidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
5#include "zoomwidget_p.h"
6
7#include <QtWidgets/qgraphicsscene.h>
8#include <QtWidgets/qgraphicsproxywidget.h>
9#include <QtWidgets/qmenu.h>
10#include <QtWidgets/qscrollbar.h>
11
12#include <QtGui/qaction.h>
13#include <QtGui/qactiongroup.h>
14#include <QtGui/qevent.h>
15
16#include <QtCore/qtextstream.h>
17#include <QtCore/qmath.h>
18#include <QtCore/qdebug.h>
19#include <QtCore/qlist.h>
20
22
23using namespace Qt::StringLiterals;
24
25enum { debugZoomWidget = 0 };
26
27static const int menuZoomList[] = { 100, 25, 50, 75, 125, 150 , 175, 200 };
28
29namespace qdesigner_internal {
30
31// ---------- ZoomMenu
32
36{
38 for (int zoom : menuZoomList) {
39 //: Zoom factor
41 a->setCheckable(true);
43 if (zoom == 100)
44 a->setChecked(true);
46 }
47}
48
49int ZoomMenu::zoomOf(const QAction *a)
50{
51 return a->data().toInt();
52}
53
55{
56 const auto za = m_menuActions->actions();
57 for (QAction *a : za) {
58 m->addAction(a);
59 if (zoomOf(a) == 100)
60 m->addSeparator();
61 }
62}
63
64int ZoomMenu::zoom() const
65{
67}
68
70{
71 const auto za = m_menuActions->actions();
72 for (QAction *a : za) {
73 if (zoomOf(a) == percent) {
74 a->setChecked(true);
75 return;
76 }
77 }
78}
79
81{
83}
84
86{
87 QList<int> rc;
88 const int nz = sizeof(menuZoomList)/sizeof(int);
89 rc.reserve(nz);
90 for (int i = 0; i < nz; i++)
92 return rc;
93}
94
95// --------- ZoomView
108
109int ZoomView::zoom() const
110{
111 return m_zoom;
112}
113
115{
116 const QPoint origin(0 ,0);
117 const QPoint current = scrollPosition();
118 if (current != origin) {
119 if (debugZoomWidget)
120 qDebug() << "ZoomView::scrollToOrigin from " << current;
122 }
123}
124
126{
127 if (debugZoomWidget)
128 qDebug() << "ZoomView::setZoom" << percent;
129
130 if (m_zoom == percent)
131 return;
132
133 m_zoom = percent;
134 const qreal hundred = 100.0;
135 m_zoomFactor = static_cast<qreal>(m_zoom) / hundred;
136
137 applyZoom();
138 if (m_zoomMenu) // Do not force them into existence
140
143}
144
146{
147}
148
150{
151 return m_zoomFactor;
152}
153
158
163
165{
166 if (!m_zoomMenu) {
167 m_zoomMenu = new ZoomMenu(this);
170 }
171 return m_zoomMenu;
172}
173
175{
176 if (debugZoomWidget > 1)
177 qDebug() << "ZoomView::contextMenuEvent" << event->pos() << event->globalPos() << zoom() << '%';
178
181 } else {
183 }
184}
185
192
197
203
204// -------------- ZoomProxyWidget
209
211{
212 switch (change) {
213 case ItemPositionChange: {
214 const QPointF newPos = value.toPointF();
215 const QPointF desiredPos = QPointF(0, 0);
217 qDebug() << "ZoomProxyWidget::itemChange: refusing " << newPos;
218 return desiredPos;
219 }
220 default:
221 break;
222 }
224}
225
226/* ZoomedEventFilterRedirector: Event filter for the zoomed widget.
227 * It redirects the events to another handler of ZoomWidget as its
228 * base class QScrollArea also implements eventFilter() for its viewport. */
229
230static constexpr auto zoomedEventFilterRedirectorNameC = "__qt_ZoomedEventFilterRedirector"_L1;
231
234
235public:
237 bool eventFilter(QObject *watched, QEvent *event) override;
238
239private:
240 ZoomWidget *m_zw;
241};
242
243ZoomedEventFilterRedirector::ZoomedEventFilterRedirector(ZoomWidget *zw, QObject *parent) :
244 QObject(parent),
245 m_zw(zw)
246{
247 setObjectName(zoomedEventFilterRedirectorNameC);
248}
249
250bool ZoomedEventFilterRedirector::eventFilter(QObject *watched, QEvent *event)
251{
252 return m_zw->zoomedEventFilter(watched, event);
253}
254
255
256// --------- ZoomWidget
257
264
266{
267 if (debugZoomWidget)
268 qDebug() << "ZoomWidget::setWidget" << w << Qt::bin << wFlags;
269
270 if (m_proxy) {
272 if (QWidget *w = m_proxy->widget()) {
273 // remove the event filter
276 }
278 }
279 // Set window flags on the outer proxy for them to take effect
280 m_proxy = createProxyWidget(nullptr, Qt::Window);
282
286 resizeToWidgetSize(); // Do manually for new widget
287 m_proxy->show();
288}
289
298
300{
301 return QSize(0, 0);
302}
303
305{
308 const QSizeF rc = QSizeF(left + right, top + bottom);
309 return rc;
310}
311
313{
314 if (m_proxy)
315 return m_proxy->widget()->size();
316 return QSize(0, 0);
317}
318
319/* Convert widget size to QGraphicsView size.
320 * Watch out for limits (0, QWIDGETSIZE_MAX); just pass them on */
321
323{
324 const QSize vpMargin = viewPortMargin();
326 const int width = s.width();
327
328 QSize rc = s;
329 bool valid = false;
330 if (width != 0 && width != QWIDGETSIZE_MAX) {
331 valid = true;
332 rc.setWidth(vpMargin.width() + qCeil(deco.width() + zoomFactor() * static_cast<qreal>(width)));
333 }
334
335 const int height = s.height();
336 if (height != 0 && height != QWIDGETSIZE_MAX) {
337 valid = true;
338 rc.setHeight(vpMargin.height() + qCeil(deco.height() + zoomFactor() * static_cast<qreal>(height)));
339 }
340
341 if (ptrToValid)
342 *ptrToValid = valid;
343
344 return rc;
345}
346
347// On changing zoom: Make QGraphicsView big enough to hold the widget
349{
350 if (!m_proxy)
351 return;
352
353 m_viewResizeBlocked = true;
354 // Convert size, apply transformed min/max size if applicable
355 const QSize wsize = widgetSize();
357
358 bool hasMinimumSize = false;
361
362 bool hasMaximumSize = false;
365
366 if (debugZoomWidget) {
367 qDebug()
368 << "ZoomWidget::resizeToWidgetSize()\n"
369 << "Widget: " << wsize << "(scaled)" << (wsize * zoomFactor()) << " Min/Max" << minimumSize << maximumSize << '\n'
371 }
372 // Apply
373 if (hasMinimumSize)
375 if (hasMaximumSize)
377 // now resize
379 if (debugZoomWidget)
380 qDebug() << "ZoomWidget::resizeToWidgetSize(): resulting view size" << size();
381 m_viewResizeBlocked = false;
382}
383
385{
387}
388
389/* virtual */ void ZoomWidget::doResize(const QSize &s)
390{
391 if (debugZoomWidget > 1)
392 qDebug() << ">ZoomWidget::doResize() " << s;
393 resize(s);
394}
395
397{
398 /* QGraphicsView Resized from outside: Adapt widget. For some reason,
399 * the size passed in the event is not to be trusted. This might be due
400 * to some QScrollArea event fiddling. Have QScrollArea resize first
401 * and the use the size ZoomView::resizeEvent(event); */
403 if (debugZoomWidget > 1)
404 qDebug() << '>' << Q_FUNC_INFO << size() << ")::resizeEvent from " << event->oldSize() << " to " << event->size();
411 m_widgetResizeBlocked = false;
412 if (debugZoomWidget > 1)
413 qDebug() << '<' << Q_FUNC_INFO << widgetSizeF << m_proxy->widget()->size() << m_proxy->size();
414 }
415}
416
418{
419 if (!m_proxy)
421
423 const QSize rc = viewPortMargin() + (wmsh * zoomFactor()).toSize();
424 if (debugZoomWidget > 1)
425 qDebug() << "minimumSizeHint()" << rc;
426 return rc;
427}
428
430{
431 if (!m_proxy)
432 return QGraphicsView::sizeHint();
433
434 const QSizeF wsh = m_proxy->widget()->sizeHint();
435 const QSize rc = viewPortMargin() + (wsh * zoomFactor()).toSize();
436 if (debugZoomWidget > 1)
437 qDebug() << "sizeHint()" << rc;
438 return rc;
439}
440
442{
443 switch (event->type()) {
444 case QEvent::KeyPress:
445 if (debugZoomWidget) { // Debug helper: Press 'D' on the zoomed widget
446 const QKeyEvent *kevent = static_cast<QKeyEvent*>(event);
447 if (kevent->key() == Qt::Key_D)
448 dump();
449 }
450 break;
451 case QEvent::Resize:
452 if (debugZoomWidget > 1) {
453 const QResizeEvent *re = static_cast<const QResizeEvent *>(event);
454 qDebug() << "ZoomWidget::zoomedEventFilter" << re->oldSize() << re->size() << " at " << m_proxy->widget()->geometry();
455 }
458
459 break;
460 case QEvent::ContextMenu:
462 // Calculate global position from scaled
465 const QPointF pos = QPointF(origin + (QPointF(ce->pos()) * zoomFactor()));
467 ce->accept();
468 return true;
469 }
470 break;
471 default:
472 break;
473 }
474 return false;
475}
476
478{
479 if (m_proxy)
480 m_proxy->setAcceptDrops(true);
481}
482
484{
485 return m_proxy ? m_proxy->acceptDrops() : false;
486}
487
488 // Factory function for QGraphicsProxyWidgets which can be overwritten. Default creates a ZoomProxyWidget
493
494void ZoomWidget::dump() const
495{
496
497 qDebug() << "ZoomWidget::dump " << geometry() << " Viewport " << viewport()->geometry()
498 << "Scroll: " << scrollPosition() << "Transform: " << transform() << " SceneRect: " << sceneRect();
499 if (m_proxy) {
500 qDebug() << "Proxy Pos: " << m_proxy->pos() << "Proxy " << m_proxy->size()
501 << "\nProxy size hint"
505 << "\nTransform: " << m_proxy->transform()
506 << "\nWidget: " << m_proxy->widget()->geometry()
507 << "scaled" << (zoomFactor() * m_proxy->widget()->size());
508 }
509}
510
511} // namespace qdesigner_internal
512
513QT_END_NAMESPACE
bool eventFilter(QObject *watched, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
static constexpr auto zoomedEventFilterRedirectorNameC
static const int menuZoomList[]
@ debugZoomWidget