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