1/* -*- C++ -*-
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1997 Tim D. Gilman <tdgilman@best.org>
4 SPDX-FileCopyrightText: 1998-2001 Mirko Boehm <mirko@kde.org>
5 SPDX-FileCopyrightText: 2007 John Layt <john@layt.net>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kpopupframe.h"
11
12#include <QEventLoop>
13#include <QGuiApplication>
14#include <QKeyEvent>
15#include <QScreen>
16
17class KPopupFramePrivate
18{
19public:
20 KPopupFramePrivate(KPopupFrame *qq);
21 ~KPopupFramePrivate();
22
23 KPopupFrame *q;
24
25 /**
26 * The result. It is returned from exec() when the popup window closes.
27 */
28 int result;
29
30 /**
31 * The only subwidget that uses the whole dialog window.
32 */
33 QWidget *main;
34
35 // TODO KF6: Remove this, add a hideEvent() reimplementation instead.
36 class OutsideClickCatcher;
37 OutsideClickCatcher *outsideClickCatcher;
38};
39
40class KPopupFramePrivate::OutsideClickCatcher : public QObject
41{
42 Q_OBJECT
43public:
44 explicit OutsideClickCatcher(QObject *parent = nullptr)
45 : QObject(parent)
46 , m_popup(nullptr)
47 {
48 }
49 ~OutsideClickCatcher() override
50 {
51 }
52
53 void setPopupFrame(KPopupFrame *popup)
54 {
55 m_popup = popup;
56 popup->installEventFilter(filterObj: this);
57 }
58
59 KPopupFrame *m_popup;
60
61 bool eventFilter(QObject *object, QEvent *event) override
62 {
63 Q_UNUSED(object);
64
65 // To catch outside clicks, it is sufficient to check for
66 // hide events on Qt::Popup type widgets
67 if (event->type() == QEvent::Hide && m_popup) {
68 // do not set d->result here, because the popup
69 // hides itself after leaving the event loop.
70 Q_EMIT m_popup->leaveModality();
71 }
72 return false;
73 }
74};
75
76KPopupFramePrivate::KPopupFramePrivate(KPopupFrame *qq)
77 : q(qq)
78 , result(0)
79 , // rejected
80 main(nullptr)
81 , outsideClickCatcher(new OutsideClickCatcher)
82{
83 outsideClickCatcher->setPopupFrame(q);
84}
85
86KPopupFramePrivate::~KPopupFramePrivate()
87{
88 delete outsideClickCatcher;
89}
90
91KPopupFrame::KPopupFrame(QWidget *parent)
92 : QFrame(parent, Qt::Popup)
93 , d(new KPopupFramePrivate(this))
94{
95 setFrameStyle(QFrame::Box | QFrame::Raised);
96 setMidLineWidth(2);
97}
98
99KPopupFrame::~KPopupFrame() = default;
100
101void KPopupFrame::keyPressEvent(QKeyEvent *e)
102{
103 if (e->key() == Qt::Key_Escape) {
104 d->result = 0; // rejected
105 Q_EMIT leaveModality();
106 // qApp->exit_loop();
107 }
108}
109
110void KPopupFrame::hideEvent(QHideEvent *e)
111{
112 QFrame::hideEvent(event: e);
113}
114
115void KPopupFrame::close(int r)
116{
117 d->result = r;
118 Q_EMIT leaveModality();
119 // qApp->exit_loop();
120}
121
122void KPopupFrame::setMainWidget(QWidget *m)
123{
124 d->main = m;
125 if (d->main) {
126 resize(w: d->main->width() + 2 * frameWidth(), h: d->main->height() + 2 * frameWidth());
127 }
128}
129
130void KPopupFrame::resizeEvent(QResizeEvent *e)
131{
132 Q_UNUSED(e);
133
134 if (d->main) {
135 d->main->setGeometry(ax: frameWidth(),
136 ay: frameWidth(), //
137 aw: width() - 2 * frameWidth(), //
138 ah: height() - 2 * frameWidth());
139 }
140}
141
142void KPopupFrame::popup(const QPoint &pos)
143{
144 // Make sure the whole popup is visible.
145 QScreen *screen = QGuiApplication::screenAt(point: pos);
146
147 int x = pos.x();
148 int y = pos.y();
149 int w = width();
150 int h = height();
151 if (screen) {
152 const QRect desktopGeometry = screen->geometry();
153 if (x + w > desktopGeometry.x() + desktopGeometry.width()) {
154 x = desktopGeometry.width() - w;
155 }
156 if (y + h > desktopGeometry.y() + desktopGeometry.height()) {
157 y = desktopGeometry.height() - h;
158 }
159 if (x < desktopGeometry.x()) {
160 x = 0;
161 }
162 if (y < desktopGeometry.y()) {
163 y = 0;
164 }
165 }
166
167 // Pop the thingy up.
168 move(ax: x, ay: y);
169 show();
170 d->main->setFocus();
171}
172
173int KPopupFrame::exec(const QPoint &pos)
174{
175 popup(pos);
176 repaint();
177 d->result = 0; // rejected
178 QEventLoop eventLoop;
179 connect(sender: this, signal: &KPopupFrame::leaveModality, context: &eventLoop, slot: &QEventLoop::quit);
180 eventLoop.exec();
181
182 hide();
183 return d->result;
184}
185
186int KPopupFrame::exec(int x, int y)
187{
188 return exec(pos: QPoint(x, y));
189}
190
191#include "kpopupframe.moc"
192#include "moc_kpopupframe.cpp"
193

source code of kwidgetsaddons/src/kpopupframe.cpp