Signed-off-by: falkTX <falktx@falktx.com>pull/272/head
@@ -66,8 +66,13 @@ public: | |||||
*/ | */ | ||||
Window& getWindow() const noexcept; | Window& getWindow() const noexcept; | ||||
// TODO group stuff after here, convenience functions present in Window class | |||||
void repaint() noexcept; | void repaint() noexcept; | ||||
void repaint(const Rectangle<uint>& rect) noexcept; | void repaint(const Rectangle<uint>& rect) noexcept; | ||||
void setGeometryConstraints(uint minimumWidth, | |||||
uint minimumHeight, | |||||
bool keepAspectRatio = false, | |||||
bool automaticallyScale = false); | |||||
// TODO deprecated | // TODO deprecated | ||||
Application& getParentApp() const noexcept { return getApp(); } | Application& getParentApp() const noexcept { return getApp(); } | ||||
@@ -124,6 +124,9 @@ public: | |||||
*/ | */ | ||||
void close(); | void close(); | ||||
bool isResizable() const noexcept; | |||||
void setResizable(bool resizable); | |||||
/** | /** | ||||
Get width. | Get width. | ||||
*/ | */ | ||||
@@ -159,9 +162,28 @@ public: | |||||
*/ | */ | ||||
void setSize(const Size<uint>& size); | void setSize(const Size<uint>& size); | ||||
/** | |||||
Get the title of the window previously set with setTitle(). | |||||
*/ | |||||
const char* getTitle() const noexcept; | const char* getTitle() const noexcept; | ||||
/** | |||||
Set the title of the window, typically displayed in the title bar or in window switchers. | |||||
This only makes sense for non-embedded windows. | |||||
*/ | |||||
void setTitle(const char* title); | void setTitle(const char* title); | ||||
/** | |||||
Check if key repeat events are ignored. | |||||
*/ | |||||
bool isIgnoringKeyRepeat() const noexcept; | |||||
/** | |||||
Set to ignore (or not) key repeat events according to @a ignore. | |||||
*/ | |||||
void setIgnoringKeyRepeat(bool ignore) noexcept; | |||||
/** | /** | ||||
Get the application associated with this window. | Get the application associated with this window. | ||||
*/ | */ | ||||
@@ -177,9 +199,47 @@ public: | |||||
*/ | */ | ||||
uintptr_t getNativeWindowHandle() const noexcept; | uintptr_t getNativeWindowHandle() const noexcept; | ||||
/** | |||||
Get the scale factor requested for this window. | |||||
This is purely informational, and up to developers to choose what to do with it. | |||||
If you do not want to deal with this yourself, | |||||
consider using setGeometryConstraints() where you can specify to automatically scale the window contents. | |||||
@see setGeometryConstraints | |||||
*/ | |||||
double getScaleFactor() const noexcept; | |||||
/** | |||||
Grab the keyboard input focus. | |||||
*/ | |||||
void focus(); | |||||
/** | |||||
Request repaint of this window, for the entire area. | |||||
*/ | |||||
void repaint() noexcept; | void repaint() noexcept; | ||||
/** | |||||
Request partial repaint of this window, with bounds according to @a rect. | |||||
*/ | |||||
void repaint(const Rectangle<uint>& rect) noexcept; | void repaint(const Rectangle<uint>& rect) noexcept; | ||||
/** | |||||
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically. | |||||
*/ | |||||
void setGeometryConstraints(uint minimumWidth, | |||||
uint minimumHeight, | |||||
bool keepAspectRatio = false, | |||||
bool automaticallyScale = false); | |||||
/* | |||||
void setTransientWinId(uintptr_t winId); | |||||
*/ | |||||
// TODO deprecated | |||||
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | |||||
inline double getScaling() const noexcept { return getScaling(); } | |||||
protected: | protected: | ||||
/** | /** | ||||
A function called when the window is resized. | A function called when the window is resized. | ||||
@@ -266,28 +326,15 @@ END_NAMESPACE_DGL | |||||
void exec(bool lockWait = false); | void exec(bool lockWait = false); | ||||
void focus(); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
bool isResizable() const noexcept; | |||||
void setResizable(bool resizable); | |||||
bool getIgnoringKeyRepeat() const noexcept; | |||||
void setIgnoringKeyRepeat(bool ignore) noexcept; | |||||
void setGeometryConstraints(uint width, uint height, bool aspect); | |||||
void setTransientWinId(uintptr_t winId); | |||||
double getScaling() const noexcept; | |||||
const GraphicsContext& getGraphicsContext() const noexcept; | const GraphicsContext& getGraphicsContext() const noexcept; | ||||
void addIdleCallback(IdleCallback* const callback); | void addIdleCallback(IdleCallback* const callback); | ||||
void removeIdleCallback(IdleCallback* const callback); | void removeIdleCallback(IdleCallback* const callback); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
protected: | protected: | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
@@ -65,7 +65,7 @@ void Rectangle<T>::_draw(const bool outline) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaling) | |||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | { | ||||
/* | /* | ||||
if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | ||||
@@ -83,7 +83,7 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
cairo_set_matrix(cr, &matrix); | cairo_set_matrix(cr, &matrix); | ||||
// displaySubWidgets(width, height, autoScaling); | |||||
// displaySubWidgets(width, height, autoScaleFactor); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -327,7 +327,7 @@ void OpenGLImage::drawAt(const Point<int>& pos) | |||||
#if 0 | #if 0 | ||||
void Widget::PrivateData::display(const uint width, | void Widget::PrivateData::display(const uint width, | ||||
const uint height, | const uint height, | ||||
const double autoScaling, | |||||
const double autoScaleFactor, | |||||
const bool renderingSubWidget) | const bool renderingSubWidget) | ||||
{ | { | ||||
printf("Widget::PrivateData::display INIT\n"); | printf("Widget::PrivateData::display INIT\n"); | ||||
@@ -346,9 +346,9 @@ void Widget::PrivateData::display(const uint width, | |||||
{ | { | ||||
// full viewport size | // full viewport size | ||||
glViewport(0, | glViewport(0, | ||||
-(height * autoScaling - height), | |||||
width * autoScaling, | |||||
height * autoScaling); | |||||
-(height * autoScaleFactor - height), | |||||
width * autoScaleFactor, | |||||
height * autoScaleFactor); | |||||
} | } | ||||
#if 0 | #if 0 | ||||
else if (needsScaling) | else if (needsScaling) | ||||
@@ -362,16 +362,16 @@ void Widget::PrivateData::display(const uint width, | |||||
else | else | ||||
{ | { | ||||
// only set viewport pos | // only set viewport pos | ||||
glViewport(absolutePos.getX() * autoScaling, | |||||
-std::round((height * autoScaling - height) + (absolutePos.getY() * autoScaling)), | |||||
std::round(width * autoScaling), | |||||
std::round(height * autoScaling)); | |||||
glViewport(absolutePos.getX() * autoScaleFactor, | |||||
-std::round((height * autoScaleFactor - height) + (absolutePos.getY() * autoScaleFactor)), | |||||
std::round(width * autoScaleFactor), | |||||
std::round(height * autoScaleFactor)); | |||||
// then cut the outer bounds | // then cut the outer bounds | ||||
glScissor(absolutePos.getX() * autoScaling, | |||||
height - std::round((self->getHeight() + absolutePos.getY()) * autoScaling), | |||||
std::round(self->getWidth() * autoScaling), | |||||
std::round(self->getHeight() * autoScaling)); | |||||
glScissor(absolutePos.getX() * autoScaleFactor, | |||||
height - std::round((self->getHeight() + absolutePos.getY()) * autoScaleFactor), | |||||
std::round(self->getWidth() * autoScaleFactor), | |||||
std::round(self->getHeight() * autoScaleFactor)); | |||||
glEnable(GL_SCISSOR_TEST); | glEnable(GL_SCISSOR_TEST); | ||||
needsDisableScissor = true; | needsDisableScissor = true; | ||||
@@ -387,11 +387,11 @@ void Widget::PrivateData::display(const uint width, | |||||
needsDisableScissor = false; | needsDisableScissor = false; | ||||
} | } | ||||
displaySubWidgets(width, height, autoScaling); | |||||
displaySubWidgets(width, height, autoScaleFactor); | |||||
} | } | ||||
#endif | #endif | ||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaling) | |||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | { | ||||
bool needsDisableScissor = false; | bool needsDisableScissor = false; | ||||
@@ -399,9 +399,9 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
{ | { | ||||
// full viewport size | // full viewport size | ||||
glViewport(0, | glViewport(0, | ||||
-(height * autoScaling - height), | |||||
width * autoScaling, | |||||
height * autoScaling); | |||||
-(height * autoScaleFactor - height), | |||||
width * autoScaleFactor, | |||||
height * autoScaleFactor); | |||||
} | } | ||||
else if (needsViewportScaling) | else if (needsViewportScaling) | ||||
{ | { | ||||
@@ -414,16 +414,16 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
else | else | ||||
{ | { | ||||
// only set viewport pos | // only set viewport pos | ||||
glViewport(absolutePos.getX() * autoScaling, | |||||
-std::round((height * autoScaling - height) + (absolutePos.getY() * autoScaling)), | |||||
std::round(width * autoScaling), | |||||
std::round(height * autoScaling)); | |||||
glViewport(absolutePos.getX() * autoScaleFactor, | |||||
-std::round((height * autoScaleFactor - height) + (absolutePos.getY() * autoScaleFactor)), | |||||
std::round(width * autoScaleFactor), | |||||
std::round(height * autoScaleFactor)); | |||||
// then cut the outer bounds | // then cut the outer bounds | ||||
glScissor(absolutePos.getX() * autoScaling, | |||||
height - std::round((self->getHeight() + absolutePos.getY()) * autoScaling), | |||||
std::round(self->getWidth() * autoScaling), | |||||
std::round(self->getHeight() * autoScaling)); | |||||
glScissor(absolutePos.getX() * autoScaleFactor, | |||||
height - std::round((self->getHeight() + absolutePos.getY()) * autoScaleFactor), | |||||
std::round(self->getWidth() * autoScaleFactor), | |||||
std::round(self->getHeight() * autoScaleFactor)); | |||||
glEnable(GL_SCISSOR_TEST); | glEnable(GL_SCISSOR_TEST); | ||||
needsDisableScissor = true; | needsDisableScissor = true; | ||||
@@ -438,7 +438,7 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
needsDisableScissor = false; | needsDisableScissor = false; | ||||
} | } | ||||
// displaySubWidgets(width, height, autoScaling); | |||||
// displaySubWidgets(width, height, autoScaleFactor); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -446,18 +446,22 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
void TopLevelWidget::PrivateData::display() | void TopLevelWidget::PrivateData::display() | ||||
{ | { | ||||
const Size<uint> size(window.getSize()); | const Size<uint> size(window.getSize()); | ||||
const uint width = size.getWidth(); | |||||
const uint height = size.getHeight(); | |||||
const double autoScaling = window.pData->autoScaling; | |||||
const uint width = size.getWidth(); | |||||
const uint height = size.getHeight(); | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
// full viewport size | // full viewport size | ||||
glViewport(0, -(height * autoScaling - height), width * autoScaling, height * autoScaling); | |||||
if (window.pData->autoScaling) | |||||
glViewport(0, -height, width, height); | |||||
else | |||||
glViewport(0, -(height * autoScaleFactor - height), width * autoScaleFactor, height * autoScaleFactor); | |||||
// main widget drawing | // main widget drawing | ||||
self->onDisplay(); | self->onDisplay(); | ||||
// now draw subwidgets if there are any | // now draw subwidgets if there are any | ||||
selfw->pData->displaySubWidgets(width, height, autoScaling); | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -33,7 +33,7 @@ struct SubWidget::PrivateData { | |||||
~PrivateData(); | ~PrivateData(); | ||||
// NOTE display function is different depending on build type, must call displaySubWidgets at the end | // NOTE display function is different depending on build type, must call displaySubWidgets at the end | ||||
void display(uint width, uint height, double autoScaling); | |||||
void display(uint width, uint height, double autoScaleFactor); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | ||||
}; | }; | ||||
@@ -50,6 +50,14 @@ void TopLevelWidget::repaint(const Rectangle<uint>& rect) noexcept | |||||
pData->window.repaint(rect); | pData->window.repaint(rect); | ||||
} | } | ||||
void TopLevelWidget::setGeometryConstraints(const uint minimumWidth, | |||||
const uint minimumHeight, | |||||
const bool keepAspectRatio, | |||||
const bool automaticallyScale) | |||||
{ | |||||
pData->window.setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -41,12 +41,12 @@ void TopLevelWidget::PrivateData::mouseEvent(const Events::MouseEvent& ev) | |||||
{ | { | ||||
Events::MouseEvent rev = ev; | Events::MouseEvent rev = ev; | ||||
const double autoScaling = window.pData->autoScaling; | |||||
if (autoScaling != 1.0) | |||||
if (window.pData->autoScaling) | |||||
{ | { | ||||
rev.pos.setX(ev.pos.getX() / autoScaling); | |||||
rev.pos.setY(ev.pos.getY() / autoScaling); | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
rev.pos.setX(ev.pos.getX() / autoScaleFactor); | |||||
rev.pos.setY(ev.pos.getY() / autoScaleFactor); | |||||
} | } | ||||
// give top-level widget chance to catch this event first | // give top-level widget chance to catch this event first | ||||
@@ -53,7 +53,7 @@ Widget::PrivateData::~PrivateData() | |||||
subWidgets.clear(); | subWidgets.clear(); | ||||
} | } | ||||
void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, const double scaling) | |||||
void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | { | ||||
if (subWidgets.size() == 0) | if (subWidgets.size() == 0) | ||||
return; | return; | ||||
@@ -63,7 +63,7 @@ void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, | |||||
SubWidget* const subwidget(*it); | SubWidget* const subwidget(*it); | ||||
if (subwidget->isVisible()) | if (subwidget->isVisible()) | ||||
subwidget->pData->display(width, height, scaling); | |||||
subwidget->pData->display(width, height, autoScaleFactor); | |||||
} | } | ||||
} | } | ||||
@@ -41,7 +41,7 @@ struct Widget::PrivateData { | |||||
explicit PrivateData(Widget* const s, Widget* const pw); | explicit PrivateData(Widget* const s, Widget* const pw); | ||||
~PrivateData(); | ~PrivateData(); | ||||
void displaySubWidgets(uint width, uint height, double autoScaling); | |||||
void displaySubWidgets(uint width, uint height, double autoScaleFactor); | |||||
void giveMouseEventForSubWidgets(Events::MouseEvent& ev); | void giveMouseEventForSubWidgets(Events::MouseEvent& ev); | ||||
static TopLevelWidget* findTopLevelWidget(Widget* const w); | static TopLevelWidget* findTopLevelWidget(Widget* const w); | ||||
@@ -81,6 +81,16 @@ void Window::close() | |||||
pData->close(); | pData->close(); | ||||
} | } | ||||
bool Window::isResizable() const noexcept | |||||
{ | |||||
return puglGetViewHint(pData->view, PUGL_RESIZABLE) == PUGL_TRUE; | |||||
} | |||||
void Window::setResizable(const bool resizable) | |||||
{ | |||||
pData->setResizable(resizable); | |||||
} | |||||
uint Window::getWidth() const noexcept | uint Window::getWidth() const noexcept | ||||
{ | { | ||||
return puglGetFrame(pData->view).width; | return puglGetFrame(pData->view).width; | ||||
@@ -129,6 +139,16 @@ void Window::setTitle(const char* const title) | |||||
puglSetWindowTitle(pData->view, title); | puglSetWindowTitle(pData->view, title); | ||||
} | } | ||||
bool Window::isIgnoringKeyRepeat() const noexcept | |||||
{ | |||||
return puglGetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT) == PUGL_TRUE; | |||||
} | |||||
void Window::setIgnoringKeyRepeat(const bool ignore) noexcept | |||||
{ | |||||
puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); | |||||
} | |||||
Application& Window::getApp() const noexcept | Application& Window::getApp() const noexcept | ||||
{ | { | ||||
return pData->app; | return pData->app; | ||||
@@ -139,6 +159,19 @@ uintptr_t Window::getNativeWindowHandle() const noexcept | |||||
return puglGetNativeWindow(pData->view); | return puglGetNativeWindow(pData->view); | ||||
} | } | ||||
double Window::getScaleFactor() const noexcept | |||||
{ | |||||
return pData->scaleFactor; | |||||
} | |||||
void Window::focus() | |||||
{ | |||||
if (! pData->isEmbed) | |||||
puglRaiseWindow(pData->view); | |||||
puglGrabFocus(pData->view); | |||||
} | |||||
void Window::repaint() noexcept | void Window::repaint() noexcept | ||||
{ | { | ||||
puglPostRedisplay(pData->view); | puglPostRedisplay(pData->view); | ||||
@@ -155,82 +188,64 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||||
puglPostRedisplayRect(pData->view, prect); | puglPostRedisplayRect(pData->view, prect); | ||||
} | } | ||||
void Window::onReshape(uint, uint) | |||||
void Window::setGeometryConstraints(const uint minimumWidth, | |||||
const uint minimumHeight, | |||||
const bool keepAspectRatio, | |||||
const bool automaticallyScale) | |||||
{ | { | ||||
puglFallbackOnResize(pData->view); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,); | |||||
bool Window::onClose() | |||||
{ | |||||
return true; | |||||
} | |||||
#if 0 | |||||
#if 0 | |||||
void Window::exec(bool lockWait) | |||||
{ | |||||
pData->exec(lockWait); | |||||
} | |||||
#endif | |||||
if (pData->isEmbed) { | |||||
// Did you forget to set DISTRHO_UI_USER_RESIZABLE ? | |||||
DISTRHO_SAFE_ASSERT_RETURN(isResizable(),); | |||||
} else if (! isResizable()) { | |||||
setResizable(true); | |||||
} | |||||
void Window::focus() | |||||
{ | |||||
if (! pData->fUsingEmbed) | |||||
puglRaiseWindow(pData->fView); | |||||
pData->minWidth = minimumWidth; | |||||
pData->minHeight = minimumHeight; | |||||
pData->autoScaling = automaticallyScale; | |||||
puglGrabFocus(pData->fView); | |||||
} | |||||
const double scaleFactor = pData->scaleFactor; | |||||
bool Window::isResizable() const noexcept | |||||
{ | |||||
return puglGetViewHint(pData->fView, PUGL_RESIZABLE) == PUGL_TRUE; | |||||
} | |||||
puglSetGeometryConstraints(pData->view, | |||||
minimumWidth * scaleFactor, | |||||
minimumHeight * scaleFactor, | |||||
keepAspectRatio); | |||||
void Window::setResizable(const bool resizable) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->fUsingEmbed,); | |||||
if (pData->fUsingEmbed) | |||||
if (scaleFactor != 1.0) | |||||
{ | { | ||||
DGL_DBG("Window setResizable cannot be called when embedded\n"); | |||||
return; | |||||
} | |||||
const Size<uint> size(getSize()); | |||||
DGL_DBG("Window setResizable called\n"); | |||||
puglSetViewHint(pData->fView, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
puglWin32SetWindowResizable(pData->fView, resizable); | |||||
#endif | |||||
setSize(size.getWidth() * scaleFactor, | |||||
size.getHeight() * scaleFactor); | |||||
} | |||||
} | } | ||||
bool Window::getIgnoringKeyRepeat() const noexcept | |||||
void Window::onReshape(uint, uint) | |||||
{ | { | ||||
return puglGetViewHint(pData->fView, PUGL_IGNORE_KEY_REPEAT) == PUGL_TRUE; | |||||
puglFallbackOnResize(pData->view); | |||||
} | } | ||||
void Window::setIgnoringKeyRepeat(const bool ignore) noexcept | |||||
bool Window::onClose() | |||||
{ | { | ||||
puglSetViewHint(pData->fView, PUGL_IGNORE_KEY_REPEAT, ignore); | |||||
return true; | |||||
} | } | ||||
void Window::setGeometryConstraints(const uint width, const uint height, bool aspect) | |||||
#if 0 | |||||
#if 0 | |||||
void Window::exec(bool lockWait) | |||||
{ | { | ||||
// Did you forget to set DISTRHO_UI_USER_RESIZABLE ? | |||||
DISTRHO_SAFE_ASSERT_RETURN(isResizable(),); | |||||
puglUpdateGeometryConstraints(pData->fView, width, height, aspect); | |||||
pData->exec(lockWait); | |||||
} | } | ||||
#endif | |||||
void Window::setTransientWinId(const uintptr_t winId) | void Window::setTransientWinId(const uintptr_t winId) | ||||
{ | { | ||||
puglSetTransientFor(pData->fView, winId); | puglSetTransientFor(pData->fView, winId); | ||||
} | } | ||||
double Window::getScaling() const noexcept | |||||
{ | |||||
return pData->fScaling; | |||||
} | |||||
#if 0 | #if 0 | ||||
Application& Window::getApp() const noexcept | Application& Window::getApp() const noexcept | ||||
{ | { | ||||
@@ -238,13 +253,6 @@ Application& Window::getApp() const noexcept | |||||
} | } | ||||
#endif | #endif | ||||
void Window::_setAutoScaling(double scaling) noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,); | |||||
pData->fAutoScaling = scaling; | |||||
} | |||||
void Window::_addWidget(Widget* const widget) | void Window::_addWidget(Widget* const widget) | ||||
{ | { | ||||
pData->addWidget(widget); | pData->addWidget(widget); | ||||
@@ -49,8 +49,11 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
isClosed(true), | isClosed(true), | ||||
isVisible(false), | isVisible(false), | ||||
isEmbed(false), | isEmbed(false), | ||||
scaling(1.0), | |||||
autoScaling(1.0), | |||||
scaleFactor(1.0), | |||||
autoScaling(false), | |||||
autoScaleFactor(1.0), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
pendingVisibility(kPendingVisibilityNone) | pendingVisibility(kPendingVisibilityNone) | ||||
{ | { | ||||
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
@@ -65,8 +68,11 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transi | |||||
isClosed(true), | isClosed(true), | ||||
isVisible(false), | isVisible(false), | ||||
isEmbed(false), | isEmbed(false), | ||||
scaling(1.0), | |||||
autoScaling(1.0), | |||||
scaleFactor(1.0), | |||||
autoScaling(false), | |||||
autoScaleFactor(1.0), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
pendingVisibility(kPendingVisibilityNone) | pendingVisibility(kPendingVisibilityNone) | ||||
{ | { | ||||
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
@@ -85,8 +91,11 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
isVisible(parentWindowHandle != 0), | isVisible(parentWindowHandle != 0), | ||||
isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
scaling(scale), | |||||
autoScaling(1.0), | |||||
scaleFactor(scale), | |||||
autoScaling(false), | |||||
autoScaleFactor(1.0), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
pendingVisibility(kPendingVisibilityNone) | pendingVisibility(kPendingVisibilityNone) | ||||
{ | { | ||||
if (isEmbed) | if (isEmbed) | ||||
@@ -116,8 +125,11 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
isVisible(parentWindowHandle != 0), | isVisible(parentWindowHandle != 0), | ||||
isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
scaling(scale), | |||||
autoScaling(1.0), | |||||
scaleFactor(scale), | |||||
autoScaling(false), | |||||
autoScaleFactor(1.0), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
pendingVisibility(kPendingVisibilityNone) | pendingVisibility(kPendingVisibilityNone) | ||||
{ | { | ||||
if (isEmbed) | if (isEmbed) | ||||
@@ -293,6 +305,20 @@ void Window::PrivateData::close() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::setResizable(const bool resizable) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(! isEmbed,); | |||||
DGL_DBG("Window setResizable called\n"); | |||||
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
puglWin32SetWindowResizable(view, resizable); | |||||
#endif | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void Window::PrivateData::idleCallback() | void Window::PrivateData::idleCallback() | ||||
{ | { | ||||
// #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | // #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | ||||
@@ -329,6 +355,13 @@ void Window::PrivateData::onPuglReshape(const int width, const int height) | |||||
DGL_DBGp("PUGL: onReshape : %i %i\n", width, height); | DGL_DBGp("PUGL: onReshape : %i %i\n", width, height); | ||||
if (autoScaling) | |||||
{ | |||||
const double scaleHorizontal = static_cast<double>(width) / static_cast<double>(minWidth); | |||||
const double scaleVertical = static_cast<double>(height) / static_cast<double>(minHeight); | |||||
autoScaleFactor = scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical; | |||||
} | |||||
self->onReshape(width, height); | self->onReshape(width, height); | ||||
#ifndef DPF_TEST_WINDOW_CPP | #ifndef DPF_TEST_WINDOW_CPP | ||||
@@ -58,11 +58,15 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | ||||
const bool isEmbed; | const bool isEmbed; | ||||
/** Scaling to report to widgets on request, purely informational. */ | |||||
double scaling; | |||||
/** Scale factor to report to widgets on request, purely informational. */ | |||||
double scaleFactor; | |||||
/** Automatic scaling to apply on widgets, implemented internally. */ | /** Automatic scaling to apply on widgets, implemented internally. */ | ||||
double autoScaling; | |||||
bool autoScaling; | |||||
double autoScaleFactor; | |||||
/** Pugl minWidth, minHeight access. */ | |||||
uint minWidth, minHeight; | |||||
/** Pending state of visility, used for the action to be triggered during Pugl create events. */ | /** Pending state of visility, used for the action to be triggered during Pugl create events. */ | ||||
enum PendingVisibility { | enum PendingVisibility { | ||||
@@ -102,6 +106,8 @@ struct Window::PrivateData : IdleCallback { | |||||
*/ | */ | ||||
void close(); | void close(); | ||||
void setResizable(bool resizable); | |||||
const GraphicsContext& getGraphicsContext() const noexcept; | const GraphicsContext& getGraphicsContext() const noexcept; | ||||
void idleCallback() override; | void idleCallback() override; | ||||
@@ -85,6 +85,14 @@ START_NAMESPACE_DGL | |||||
#include "pugl-upstream/src/implementation.c" | #include "pugl-upstream/src/implementation.c" | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// expose backend enter | |||||
void puglBackendEnter(PuglView* view) | |||||
{ | |||||
view->backend->enter(view, NULL); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// missing in pugl, directly returns title char* pointer | // missing in pugl, directly returns title char* pointer | ||||
@@ -94,11 +102,68 @@ const char* puglGetWindowTitle(const PuglView* view) | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// expose backend enter | |||||
// bring view window into the foreground, aka "raise" window | |||||
void puglBackendEnter(PuglView* view) | |||||
void puglRaiseWindow(PuglView* view) | |||||
{ | { | ||||
view->backend->enter(view, NULL); | |||||
#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) | |||||
// nothing here yet | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
SetForegroundWindow(view->impl->hwnd); | |||||
SetActiveWindow(view->impl->hwnd); | |||||
#else | |||||
XRaiseWindow(view->impl->display, view->impl->win); | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// set backend that matches current build | |||||
void puglSetMatchingBackendForCurrentBuild(PuglView* view) | |||||
{ | |||||
#ifdef DGL_CAIRO | |||||
puglSetBackend(view, puglCairoBackend()); | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
puglSetBackend(view, puglGlBackend()); | |||||
#endif | |||||
#ifdef DGL_Vulkan | |||||
puglSetBackend(view, puglVulkanBackend()); | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Combine puglSetMinSize and puglSetAspectRatio | |||||
PuglStatus puglSetGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) | |||||
{ | |||||
view->minWidth = width; | |||||
view->minHeight = height; | |||||
if (aspect) { | |||||
view->minAspectX = width; | |||||
view->minAspectY = height; | |||||
view->maxAspectX = width; | |||||
view->maxAspectY = height; | |||||
} | |||||
#if defined(DISTRHO_OS_HAIKU) | |||||
// nothing? | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
if (view->impl->window) | |||||
{ | |||||
[view->impl->window setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; | |||||
if (aspect) | |||||
[view->impl->window setContentAspectRatio:sizePoints(view, view->minAspectX, view->minAspectY)]; | |||||
} | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
// nothing | |||||
#else | |||||
return updateSizeHints(view); | |||||
#endif | |||||
return PUGL_SUCCESS; | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -161,22 +226,6 @@ PuglStatus puglSetWindowSize(PuglView* view, unsigned int width, unsigned int he | |||||
return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// set backend that matches current build | |||||
void puglSetMatchingBackendForCurrentBuild(PuglView* view) | |||||
{ | |||||
#ifdef DGL_CAIRO | |||||
puglSetBackend(view, puglCairoBackend()); | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
puglSetBackend(view, puglGlBackend()); | |||||
#endif | |||||
#ifdef DGL_Vulkan | |||||
puglSetBackend(view, puglVulkanBackend()); | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// DGL specific, build-specific drawing prepare | // DGL specific, build-specific drawing prepare | ||||
@@ -33,22 +33,30 @@ START_NAMESPACE_DGL | |||||
PUGL_BEGIN_DECLS | PUGL_BEGIN_DECLS | ||||
// expose backend enter | |||||
PUGL_API void | |||||
puglBackendEnter(PuglView* view); | |||||
// missing in pugl, directly returns title char* pointer | // missing in pugl, directly returns title char* pointer | ||||
PUGL_API const char* | PUGL_API const char* | ||||
puglGetWindowTitle(const PuglView* view); | puglGetWindowTitle(const PuglView* view); | ||||
// expose backend enter | |||||
// bring view window into the foreground, aka "raise" window | |||||
PUGL_API void | PUGL_API void | ||||
puglBackendEnter(PuglView* view); | |||||
// set window size without changing frame x/y position | |||||
PUGL_API PuglStatus | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); | |||||
puglRaiseWindow(PuglView* view); | |||||
// DGL specific, assigns backend that matches current DGL build | // DGL specific, assigns backend that matches current DGL build | ||||
PUGL_API void | PUGL_API void | ||||
puglSetMatchingBackendForCurrentBuild(PuglView* view); | puglSetMatchingBackendForCurrentBuild(PuglView* view); | ||||
// Combine puglSetMinSize and puglSetAspectRatio | |||||
PUGL_API PuglStatus | |||||
puglSetGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect); | |||||
// set window size without changing frame x/y position | |||||
PUGL_API PuglStatus | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); | |||||
// DGL specific, build-specific drawing prepare | // DGL specific, build-specific drawing prepare | ||||
PUGL_API void | PUGL_API void | ||||
puglOnDisplayPrepare(PuglView* view); | puglOnDisplayPrepare(PuglView* view); | ||||
@@ -69,15 +69,6 @@ public: | |||||
*/ | */ | ||||
virtual ~UI(); | virtual ~UI(); | ||||
#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | |||||
Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. | |||||
@see Window::setGeometryConstraints(uint,uint,bool) | |||||
@see Window::setScaling(double) | |||||
*/ | |||||
void setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale = false); | |||||
#endif | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* Host state */ | * Host state */ | ||||
@@ -87,28 +87,6 @@ UI::~UI() | |||||
delete uiData; | delete uiData; | ||||
} | } | ||||
#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(minHeight > 0,); | |||||
uiData->automaticallyScale = automaticallyScale; | |||||
uiData->minWidth = minWidth; | |||||
uiData->minHeight = minHeight; | |||||
#if 0 /* TODO */ | |||||
Window& window(getParentWindow()); | |||||
const double uiScaleFactor = window.getScaling(); | |||||
window.setGeometryConstraints(minWidth * uiScaleFactor, minHeight * uiScaleFactor, keepAspectRatio); | |||||
if (d_isNotZero(uiScaleFactor - 1.0)) | |||||
setSize(getWidth() * uiScaleFactor, getHeight() * uiScaleFactor); | |||||
#endif | |||||
} | |||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* Host state */ | * Host state */ | ||||
@@ -95,15 +95,6 @@ protected: | |||||
UI::PrivateData* const uiData = fUI->uiData; | UI::PrivateData* const uiData = fUI->uiData; | ||||
DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | ||||
#if 0 /* TODO */ | |||||
if (uiData->automaticallyScale) | |||||
{ | |||||
const double scaleHorizontal = static_cast<double>(width) / static_cast<double>(uiData->minWidth); | |||||
const double scaleVertical = static_cast<double>(height) / static_cast<double>(uiData->minHeight); | |||||
_setAutoScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); | |||||
} | |||||
#endif | |||||
uiData->resizeInProgress = true; | uiData->resizeInProgress = true; | ||||
fUI->setSize(width, height); | fUI->setSize(width, height); | ||||
uiData->resizeInProgress = false; | uiData->resizeInProgress = false; | ||||
@@ -342,9 +333,7 @@ public: | |||||
void focus() | void focus() | ||||
{ | { | ||||
#if 0 /* TODO */ | |||||
glWindow.focus(); | glWindow.focus(); | ||||
#endif | |||||
} | } | ||||
bool idle() | bool idle() | ||||