Visual Computing Library  devel
Loading...
Searching...
No Matches
widget_manager.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_QT_WIDGET_MANAGER_H
24#define VCL_QT_WIDGET_MANAGER_H
25
26#include "input.h"
27
28#include <vclib/render/concepts/render_app.h>
29#include <vclib/render/window_managers.h>
30#include <vclib/space/core/point.h>
31
32#if defined(VCLIB_RENDER_BACKEND_BGFX)
33#include <QWidget>
34#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
35#include <QOpenGLWidget>
36#endif
37
38#include <QGuiApplication>
39#include <QMouseEvent>
40
41namespace vcl::qt {
42
43template<typename DerivedRenderApp>
45#if defined(VCLIB_RENDER_BACKEND_BGFX)
46 public QWidget
47#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
48 public QOpenGLWidget
49#endif
50{
51#if defined(VCLIB_RENDER_BACKEND_BGFX)
52 using Base = QWidget;
53#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
54 using Base = QOpenGLWidget;
55#endif
56
57public:
63 using ParentType = QWidget;
64
70 static const uint WINDOW_MANAGER_ID = WindowManagerId::QT_WIDGET;
71
72 WidgetManager(QWidget* parent = nullptr) : Base(parent)
73 {
74 static_assert(
76 "The DerivedRenderApp must satisfy the RenderAppConcept.");
77#if defined(VCLIB_RENDER_BACKEND_BGFX)
79 Qt::WA_PaintOnScreen); // do not remove - needed on macos and x
80 setAttribute(Qt::WA_DontCreateNativeAncestors);
81 setAttribute(Qt::WA_NativeWindow);
82#endif
83 setFocusPolicy(Qt::StrongFocus);
84 }
85
86 explicit WidgetManager(
87 const std::string& windowTitle,
88 uint width = 1024,
89 uint height = 768,
90 QWidget* parent = nullptr) : WidgetManager(parent)
91 {
92 setGeometry(100, 100, width, height);
93 setWindowTitle(windowTitle.c_str());
94 }
95
96 ~WidgetManager() = default;
97
98 const std::string& windowTitle() const
99 {
100 return QWidget::windowTitle().toStdString();
101 }
102
103 void setWindowTitle(const std::string& title)
104 {
105 QWidget::setWindowTitle(title.c_str());
106 }
107
108 Point2f dpiScale() const { return Point2f(pixelRatio(), pixelRatio()); }
109
110 void* displayId() const
111 {
112 void* displayID = nullptr;
113#ifdef Q_OS_LINUX
115 QNativeInterface::QX11Application* x11AppInfo =
116 qApp->nativeInterface<QNativeInterface::QX11Application>();
117 if (x11AppInfo) {
118 displayID = x11AppInfo->display();
119 }
120 else {
121 QNativeInterface::QWaylandApplication* wayAppInfo =
122 qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
123 if (wayAppInfo) {
124 displayID = wayAppInfo->display();
125 }
126 else {
127 exit(-1);
128 }
129 }
130#endif
131 return displayID;
132 }
133
134 QPaintEngine* paintEngine() const override { return nullptr; }
135
136protected:
137 void* windowPtr() { return reinterpret_cast<void*>(this); }
138
139#ifdef Q_OS_MACOS
140 // TODO: eventually choose if checking for pixel ratio every update
141
142 // current pixel ratio
143 // values > 0 are used to detect changes in pixel ratio
144 double mCurrentPixelRatio = -1.0;
145#endif
146
147 bool event(QEvent* event) override
148 {
149#ifdef Q_OS_MACOS
150 if (event->type() == QEvent::DevicePixelRatioChange) {
151 // save current ratio
152 mCurrentPixelRatio = pixelRatio();
153 // send update event
154 this->update();
155 }
156
157 if (event->type() == QEvent::UpdateRequest) {
158 if (mCurrentPixelRatio > 0 && mCurrentPixelRatio != pixelRatio()) {
159 const double ratio = pixelRatio();
160
161 // reset current ratio
162 mCurrentPixelRatio = -1.0;
163
164 // send resize event
165 QResizeEvent resizeEvent(size(), size());
166 auto app = qobject_cast<QGuiApplication*>(
167 QCoreApplication::instance());
168 app->sendEvent(this, &resizeEvent);
169 }
170 }
171#endif
172 // if widgets' window is blocked or deactivated, reset mofiifers
173 if (event->type() == QEvent::WindowBlocked ||
174 event->type() == QEvent::WindowDeactivate) {
175 DerivedRenderApp::WM::setModifiers(
176 derived(), {KeyModifier::NO_MODIFIER});
177 }
178
179 return Base::event(event);
180 }
181
182#if defined(VCLIB_RENDER_BACKEND_BGFX)
183 void resizeEvent(QResizeEvent* event) override
184 {
185 Base::resizeEvent(event);
186 DerivedRenderApp::WM::resize(
187 derived(), width() * pixelRatio(), height() * pixelRatio());
188 }
189#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
190 void resizeGL(int w, int h) override
191 {
192 Base::resizeGL(w, h);
193 DerivedRenderApp::WM::resize(
194 derived(), w * pixelRatio(), h * pixelRatio());
195 }
196#endif
197
198#if defined(VCLIB_RENDER_BACKEND_BGFX)
199 void showEvent(QShowEvent* event) override
200 {
201 Base::showEvent(event);
202 DerivedRenderApp::WM::init(derived());
203 }
204#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
205 void initializeGL() override { DerivedRenderApp::WM::init(derived()); }
206#endif
207
208 void keyPressEvent(QKeyEvent* event) override
209 {
210 DerivedRenderApp::WM::setModifiers(
211 derived(), vcl::qt::fromQt(event->modifiers()));
212
213 DerivedRenderApp::WM::keyPress(
214 derived(),
215 vcl::qt::fromQt((Qt::Key) event->key(), event->modifiers()));
216 Base::keyPressEvent(event);
217 update();
218 }
219
220 void keyReleaseEvent(QKeyEvent* event) override
221 {
222 DerivedRenderApp::WM::setModifiers(
223 derived(), vcl::qt::fromQt(event->modifiers()));
224
225 DerivedRenderApp::WM::keyRelease(
226 derived(),
227 vcl::qt::fromQt((Qt::Key) event->key(), event->modifiers()));
228 Base::keyReleaseEvent(event);
229 update();
230 }
231
232 void mouseMoveEvent(QMouseEvent* event) override
233 {
234 DerivedRenderApp::WM::mouseMove(
235 derived(),
236 event->pos().x() * pixelRatio(),
237 event->pos().y() * pixelRatio());
238 Base::mouseMoveEvent(event);
239 update();
240 }
241
242 void mousePressEvent(QMouseEvent* event) override
243 {
244 DerivedRenderApp::WM::mousePress(
245 derived(),
246 vcl::qt::fromQt(event->button()),
247 event->pos().x() * pixelRatio(),
248 event->pos().y() * pixelRatio());
249 Base::mousePressEvent(event);
250 update();
251 }
252
253 void mouseReleaseEvent(QMouseEvent* event) override
254 {
255 DerivedRenderApp::WM::mouseRelease(
256 derived(),
257 vcl::qt::fromQt(event->button()),
258 event->pos().x() * pixelRatio(),
259 event->pos().y() * pixelRatio());
260 Base::mouseReleaseEvent(event);
261 update();
262 }
263
264 void mouseDoubleClickEvent(QMouseEvent* event) override
265 {
266 DerivedRenderApp::WM::mouseDoubleClick(
267 derived(),
268 vcl::qt::fromQt(event->button()),
269 event->pos().x() * pixelRatio(),
270 event->pos().y() * pixelRatio());
271 Base::mouseDoubleClickEvent(event);
272 update();
273 }
274
275 void wheelEvent(QWheelEvent* event) override
276 {
277 // FIXME: this is not correct, define a proper equivalence
278 if (!event->pixelDelta().isNull())
279 DerivedRenderApp::WM::mouseScroll(
280 derived(), event->pixelDelta().x(), event->pixelDelta().y());
281 else
282 DerivedRenderApp::WM::mouseScroll(
283 derived(), event->angleDelta().x(), event->angleDelta().y());
284
285 Base::wheelEvent(event);
286 update();
287 }
288
289 double pixelRatio() const
290 {
291 auto* screen = this->screen();
292 return double(screen ? screen->devicePixelRatio() : 1.0);
293 }
294
295private:
296#if defined(VCLIB_RENDER_BACKEND_BGFX)
297 void paintEvent(QPaintEvent* event) override
298 {
299 DerivedRenderApp::WM::paint(derived());
300 QWidget::paintEvent(event);
301 }
302#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
303 void paintGL() override { DerivedRenderApp::WM::paint(derived()); }
304#endif
305
306 auto* derived() { return static_cast<DerivedRenderApp*>(this); }
307
308 const auto* derived() const
309 {
310 return static_cast<const DerivedRenderApp*>(this);
311 }
312};
313
314} // namespace vcl::qt
315
316#endif // VCL_QT_WIDGET_MANAGER_H
A class representing a box in N-dimensional space.
Definition box.h:46
Definition widget_manager.h:50
static const uint WINDOW_MANAGER_ID
The WINDOW_MANAGER_ID is the ID of the window manager. It is used to identify the window manager impl...
Definition widget_manager.h:70
QWidget ParentType
The ParentType is the type of the parent class. It is used to initialize the base class (if any)....
Definition widget_manager.h:63
Definition render_app.h:31
Point2< float > Point2f
A convenience alias for a 2-dimensional Point with floating-point components.
Definition point.h:718