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