Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
Qt6Widget.hpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #ifndef Qt6Window_INCLUDE_ONCE
33 #define Qt6Window_INCLUDE_ONCE
34 
35 #include <vlQt6/link_config.hpp>
38 #include <QApplication>
39 #include <QMouseEvent>
40 #include <QWidget>
41 #include <QUrl>
42 #include <QTimer>
43 #include <QObject>
44 #include <QMimeData>
45 #include <QOpenGLWidget>
46 #include <QOpenGLContext>
47 //#include <QGLFormat>
48 
49 namespace vlQt6
50 {
51  //-----------------------------------------------------------------------------
52  // Qt6Widget
53  //-----------------------------------------------------------------------------
55  class VLQT6_EXPORT Qt6Widget : public QOpenGLWidget, public vl::OpenGLContext
56  {
57  Q_OBJECT
58 
59  public:
60  using QObject::setObjectName;
62 
64  QWidget *parent = NULL,
65  Qt::WindowFlags f = Qt::WindowFlags()
66  ):
67  QOpenGLWidget(parent, f),
68  mRefresh(10) // 100 fps
69  {
70  setContinuousUpdate(true);
71  setMouseTracking(true);
72  //setAutoBufferSwap(false); MIC FIXME?
73  setAcceptDrops(true);
74  // let Qt take care of object destruction.
76  }
77 
79  {
80  dispatchDestroyEvent();
81  }
82 
83  void dragEnterEvent(QDragEnterEvent *ev)
84  {
85  if (ev->mimeData()->hasUrls())
86  ev->acceptProposedAction();
87  }
88 
89  void dropEvent(QDropEvent *ev)
90  {
91  if (ev->mimeData()->hasUrls())
92  {
93  std::vector<vl::String> files;
94  QList<QUrl> list = ev->mimeData()->urls();
95  for (int i = 0; i < list.size(); ++i)
96  {
97  if (list[i].path().isEmpty())
98  continue;
99 #ifdef WIN32
100  if (list[i].path()[0] == '/')
101  files.push_back(list[i].path().toStdString().c_str() + 1);
102  else
103  files.push_back(list[i].path().toStdString().c_str());
104 #else
105  files.push_back(list[i].path().toStdString().c_str());
106 #endif
107  }
108  dispatchFileDroppedEvent(files);
109  }
110  }
111 
112  bool initQt6Widget(const vl::String &title, const vl::OpenGLContextFormat &info, int x = 0, int y = 0, int width = 640, int height = 480)
113  {
114  QSurfaceFormat fmt = format();
115 
116  switch (info.openGLProfile())
117  {
119  fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
120  if (info.majVersion())
121  {
122  fmt.setVersion(info.majVersion(), info.minVersion());
123  }
124  break;
125  case vl::GLP_Core:
126  fmt.setProfile(QSurfaceFormat::CoreProfile);
127  if (info.majVersion())
128  {
129  fmt.setVersion(info.majVersion(), info.minVersion());
130  }
131  break;
132  case vl::GLP_Default:
133  // Don't care
134  break;
135  }
136 
137  // double buffer
138  fmt.setSwapBehavior( info.doubleBuffer() ? QSurfaceFormat::DoubleBuffer : QSurfaceFormat::SingleBuffer );
139  //fmt.setDoubleBuffer();
140 
141  // color buffer
142  fmt.setRedBufferSize(info.rgbaBits().r());
143  fmt.setGreenBufferSize(info.rgbaBits().g());
144  fmt.setBlueBufferSize(info.rgbaBits().b());
145  // setAlpha == true makes the create() function alway fail
146  // even if the returned format has the requested alpha channel
147  fmt.setAlphaBufferSize(info.rgbaBits().a());
148 
149  // accumulation buffer - not supported in Qt 6?
150  /*
151  int accum = vl::max(info.accumRGBABits().r(), info.accumRGBABits().g());
152  accum = vl::max(accum, info.accumRGBABits().b());
153  accum = vl::max(accum, info.accumRGBABits().a());
154  fmt.setAccumBufferSize(accum);
155  fmt.setAccum(accum != 0);
156  */
157 
158  // multisampling
159  if ( info.multisample() )
160  {
161  fmt.setSamples( info.multisampleSamples() );
162  }
163 
164  // depth buffer
165  fmt.setDepthBufferSize(info.depthBufferBits());
166 
167  // stencil buffer
168  fmt.setStencilBufferSize(info.stencilBufferBits());
169 
170  // stereo
171  fmt.setStereo(info.stereo());
172 
173  // swap interval / v-sync
174  fmt.setSwapInterval( info.vSync() ? 1 : 0 );
175 
176  this->QOpenGLWidget::setFormat( fmt ); // must be called before the widget or its parent window gets shown
177 
178  framebuffer()->setWidth(width);
179  framebuffer()->setHeight(height);
180 
181 #ifndef NDEBUG
182  printf("--------------------------------------------\n");
183  printf("REQUESTED OpenGL Format:\n");
184  printf("--------------------------------------------\n");
185  printf("rgba = %d %d %d %d\n", fmt.redBufferSize(), fmt.greenBufferSize(), fmt.blueBufferSize(), fmt.alphaBufferSize());
186  printf("double buffer = %d\n", (int)fmt.swapBehavior() == QSurfaceFormat::DoubleBuffer );
187  printf("depth buffer size = %d\n", fmt.depthBufferSize());
188  printf("depth buffer = %d\n", fmt.depthBufferSize());
189  printf("stencil buffer size = %d\n", fmt.stencilBufferSize());
190  printf("stencil buffer = %d\n", fmt.stencilBufferSize());
191  printf("accum buffer size %d\n", 0);
192  printf("accum buffer %d\n", 0);
193  printf("stereo = %d\n", (int)fmt.stereo());
194  printf("swap interval = %d\n", fmt.swapInterval());
195  printf("multisample = %d\n", (int)fmt.samples() != 0);
196  printf("multisample samples = %d\n", (int)fmt.samples());
197 
198  fmt = format();
199 
200  printf("--------------------------------------------\n");
201  printf("OBTAINED OpenGL Format:\n");
202  printf("--------------------------------------------\n");
203  printf("rgba = %d %d %d %d\n", fmt.redBufferSize(), fmt.greenBufferSize(), fmt.blueBufferSize(), fmt.alphaBufferSize());
204  printf("double buffer = %d\n", (int)fmt.swapBehavior() == QSurfaceFormat::DoubleBuffer );
205  printf("depth buffer size = %d\n", fmt.depthBufferSize());
206  printf("depth buffer = %d\n", fmt.depthBufferSize());
207  printf("stencil buffer size = %d\n", fmt.stencilBufferSize());
208  printf("stencil buffer = %d\n", fmt.stencilBufferSize());
209  printf("accum buffer size %d\n", 0);
210  printf("accum buffer %d\n", 0);
211  printf("stereo = %d\n", (int)fmt.stereo());
212  printf("swap interval = %d\n", fmt.swapInterval());
213  printf("multisample = %d\n", (int)fmt.samples() != 0);
214  printf("multisample samples = %d\n", (int)fmt.samples());
215  printf("--------------------------------------------\n");
216 #endif
217 
218  setWindowTitle(title);
219  move(x, y);
220  resize(width, height);
221 
222  if (info.fullscreen())
223  setFullscreen(true);
224 
225  return true;
226  }
227 
228  virtual void setContinuousUpdate(bool continuous)
229  {
230  mContinuousUpdate = continuous;
231  if (continuous)
232  {
233  disconnect(&mUpdateTimer, SIGNAL(timeout()), this, SLOT(update()));
234  connect(&mUpdateTimer, SIGNAL(timeout()), this, SLOT(update()));
235  mUpdateTimer.setSingleShot(false);
236  mUpdateTimer.setInterval(mRefresh);
237  mUpdateTimer.start(0);
238  }
239  else
240  {
241  disconnect(&mUpdateTimer, SIGNAL(timeout()), this, SLOT(update()));
242  mUpdateTimer.stop();
243  }
244  }
245 
246  void setRefreshRate(int msec)
247  {
248  mRefresh = msec;
249  mUpdateTimer.setInterval(mRefresh);
250  }
251 
253  {
254  return mRefresh;
255  }
256 
258  {
259  // OpenGL extensions initialization
260  initGLContext();
261 
262  // Important! Qt 6 instead of using the default framebuffer 0 uses its own framebuffer for offscreen rendering which also changes at every resize.
263  // We set to FBO to externally managed so VL does not override the FBO settings prepared by Qt upon pain event.
265 
266  dispatchInitEvent();
267  }
268 
269  void resizeGL(int width, int height)
270  {
271  dispatchResizeEvent(width, height);
272  }
273 
274  void paintGL()
275  {
276  dispatchUpdateEvent();
277  }
278 
279  void update()
280  {
281  QOpenGLWidget::update();
282  }
283 
284  virtual void setWindowTitle(const vl::String &title)
285  {
286  QOpenGLWidget::setWindowTitle(QString::fromStdString(title.toStdString()));
287  }
288 
289  virtual bool setFullscreen(bool fullscreen)
290  {
291  mFullscreen = fullscreen;
292  if (fullscreen)
293  QOpenGLWidget::setWindowState(QOpenGLWidget::windowState() | Qt::WindowFullScreen);
294  else
295  QOpenGLWidget::setWindowState(QOpenGLWidget::windowState() & (~Qt::WindowFullScreen));
296  return true;
297  }
298 
299  virtual void quitApplication()
300  {
301  eraseAllEventListeners();
302  QApplication::quit();
303  }
304 
305  virtual void show()
306  {
307  QOpenGLWidget::show();
308  }
309 
310  virtual void hide()
311  {
312  QOpenGLWidget::hide();
313  }
314 
315  virtual void setPosition(int x, int y)
316  {
317  QOpenGLWidget::move(x, y);
318  }
319 
320  virtual vl::ivec2 position() const
321  {
322  return vl::ivec2(QOpenGLWidget::pos().x(), QOpenGLWidget::pos().y());
323  }
324 
325  virtual void setSize(int w, int h)
326  {
327  // this already excludes the window's frame so it's ok for Visualization Library standards
328  QOpenGLWidget::resize(w, h);
329  }
330 
331  virtual vl::ivec2 size() const
332  {
333  // this already excludes the window's frame so it's ok for Visualization Library standards
334  return vl::ivec2(QOpenGLWidget::size().width(), QOpenGLWidget::size().height());
335  }
336 
337  void swapBuffers()
338  {
339  // Not supported anymore in Qt 6. Docs say to use update() instead.
340  // QOpenGLWidget::swapBuffers();
341  }
342 
343  void makeCurrent()
344  {
345  QOpenGLWidget::makeCurrent();
346  }
347 
348  void setMousePosition(int x, int y)
349  {
350  QCursor::setPos(mapToGlobal(QPoint(x, y)));
351  }
352 
353  void mouseMoveEvent(QMouseEvent *ev)
354  {
355  if (!mIgnoreNextMouseMoveEvent)
356  dispatchMouseMoveEvent(ev->position().x(), ev->position().y());
357  mIgnoreNextMouseMoveEvent = false;
358  }
359 
360  void mousePressEvent(QMouseEvent *ev)
361  {
363  switch (ev->button())
364  {
365  case Qt::LeftButton:
366  bt = vl::LeftButton;
367  break;
368  case Qt::RightButton:
369  bt = vl::RightButton;
370  break;
371  case Qt::MiddleButton:
372  bt = vl::MiddleButton;
373  break;
374  default:
375  bt = vl::UnknownButton;
376  break;
377  }
378  dispatchMouseDownEvent(bt, ev->position().x(), ev->position().y());
379  }
380 
381  void mouseReleaseEvent(QMouseEvent *ev)
382  {
384  switch (ev->button())
385  {
386  case Qt::LeftButton:
387  bt = vl::LeftButton;
388  break;
389  case Qt::RightButton:
390  bt = vl::RightButton;
391  break;
392  case Qt::MiddleButton:
393  bt = vl::MiddleButton;
394  break;
395  default:
396  bt = vl::UnknownButton;
397  break;
398  }
399  dispatchMouseUpEvent(bt, ev->position().x(), ev->position().y());
400  }
401 
402  void wheelEvent(QWheelEvent *ev)
403  {
404  dispatchMouseWheelEvent(ev->angleDelta().y() / 120);
405  }
406 
407  void keyPressEvent(QKeyEvent *ev)
408  {
409  unsigned short unicode_ch = 0;
410  vl::EKey key = vl::Key_None;
411  translateKeyEvent(ev, unicode_ch, key);
412  dispatchKeyPressEvent(unicode_ch, key);
413  }
414 
415  void keyReleaseEvent(QKeyEvent *ev)
416  {
417  unsigned short unicode_ch = 0;
418  vl::EKey key = vl::Key_None;
419  translateKeyEvent(ev, unicode_ch, key);
420  dispatchKeyReleaseEvent(unicode_ch, key);
421  }
422 
423  virtual void setMouseVisible(bool visible)
424  {
425  mMouseVisible = visible;
426  if (visible)
427  QOpenGLWidget::setCursor(Qt::ArrowCursor);
428  else
429  QOpenGLWidget::setCursor(Qt::BlankCursor);
430  }
431 
432  virtual void getFocus()
433  {
434  QOpenGLWidget::setFocus(Qt::OtherFocusReason);
435  }
436 
437  protected:
438  void translateKeyEvent(QKeyEvent *ev, unsigned short &unicode_out, vl::EKey &key_out);
439 
440  protected:
441  int mRefresh;
442  QTimer mUpdateTimer;
443  };
444  //-----------------------------------------------------------------------------
445 } // namespace vlQt6
446 
447 #endif
Vector2< int > ivec2
A 2 components vector with int precision.
Definition: Vector2.hpp:279
void keyReleaseEvent(QKeyEvent *ev)
Definition: Qt6Widget.hpp:415
virtual void getFocus()
If the OpenGL context is a widget this function requests the mouse focus on it.
Definition: Qt6Widget.hpp:432
void keyPressEvent(QKeyEvent *ev)
Definition: Qt6Widget.hpp:407
void setAutomaticDelete(bool autodel_on)
If set to true the Object is deleted when its reference count reaches 0.
Definition: Object.hpp:275
void setObjectName(const char *name)
The name of the object, by default set to the object&#39;s class name in debug builds.
Definition: Object.hpp:220
virtual void hide()
If the OpenGL context is a widget this function makes it invisible to the user.
Definition: Qt6Widget.hpp:310
void setExternallyManaged(bool em)
Wen externallyManaged() == true then this function does nothing.
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
int multisampleSamples() const
const T_Scalar & r() const
Definition: Vector4.hpp:112
virtual vl::ivec2 size() const
Definition: Qt6Widget.hpp:331
virtual void setMouseVisible(bool visible)
If the OpenGL context is a widget this function sets whether the mouse is visible over it or not...
Definition: Qt6Widget.hpp:423
Represents an OpenGL context, possibly a widget or a pbuffer, which can also respond to keyboard...
bool initQt6Widget(const vl::String &title, const vl::OpenGLContextFormat &info, int x=0, int y=0, int width=640, int height=480)
Definition: Qt6Widget.hpp:112
void setMousePosition(int x, int y)
If the OpenGL context is a widget this function sets the mouse position.
Definition: Qt6Widget.hpp:348
FramebufferObject * framebuffer()
The default render target (always returns leftFramebuffer()).
void wheelEvent(QWheelEvent *ev)
Definition: Qt6Widget.hpp:402
void dropEvent(QDropEvent *ev)
Definition: Qt6Widget.hpp:89
void resizeGL(int width, int height)
Definition: Qt6Widget.hpp:269
void dragEnterEvent(QDragEnterEvent *ev)
Definition: Qt6Widget.hpp:83
virtual void setPosition(int x, int y)
If the OpenGL context is a widget this function sets its position.
Definition: Qt6Widget.hpp:315
virtual void quitApplication()
Asks to the windowing system that is managing the OpenGLContext to quit the application.
Definition: Qt6Widget.hpp:299
const T_Scalar & g() const
Definition: Vector4.hpp:113
The OpenGLContextFormat class encapsulates the settings of an OpenGL rendering context.
virtual bool setFullscreen(bool fullscreen)
If the OpenGL context is a widget this function requests a maximization to fullscreen.
Definition: Qt6Widget.hpp:289
const ivec4 & rgbaBits() const
virtual vl::ivec2 position() const
If the OpenGL context is a widget this function returns its position.
Definition: Qt6Widget.hpp:320
Qt6Widget(QWidget *parent=NULL, Qt::WindowFlags f=Qt::WindowFlags())
Definition: Qt6Widget.hpp:63
EMouseButton
const T_Scalar & b() const
Definition: Vector4.hpp:114
#define NULL
Definition: OpenGLDefs.hpp:81
void mouseMoveEvent(QMouseEvent *ev)
Definition: Qt6Widget.hpp:353
virtual void setSize(int w, int h)
If the OpenGL context is a widget this function sets its size.
Definition: Qt6Widget.hpp:325
void setRefreshRate(int msec)
Definition: Qt6Widget.hpp:246
EOpenGLProfile openGLProfile() const
VLEGL_EXPORT void translateKeyEvent(WPARAM wParam, LPARAM lParam, unsigned short &unicode_out, vl::EKey &key_out)
Definition: EGLWindow.cpp:584
void swapBuffers()
Swaps the back and front buffers to present the last rendering.
Definition: Qt6Widget.hpp:337
void update()
If the OpenGLContext is a widget this function requests a redraw and generates an updateEvent()...
Definition: Qt6Widget.hpp:279
virtual void setContinuousUpdate(bool continuous)
If the OpenGL context is a widget this function sets whether its area is continuously updated at each...
Definition: Qt6Widget.hpp:228
virtual void show()
If the OpenGL context is a widget this function makes it visible to the user.
Definition: Qt6Widget.hpp:305
std::string toStdString() const
Returns a UTF8 encoded std::string.
Definition: String.cpp:1156
void mouseReleaseEvent(QMouseEvent *ev)
Definition: Qt6Widget.hpp:381
virtual void setWindowTitle(const vl::String &title)
If the OpenGL context is a top window this function sets its title.
Definition: Qt6Widget.hpp:284
void makeCurrent()
Sets the OpenGL context as current for the calling thread.
Definition: Qt6Widget.hpp:343
const T_Scalar & a() const
Definition: Vector4.hpp:115
The Qt6Widget class implements an OpenGLContext using the Qt6 API.
Definition: Qt6Widget.hpp:55
void mousePressEvent(QMouseEvent *ev)
Definition: Qt6Widget.hpp:360