@@ -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(); | |||||
} | } | ||||
} | } | ||||