File indexing completed on 2025-02-02 14:20:09
0001 /* -*- C++ -*- 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1997 Tim D. Gilman <tdgilman@best.org> 0004 SPDX-FileCopyrightText: 1998-2001 Mirko Boehm <mirko@kde.org> 0005 SPDX-FileCopyrightText: 2007 John Layt <john@layt.net> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kpopupframe.h" 0011 0012 #include <QEventLoop> 0013 #include <QGuiApplication> 0014 #include <QKeyEvent> 0015 #include <QScreen> 0016 0017 class KPopupFramePrivate 0018 { 0019 public: 0020 KPopupFramePrivate(KPopupFrame *qq); 0021 ~KPopupFramePrivate(); 0022 0023 KPopupFrame *q; 0024 0025 /** 0026 * The result. It is returned from exec() when the popup window closes. 0027 */ 0028 int result; 0029 0030 /** 0031 * The only subwidget that uses the whole dialog window. 0032 */ 0033 QWidget *main; 0034 0035 // TODO KF6: Remove this, add a hideEvent() reimplementation instead. 0036 class OutsideClickCatcher; 0037 OutsideClickCatcher *outsideClickCatcher; 0038 }; 0039 0040 class KPopupFramePrivate::OutsideClickCatcher : public QObject 0041 { 0042 Q_OBJECT 0043 public: 0044 explicit OutsideClickCatcher(QObject *parent = nullptr) 0045 : QObject(parent) 0046 , m_popup(nullptr) 0047 { 0048 } 0049 ~OutsideClickCatcher() override 0050 { 0051 } 0052 0053 void setPopupFrame(KPopupFrame *popup) 0054 { 0055 m_popup = popup; 0056 popup->installEventFilter(this); 0057 } 0058 0059 KPopupFrame *m_popup; 0060 0061 bool eventFilter(QObject *object, QEvent *event) override 0062 { 0063 Q_UNUSED(object); 0064 0065 // To catch outside clicks, it is sufficient to check for 0066 // hide events on Qt::Popup type widgets 0067 if (event->type() == QEvent::Hide && m_popup) { 0068 // do not set d->result here, because the popup 0069 // hides itself after leaving the event loop. 0070 Q_EMIT m_popup->leaveModality(); 0071 } 0072 return false; 0073 } 0074 }; 0075 0076 KPopupFramePrivate::KPopupFramePrivate(KPopupFrame *qq) 0077 : q(qq) 0078 , result(0) 0079 , // rejected 0080 main(nullptr) 0081 , outsideClickCatcher(new OutsideClickCatcher) 0082 { 0083 outsideClickCatcher->setPopupFrame(q); 0084 } 0085 0086 KPopupFramePrivate::~KPopupFramePrivate() 0087 { 0088 delete outsideClickCatcher; 0089 } 0090 0091 KPopupFrame::KPopupFrame(QWidget *parent) 0092 : QFrame(parent, Qt::Popup) 0093 , d(new KPopupFramePrivate(this)) 0094 { 0095 setFrameStyle(QFrame::Box | QFrame::Raised); 0096 setMidLineWidth(2); 0097 } 0098 0099 KPopupFrame::~KPopupFrame() = default; 0100 0101 void KPopupFrame::keyPressEvent(QKeyEvent *e) 0102 { 0103 if (e->key() == Qt::Key_Escape) { 0104 d->result = 0; // rejected 0105 Q_EMIT leaveModality(); 0106 // qApp->exit_loop(); 0107 } 0108 } 0109 0110 void KPopupFrame::hideEvent(QHideEvent *e) 0111 { 0112 QFrame::hideEvent(e); 0113 } 0114 0115 void KPopupFrame::close(int r) 0116 { 0117 d->result = r; 0118 Q_EMIT leaveModality(); 0119 // qApp->exit_loop(); 0120 } 0121 0122 void KPopupFrame::setMainWidget(QWidget *m) 0123 { 0124 d->main = m; 0125 if (d->main) { 0126 resize(d->main->width() + 2 * frameWidth(), d->main->height() + 2 * frameWidth()); 0127 } 0128 } 0129 0130 void KPopupFrame::resizeEvent(QResizeEvent *e) 0131 { 0132 Q_UNUSED(e); 0133 0134 if (d->main) { 0135 d->main->setGeometry(frameWidth(), 0136 frameWidth(), // 0137 width() - 2 * frameWidth(), // 0138 height() - 2 * frameWidth()); 0139 } 0140 } 0141 0142 void KPopupFrame::popup(const QPoint &pos) 0143 { 0144 // Make sure the whole popup is visible. 0145 QScreen *screen = QGuiApplication::screenAt(pos); 0146 0147 int x = pos.x(); 0148 int y = pos.y(); 0149 int w = width(); 0150 int h = height(); 0151 if (screen) { 0152 const QRect desktopGeometry = screen->geometry(); 0153 if (x + w > desktopGeometry.x() + desktopGeometry.width()) { 0154 x = desktopGeometry.width() - w; 0155 } 0156 if (y + h > desktopGeometry.y() + desktopGeometry.height()) { 0157 y = desktopGeometry.height() - h; 0158 } 0159 if (x < desktopGeometry.x()) { 0160 x = 0; 0161 } 0162 if (y < desktopGeometry.y()) { 0163 y = 0; 0164 } 0165 } 0166 0167 // Pop the thingy up. 0168 move(x, y); 0169 show(); 0170 d->main->setFocus(); 0171 } 0172 0173 int KPopupFrame::exec(const QPoint &pos) 0174 { 0175 popup(pos); 0176 repaint(); 0177 d->result = 0; // rejected 0178 QEventLoop eventLoop; 0179 connect(this, &KPopupFrame::leaveModality, &eventLoop, &QEventLoop::quit); 0180 eventLoop.exec(); 0181 0182 hide(); 0183 return d->result; 0184 } 0185 0186 int KPopupFrame::exec(int x, int y) 0187 { 0188 return exec(QPoint(x, y)); 0189 } 0190 0191 #include "kpopupframe.moc" 0192 #include "moc_kpopupframe.cpp"