@@ -867,38 +867,22 @@ public: | |||||
Constructor. | Constructor. | ||||
@see CreateFlags | @see CreateFlags | ||||
*/ | */ | ||||
explicit NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS) | |||||
: Widget(parent), | |||||
NanoVG(flags), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
fNeedsScaling = true; | |||||
} | |||||
explicit NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Constructor for a subwidget. | Constructor for a subwidget. | ||||
*/ | */ | ||||
explicit NanoWidget(Widget* groupWidget, int flags = CREATE_ANTIALIAS) | |||||
: Widget(groupWidget, true), | |||||
NanoVG(flags), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
fNeedsScaling = true; | |||||
} | |||||
explicit NanoWidget(Widget* groupWidget, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Constructor for a subwidget. | |||||
Constructor for a subwidget, reusing a NanoVG context. | |||||
*/ | */ | ||||
explicit NanoWidget(NanoWidget* groupWidget) | |||||
: Widget(groupWidget, false), | |||||
NanoVG(groupWidget), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
fNeedsScaling = true; | |||||
groupWidget->fNanoSubWidgets.push_back(this); | |||||
} | |||||
explicit NanoWidget(NanoWidget* groupWidget); | |||||
// fNanoSubWidgets.clear(); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
virtual ~NanoWidget(); | |||||
protected: | protected: | ||||
/** | /** | ||||
@@ -908,25 +892,21 @@ protected: | |||||
virtual void onNanoDisplay() = 0; | virtual void onNanoDisplay() = 0; | ||||
private: | private: | ||||
std::vector<NanoWidget*> fNanoSubWidgets; | |||||
struct PrivateData; | |||||
PrivateData* const nData; | |||||
/** | /** | ||||
Widget display function. | Widget display function. | ||||
Implemented internally to wrap begin/endFrame() automatically. | Implemented internally to wrap begin/endFrame() automatically. | ||||
*/ | */ | ||||
void onDisplay() override | |||||
{ | |||||
beginFrame(getWidth(), getHeight()); | |||||
onNanoDisplay(); | |||||
for (std::vector<NanoWidget*>::iterator it = fNanoSubWidgets.begin(); it != fNanoSubWidgets.end(); ++it) | |||||
{ | |||||
NanoWidget* const widget(*it); | |||||
widget->onNanoDisplay(); | |||||
} | |||||
void onDisplay() override; | |||||
endFrame(); | |||||
} | |||||
// these should not be used | |||||
void beginFrame(uint,uint) {} | |||||
void beginFrame(uint,uint,float) {} | |||||
void beginFrame(Widget*) {} | |||||
void cancelFrame() {} | |||||
void endFrame() {} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoWidget) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoWidget) | ||||
}; | }; | ||||
@@ -29,47 +29,27 @@ class StandaloneWindow : public Application, | |||||
public Window | public Window | ||||
{ | { | ||||
public: | public: | ||||
StandaloneWindow() | |||||
: Application(), | |||||
Window((Application&)*this), | |||||
fWidget(nullptr) {} | |||||
/** | |||||
Constructor. | |||||
*/ | |||||
StandaloneWindow(); | |||||
void exec() | |||||
{ | |||||
Window::show(); | |||||
Application::exec(); | |||||
} | |||||
protected: | |||||
void onReshape(uint width, uint height) override | |||||
{ | |||||
if (fWidget != nullptr) | |||||
fWidget->setSize(width, height); | |||||
Window::onReshape(width, height); | |||||
} | |||||
/** | |||||
Show window and execute application. | |||||
*/ | |||||
void exec(); | |||||
private: | private: | ||||
Widget* fWidget; | Widget* fWidget; | ||||
void _addWidget(Widget* widget) override | |||||
{ | |||||
if (fWidget == nullptr) | |||||
{ | |||||
fWidget = widget; | |||||
fWidget->fNeedsFullViewport = true; | |||||
} | |||||
Window::_addWidget(widget); | |||||
} | |||||
/** @internal */ | |||||
void onReshape(uint width, uint height) override; | |||||
/** @internal */ | |||||
void _addWidget(Widget* widget) override; | |||||
void _removeWidget(Widget* widget) override | |||||
{ | |||||
if (fWidget == widget) | |||||
{ | |||||
fWidget->fNeedsFullViewport = false; | |||||
fWidget = nullptr; | |||||
} | |||||
Window::_removeWidget(widget); | |||||
} | |||||
/** @internal */ | |||||
void _removeWidget(Widget* widget) override; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | ||||
}; | }; | ||||
@@ -363,22 +363,12 @@ protected: | |||||
virtual void onResize(const ResizeEvent&); | virtual void onResize(const ResizeEvent&); | ||||
private: | private: | ||||
Window& fParent; | |||||
bool fNeedsFullViewport; | |||||
bool fNeedsScaling; | |||||
bool fSkipDisplay; | |||||
bool fVisible; | |||||
uint fId; | |||||
Point<int> fAbsolutePos; | |||||
Size<uint> fSize; | |||||
std::vector<Widget*> fSubWidgets; | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
/** @internal */ | /** @internal */ | ||||
explicit Widget(Widget* groupWidget, bool addToSubWidgets); | explicit Widget(Widget* groupWidget, bool addToSubWidgets); | ||||
/** @internal */ | |||||
void _displaySubWidgets(); | |||||
friend class ImageSlider; | friend class ImageSlider; | ||||
friend class NanoWidget; | friend class NanoWidget; | ||||
friend class Window; | friend class Window; | ||||
@@ -15,8 +15,7 @@ | |||||
*/ | */ | ||||
#include "../ImageWidgets.hpp" | #include "../ImageWidgets.hpp" | ||||
#include <cmath> | |||||
#include "WidgetPrivateData.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
@@ -742,7 +741,7 @@ ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept | |||||
fSliderArea(), | fSliderArea(), | ||||
leakDetector_ImageSlider() | leakDetector_ImageSlider() | ||||
{ | { | ||||
fNeedsFullViewport = true; | |||||
pData->needsFullViewport = true; | |||||
} | } | ||||
ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept | ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept | ||||
@@ -764,7 +763,7 @@ ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept | |||||
fSliderArea(), | fSliderArea(), | ||||
leakDetector_ImageSlider() | leakDetector_ImageSlider() | ||||
{ | { | ||||
fNeedsFullViewport = true; | |||||
pData->needsFullViewport = true; | |||||
} | } | ||||
float ImageSlider::getValue() const noexcept | float ImageSlider::getValue() const noexcept | ||||
@@ -15,7 +15,7 @@ | |||||
*/ | */ | ||||
#include "../NanoVG.hpp" | #include "../NanoVG.hpp" | ||||
#include "../Window.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Ignore some warnings if debugging | // Ignore some warnings if debugging | ||||
@@ -859,6 +859,69 @@ int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWi | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
struct NanoWidget::PrivateData { | |||||
NanoWidget* const self; | |||||
std::vector<NanoWidget*> subWidgets; | |||||
PrivateData(NanoWidget* const s) | |||||
: self(s), | |||||
subWidgets() {} | |||||
~PrivateData() | |||||
{ | |||||
subWidgets.clear(); | |||||
} | |||||
}; | |||||
NanoWidget::NanoWidget(Window& parent, int flags) | |||||
: Widget(parent), | |||||
NanoVG(flags), | |||||
nData(new PrivateData(this)), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
pData->needsScaling = true; | |||||
} | |||||
NanoWidget::NanoWidget(Widget* groupWidget, int flags) | |||||
: Widget(groupWidget, true), | |||||
NanoVG(flags), | |||||
nData(new PrivateData(this)), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
pData->needsScaling = true; | |||||
} | |||||
NanoWidget::NanoWidget(NanoWidget* groupWidget) | |||||
: Widget(groupWidget, false), | |||||
NanoVG(groupWidget), | |||||
nData(new PrivateData(this)), | |||||
leakDetector_NanoWidget() | |||||
{ | |||||
pData->needsScaling = true; | |||||
groupWidget->nData->subWidgets.push_back(this); | |||||
} | |||||
NanoWidget::~NanoWidget() | |||||
{ | |||||
delete nData; | |||||
} | |||||
void NanoWidget::onDisplay() | |||||
{ | |||||
NanoVG::beginFrame(getWidth(), getHeight()); | |||||
onNanoDisplay(); | |||||
for (std::vector<NanoWidget*>::iterator it = nData->subWidgets.begin(); it != nData->subWidgets.end(); ++it) | |||||
{ | |||||
NanoWidget* const widget(*it); | |||||
widget->onNanoDisplay(); | |||||
} | |||||
NanoVG::endFrame(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
extern "C" { | extern "C" { | ||||
@@ -14,8 +14,7 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "../Widget.hpp" | |||||
#include "../Window.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
@@ -23,69 +22,44 @@ START_NAMESPACE_DGL | |||||
// Widget | // Widget | ||||
Widget::Widget(Window& parent) | Widget::Widget(Window& parent) | ||||
: fParent(parent), | |||||
fNeedsFullViewport(false), | |||||
fNeedsScaling(false), | |||||
fSkipDisplay(false), | |||||
fVisible(true), | |||||
fId(0), | |||||
fAbsolutePos(0, 0), | |||||
fSize(0, 0), | |||||
: pData(new PrivateData(this, parent, nullptr, false)), | |||||
leakDetector_Widget() | leakDetector_Widget() | ||||
{ | { | ||||
fParent._addWidget(this); | |||||
parent._addWidget(this); | |||||
} | } | ||||
Widget::Widget(Widget* groupWidget) | Widget::Widget(Widget* groupWidget) | ||||
: fParent(groupWidget->getParentWindow()), | |||||
fNeedsFullViewport(false), | |||||
fNeedsScaling(false), | |||||
fSkipDisplay(true), | |||||
fVisible(true), | |||||
fId(0), | |||||
fAbsolutePos(0, 0), | |||||
fSize(0, 0), | |||||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, true)), | |||||
leakDetector_Widget() | leakDetector_Widget() | ||||
{ | { | ||||
fParent._addWidget(this); | |||||
groupWidget->fSubWidgets.push_back(this); | |||||
pData->parent._addWidget(this); | |||||
} | } | ||||
Widget::Widget(Widget* groupWidget, bool addToSubWidgets) | 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), | |||||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, addToSubWidgets)), | |||||
leakDetector_Widget() | leakDetector_Widget() | ||||
{ | { | ||||
fParent._addWidget(this); | |||||
if (addToSubWidgets) | |||||
groupWidget->fSubWidgets.push_back(this); | |||||
pData->parent._addWidget(this); | |||||
} | } | ||||
Widget::~Widget() | Widget::~Widget() | ||||
{ | { | ||||
fParent._removeWidget(this); | |||||
fSubWidgets.clear(); | |||||
pData->parent._removeWidget(this); | |||||
delete pData; | |||||
} | } | ||||
bool Widget::isVisible() const noexcept | bool Widget::isVisible() const noexcept | ||||
{ | { | ||||
return fVisible; | |||||
return pData->visible; | |||||
} | } | ||||
void Widget::setVisible(bool yesNo) | void Widget::setVisible(bool yesNo) | ||||
{ | { | ||||
if (fVisible == yesNo) | |||||
if (pData->visible == yesNo) | |||||
return; | return; | ||||
fVisible = yesNo; | |||||
fParent.repaint(); | |||||
pData->visible = yesNo; | |||||
pData->parent.repaint(); | |||||
} | } | ||||
void Widget::show() | void Widget::show() | ||||
@@ -100,47 +74,47 @@ void Widget::hide() | |||||
uint Widget::getWidth() const noexcept | uint Widget::getWidth() const noexcept | ||||
{ | { | ||||
return fSize.getWidth(); | |||||
return pData->size.getWidth(); | |||||
} | } | ||||
uint Widget::getHeight() const noexcept | uint Widget::getHeight() const noexcept | ||||
{ | { | ||||
return fSize.getHeight(); | |||||
return pData->size.getHeight(); | |||||
} | } | ||||
const Size<uint>& Widget::getSize() const noexcept | const Size<uint>& Widget::getSize() const noexcept | ||||
{ | { | ||||
return fSize; | |||||
return pData->size; | |||||
} | } | ||||
void Widget::setWidth(uint width) noexcept | void Widget::setWidth(uint width) noexcept | ||||
{ | { | ||||
if (fSize.getWidth() == width) | |||||
if (pData->size.getWidth() == width) | |||||
return; | return; | ||||
ResizeEvent ev; | ResizeEvent ev; | ||||
ev.oldSize = fSize; | |||||
ev.size = Size<uint>(width, fSize.getHeight()); | |||||
ev.oldSize = pData->size; | |||||
ev.size = Size<uint>(width, pData->size.getHeight()); | |||||
fSize.setWidth(width); | |||||
pData->size.setWidth(width); | |||||
onResize(ev); | onResize(ev); | ||||
fParent.repaint(); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
void Widget::setHeight(uint height) noexcept | void Widget::setHeight(uint height) noexcept | ||||
{ | { | ||||
if (fSize.getHeight() == height) | |||||
if (pData->size.getHeight() == height) | |||||
return; | return; | ||||
ResizeEvent ev; | ResizeEvent ev; | ||||
ev.oldSize = fSize; | |||||
ev.size = Size<uint>(fSize.getWidth(), height); | |||||
ev.oldSize = pData->size; | |||||
ev.size = Size<uint>(pData->size.getWidth(), height); | |||||
fSize.setHeight(height); | |||||
pData->size.setHeight(height); | |||||
onResize(ev); | onResize(ev); | ||||
fParent.repaint(); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
void Widget::setSize(uint width, uint height) noexcept | void Widget::setSize(uint width, uint height) noexcept | ||||
@@ -150,50 +124,50 @@ void Widget::setSize(uint width, uint height) noexcept | |||||
void Widget::setSize(const Size<uint>& size) noexcept | void Widget::setSize(const Size<uint>& size) noexcept | ||||
{ | { | ||||
if (fSize == size) | |||||
if (pData->size == size) | |||||
return; | return; | ||||
ResizeEvent ev; | ResizeEvent ev; | ||||
ev.oldSize = fSize; | |||||
ev.oldSize = pData->size; | |||||
ev.size = size; | ev.size = size; | ||||
fSize = size; | |||||
pData->size = size; | |||||
onResize(ev); | onResize(ev); | ||||
fParent.repaint(); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
int Widget::getAbsoluteX() const noexcept | int Widget::getAbsoluteX() const noexcept | ||||
{ | { | ||||
return fAbsolutePos.getX(); | |||||
return pData->absolutePos.getX(); | |||||
} | } | ||||
int Widget::getAbsoluteY() const noexcept | int Widget::getAbsoluteY() const noexcept | ||||
{ | { | ||||
return fAbsolutePos.getY(); | |||||
return pData->absolutePos.getY(); | |||||
} | } | ||||
const Point<int>& Widget::getAbsolutePos() const noexcept | const Point<int>& Widget::getAbsolutePos() const noexcept | ||||
{ | { | ||||
return fAbsolutePos; | |||||
return pData->absolutePos; | |||||
} | } | ||||
void Widget::setAbsoluteX(int x) noexcept | void Widget::setAbsoluteX(int x) noexcept | ||||
{ | { | ||||
if (fAbsolutePos.getX() == x) | |||||
if (pData->absolutePos.getX() == x) | |||||
return; | return; | ||||
fAbsolutePos.setX(x); | |||||
fParent.repaint(); | |||||
pData->absolutePos.setX(x); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
void Widget::setAbsoluteY(int y) noexcept | void Widget::setAbsoluteY(int y) noexcept | ||||
{ | { | ||||
if (fAbsolutePos.getY() == y) | |||||
if (pData->absolutePos.getY() == y) | |||||
return; | return; | ||||
fAbsolutePos.setY(y); | |||||
fParent.repaint(); | |||||
pData->absolutePos.setY(y); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
void Widget::setAbsolutePos(int x, int y) noexcept | void Widget::setAbsolutePos(int x, int y) noexcept | ||||
@@ -203,26 +177,26 @@ void Widget::setAbsolutePos(int x, int y) noexcept | |||||
void Widget::setAbsolutePos(const Point<int>& pos) noexcept | void Widget::setAbsolutePos(const Point<int>& pos) noexcept | ||||
{ | { | ||||
if (fAbsolutePos == pos) | |||||
if (pData->absolutePos == pos) | |||||
return; | return; | ||||
fAbsolutePos = pos; | |||||
fParent.repaint(); | |||||
pData->absolutePos = pos; | |||||
pData->parent.repaint(); | |||||
} | } | ||||
Application& Widget::getParentApp() const noexcept | Application& Widget::getParentApp() const noexcept | ||||
{ | { | ||||
return fParent.getApp(); | |||||
return pData->parent.getApp(); | |||||
} | } | ||||
Window& Widget::getParentWindow() const noexcept | Window& Widget::getParentWindow() const noexcept | ||||
{ | { | ||||
return fParent; | |||||
return pData->parent; | |||||
} | } | ||||
bool Widget::contains(int x, int y) const noexcept | bool Widget::contains(int x, int y) const noexcept | ||||
{ | { | ||||
return (x >= 0 && y >= 0 && static_cast<uint>(x) < fSize.getWidth() && static_cast<uint>(y) < fSize.getHeight()); | |||||
return (x >= 0 && y >= 0 && static_cast<uint>(x) < pData->size.getWidth() && static_cast<uint>(y) < pData->size.getHeight()); | |||||
} | } | ||||
bool Widget::contains(const Point<int>& pos) const noexcept | bool Widget::contains(const Point<int>& pos) const noexcept | ||||
@@ -232,17 +206,17 @@ bool Widget::contains(const Point<int>& pos) const noexcept | |||||
void Widget::repaint() noexcept | void Widget::repaint() noexcept | ||||
{ | { | ||||
fParent.repaint(); | |||||
pData->parent.repaint(); | |||||
} | } | ||||
uint Widget::getId() const noexcept | uint Widget::getId() const noexcept | ||||
{ | { | ||||
return fId; | |||||
return pData->id; | |||||
} | } | ||||
void Widget::setId(uint id) noexcept | void Widget::setId(uint id) noexcept | ||||
{ | { | ||||
fId = id; | |||||
pData->id = id; | |||||
} | } | ||||
bool Widget::onKeyboard(const KeyboardEvent&) | bool Widget::onKeyboard(const KeyboardEvent&) | ||||
@@ -274,44 +248,6 @@ void Widget::onResize(const ResizeEvent&) | |||||
{ | { | ||||
} | } | ||||
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 |
@@ -0,0 +1,133 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#define DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#include "../Widget.hpp" | |||||
#include "../Window.hpp" | |||||
#include <vector> | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
struct Widget::PrivateData { | |||||
Widget* const self; | |||||
Window& parent; | |||||
Point<int> absolutePos; | |||||
Size<uint> size; | |||||
std::vector<Widget*> subWidgets; | |||||
uint id; | |||||
bool needsFullViewport; | |||||
bool needsScaling; | |||||
bool skipDisplay; | |||||
bool visible; | |||||
PrivateData(Widget* const s, Window& p, Widget* groupWidget, bool addToSubWidgets) | |||||
: self(s), | |||||
parent(p), | |||||
absolutePos(0, 0), | |||||
size(0, 0), | |||||
id(0), | |||||
needsFullViewport(false), | |||||
needsScaling(false), | |||||
skipDisplay(false), | |||||
visible(true) | |||||
{ | |||||
if (addToSubWidgets && groupWidget != nullptr) | |||||
groupWidget->pData->subWidgets.push_back(self); | |||||
} | |||||
~PrivateData() | |||||
{ | |||||
subWidgets.clear(); | |||||
} | |||||
void display(const uint width, const uint height) | |||||
{ | |||||
if (skipDisplay || ! visible) | |||||
return; | |||||
bool needsDisableScissor = false; | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
if (needsFullViewport || (absolutePos.isZero() && size == Size<uint>(width, height))) | |||||
{ | |||||
// full viewport size | |||||
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||||
} | |||||
else if (needsScaling) | |||||
{ | |||||
// limit viewport to widget bounds | |||||
glViewport(absolutePos.getX(), | |||||
height - static_cast<int>(self->getHeight()) - absolutePos.getY(), | |||||
static_cast<GLsizei>(self->getWidth()), | |||||
static_cast<GLsizei>(self->getHeight())); | |||||
} | |||||
else | |||||
{ | |||||
// only set viewport pos | |||||
glViewport(absolutePos.getX(), | |||||
/*height - static_cast<int>(self->getHeight())*/ - absolutePos.getY(), | |||||
static_cast<GLsizei>(width), | |||||
static_cast<GLsizei>(height)); | |||||
// then cut the outer bounds | |||||
glScissor(absolutePos.getX(), | |||||
height - static_cast<int>(self->getHeight()) - absolutePos.getY(), | |||||
static_cast<GLsizei>(self->getWidth()), | |||||
static_cast<GLsizei>(self->getHeight())); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = true; | |||||
} | |||||
// display widget | |||||
self->onDisplay(); | |||||
if (needsDisableScissor) | |||||
{ | |||||
glDisable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = false; | |||||
} | |||||
displaySubWidgets(width, height); | |||||
} | |||||
void displaySubWidgets(const uint width, const uint height) | |||||
{ | |||||
for (std::vector<Widget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | |||||
{ | |||||
Widget* const widget(*it); | |||||
DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | |||||
widget->pData->display(width, height); | |||||
} | |||||
} | |||||
DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED |
@@ -40,8 +40,8 @@ extern "C" { | |||||
#endif | #endif | ||||
#include "ApplicationPrivateData.hpp" | #include "ApplicationPrivateData.hpp" | ||||
#include "../Widget.hpp" | |||||
#include "../Window.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "../StandaloneWindow.hpp" | |||||
#include "../../distrho/extra/String.hpp" | #include "../../distrho/extra/String.hpp" | ||||
#define FOR_EACH_WIDGET(it) \ | #define FOR_EACH_WIDGET(it) \ | ||||
@@ -671,62 +671,10 @@ struct Window::PrivateData { | |||||
{ | { | ||||
fSelf->onDisplayBefore(); | fSelf->onDisplayBefore(); | ||||
bool needsDisableScissor = false; | |||||
FOR_EACH_WIDGET(it) | FOR_EACH_WIDGET(it) | ||||
{ | { | ||||
Widget* const widget(*it); | Widget* const widget(*it); | ||||
if (widget->isVisible() && ! widget->fSkipDisplay) | |||||
{ | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
if (widget->fNeedsFullViewport || (widget->fAbsolutePos.isZero() && widget->fSize == Size<uint>(fWidth, fHeight))) | |||||
{ | |||||
// full viewport size | |||||
glViewport(0, | |||||
0, | |||||
static_cast<GLsizei>(fWidth), | |||||
static_cast<GLsizei>(fHeight)); | |||||
} | |||||
else if (! widget->fNeedsScaling) | |||||
{ | |||||
// only set viewport pos | |||||
glViewport(widget->getAbsoluteX(), | |||||
/*fView->height - static_cast<int>(widget->getHeight())*/ - widget->getAbsoluteY(), | |||||
static_cast<GLsizei>(fWidth), | |||||
static_cast<GLsizei>(fHeight)); | |||||
// then cut the outer bounds | |||||
glScissor(widget->getAbsoluteX(), | |||||
fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||||
static_cast<GLsizei>(widget->getWidth()), | |||||
static_cast<GLsizei>(widget->getHeight())); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = true; | |||||
} | |||||
else | |||||
{ | |||||
// limit viewport to widget bounds | |||||
glViewport(widget->getAbsoluteX(), | |||||
fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||||
static_cast<GLsizei>(widget->getWidth()), | |||||
static_cast<GLsizei>(widget->getHeight())); | |||||
} | |||||
// display widget | |||||
widget->onDisplay(); | |||||
if (needsDisableScissor) | |||||
{ | |||||
glDisable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = false; | |||||
} | |||||
widget->_displaySubWidgets(); | |||||
} | |||||
widget->pData->display(fWidth, fHeight); | |||||
} | } | ||||
fSelf->onDisplayAfter(); | fSelf->onDisplayAfter(); | ||||
@@ -864,7 +812,7 @@ struct Window::PrivateData { | |||||
{ | { | ||||
Widget* const widget(*it); | Widget* const widget(*it); | ||||
if (widget->fNeedsFullViewport) | |||||
if (widget->pData->needsFullViewport) | |||||
widget->setSize(fWidth, fHeight); | widget->setSize(fWidth, fHeight); | ||||
} | } | ||||
} | } | ||||
@@ -1246,6 +1194,46 @@ void Window::fileBrowserSelected(const char*) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
StandaloneWindow::StandaloneWindow() | |||||
: Application(), | |||||
Window((Application&)*this), | |||||
fWidget(nullptr) {} | |||||
void StandaloneWindow::exec() | |||||
{ | |||||
Window::show(); | |||||
Application::exec(); | |||||
} | |||||
void StandaloneWindow::onReshape(uint width, uint height) | |||||
{ | |||||
if (fWidget != nullptr) | |||||
fWidget->setSize(width, height); | |||||
Window::onReshape(width, height); | |||||
} | |||||
void StandaloneWindow::_addWidget(Widget* widget) | |||||
{ | |||||
if (fWidget == nullptr) | |||||
{ | |||||
fWidget = widget; | |||||
fWidget->pData->needsFullViewport = true; | |||||
} | |||||
Window::_addWidget(widget); | |||||
} | |||||
void StandaloneWindow::_removeWidget(Widget* widget) | |||||
{ | |||||
if (fWidget == widget) | |||||
{ | |||||
fWidget->pData->needsFullViewport = false; | |||||
fWidget = nullptr; | |||||
} | |||||
Window::_removeWidget(widget); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
#undef DBG | #undef DBG | ||||
@@ -225,6 +225,7 @@ puglEnterContext(PuglView* view); | |||||
void | void | ||||
puglLeaveContext(PuglView* view, bool flush); | puglLeaveContext(PuglView* view, bool flush); | ||||
#if 0 | |||||
/** Return the code point for buf, or the replacement character on error. */ | /** Return the code point for buf, or the replacement character on error. */ | ||||
static uint32_t | static uint32_t | ||||
puglDecodeUTF8(const uint8_t* buf) | puglDecodeUTF8(const uint8_t* buf) | ||||
@@ -258,6 +259,7 @@ puglDecodeUTF8(const uint8_t* buf) | |||||
} | } | ||||
return 0xFFFD; | return 0xFFFD; | ||||
} | } | ||||
#endif | |||||
static void | static void | ||||
puglDefaultReshape(PuglView* view, int width, int height) | puglDefaultReshape(PuglView* view, int width, int height) | ||||
@@ -603,4 +603,7 @@ puglGetContext(PuglView* view) | |||||
} | } | ||||
#endif | #endif | ||||
return NULL; | return NULL; | ||||
// may be unused | |||||
(void)view; | |||||
} | } |