From c6e9bec69384bbb47fd6dffe30abb601d07804b8 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 6 May 2021 17:29:41 +0100 Subject: [PATCH] Start adding back widget stuff, almost at drawing step Signed-off-by: falkTX --- dgl/Application.hpp | 2 +- dgl/Cairo.hpp | 49 ++++++- dgl/StandaloneWindow.hpp | 54 ++++--- dgl/TopLevelWidget.hpp | 14 +- dgl/Widget.hpp | 73 ++++++---- dgl/Window.hpp | 19 ++- dgl/src/Cairo.cpp | 69 ++++----- dgl/src/OpenGL.cpp | 106 ++++++++------ dgl/src/StandaloneWindow.cpp | 9 +- dgl/src/SubWidget.cpp | 15 +- dgl/src/SubWidgetPrivateData.hpp | 20 +-- dgl/src/TopLevelWidget.cpp | 12 +- dgl/src/TopLevelWidgetPrivateData.cpp | 22 +-- dgl/src/Widget.cpp | 27 ++-- dgl/src/WidgetPrivateData.cpp | 117 +++++++-------- dgl/src/WidgetPrivateData.hpp | 56 +++----- dgl/src/Window.cpp | 14 +- dgl/src/WindowPrivateData.cpp | 31 ++-- dgl/src/WindowPrivateData.hpp | 22 +-- tests/Demo.cpp | 198 ++++++++++++++++++++++++++ tests/Makefile | 12 +- tests/widgets/ExampleColorWidget.hpp | 134 +++++++++++++++++ 22 files changed, 747 insertions(+), 328 deletions(-) create mode 100644 tests/Demo.cpp create mode 100644 tests/widgets/ExampleColorWidget.hpp diff --git a/dgl/Application.hpp b/dgl/Application.hpp index ee11db3c..3d574ca0 100644 --- a/dgl/Application.hpp +++ b/dgl/Application.hpp @@ -38,7 +38,7 @@ public: Constructor. */ // NOTE: the default value is not yet passed, so we catch where we use this - Application(bool isStandalone /* = true */); + Application(bool isStandalone = true); /** Destructor. diff --git a/dgl/Cairo.hpp b/dgl/Cairo.hpp index a234b009..9a896ec7 100644 --- a/dgl/Cairo.hpp +++ b/dgl/Cairo.hpp @@ -17,13 +17,14 @@ #ifndef DGL_CAIRO_HPP_INCLUDED #define DGL_CAIRO_HPP_INCLUDED -#include "Base.hpp" +#include "SubWidget.hpp" +#include "TopLevelWidget.hpp" #include START_NAMESPACE_DGL -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- /** Cairo Graphics context. @@ -33,7 +34,49 @@ struct CairoGraphicsContext : GraphicsContext cairo_t* handle; }; -// ----------------------------------------------------------------------- +/** + Cairo SubWidget, handy class that takes graphics context during onDisplay and passes it in a new function. + */ +class CairoSubWidget : public SubWidget +{ +public: + CairoSubWidget(Widget* widgetToGroupTo) + : SubWidget(widgetToGroupTo) {} + +protected: + void onDisplay() override + { + const CairoGraphicsContext& context((const CairoGraphicsContext&)getGraphicsContext()); + onCairoDisplay(context); + } + + virtual void onCairoDisplay(const CairoGraphicsContext& context) = 0; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CairoSubWidget); +}; + +/** + Cairo TopLevelWidget, handy class that takes graphics context during onDisplay and passes it in a new function. + */ +class CairoTopLevelWidget : public TopLevelWidget +{ +public: + CairoTopLevelWidget(Window& windowToMapTo) + : TopLevelWidget(windowToMapTo) {} + +protected: + void onDisplay() override + { + const CairoGraphicsContext& context((const CairoGraphicsContext&)getGraphicsContext()); + onCairoDisplay(context); + } + + virtual void onCairoDisplay(const CairoGraphicsContext& context) = 0; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CairoTopLevelWidget); +}; + +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/StandaloneWindow.hpp b/dgl/StandaloneWindow.hpp index 3bdfec5a..a788dfb0 100644 --- a/dgl/StandaloneWindow.hpp +++ b/dgl/StandaloneWindow.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -17,7 +17,6 @@ #ifndef DGL_STANDALONE_WINDOW_HPP_INCLUDED #define DGL_STANDALONE_WINDOW_HPP_INCLUDED -#include "Application.hpp" #include "TopLevelWidget.hpp" #include "Window.hpp" @@ -25,33 +24,54 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -class StandaloneWindow : public Application, - public Window +class StandaloneWindow : public Window, + public TopLevelWidget { public: /** Constructor. */ - StandaloneWindow(); + StandaloneWindow(Application& app) + : Window(app), + TopLevelWidget((Window&)*this) {} /** - Show window and execute application. + Overloaded functions to ensure they apply to the Window class. */ - void exec(); + bool isVisible() const noexcept { return Window::isVisible(); } + void setVisible(bool yesNo) { Window::setVisible(yesNo); } + void hide() { Window::hide(); } + void show() { Window::show(); } + uint getWidth() const noexcept { return Window::getWidth(); } + uint getHeight() const noexcept { return Window::getHeight(); } + const Size getSize() const noexcept { return Window::getSize(); } -private: - TopLevelWidget* fWidget; + /** + Overloaded functions to ensure size changes apply on both TopLevelWidget and Window classes. + */ + void setWidth(uint width) + { + TopLevelWidget::setWidth(width); + Window::setWidth(width); + } - /** @internal */ - void onReshape(uint width, uint height) override; + void setHeight(uint height) + { + TopLevelWidget::setHeight(height); + Window::setHeight(height); + } -#if 0 - /** @internal */ - void _addWidget(TopLevelWidget* widget) override; + void setSize(uint width, uint height) + { + TopLevelWidget::setSize(width, height); + Window::setSize(width, height); + } - /** @internal */ - void _removeWidget(TopLevelWidget* widget) override; -#endif + void setSize(const Size& size) + { + TopLevelWidget::setSize(size); + Window::setSize(size); + } DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) }; diff --git a/dgl/TopLevelWidget.hpp b/dgl/TopLevelWidget.hpp index 96f39c73..53773073 100644 --- a/dgl/TopLevelWidget.hpp +++ b/dgl/TopLevelWidget.hpp @@ -52,18 +52,10 @@ public: protected: /** - A function called before any draw operations begin (in the current event-loop cycle). - Can be used to setup any resources for needed drawing. - The default implementation simply paints the full Widget contents black. + A function called to draw the widget contents. + Reimplemented from Widget::onDisplay. */ - virtual void onDisplayBefore(); - - /** - A function called after all draw operations have ended (in the current event-loop cycle). - Can be used to clear any resources setup during onDisplayBefore(). - The default implementation does nothing. - */ - virtual void onDisplayAfter(); + void onDisplay() override; /** A function called when the widget is resized. diff --git a/dgl/Widget.hpp b/dgl/Widget.hpp index 31cca833..07fe4eb1 100644 --- a/dgl/Widget.hpp +++ b/dgl/Widget.hpp @@ -30,11 +30,11 @@ START_NAMESPACE_DGL -// class Application; +class Application; // class NanoWidget; // class Window; // class StandaloneWindow; -// class SubWidget; +class SubWidget; class TopLevelWidget; using namespace Events; @@ -46,26 +46,31 @@ using namespace Events; This is the base Widget class, from which all widgets are built. - All widgets have a parent Window where they'll be drawn. - This parent is never changed during the widget lifetime. + All widgets have a parent widget where they'll be drawn, this can be the top-level widget or a group widget. + This parent is never changed during a widget's lifetime. - Widgets receive events in relative coordinates. - (0, 0) means its top-left position. + Widgets receive events in relative coordinates. (0, 0) means its top-left position. - Windows paint widgets in the order they are constructed. - Early widgets are drawn first, at the bottom, then newer ones on top. - Events are sent in the inverse order so that the top-most widget gets + The top-level widget will draw subwidgets in the order they are constructed. + Early subwidgets are drawn first, at the bottom, then newer ones on top. + Events are sent in the inverse order so that the top-most widgets get a chance to catch the event and stop its propagation. - All widget event callbacks do nothing by default. + All widget event callbacks do nothing by default and onDisplay MUST be reimplemented by subclasses. + + @note It is not possible to subclass this Widget class directly, you must use SubWidget or TopLevelWidget instead. */ class Widget { /** - Constructor, reserved for DGL .. - use TopLevelWidget or SubWidget instead + Private constructor, reserved for SubWidget class. + */ + explicit Widget(Widget* widgetToGroupTo); + + /** + Private constructor, reserved for TopLevelWidget class. */ - explicit Widget(TopLevelWidget& topLevelWidget); + explicit Widget(TopLevelWidget* topLevelWidget); public: /** @@ -109,7 +114,7 @@ public: /** Get size. */ - const Size& getSize() const noexcept; + const Size getSize() const noexcept; /** Set width. @@ -131,17 +136,6 @@ public: */ void setSize(const Size& size) noexcept; - /** - Get top-level widget, as passed in the constructor. - */ - TopLevelWidget& getTopLevelWidget() const noexcept; - - /** - Tell this widget's window to repaint itself. - FIXME better description, partial redraw - */ - void repaint() noexcept; - /** Get the Id associated with this widget. @see setId @@ -154,9 +148,35 @@ public: */ void setId(uint id) noexcept; + /** + Get the application associated with this widget's window. + This is the same as calling `getTopLevelWidget()->getApp()`. + */ + Application& getApp() const noexcept; + + /** + Get the graphics context associated with this widget. + GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable, + for example GraphicsContext. + @see CairoSubWidget, CairoTopLevelWidget + */ + const GraphicsContext& getGraphicsContext() const noexcept; + + /** + Get top-level widget, as passed directly in the constructor + or going up the chain of group widgets until it finds the top-level widget. + */ + TopLevelWidget* getTopLevelWidget() const noexcept; + + /** + Tell this widget's window to repaint itself. + FIXME better description, partial redraw + */ + void repaint() noexcept; + protected: /** - A function called to draw the view contents with OpenGL. + A function called to draw the widget contents. */ virtual void onDisplay() = 0; @@ -208,6 +228,7 @@ private: // friend class NanoWidget; // friend class Window; // friend class StandaloneWindow; + friend class SubWidget; friend class TopLevelWidget; // #ifdef DISTRHO_DEFINES_H_INCLUDED // friend class DISTRHO_NAMESPACE::UI; diff --git a/dgl/Window.hpp b/dgl/Window.hpp index 0868f7be..bb039b6e 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -22,6 +22,7 @@ START_NAMESPACE_DGL class Application; +class TopLevelWidget; // ----------------------------------------------------------------------- @@ -151,6 +152,11 @@ public: const char* getTitle() const noexcept; void setTitle(const char* title); + /** + Get the application associated with this window. + */ + Application& getApp() const noexcept; + /** Get the "native" window handle. Returned value depends on the platform: @@ -161,10 +167,18 @@ public: */ uintptr_t getNativeWindowHandle() const noexcept; +protected: + /** + A function called when the window is resized. + If there is a top-level widget associated with this window, its size will be set right after this function. + */ + virtual void onReshape(uint width, uint height); + private: struct PrivateData; PrivateData* const pData; friend class Application; + friend class TopLevelWidget; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); }; @@ -251,11 +265,6 @@ END_NAMESPACE_DGL double getScaling() const noexcept; -#if 0 - // should this be removed? - Application& getApp() const noexcept; -#endif - const GraphicsContext& getGraphicsContext() const noexcept; void addIdleCallback(IdleCallback* const callback); diff --git a/dgl/src/Cairo.cpp b/dgl/src/Cairo.cpp index ac9fff5c..2c1f60d4 100644 --- a/dgl/src/Cairo.cpp +++ b/dgl/src/Cairo.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "../Geometry.hpp" #include "../Cairo.hpp" +#include "WidgetPrivateData.hpp" START_NAMESPACE_DGL @@ -63,49 +63,28 @@ void Rectangle::_draw(const bool outline) } // ----------------------------------------------------------------------- -// Possible template data types - -template class Point; -template class Point; -template class Point; -template class Point; -template class Point; -template class Point; - -template class Size; -template class Size; -template class Size; -template class Size; -template class Size; -template class Size; - -template class Line; -template class Line; -template class Line; -template class Line; -template class Line; -template class Line; - -template class Circle; -template class Circle; -template class Circle; -template class Circle; -template class Circle; -template class Circle; - -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; - -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; + +void Widget::PrivateData::display(const uint width, + const uint height, + const double scaling, + const bool renderingSubWidget) +{ + if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) + return; + + cairo_t* cr = static_cast(parent.getGraphicsContext()).cairo; + cairo_matrix_t matrix; + cairo_get_matrix(cr, &matrix); + cairo_translate(cr, absolutePos.getX(), absolutePos.getY()); + // TODO: scaling and cropping + + // display widget + self->onDisplay(); + + cairo_set_matrix(cr, &matrix); + + displaySubWidgets(width, height, scaling); +} // ----------------------------------------------------------------------- diff --git a/dgl/src/OpenGL.cpp b/dgl/src/OpenGL.cpp index 25a38619..6d3c5bb9 100644 --- a/dgl/src/OpenGL.cpp +++ b/dgl/src/OpenGL.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -14,8 +14,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "../Geometry.hpp" #include "../OpenGL.hpp" +#include "WidgetPrivateData.hpp" START_NAMESPACE_DGL @@ -108,49 +108,65 @@ void Rectangle::_draw(const bool outline) } // ----------------------------------------------------------------------- -// Possible template data types - -template class Point; -template class Point; -template class Point; -template class Point; -template class Point; -template class Point; - -template class Size; -template class Size; -template class Size; -template class Size; -template class Size; -template class Size; - -template class Line; -template class Line; -template class Line; -template class Line; -template class Line; -template class Line; - -template class Circle; -template class Circle; -template class Circle; -template class Circle; -template class Circle; -template class Circle; - -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; -template class Triangle; - -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; -template class Rectangle; + +void Widget::PrivateData::display(const uint width, + const uint height, + const double scaling, + const bool renderingSubWidget) +{ + if (/*(skipDisplay && ! renderingSubWidget) ||*/ size.isInvalid() || ! visible) + return; + +// bool needsDisableScissor = false; + + // reset color + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + +// if (needsFullViewport || (absolutePos.isZero() && size == Size(width, height))) + { + // full viewport size + glViewport(0, + -(height * scaling - height), + width * scaling, + height * scaling); + } +// else if (needsScaling) +// { +// // limit viewport to widget bounds +// glViewport(absolutePos.getX(), +// height - self->getHeight() - absolutePos.getY(), +// self->getWidth(), +// self->getHeight()); +// } +// else +// { +// // only set viewport pos +// glViewport(absolutePos.getX() * scaling, +// -std::round((height * scaling - height) + (absolutePos.getY() * scaling)), +// std::round(width * scaling), +// std::round(height * scaling)); +// +// // then cut the outer bounds +// glScissor(absolutePos.getX() * scaling, +// height - std::round((self->getHeight() + absolutePos.getY()) * scaling), +// std::round(self->getWidth() * scaling), +// std::round(self->getHeight() * scaling)); +// +// glEnable(GL_SCISSOR_TEST); +// needsDisableScissor = true; +// } + + // display widget + self->onDisplay(); + +// if (needsDisableScissor) +// { +// glDisable(GL_SCISSOR_TEST); +// needsDisableScissor = false; +// } + + displaySubWidgets(width, height, scaling); +} // ----------------------------------------------------------------------- diff --git a/dgl/src/StandaloneWindow.cpp b/dgl/src/StandaloneWindow.cpp index 735acd04..6de8a291 100644 --- a/dgl/src/StandaloneWindow.cpp +++ b/dgl/src/StandaloneWindow.cpp @@ -15,16 +15,15 @@ */ #include "../StandaloneWindow.hpp" -#include "WidgetPrivateData.hpp" +#include "../TopLevelWidget.hpp" START_NAMESPACE_DGL // ----------------------------------------------------------------------- -StandaloneWindow::StandaloneWindow() - : Application(true), - Window((Application&)*this), - fWidget(nullptr) {} +StandaloneWindow::StandaloneWindow(Application& app) + : Window(app), + TopLevelWidget(this) {} void StandaloneWindow::exec() { diff --git a/dgl/src/SubWidget.cpp b/dgl/src/SubWidget.cpp index f7934d75..7a4838b6 100644 --- a/dgl/src/SubWidget.cpp +++ b/dgl/src/SubWidget.cpp @@ -15,9 +15,15 @@ */ #include "SubWidgetPrivateData.hpp" +#include "../TopLevelWidget.hpp" + +START_NAMESPACE_DGL + +// -------------------------------------------------------------------------------------------------------------------- SubWidget::SubWidget(Widget* const widgetToGroupTo) - : pData(new PrivateData(this, widgetToGroupTo)) {} + : Widget(widgetToGroupTo), + pData(new PrivateData(this, widgetToGroupTo)) {} SubWidget::~SubWidget() { @@ -79,9 +85,14 @@ void SubWidget::setAbsolutePos(const Point& pos) noexcept pData->absolutePos = pos; onPositionChanged(ev); - getTopLevelWidget().repaint(); + // repaint the whole thing + pData->parent->repaint(); } void SubWidget::onPositionChanged(const PositionChangedEvent&) { } + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DGL diff --git a/dgl/src/SubWidgetPrivateData.hpp b/dgl/src/SubWidgetPrivateData.hpp index fb9d490b..12b893ab 100644 --- a/dgl/src/SubWidgetPrivateData.hpp +++ b/dgl/src/SubWidgetPrivateData.hpp @@ -18,31 +18,25 @@ #define DGL_SUBWIDGET_PRIVATE_DATA_HPP_INCLUDED #include "../SubWidget.hpp" -#include "../WidgetPrivateData.hpp" - -#include START_NAMESPACE_DGL -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- struct SubWidget::PrivateData { SubWidget* const self; - Widget* const groupWidget; + Widget* const parent; Point absolutePos; - PrivateData(SubWidget* const s, Widget* const g) + PrivateData(SubWidget* const s, Widget* const p) : self(s), - groupWidget(g), - absolutePos() - { - groupWidget->pData->subWidgets.push_back(self); - } + parent(p), + absolutePos() {} - DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) }; -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/src/TopLevelWidget.cpp b/dgl/src/TopLevelWidget.cpp index 59525400..2a862243 100644 --- a/dgl/src/TopLevelWidget.cpp +++ b/dgl/src/TopLevelWidget.cpp @@ -15,14 +15,14 @@ */ #include "TopLevelWidgetPrivateData.hpp" -#include "pugl.hpp" +// #include "pugl.hpp" START_NAMESPACE_DGL // ----------------------------------------------------------------------- TopLevelWidget::TopLevelWidget(Window& windowToMapTo) - : Widget(*this), + : Widget(this), pData(new PrivateData(this, windowToMapTo)) {} TopLevelWidget::~TopLevelWidget() @@ -30,16 +30,14 @@ TopLevelWidget::~TopLevelWidget() delete pData; } -void TopLevelWidget::onDisplayBefore() -{ -} - -void TopLevelWidget::onDisplayAfter() +void TopLevelWidget::onDisplay() { + pData->display(); } void TopLevelWidget::onResize(const ResizeEvent& ev) { + pData->resize(ev.size.getWidth(), ev.size.getHeight()); Widget::onResize(ev); } diff --git a/dgl/src/TopLevelWidgetPrivateData.cpp b/dgl/src/TopLevelWidgetPrivateData.cpp index 5c20e7ad..85df0f68 100644 --- a/dgl/src/TopLevelWidgetPrivateData.cpp +++ b/dgl/src/TopLevelWidgetPrivateData.cpp @@ -15,16 +15,17 @@ */ #include "TopLevelWidgetPrivateData.hpp" -#include "../Window.hpp" -// #include "pugl.hpp" +#include "WidgetPrivateData.hpp" +#include "WindowPrivateData.hpp" +#include "pugl.hpp" START_NAMESPACE_DGL #define FOR_EACH_WIDGET(it) \ - for (std::list::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it) + for (std::list::iterator it = widgets.begin(); it != widgets.end(); ++it) #define FOR_EACH_WIDGET_INV(rit) \ - for (std::list::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit) + for (std::list::reverse_iterator rit = widgets.rbegin(); rit != widgets.rend(); ++rit) // ----------------------------------------------------------------------- @@ -35,17 +36,20 @@ TopLevelWidget::PrivateData::PrivateData(TopLevelWidget* const s, Window& w) void TopLevelWidget::PrivateData::display() { + puglFallbackOnDisplay(window.pData->view); + if (widgets.size() == 0) return; const Size size(window.getSize()); -// const int width = rect.width; -// const int height = rect.height; + const uint width = size.getWidth(); + const uint height = size.getHeight(); + const double scaling = window.pData->autoScaling; FOR_EACH_WIDGET(it) { Widget* const widget(*it); - widget->pData->display(width, height, fAutoScaling, false); + widget->pData->display(width, height, scaling, false); } } @@ -53,14 +57,14 @@ void TopLevelWidget::PrivateData::resize(const uint width, const uint height) { if (widgets.size() == 0) return; - +/* FOR_EACH_WIDGET(it) { Widget* const widget(*it); if (widget->pData->needsFullViewport) widget->setSize(width, height); - } + }*/ } // ----------------------------------------------------------------------- diff --git a/dgl/src/Widget.cpp b/dgl/src/Widget.cpp index 3ad64d70..c331b021 100644 --- a/dgl/src/Widget.cpp +++ b/dgl/src/Widget.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -21,8 +21,11 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- // Widget -Widget::Widget(TopLevelWidget& tlw) - : pData(new PrivateData(this, tlw)) {} +Widget::Widget(Widget* const widgetToGroupTo) + : pData(new PrivateData(this, widgetToGroupTo)) {} + +Widget::Widget(TopLevelWidget* const topLevelWidget) + : pData(new PrivateData(this, topLevelWidget)) {} Widget::~Widget() { @@ -40,7 +43,7 @@ void Widget::setVisible(bool yesNo) return; pData->visible = yesNo; - pData->topLevelWidget.repaint(); + repaint(); } void Widget::show() @@ -63,7 +66,7 @@ uint Widget::getHeight() const noexcept return pData->size.getHeight(); } -const Size& Widget::getSize() const noexcept +const Size Widget::getSize() const noexcept { return pData->size; } @@ -80,7 +83,7 @@ void Widget::setWidth(uint width) noexcept pData->size.setWidth(width); onResize(ev); - pData->topLevelWidget.repaint(); + pData->repaint(); } void Widget::setHeight(uint height) noexcept @@ -95,7 +98,7 @@ void Widget::setHeight(uint height) noexcept pData->size.setHeight(height); onResize(ev); - pData->topLevelWidget.repaint(); + pData->repaint(); } void Widget::setSize(uint width, uint height) noexcept @@ -115,17 +118,15 @@ void Widget::setSize(const Size& size) noexcept pData->size = size; onResize(ev); - pData->topLevelWidget.repaint(); + pData->repaint(); } -#if 0 -Application& Widget::getParentApp() const noexcept +Application& Widget::getApp() const noexcept { - return pData->parent.getApp(); + return pData->topLevelWidget->getApp(); } -#endif -TopLevelWidget& Widget::getTopLevelWidget() const noexcept +TopLevelWidget* Widget::getTopLevelWidget() const noexcept { return pData->topLevelWidget; } diff --git a/dgl/src/WidgetPrivateData.cpp b/dgl/src/WidgetPrivateData.cpp index b28bf176..73f493c2 100644 --- a/dgl/src/WidgetPrivateData.cpp +++ b/dgl/src/WidgetPrivateData.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -15,6 +15,7 @@ */ #include "WidgetPrivateData.hpp" +#include "../TopLevelWidget.hpp" #ifdef DGL_CAIRO # include "../Cairo.hpp" @@ -27,79 +28,67 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -void Widget::PrivateData::display(const uint width, - const uint height, - const double scaling, - const bool renderingSubWidget) +Widget::PrivateData::PrivateData(Widget* const s, TopLevelWidget* const tlw) + : self(s), + topLevelWidget(tlw), + groupWidget(nullptr), + id(0), + needsScaling(false), + visible(true), + size(0, 0), + subWidgets() { - if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) - return; +} -#ifdef DGL_OPENGL - bool needsDisableScissor = false; +Widget::PrivateData::PrivateData(Widget* const s, Widget* const g) + : self(s), + topLevelWidget(findTopLevelWidget(g)), + groupWidget(g), + id(0), + needsScaling(false), + visible(true), + size(0, 0), + subWidgets() +{ + groupWidget->pData->subWidgets.push_back(self); +} - // reset color - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +Widget::PrivateData::~PrivateData() +{ + if (groupWidget != nullptr) + groupWidget->pData->subWidgets.remove(self); - if (needsFullViewport || (absolutePos.isZero() && size == Size(width, height))) - { - // full viewport size - glViewport(0, - -(height * scaling - height), - width * scaling, - height * scaling); - } - else if (needsScaling) - { - // limit viewport to widget bounds - glViewport(absolutePos.getX(), - height - self->getHeight() - absolutePos.getY(), - self->getWidth(), - self->getHeight()); - } - else - { - // only set viewport pos - glViewport(absolutePos.getX() * scaling, - -std::round((height * scaling - height) + (absolutePos.getY() * scaling)), - std::round(width * scaling), - std::round(height * scaling)); + subWidgets.clear(); +} - // then cut the outer bounds - glScissor(absolutePos.getX() * scaling, - height - std::round((self->getHeight() + absolutePos.getY()) * scaling), - std::round(self->getWidth() * scaling), - std::round(self->getHeight() * scaling)); +void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, const double scaling) +{ + for (std::list::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) + { + Widget* const widget(*it); + DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); - glEnable(GL_SCISSOR_TEST); - needsDisableScissor = true; + widget->pData->display(width, height, scaling, true); } -#endif - -#ifdef DGL_CAIRO - cairo_t* cr = static_cast(parent.getGraphicsContext()).cairo; - cairo_matrix_t matrix; - cairo_get_matrix(cr, &matrix); - cairo_translate(cr, absolutePos.getX(), absolutePos.getY()); - // TODO: scaling and cropping -#endif - - // display widget - self->onDisplay(); +} -#ifdef DGL_CAIRO - cairo_set_matrix(cr, &matrix); -#endif +void Widget::PrivateData::repaint() +{ + if (groupWidget != nullptr) + groupWidget->repaint(); + else if (topLevelWidget != nullptr) + topLevelWidget->repaint(); +} -#ifdef DGL_OPENGL - if (needsDisableScissor) - { - glDisable(GL_SCISSOR_TEST); - needsDisableScissor = false; - } -#endif +// ----------------------------------------------------------------------- - displaySubWidgets(width, height, scaling); +TopLevelWidget* Widget::PrivateData::findTopLevelWidget(Widget* const w) +{ + if (w->pData->topLevelWidget != nullptr) + return w->pData->topLevelWidget; + if (w->pData->groupWidget != nullptr) + return findTopLevelWidget(w->pData->groupWidget); + return nullptr; } // ----------------------------------------------------------------------- diff --git a/dgl/src/WidgetPrivateData.hpp b/dgl/src/WidgetPrivateData.hpp index 1007eafd..7df7a623 100644 --- a/dgl/src/WidgetPrivateData.hpp +++ b/dgl/src/WidgetPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * 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 @@ -17,61 +17,41 @@ #ifndef DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED #define DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED -#include "../TopLevelWidget.hpp" -#include "../Window.hpp" +#include "../Widget.hpp" -#include +#include START_NAMESPACE_DGL -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- struct Widget::PrivateData { Widget* const self; - Size size; - std::vector subWidgets; - TopLevelWidget& topLevelWidget; - + TopLevelWidget* const topLevelWidget; + Widget* const groupWidget; uint id; bool needsScaling; bool visible; + Size size; + std::list subWidgets; - PrivateData(Widget* const s, TopLevelWidget& tlw) - : self(s), - size(0, 0), - subWidgets(), - topLevelWidget(tlw), - id(0), - needsScaling(false), - visible(true) - { -// parent._addWidget(self); - } - - ~PrivateData() - { -// parent._removeWidget(self); - subWidgets.clear(); - } + PrivateData(Widget* const s, TopLevelWidget* const tlw); + PrivateData(Widget* const s, Widget* const g); + ~PrivateData(); - // display function is different depending on build type + // NOTE display function is different depending on build type void display(const uint width, const uint height, const double scaling, const bool renderingSubWidget); - void displaySubWidgets(const uint width, const uint height, const double scaling) - { - for (std::vector::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) - { - Widget* const widget(*it); - DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); + void displaySubWidgets(const uint width, const uint height, const double scaling); + + void repaint(); - widget->pData->display(width, height, scaling, true); - } - } + static TopLevelWidget* findTopLevelWidget(Widget* const w); - DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) }; -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index cade10cd..096f580c 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -27,7 +27,7 @@ START_NAMESPACE_DGL // : pData(new PrivateData(transientParentWindow.pData->fAppData, this, transientParentWindow)) {} Window::Window(Application& app) - : pData(new PrivateData(app.pData, this)) {} + : pData(new PrivateData(app, this)) {} Window::Window(Application& app, const uintptr_t parentWindowHandle, @@ -35,7 +35,7 @@ Window::Window(Application& app, const uint height, const double scaling, const bool resizable) - : pData(new PrivateData(app.pData, this, parentWindowHandle, width, height, scaling, resizable)) {} + : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaling, resizable)) {} Window::~Window() { @@ -123,11 +123,21 @@ void Window::setTitle(const char* const title) puglSetWindowTitle(pData->view, title); } +Application& Window::getApp() const noexcept +{ + return pData->app; +} + uintptr_t Window::getNativeWindowHandle() const noexcept { return puglGetNativeWindow(pData->view); } +void Window::onReshape(const uint width, const uint height) +{ + puglFallbackOnResize(pData->view); +} + #if 0 #if 0 void Window::exec(bool lockWait) diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index 72d891f0..8735541e 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -40,8 +40,9 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s) - : appData(a), +Window::PrivateData::PrivateData(Application& a, Window* const s) + : app(a), + appData(a.pData), self(s), view(puglNewView(appData->world)), topLevelWidget(nullptr), @@ -52,31 +53,37 @@ Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* cons init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); } -Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s, Window& transientWindow) - : appData(a), +Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transientWindow) + : app(a), + appData(a.pData), self(s), view(puglNewView(appData->world)), topLevelWidget(nullptr), isClosed(true), isVisible(false), - isEmbed(false) + isEmbed(false), + scaling(1.0), + autoScaling(1.0) { init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); puglSetTransientFor(view, transientWindow.getNativeWindowHandle()); } -Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s, +Window::PrivateData::PrivateData(Application& a, Window* const s, const uintptr_t parentWindowHandle, const uint width, const uint height, - const double scaling, const bool resizable) - : appData(a), + const double scale, const bool resizable) + : app(a), + appData(a.pData), self(s), view(puglNewView(appData->world)), topLevelWidget(nullptr), isClosed(parentWindowHandle == 0), isVisible(parentWindowHandle != 0), - isEmbed(parentWindowHandle != 0) + isEmbed(parentWindowHandle != 0), + scaling(scale), + autoScaling(1.0) { init(width, height, resizable); @@ -257,9 +264,7 @@ void Window::PrivateData::onPuglDisplay() #ifndef DPF_TEST_WINDOW_CPP if (topLevelWidget != nullptr) { - topLevelWidget->onDisplayBefore(); topLevelWidget->onDisplay(); - topLevelWidget->onDisplayAfter(); } else #endif @@ -274,12 +279,12 @@ void Window::PrivateData::onPuglReshape(const int width, const int height) DGL_DBGp("PUGL: onReshape : %i %i\n", width, height); + self->onReshape(width, height); + #ifndef DPF_TEST_WINDOW_CPP if (topLevelWidget != nullptr) topLevelWidget->setSize(width, height); - else #endif - puglFallbackOnResize(view); } static int printEvent(const PuglEvent* event, const char* prefix, const bool verbose); diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index 8f47cebb..0c626d52 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -29,13 +29,13 @@ class TopLevelWidget; // ----------------------------------------------------------------------- struct Window::PrivateData : IdleCallback { - /** Handy typedef for ... */ - typedef Application::PrivateData AppData; + /* Reference to the DGL Application class this (private data) window associates with. */ + Application& app; - /** Direct access to DGL Application private data where we registers ourselves in. */ - AppData* const appData; + /** Direct access to the DGL Application private data where we registers ourselves in. */ + Application::PrivateData* const appData; - /** Pointer to the DGL Window class that this private data belongs to. */ + /** Pointer to the the DGL Window class that this private data belongs to. */ Window* const self; /** Pugl view instance. */ @@ -57,14 +57,20 @@ struct Window::PrivateData : IdleCallback { /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ const bool isEmbed; + /** Scaling to report to widgets on request, purely informational. */ + double scaling; + + /** Automatic scaling to apply on widgets, implemented internally. */ + double autoScaling; + /** Constructor for a regular, standalone window. */ - PrivateData(AppData* appData, Window* self); + PrivateData(Application& app, Window* self); /** Constructor for a regular, standalone window with a transient parent. */ - PrivateData(AppData* appData, Window* self, Window& transientWindow); + PrivateData(Application& app, Window* self, Window& transientWindow); /** Constructor for an embed Window, with a few extra hints from the host side. */ - PrivateData(AppData* appData, Window* self, uintptr_t parentWindowHandle, + PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, uint width, uint height, double scaling, bool resizable); /** Destructor. */ diff --git a/tests/Demo.cpp b/tests/Demo.cpp new file mode 100644 index 00000000..e484e3e9 --- /dev/null +++ b/tests/Demo.cpp @@ -0,0 +1,198 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 Filipe Coelho + * + * 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_OPENGL +#error OpenGL build required for Demo +#endif + +#include "tests.hpp" + +// #define DPF_TEST_POINT_CPP +#include "dgl/src/pugl.cpp" +// #include "dgl/src/SubWidget.cpp" +#include "dgl/src/Application.cpp" +#include "dgl/src/ApplicationPrivateData.cpp" +#include "dgl/src/Geometry.cpp" +#include "dgl/src/OpenGL.cpp" +#include "dgl/src/SubWidget.cpp" +#include "dgl/src/TopLevelWidget.cpp" +#include "dgl/src/TopLevelWidgetPrivateData.cpp" +#include "dgl/src/Widget.cpp" +#include "dgl/src/WidgetPrivateData.cpp" +#include "dgl/src/Window.cpp" +#include "dgl/src/WindowPrivateData.cpp" +#include "dgl/StandaloneWindow.hpp" + +#include "widgets/ExampleColorWidget.hpp" + +START_NAMESPACE_DGL + +// -------------------------------------------------------------------------------------------------------------------- + +// ------------------------------------------------------ +// Left side tab-like widget + +class LeftSideWidget : public SubWidget +{ +public: + static const int kPageCount = 5; + + class Callback + { + public: + virtual ~Callback() {} + virtual void curPageChanged(int curPage) = 0; + }; + + LeftSideWidget(Widget* parent, Callback* const cb) + : SubWidget(parent), + callback(cb), + curPage(0), + curHover(-1) + { + // for text +// font = nvg.createFontFromFile("sans", "./nanovg_res/Roboto-Regular.ttf"); + +// using namespace DemoArtwork; +// img1.loadFromMemory(ico1Data, ico1Width, ico1Height, GL_BGR); +// img2.loadFromMemory(ico2Data, ico2Width, ico2Height, GL_BGR); +// img3.loadFromMemory(ico3Data, ico3Width, ico2Height, GL_BGR); +// img4.loadFromMemory(ico4Data, ico4Width, ico4Height, GL_BGR); +// img5.loadFromMemory(ico5Data, ico5Width, ico5Height, GL_BGR); + } + +private: + Callback* const callback; + int curPage, curHover; +// Rectangle bgIcon; +// Line lineSep; +// Image img1, img2, img3, img4, img5; + + // for text +// NanoVG nvg; +// NanoVG::FontId font; +}; + +// ------------------------------------------------------ +// Our Demo Window + +class DemoWindow : public StandaloneWindow, + public LeftSideWidget::Callback +{ + static const int kSidebarWidth = 81; + + ExampleColorWidget wColor; + Widget* curWidget; + +public: + DemoWindow(Application& app) + : StandaloneWindow(app), + wColor(this), + curWidget(nullptr) + { + wColor.hide(); +// wImages.hide(); +// wRects.hide(); +// wShapes.hide(); +// wText.hide(); +// //wPerf.hide(); + + wColor.setAbsoluteX(kSidebarWidth); +// wImages.setAbsoluteX(kSidebarWidth); +// wRects.setAbsoluteX(kSidebarWidth); +// wShapes.setAbsoluteX(kSidebarWidth); +// wText.setAbsoluteX(kSidebarWidth); +// wLeft.setAbsolutePos(2, 2); +// wPerf.setAbsoluteY(5); + + setSize(600, 500); + setTitle("DGL Demo"); + + curPageChanged(0); + } + +protected: + void curPageChanged(int curPage) override + { + if (curWidget != nullptr) + { + curWidget->hide(); + curWidget = nullptr; + } + + switch (curPage) + { + case 0: + curWidget = &wColor; + break; +// case 1: +// curWidget = &wImages; +// break; +// case 2: +// curWidget = &wRects; +// break; +// case 3: +// curWidget = &wShapes; +// break; +// case 4: +// curWidget = &wText; +// break; + } + + if (curWidget != nullptr) + curWidget->show(); + } + + void onReshape(uint width, uint height) override + { + StandaloneWindow::onReshape(width, height); + + if (width < kSidebarWidth) + return; + + Size size(width-kSidebarWidth, height); + wColor.setSize(size); +// wImages.setSize(size); +// wRects.setSize(size); +// wShapes.setSize(size); +// wText.setSize(size); + +// wLeft.setSize(kSidebarWidth-4, height-4); +// //wRezHandle.setAbsoluteX(width-wRezHandle.getWidth()); +// //wRezHandle.setAbsoluteY(height-wRezHandle.getHeight()); +// +// wPerf.setAbsoluteX(width-wPerf.getWidth()-5); + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DGL + +int main() +{ + USE_NAMESPACE_DGL; + + Application app; + DemoWindow win(app); + + win.show(); + app.exec(); + + return 0; +} + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/tests/Makefile b/tests/Makefile index 276b3360..93c6e6c5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -25,6 +25,7 @@ ifeq ($(HAVE_CAIRO),true) WTESTS = Window.cairo endif ifeq ($(HAVE_OPENGL),true) +TESTS += Demo WTESTS = Window.opengl endif ifeq ($(HAVE_VULKAN),true) @@ -87,12 +88,17 @@ clean: @echo "Compiling $< (Cairo)" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ +../build/tests/Demo.cpp.o: Demo.cpp + -@mkdir -p ../build/tests + @echo "Compiling $< (OpenGL)" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ + ../build/tests/%.cpp.opengl.o: %.cpp -@mkdir -p ../build/tests @echo "Compiling $< (OpenGL)" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ -../build/tests/%.cpp.vulkan.o: Window.cpp +../build/tests/%.cpp.vulkan.o: %.cpp -@mkdir -p ../build/tests @echo "Compiling $< (Vulkan)" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_VULKAN -c -o $@ @@ -108,6 +114,10 @@ clean: @echo "Linking $*" $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(CAIRO_LIBS) -o $@ +../build/tests/Demo: ../build/tests/Demo.cpp.o + @echo "Linking Demo" + $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ + ../build/tests/%.opengl: ../build/tests/%.cpp.opengl.o @echo "Linking $*" $(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ diff --git a/tests/widgets/ExampleColorWidget.hpp b/tests/widgets/ExampleColorWidget.hpp new file mode 100644 index 00000000..ce35e5e6 --- /dev/null +++ b/tests/widgets/ExampleColorWidget.hpp @@ -0,0 +1,134 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2015 Filipe Coelho + * + * 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 EXAMPLE_COLOR_WIDGET_HPP_INCLUDED +#define EXAMPLE_COLOR_WIDGET_HPP_INCLUDED + +// ------------------------------------------------------ +// DGL Stuff + +#include "../../dgl/SubWidget.hpp" +// #include "Window.hpp" + +START_NAMESPACE_DGL + +// ------------------------------------------------------ +// our widget + +class ExampleColorWidget : public SubWidget, + public IdleCallback +{ +public: + ExampleColorWidget(TopLevelWidget* const topWidget) + : SubWidget(topWidget), + cur('r'), + reverse(false), + r(0), g(0), b(0) + { + setSize(300, 300); + +// groupWidget->getApp().addIdleCallback(this); + } + +protected: + void idleCallback() noexcept override + { + switch (cur) + { + case 'r': + if (reverse) + { + if (--r == 0) + cur = 'g'; + } + else + { + if (++r == 100) + cur = 'g'; + } + break; + + case 'g': + if (reverse) + { + if (--g == 0) + cur = 'b'; + } + else + { + if (++g == 100) + cur = 'b'; + } + break; + + case 'b': + if (reverse) + { + if (--b == 0) + { + cur = 'r'; + reverse = false; + } + } + else + { + if (++b == 100) + { + cur = 'r'; + reverse = true; + } + } + break; + } + + repaint(); + } + + void onDisplay() override + { + // paint bg color (in full size) + glColor3b(r, g, b); + bgFull.draw(); + + // paint inverted color (in 2/3 size) + glColor3b(100-r, 100-g, 100-b); + bgSmall.draw(); + } + + void onResize(const ResizeEvent& ev) override + { + const uint width = ev.size.getWidth(); + const uint height = ev.size.getHeight(); + + // full bg + bgFull = Rectangle(0, 0, width, height); + + // small bg, centered 2/3 size + bgSmall = Rectangle(width/6, height/6, width*2/3, height*2/3); + } + + char cur; + bool reverse; + int r, g, b; + + Rectangle bgFull, bgSmall; +}; + +// ------------------------------------------------------ + +END_NAMESPACE_DGL + +#endif // EXAMPLE_COLOR_WIDGET_HPP_INCLUDED