KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
QWidgetAdapter_quick.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
21#include "QWidgetAdapter.h"
22#include "MainWindowBase.h"
23
24#include "../DockRegistry_p.h"
25#include "../Utils_p.h"
26#include "../FloatingWindow_p.h"
27#include "../multisplitter/Item_p.h"
28
29#include <QResizeEvent>
30#include <QMouseEvent>
31#include <QQmlComponent>
32#include <QQuickItem>
33#include <QQmlEngine>
34#include <QQuickView>
35#include <QScopedValueRollback>
36
37#include <qpa/qplatformwindow.h>
38#include <QtGui/private/qhighdpiscaling_p.h>
39
40using namespace KDDockWidgets;
41
42namespace KDDockWidgets {
43
49class MouseEventRedirector : public QObject
50{
52public:
53 explicit MouseEventRedirector(QObject *eventSource, QObject *eventTarget)
55 , m_eventSource(eventSource)
56 , m_eventTarget(eventTarget)
57 {
58 eventSource->installEventFilter(this);
59
60 // Each source can only have one MouseEventRedirector
61 auto oldRedirector = s_mouseEventRedirectors.take(eventSource);
62 if (oldRedirector) {
63 eventSource->removeEventFilter(oldRedirector);
64 oldRedirector->deleteLater();
65 }
66
67 s_mouseEventRedirectors.insert(eventSource, this);
68 }
69
70 static MouseEventRedirector *redirectorForSource(QObject *eventSource)
71 {
72 return s_mouseEventRedirectors.value(eventSource);
73 }
74
75 ~MouseEventRedirector() override;
76
77 bool eventFilter(QObject *source, QEvent *ev) override
78 {
80 if (!me)
81 return false;
82
83 // MouseArea.enable is different from Item.enabled. The former still lets the events
84 // go through event loops. So query MouseArea.enable here and bail out if false.
85 const QVariant v = source->property("enabled");
86 if (v.isValid() && !v.toBool())
87 return false;
88
89 // Finally send the event
90 m_eventTarget->setProperty("cursorPosition", m_eventSource->property("cursorPosition"));
91 qApp->sendEvent(m_eventTarget, me);
92 m_eventTarget->setProperty("cursorPosition", CursorPosition_Undefined);
93
94 return false;
95 }
96
97 QObject *const m_eventSource;
98 QObject *const m_eventTarget;
99 static QHash<QObject *, MouseEventRedirector *> s_mouseEventRedirectors;
100};
101
102QHash<QObject *, MouseEventRedirector *> MouseEventRedirector::s_mouseEventRedirectors = {};
103
104MouseEventRedirector::~MouseEventRedirector()
105{
106 s_mouseEventRedirectors.remove(m_eventSource);
107}
108
109}
110
112{
113 return flags & (Qt::Window | Qt::Tool);
114}
115
116static QQuickItem *actualParentItem(QQuickItem *candidateParentItem, Qt::WindowFlags flags)
117{
118 // When we have a top-level, such as FloatingWindow, we only want to set QObject parentship
119 // and not parentItem.
120 return flagsAreTopLevelFlags(flags) ? nullptr
121 : candidateParentItem;
122}
123
124QWidgetAdapter::QWidgetAdapter(QQuickItem *parent, Qt::WindowFlags flags)
125 : QQuickItem(actualParentItem(parent, flags))
126 , m_windowFlags(flags)
127{
128 if (parent && flagsAreTopLevelFlags(flags)) {
129 // See comment in actualParentItem(). We set only the QObject parent. Mimics QWidget behaviour
130 QObject::setParent(parent);
131 }
132
133 connect(this, &QQuickItem::widthChanged, this, [this] {
134 onResize(size());
135 updateGeometry();
136 });
137
138 connect(this, &QQuickItem::heightChanged, this, [this] {
139 if (!m_windowIsBeingDestroyed) { // If Window is being destroyed we don't bother
140 onResize(size());
141 updateGeometry();
142 }
143 });
144
145 qApp->installEventFilter(this);
146
147 setSize(QSize(800, 800));
148}
149
150QWidgetAdapter::~QWidgetAdapter()
151{
152}
153
154void QWidgetAdapter::raiseAndActivate()
155{
156 if (QWindow *w = windowHandle()) {
157 w->raise();
158 w->requestActivate();
159 }
160}
161
162void QWidgetAdapter::setWindowOpacity(qreal level)
163{
164 if (QWindow *w = windowHandle())
165 w->setOpacity(level);
166}
167
168bool QWidgetAdapter::onResize(QSize)
169{
170 return false;
171}
172void QWidgetAdapter::onLayoutRequest()
173{
174}
175void QWidgetAdapter::onMousePress()
176{
177}
178void QWidgetAdapter::onMouseMove(QPoint)
179{
180}
181void QWidgetAdapter::onMouseRelease()
182{
183}
184void QWidgetAdapter::onCloseEvent(QCloseEvent *)
185{
186}
187void QWidgetAdapter::onResizeEvent(QResizeEvent *)
188{
189 updateNormalGeometry();
190}
191void QWidgetAdapter::onMoveEvent(QMoveEvent *)
192{
193 updateNormalGeometry();
194}
195
196void QWidgetAdapter::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
197{
198 QQuickItem::itemChange(change, data);
199
200 // Emulate the QWidget behaviour as QQuickItem doesn't receive some QEvents.
201 switch (change) {
202 case QQuickItem::ItemParentHasChanged: {
204 qApp->sendEvent(this, &ev); // Not calling event() directly, otherwise it would skip event filters
205 Q_EMIT parentChanged(this);
206 break;
207 }
208 case QQuickItem::ItemVisibleHasChanged: {
209 if (m_inSetParent) {
210 // Setting parent to nullptr will emit visible true in QtQuick
211 // which we don't want, as we're going to hide it (as we do with QtWidgets)
212 break;
213 }
214
215 QEvent ev(isVisible() ? QEvent::Show : QEvent::Hide);
216 event(&ev);
217 break;
218 }
219 default:
220 break;
221 }
222}
223
224void QWidgetAdapter::updateNormalGeometry()
225{
226 QWindow *window = windowHandle();
227 if (!window) {
228 return;
229 }
230
231 QRect normalGeometry;
232 if (const QPlatformWindow *pw = window->handle()) {
233 normalGeometry = QHighDpi::fromNativePixels(pw->normalGeometry(), pw->window());
234 }
235
236 if (!normalGeometry.isValid() && isNormalWindowState(window->windowState())) {
237 normalGeometry = window->geometry();
238 }
239
240 if (normalGeometry.isValid()) {
241 setNormalGeometry(normalGeometry);
242 }
243}
244
245void QWidgetAdapter::QQUICKITEMgeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
246{
247 // Send a few events manually, since QQuickItem doesn't do it for us.
248 QQuickItem::QQUICKITEMgeometryChanged(newGeometry, oldGeometry);
249
250 // Not calling event() directly, otherwise it would skip event filters
251
252 if (newGeometry.size() != oldGeometry.size()) {
254 qApp->sendEvent(this, &ev);
255 }
256
257 if (newGeometry.topLeft() != oldGeometry.topLeft()) {
259 qApp->sendEvent(this, &ev);
260 }
261
262 Q_EMIT widgetGeometryChanged();
263}
264
265void QWidgetAdapter::raise()
266{
267 if (isTopLevel()) {
268 if (QWindow *w = windowHandle())
269 w->raise();
270 } else if (auto p = QQuickItem::parentItem()) {
271 // It's not a top-level, so just increase its Z-order
272 const auto siblings = p->childItems();
273 QQuickItem *last = siblings.last();
274 if (last != this)
275 stackAfter(last);
276 }
277}
278
279QSize QWidgetAdapter::minimumSize() const
280{
281 if (m_isWrapper) {
282 const auto children = childItems();
283 if (!children.isEmpty()) {
284 const QSize min = children.constFirst()->property("kddockwidgets_min_size").toSize();
285 return min.expandedTo(Layouting::Item::hardcodedMinimumSize);
286 }
287 }
288
289 const QSize min = property("kddockwidgets_min_size").toSize();
290 return min.expandedTo(Layouting::Item::hardcodedMinimumSize);
291}
292
293QSize QWidgetAdapter::maximumSize() const
294{
295 if (m_isWrapper) {
296 const auto children = childItems();
297 if (!children.isEmpty()) {
298 const QSize max = children.constFirst()->property("kddockwidgets_max_size").toSize();
299 return max.isEmpty() ? Layouting::Item::hardcodedMaximumSize
300 : max.boundedTo(Layouting::Item::hardcodedMaximumSize);
301 }
302 }
303
304 const QSize max = property("kddockwidgets_max_size").toSize();
305 return max.isEmpty() ? Layouting::Item::hardcodedMaximumSize
306 : max.boundedTo(Layouting::Item::hardcodedMaximumSize);
307}
308
309WId QWidgetAdapter::winId() const
310{
311 if (QWindow *w = windowHandle())
312 return w->winId();
313
314 return WId(-1);
315}
316
317FloatingWindow *QWidgetAdapter::floatingWindow() const
318{
319 if (auto fw = qobject_cast<FloatingWindow *>(window()))
320 return fw;
321
322 return nullptr;
323}
324
325QRect QWidgetAdapter::geometry() const
326{
327 if (isTopLevel()) {
328 if (QWindow *w = windowHandle()) {
329 return w->geometry();
330 }
331 }
332
333 return KDDockWidgets::Private::geometry(this);
334}
335
336QRect QWidgetAdapter::normalGeometry() const
337{
338 return m_normalGeometry;
339}
340
341void QWidgetAdapter::setNormalGeometry(QRect geo)
342{
343 m_normalGeometry = geo;
344}
345
346QRect QWidgetAdapter::rect() const
347{
348 return QRectF(0, 0, width(), height()).toRect();
349}
350
351QPoint QWidgetAdapter::pos() const
352{
353 return geometry().topLeft();
354}
355
356void QWidgetAdapter::show()
357{
358 setVisible(true);
359}
360
361void QWidgetAdapter::setFixedHeight(int height)
362{
363 setHeight(height);
364}
365
366void QWidgetAdapter::setFixedWidth(int width)
367{
368 setWidth(width);
369}
370
371void QWidgetAdapter::setGeometry(QRect rect)
372{
373 setWidth(rect.width());
374 setHeight(rect.height());
375 move(rect.topLeft());
376}
377
378QRect QWidgetAdapter::frameGeometry() const
379{
380 if (QWindow *w = windowHandle())
381 return w->frameGeometry();
382
383 return geometry();
384}
385
386void QWidgetAdapter::grabMouse()
387{
388 QQuickItem::grabMouse();
389}
390
391void QWidgetAdapter::releaseMouse()
392{
393 QQuickItem::ungrabMouse();
394}
395
396void QWidgetAdapter::releaseKeyboard()
397{
398 // Not needed apparently
399}
400
401void QWidgetAdapter::setMinimumSize(QSize sz)
402{
403 if (minimumSize() != sz) {
404 setProperty("kddockwidgets_min_size", sz);
405 updateGeometry();
406 }
407}
408
409void QWidgetAdapter::setMaximumSize(QSize sz)
410{
411 if (maximumSize() != sz) {
412 setProperty("kddockwidgets_max_size", sz);
413 updateGeometry();
414 }
415}
416
417void QWidgetAdapter::setMaximumSize(int w, int h)
418{
419 QWidgetAdapter::setMaximumSize(QSize(w, h));
420}
421
422void QWidgetAdapter::setMinimumSize(int w, int h)
423{
424 QWidgetAdapter::setMinimumSize(QSize(w, h));
425}
426
427void QWidgetAdapter::updateGeometry()
428{
429 Q_EMIT geometryUpdated();
430}
431
432void QWidgetAdapter::resize(QSize sz)
433{
434 setWidth(sz.width());
435 setHeight(sz.height());
436}
437
438void QWidgetAdapter::resize(int w, int h)
439{
440 resize({ w, h });
441}
442
443bool QWidgetAdapter::isWindow() const
444{
445 QQuickItem *parent = parentItem();
446 if (!parent)
447 return true;
448
449 if (QQuickView *w = quickView()) {
450 if (parent == w->contentItem() || parent == w->rootObject())
451 return true;
452 }
453
454 return false;
455}
456
457bool QWidgetAdapter::isMaximized() const
458{
459 if (QWindow *w = windowHandle())
460 return w->windowStates() & Qt::WindowMaximized;
461
462 return false;
463}
464
465bool QWidgetAdapter::isFullScreen() const
466{
467 if (QWindow *w = windowHandle())
468 return w->windowStates() & Qt::WindowFullScreen;
469
470 return false;
471}
472
473bool QWidgetAdapter::isMinimized() const
474{
475 if (QWindow *w = windowHandle())
476 return w->windowStates() & Qt::WindowMinimized;
477
478 return false;
479}
480
481bool KDDockWidgets::QWidgetAdapter::isActiveWindow() const
482{
483 if (QWindow *w = windowHandle())
484 return w->isActive();
485
486 return false;
487}
488
489void QWidgetAdapter::showMaximized()
490{
491 if (QWindow *w = windowHandle())
492 w->showMaximized();
493}
494
495void QWidgetAdapter::showMinimized()
496{
497 if (QWindow *w = windowHandle())
498 w->showMinimized();
499}
500
501void QWidgetAdapter::showNormal()
502{
503 if (QWindow *w = windowHandle())
504 w->showNormal();
505}
506
507QQuickView *QWidgetAdapter::quickView() const
508{
509 return qobject_cast<QQuickView *>(QQuickItem::window());
510}
511
512QWindow *QWidgetAdapter::windowHandle() const
513{
514 return QQuickItem::window();
515}
516
517QWidgetAdapter *QWidgetAdapter::window() const
518{
519 // We return the top-most QWidgetAdapter
520
521 if (QWidgetAdapter *w = parentWidget(/*includeTransient =*/false))
522 return w->window();
523
524 return const_cast<QWidgetAdapter *>(this);
525}
526
527QWidgetAdapter *QWidgetAdapter::parentWidget(bool includeTransient) const
528{
529 QQuickItem *p = parentItem();
530 while (p) {
531 if (auto qa = qobject_cast<QWidgetAdapter *>(p))
532 return qa;
533
534 p = p->parentItem();
535 }
536
537 if (includeTransient) {
538 if (QQuickView *w = quickView()) {
539 // Here we're mimicking QWidget::parentWidget(), which can return the transient parent of the QWindow.
540 MainWindowBase *mw = DockRegistry::self()->mainWindowForHandle(w->transientParent());
541 if (mw)
542 return mw;
543 }
544 }
545
546
547 return nullptr;
548}
549
550QPoint QWidgetAdapter::mapToGlobal(QPoint pt) const
551{
552 return QQuickItem::mapToGlobal(pt).toPoint();
553}
554
555QPoint QWidgetAdapter::mapFromGlobal(QPoint pt) const
556{
557 return QQuickItem::mapFromGlobal(pt).toPoint();
558}
559
560QPoint QWidgetAdapter::mapTo(const QQuickItem *parent, QPoint pos) const
561{
562 if (!parent)
563 return {};
564
565 return parent->mapFromGlobal(QQuickItem::mapToGlobal(pos)).toPoint();
566}
567
568bool QWidgetAdapter::testAttribute(Qt::WidgetAttribute attr) const
569{
570 return m_widgetAttributes & attr;
571}
572
573void QWidgetAdapter::setAttribute(Qt::WidgetAttribute attr, bool enable)
574{
575 if (enable)
576 m_widgetAttributes |= attr;
577 else
578 m_widgetAttributes &= ~attr;
579}
580
581void QWidgetAdapter::setWindowTitle(const QString &title)
582{
583 if (QWindow *window = windowHandle())
584 window->setTitle(title);
585}
586
587void QWidgetAdapter::setWindowIcon(const QIcon &icon)
588{
589 if (QWindow *window = windowHandle())
590 window->setIcon(icon);
591}
592
593bool QWidgetAdapter::close()
594{
595 QCloseEvent ev;
596 onCloseEvent(&ev);
597
598 if (ev.isAccepted()) {
599 setVisible(false);
600 return true;
601 }
602
603 return false;
604}
605
606QQuickItem *QWidgetAdapter::childAt(QPoint p) const
607{
608 return QQuickItem::childAt(p.x(), p.y());
609}
610
611void QWidgetAdapter::move(QPoint pt)
612{
613 move(pt.x(), pt.y());
614}
615
616void QWidgetAdapter::move(int x, int y)
617{
618 if (isTopLevel()) {
619 if (QWindow *w = windowHandle()) {
620 w->setPosition(x, y);
621 return;
622 }
623 }
624
625 setX(x);
626 setY(y);
627 setAttribute(Qt::WA_Moved);
628}
629
630void QWidgetAdapter::setSize(QSize size)
631{
632 QQuickItem::setSize(QSizeF(size));
633}
634
635void QWidgetAdapter::setParent(QQuickItem *p)
636{
637 {
638 QScopedValueRollback<bool> guard(m_inSetParent, true);
639
640 QQuickItem::setParent(p);
641 QQuickItem::setParentItem(p);
642 }
643
644 // Mimic QWidget::setParent(), hide widget when setting parent
645 if (!p)
646 setVisible(false);
647}
648
649void QWidgetAdapter::activateWindow()
650{
651 if (QWindow *w = windowHandle())
652 w->requestActivate();
653}
654
655void QWidgetAdapter::setSizePolicy(QSizePolicy sp)
656{
657 m_sizePolicy = sp;
658}
659
660QSizePolicy QWidgetAdapter::sizePolicy() const
661{
662 return m_sizePolicy;
663}
664
665QSize QWidgetAdapter::sizeHint() const
666{
667 return m_sizeHint;
668}
669
670bool QWidgetAdapter::hasFocus() const
671{
672 return hasActiveFocus();
673}
674
675void QWidgetAdapter::setWindowFlag(int flag, bool enable)
676{
677 Q_UNUSED(flag);
678 Q_UNUSED(enable);
679}
680
681Qt::WindowFlags QWidgetAdapter::windowFlags() const
682{
683 return m_windowFlags;
684}
685
687QQuickItem *QWidgetAdapter::createItem(QQmlEngine *engine, const QString &filename)
688{
689 QQmlComponent component(engine, filename);
690 QObject *obj = component.create();
691 if (!obj) {
692 qWarning() << Q_FUNC_INFO << component.errorString();
693 return nullptr;
694 }
695
696 return qobject_cast<QQuickItem *>(obj);
697}
698
699void QWidgetAdapter::makeItemFillParent(QQuickItem *item)
700{
701 // This is equivalent to "anchors.fill: parent
702
703 if (!item) {
704 qWarning() << Q_FUNC_INFO << "Invalid item";
705 return;
706 }
707
708 QQuickItem *parentItem = item->parentItem();
709 if (!parentItem) {
710 qWarning() << Q_FUNC_INFO << "Invalid parentItem for" << item;
711 return;
712 }
713
714 QObject *anchors = item->property("anchors").value<QObject *>();
715 if (!anchors) {
716 qWarning() << Q_FUNC_INFO << "Invalid anchors for" << item;
717 return;
718 }
719
720 anchors->setProperty("fill", QVariant::fromValue(parentItem));
721}
722
723void QWidgetAdapter::setFlag(Qt::WindowType f, bool on)
724{
725 if (on) {
726 m_windowFlags |= f;
727 } else {
728 m_windowFlags &= ~f;
729 }
730}
731
732Qt::FocusPolicy QWidgetAdapter::focusPolicy() const
733{
734 return m_focusPolicy;
735}
736
737void QWidgetAdapter::setFocusPolicy(Qt::FocusPolicy policy)
738{
739 m_focusPolicy = policy;
740}
741
742void QWidgetAdapter::setFocus(Qt::FocusReason reason)
743{
744 QQuickItem::setFocus(true, reason);
745 forceActiveFocus(reason);
746}
747
748void QWidgetAdapter::render(QPainter *)
749{
750 qWarning() << Q_FUNC_INFO << "Implement me";
751}
752
753void QWidgetAdapter::setMouseTracking(bool enabled)
754{
755 m_mouseTrackingEnabled = enabled;
756}
757
758bool QWidgetAdapter::event(QEvent *ev)
759{
760 if (ev->type() == QEvent::Close)
761 onCloseEvent(static_cast<QCloseEvent *>(ev));
762
763 return QQuickItem::event(ev);
764}
765
766bool QWidgetAdapter::eventFilter(QObject *watched, QEvent *ev)
767{
768 if (qobject_cast<QWindow *>(watched)) {
769 if (m_mouseTrackingEnabled) {
770 switch (ev->type()) {
774 ev->ignore();
775 qApp->sendEvent(this, ev);
776 // qDebug() << "Mouse event" << ev;
777 if (ev->isAccepted())
778 return true;
779 break;
780 default:
781 break;
782 }
783 }
784
785 if (ev->type() == QEvent::Resize) {
786 onResizeEvent(static_cast<QResizeEvent *>(ev));
787 } else if (ev->type() == QEvent::Move) {
788 onMoveEvent(static_cast<QMoveEvent *>(ev));
789 }
790 }
791
792 return QQuickItem::eventFilter(watched, ev);
793}
794
795QScreen *QWidgetAdapter::screen() const
796{
797 if (QQuickView *w = quickView()) {
798 return w->screen();
799 }
800
801 return nullptr;
802}
803
804void QWidgetAdapter::setWindowIsBeingDestroyed(bool is)
805{
806 m_windowIsBeingDestroyed = is;
807}
808
809void QWidgetAdapter::create()
810{
811 // Nothing to do, for QtQuick ?
812}
813
814QQuickItem *KDDockWidgets::Private::widgetForWindow(QWindow *window)
815{
816 if (!window)
817 return nullptr;
818
819 return window->property("kddockwidgets_qwidget").value<QQuickItem *>();
820}
821
822void QWidgetAdapter::redirectMouseEvents(QObject *source)
823{
824 if (auto existingRedirector = MouseEventRedirector::redirectorForSource(source)) {
825 if (existingRedirector->m_eventTarget == this) {
826 // Nothing to do. The specified event source is already redirecting to this instance
827 return;
828 }
829 }
830
831 new MouseEventRedirector(source, this);
832}
833
834void QWidgetAdapter::setIsWrapper()
835{
836 m_isWrapper = true;
837}
838
839bool QWidgetAdapter::isWrapper() const
840{
841 return m_isWrapper;
842}
843
845
846#include "QWidgetAdapter_quick.moc"
The MainWindow base-class that's shared between QtWidgets and QtQuick stack.
Abstraction for supporting both QtWidgets and QtQuick.
static bool flagsAreTopLevelFlags(Qt::WindowFlags flags)
static QQuickItem * actualParentItem(QQuickItem *candidateParentItem, Qt::WindowFlags flags)
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
bool isAccepted() const const
void ignore()
QEvent::Type type() const const
int remove(const Key &key)
Q_OBJECTQ_OBJECT
void installEventFilter(QObject *filterObj)
QVariant property(const char *name) const const
T qobject_cast(QObject *object)
void removeEventFilter(QObject *obj)
void setParent(QObject *parent)
bool setProperty(const char *name, const QVariant &value)
int x() const const
int y() const const
int height() const const
bool isValid() const const
QPoint topLeft() const const
int width() const const
QSizeF size() const const
QRect toRect() const const
QPointF topLeft() const const
QSize boundedTo(const QSize &otherSize) const const
QSize expandedTo(const QSize &otherSize) const const
int height() const const
bool isEmpty() const const
int width() const const
FocusPolicy
FocusReason
WidgetAttribute
WindowMaximized
typedef WindowFlags
QVariant fromValue(const T &value)
T value() const const
QRect geometry() const const
void setIcon(const QIcon &icon)
void setTitle(const QString &)
Qt::WindowState windowState() const const

© 2019-2023 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Wed Nov 1 2023 00:02:31 for KDDockWidgets API Documentation by doxygen 1.9.8