Visual Computing Library
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 }
84
85 explicit WidgetManager(
86 const std::string& windowTitle,
87 uint width = 1024,
88 uint height = 768,
89 QWidget* parent = nullptr) : WidgetManager(parent)
90 {
91 setGeometry(100, 100, width, height);
92 setWindowTitle(windowTitle.c_str());
93 }
94
95 ~WidgetManager() = default;
96
97 const std::string& windowTitle() const
98 {
99 return QWidget::windowTitle().toStdString();
100 }
101
102 void setWindowTitle(const std::string& title)
103 {
104 QWidget::setWindowTitle(title.c_str());
105 }
106
107 Point2f dpiScale() const { return Point2f(pixelRatio(), pixelRatio()); }
108
109 void* displayId() const
110 {
111 void* displayID = nullptr;
112#ifdef Q_OS_LINUX
114 QNativeInterface::QX11Application* x11AppInfo =
115 qApp->nativeInterface<QNativeInterface::QX11Application>();
116 if (x11AppInfo) {
117 displayID = x11AppInfo->display();
118 }
119 else {
120 QNativeInterface::QWaylandApplication* wayAppInfo =
121 qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
122 if (wayAppInfo) {
123 displayID = wayAppInfo->display();
124 }
125 else {
126 exit(-1);
127 }
128 }
129#endif
130 return displayID;
131 }
132
133 QPaintEngine* paintEngine() const override { return nullptr; }
134
135protected:
136 void* windowPtr() { return reinterpret_cast<void*>(this); }
137
138#ifdef Q_OS_MACOS
139 // TODO: eventually choose if checking for pixel ratio every update
140
141 // current pixel ratio
142 // values > 0 are used to detect changes in pixel ratio
143 double mCurrentPixelRatio = -1.0;
144
145 bool event(QEvent* event) override
146 {
147 if (event->type() == QEvent::DevicePixelRatioChange) {
148 // save current ratio
149 mCurrentPixelRatio = pixelRatio();
150 // send update event
151 this->update();
152 }
153
154 if (event->type() == QEvent::UpdateRequest) {
155 if (mCurrentPixelRatio > 0 && mCurrentPixelRatio != pixelRatio()) {
156 const double ratio = pixelRatio();
157
158 // reset current ratio
159 mCurrentPixelRatio = -1.0;
160
161 // send resize event
162 QResizeEvent resizeEvent(size(), size());
163 auto app = qobject_cast<QGuiApplication*>(
164 QCoreApplication::instance());
165 app->sendEvent(this, &resizeEvent);
166 }
167 }
168
169 return QWidget::event(event);
170 }
171#endif
172
173#if defined(VCLIB_RENDER_BACKEND_BGFX)
174 void resizeEvent(QResizeEvent* event) override
175 {
176 Base::resizeEvent(event);
177 DerivedRenderApp::WM::resize(
178 derived(), width() * pixelRatio(), height() * pixelRatio());
179 }
180#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
181 void resizeGL(int w, int h) override
182 {
183 Base::resizeGL(w, h);
184 DerivedRenderApp::WM::resize(
185 derived(), w * pixelRatio(), h * pixelRatio());
186 }
187#endif
188
189#if defined(VCLIB_RENDER_BACKEND_BGFX)
190 void showEvent(QShowEvent* event) override
191 {
192 Base::showEvent(event);
193 DerivedRenderApp::WM::init(derived());
194 }
195#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
196 void initializeGL() override { DerivedRenderApp::WM::init(derived()); }
197#endif
198
199 void keyPressEvent(QKeyEvent* event) override
200 {
201 DerivedRenderApp::WM::setModifiers(
202 derived(), vcl::qt::fromQt(event->modifiers()));
203
204 DerivedRenderApp::WM::keyPress(
205 derived(),
206 vcl::qt::fromQt((Qt::Key) event->key(), event->modifiers()));
207 Base::keyPressEvent(event);
208 update();
209 }
210
211 void keyReleaseEvent(QKeyEvent* event) override
212 {
213 DerivedRenderApp::WM::setModifiers(
214 derived(), vcl::qt::fromQt(event->modifiers()));
215
216 DerivedRenderApp::WM::keyRelease(
217 derived(),
218 vcl::qt::fromQt((Qt::Key) event->key(), event->modifiers()));
219 Base::keyReleaseEvent(event);
220 update();
221 }
222
223 void mouseMoveEvent(QMouseEvent* event) override
224 {
225 DerivedRenderApp::WM::mouseMove(
226 derived(),
227 event->pos().x() * pixelRatio(),
228 event->pos().y() * pixelRatio());
229 Base::mouseMoveEvent(event);
230 update();
231 }
232
233 void mousePressEvent(QMouseEvent* event) override
234 {
235 DerivedRenderApp::WM::mousePress(
236 derived(),
237 vcl::qt::fromQt(event->button()),
238 event->pos().x() * pixelRatio(),
239 event->pos().y() * pixelRatio());
240 Base::mousePressEvent(event);
241 update();
242 }
243
244 void mouseReleaseEvent(QMouseEvent* event) override
245 {
246 DerivedRenderApp::WM::mouseRelease(
247 derived(),
248 vcl::qt::fromQt(event->button()),
249 event->pos().x() * pixelRatio(),
250 event->pos().y() * pixelRatio());
251 Base::mouseReleaseEvent(event);
252 update();
253 }
254
255 void mouseDoubleClickEvent(QMouseEvent* event) override
256 {
257 DerivedRenderApp::WM::mouseDoubleClick(
258 derived(),
259 vcl::qt::fromQt(event->button()),
260 event->pos().x() * pixelRatio(),
261 event->pos().y() * pixelRatio());
262 Base::mouseDoubleClickEvent(event);
263 update();
264 }
265
266 void wheelEvent(QWheelEvent* event) override
267 {
268 // FIXME: this is not correct, define a proper equivalence
269 if (!event->pixelDelta().isNull())
270 DerivedRenderApp::WM::mouseScroll(
271 derived(), event->pixelDelta().x(), event->pixelDelta().y());
272 else
273 DerivedRenderApp::WM::mouseScroll(
274 derived(), event->angleDelta().x(), event->angleDelta().y());
275
276 Base::wheelEvent(event);
277 update();
278 }
279
280 double pixelRatio() const
281 {
282 auto* screen = this->screen();
283 return double(screen ? screen->devicePixelRatio() : 1.0);
284 }
285
286private:
287#if defined(VCLIB_RENDER_BACKEND_BGFX)
288 void paintEvent(QPaintEvent* event) override
289 {
290 DerivedRenderApp::WM::paint(derived());
291 QWidget::paintEvent(event);
292 }
293#elif defined(VCLIB_RENDER_BACKEND_OPENGL2)
294 void paintGL() override { DerivedRenderApp::WM::paint(derived()); }
295#endif
296
297 auto* derived() { return static_cast<DerivedRenderApp*>(this); }
298
299 const auto* derived() const
300 {
301 return static_cast<const DerivedRenderApp*>(this);
302 }
303};
304
305} // namespace vcl::qt
306
307#endif // VCL_QT_WIDGET_MANAGER_H
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
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:743