| @@ -295,6 +295,11 @@ public: | |||
| */ | |||
| NanoVG(int flags = CREATE_ANTIALIAS); | |||
| /** | |||
| Constructor reusing a NanoVG context, used for subwidgets. | |||
| */ | |||
| NanoVG(NanoWidget* groupWidget); | |||
| /** | |||
| Destructor. | |||
| */ | |||
| @@ -838,6 +843,7 @@ public: | |||
| private: | |||
| NVGcontext* const fContext; | |||
| bool fInFrame; | |||
| bool fIsSubWidget; | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoVG) | |||
| }; | |||
| @@ -860,7 +866,7 @@ public: | |||
| Constructor. | |||
| @see CreateFlags | |||
| */ | |||
| NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS) | |||
| explicit NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS) | |||
| : Widget(parent), | |||
| NanoVG(flags), | |||
| leakDetector_NanoWidget() | |||
| @@ -868,6 +874,31 @@ public: | |||
| setNeedsScaling(true); | |||
| } | |||
| /** | |||
| Constructor for a subwidget. | |||
| */ | |||
| explicit NanoWidget(Widget* groupWidget, int flags = CREATE_ANTIALIAS) | |||
| : Widget(groupWidget, true), | |||
| NanoVG(flags), | |||
| leakDetector_NanoWidget() | |||
| { | |||
| setNeedsScaling(true); | |||
| } | |||
| /** | |||
| Constructor for a subwidget. | |||
| */ | |||
| explicit NanoWidget(NanoWidget* groupWidget) | |||
| : Widget(groupWidget, false), | |||
| NanoVG(groupWidget), | |||
| leakDetector_NanoWidget() | |||
| { | |||
| setNeedsScaling(true); | |||
| groupWidget->fNanoSubWidgets.push_back(this); | |||
| } | |||
| // fNanoSubWidgets.clear(); | |||
| protected: | |||
| /** | |||
| New virtual onDisplay function. | |||
| @@ -876,6 +907,8 @@ protected: | |||
| virtual void onNanoDisplay() = 0; | |||
| private: | |||
| std::vector<NanoWidget*> fNanoSubWidgets; | |||
| /** | |||
| Widget display function. | |||
| Implemented internally to wrap begin/endFrame() automatically. | |||
| @@ -884,6 +917,13 @@ private: | |||
| { | |||
| beginFrame(getWidth(), getHeight()); | |||
| onNanoDisplay(); | |||
| for (std::vector<NanoWidget*>::iterator it = fNanoSubWidgets.begin(); it != fNanoSubWidgets.end(); ++it) | |||
| { | |||
| NanoWidget* const widget(*it); | |||
| widget->onNanoDisplay(); | |||
| } | |||
| endFrame(); | |||
| } | |||
| @@ -19,12 +19,15 @@ | |||
| #include "Geometry.hpp" | |||
| #include <vector> | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // Forward class names | |||
| class App; | |||
| class NanoWidget; | |||
| class Window; | |||
| class StandaloneWindow; | |||
| @@ -172,6 +175,11 @@ public: | |||
| */ | |||
| explicit Widget(Window& parent); | |||
| /** | |||
| Constructor for a subwidget. | |||
| */ | |||
| explicit Widget(Widget* groupWidget); | |||
| /** | |||
| Destructor. | |||
| */ | |||
| @@ -369,11 +377,20 @@ private: | |||
| Window& fParent; | |||
| bool fNeedsFullViewport; | |||
| bool fNeedsScaling; | |||
| bool fSkipDisplay; | |||
| bool fVisible; | |||
| uint fId; | |||
| Point<int> fAbsolutePos; | |||
| Size<uint> fSize; | |||
| std::vector<Widget*> fSubWidgets; | |||
| /** @internal */ | |||
| explicit Widget(Widget* groupWidget, bool addToSubWidgets); | |||
| /** @internal */ | |||
| void _displaySubWidgets(); | |||
| friend class NanoWidget; | |||
| friend class Window; | |||
| friend class StandaloneWindow; | |||
| @@ -43,8 +43,9 @@ | |||
| // ----------------------------------------------------------------------- | |||
| // Include NanoVG OpenGL implementation | |||
| //#define STB_IMAGE_STATIC 1 | |||
| #define NANOVG_GL2_IMPLEMENTATION 1 | |||
| //#define STB_IMAGE_STATIC | |||
| #define BLENDISH_IMPLEMENTATION | |||
| #define NANOVG_GL2_IMPLEMENTATION | |||
| #include "nanovg/nanovg_gl.h" | |||
| #include "oui-blendish/blendish.h" | |||
| @@ -188,16 +189,25 @@ void NanoImage::_updateSize() | |||
| NanoVG::NanoVG(int flags) | |||
| : fContext(nvgCreateGL(flags)), | |||
| fInFrame(false), | |||
| fIsSubWidget(false), | |||
| leakDetector_NanoVG() | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,); | |||
| } | |||
| NanoVG::NanoVG(NanoWidget* groupWidget) | |||
| : fContext(groupWidget->fContext), | |||
| fInFrame(false), | |||
| fIsSubWidget(true), | |||
| leakDetector_NanoVG() | |||
| { | |||
| } | |||
| NanoVG::~NanoVG() | |||
| { | |||
| DISTRHO_SAFE_ASSERT(! fInFrame); | |||
| if (fContext != nullptr) | |||
| if (fContext != nullptr && ! fIsSubWidget) | |||
| nvgDeleteGL(fContext); | |||
| } | |||
| @@ -26,6 +26,7 @@ Widget::Widget(Window& parent) | |||
| : fParent(parent), | |||
| fNeedsFullViewport(false), | |||
| fNeedsScaling(false), | |||
| fSkipDisplay(false), | |||
| fVisible(true), | |||
| fId(0), | |||
| fAbsolutePos(0, 0), | |||
| @@ -35,9 +36,42 @@ Widget::Widget(Window& parent) | |||
| fParent._addWidget(this); | |||
| } | |||
| Widget::Widget(Widget* groupWidget) | |||
| : fParent(groupWidget->getParentWindow()), | |||
| fNeedsFullViewport(false), | |||
| fNeedsScaling(false), | |||
| fSkipDisplay(true), | |||
| fVisible(true), | |||
| fId(0), | |||
| fAbsolutePos(0, 0), | |||
| fSize(0, 0), | |||
| leakDetector_Widget() | |||
| { | |||
| fParent._addWidget(this); | |||
| groupWidget->fSubWidgets.push_back(this); | |||
| } | |||
| Widget::Widget(Widget* groupWidget, bool addToSubWidgets) | |||
| : fParent(groupWidget->getParentWindow()), | |||
| fNeedsFullViewport(false), | |||
| fNeedsScaling(false), | |||
| fSkipDisplay(true), | |||
| fVisible(true), | |||
| fId(0), | |||
| fAbsolutePos(0, 0), | |||
| fSize(0, 0), | |||
| leakDetector_Widget() | |||
| { | |||
| fParent._addWidget(this); | |||
| if (addToSubWidgets) | |||
| groupWidget->fSubWidgets.push_back(this); | |||
| } | |||
| Widget::~Widget() | |||
| { | |||
| fParent._removeWidget(this); | |||
| fSubWidgets.clear(); | |||
| } | |||
| bool Widget::isVisible() const noexcept | |||
| @@ -250,6 +284,44 @@ void Widget::setNeedsScaling(bool yesNo) noexcept | |||
| fNeedsScaling = yesNo; | |||
| } | |||
| void Widget::_displaySubWidgets() | |||
| { | |||
| for (std::vector<Widget*>::iterator it = fSubWidgets.begin(); it != fSubWidgets.end(); ++it) | |||
| { | |||
| Widget* const widget(*it); | |||
| if (widget->fNeedsScaling) | |||
| { | |||
| // limit viewport to widget bounds | |||
| glViewport(widget->getAbsoluteX(), | |||
| fParent.getHeight() - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||
| static_cast<GLsizei>(widget->getWidth()), | |||
| static_cast<GLsizei>(widget->getHeight())); | |||
| } | |||
| else | |||
| { | |||
| // only set viewport pos | |||
| glViewport(widget->getAbsoluteX(), | |||
| /*fParent.getHeight() - static_cast<int>(widget->getHeight())*/ - widget->getAbsoluteY(), | |||
| static_cast<GLsizei>(fParent.getWidth()), | |||
| static_cast<GLsizei>(fParent.getHeight())); | |||
| // then cut the outer bounds | |||
| glScissor(widget->getAbsoluteX(), | |||
| fParent.getHeight() - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||
| static_cast<GLsizei>(widget->getWidth()), | |||
| static_cast<GLsizei>(widget->getHeight())); | |||
| glEnable(GL_SCISSOR_TEST); | |||
| } | |||
| widget->onDisplay(); | |||
| if (! fNeedsScaling) | |||
| glDisable(GL_SCISSOR_TEST); | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -659,7 +659,7 @@ struct Window::PrivateData { | |||
| { | |||
| Widget* const widget(*it); | |||
| if (widget->isVisible()) | |||
| if (widget->isVisible() && ! widget->fSkipDisplay) | |||
| { | |||
| // reset color | |||
| glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
| @@ -706,6 +706,8 @@ struct Window::PrivateData { | |||
| glDisable(GL_SCISSOR_TEST); | |||
| needsDisableScissor = false; | |||
| } | |||
| widget->_displaySubWidgets(); | |||
| } | |||
| } | |||