diff --git a/dgl/ntk/NtkApp.hpp b/dgl/ntk/NtkApp.hpp index b45b3f66..20d9fdca 100644 --- a/dgl/ntk/NtkApp.hpp +++ b/dgl/ntk/NtkApp.hpp @@ -42,7 +42,7 @@ public: Constructor. */ NtkApp() - : fIsRunning(false), + : fIsRunning(true), fWindows() { static bool initialized = false; @@ -51,7 +51,9 @@ public: { initialized = true; fl_register_images(); +#ifdef DISTRHO_OS_LINUX fl_open_display(); +#endif } } @@ -67,7 +69,7 @@ public: /** Idle function. - This calls the NTK event-loop once. + This calls the NTK event-loop once (and all idle callbacks). */ void idle() { @@ -115,6 +117,28 @@ private: friend class NtkWindow; + /** @internal used by NtkWindow. */ + void addWindow(Fl_Double_Window* const window) + { + DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); + + if (fWindows.size() == 0) + fIsRunning = true; + + fWindows.push_back(window); + } + + /** @internal used by NtkWindow. */ + void removeWindow(Fl_Double_Window* const window) + { + DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); + + fWindows.remove(window); + + if (fWindows.size() == 0) + fIsRunning = false; + } + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp) }; diff --git a/dgl/ntk/NtkWidget.hpp b/dgl/ntk/NtkWidget.hpp index 91603fb8..b11e4e92 100644 --- a/dgl/ntk/NtkWidget.hpp +++ b/dgl/ntk/NtkWidget.hpp @@ -19,8 +19,6 @@ #include "NtkWindow.hpp" -#include "../Geometry.hpp" - START_NAMESPACE_DGL // ----------------------------------------------------------------------- @@ -29,16 +27,18 @@ START_NAMESPACE_DGL DGL compatible Widget class that uses NTK instead of OpenGL. @see Widget */ -class NtkWidget : public Fl_Group +class NtkWidget : public Fl_Double_Window { public: /** Constructor. */ explicit NtkWidget(NtkWindow& parent) - : Fl_Group(0, 0, 0, 0), + : Fl_Double_Window(100, 100), fParent(parent) { + fParent.add(this); + show(); } /** @@ -46,6 +46,181 @@ public: */ ~NtkWidget() override { + hide(); + fParent.remove(this); + } + + /** + Check if this widget is visible within its parent window. + Invisible widgets do not receive events except resize. + */ + bool isVisible() const + { + return visible(); + } + + /** + Set widget visible (or not) according to @a yesNo. + */ + void setVisible(bool yesNo) + { + if (yesNo) + show(); + else + hide(); + } + + /** + Get width. + */ + int getWidth() const + { + return w(); + } + + /** + Get height. + */ + int getHeight() const + { + return h(); + } + + /** + Get size. + */ + Size getSize() const + { + return Size(w(), h()); + } + + /** + Set width. + */ + void setWidth(int width) + { + resize(x(), y(), width, h()); + } + + /** + Set height. + */ + void setHeight(int height) + { + resize(x(), y(), w(), height); + } + + /** + Set size using @a width and @a height values. + */ + void setSize(int width, int height) + { + resize(x(), y(), width, height); + } + + /** + Set size. + */ + void setSize(const Size& size) + { + resize(x(), y(), size.getWidth(), size.getHeight()); + } + + /** + Get absolute X. + */ + int getAbsoluteX() const + { + return x(); + } + + /** + Get absolute Y. + */ + int getAbsoluteY() const + { + return y(); + } + + /** + Get absolute position. + */ + Point getAbsolutePos() const + { + return Point(x(), y()); + } + + /** + Set absolute X. + */ + void setAbsoluteX(int x) + { + resize(x, y(), w(), h()); + } + + /** + Set absolute Y. + */ + void setAbsoluteY(int y) + { + resize(x(), y, w(), h()); + } + + /** + Set absolute position using @a x and @a y values. + */ + void setAbsolutePos(int x, int y) + { + resize(x, y, w(), h()); + } + + /** + Set absolute position. + */ + void setAbsolutePos(const Point& pos) + { + resize(pos.getX(), pos.getY(), w(), h()); + } + + /** + Get this widget's window application. + Same as calling getParentWindow().getApp(). + */ + NtkApp& getParentApp() const noexcept + { + return fParent.getApp(); + } + + /** + Get parent window, as passed in the constructor. + */ + NtkWindow& getParentWindow() const noexcept + { + return fParent; + } + + /** + Check if this widget contains the point defined by @a x and @a y. + */ + bool contains(int x, int y) const + { + return (x >= 0 && y >= 0 && x < w() && y < h()); + } + + /** + Check if this widget contains the point @a pos. + */ + bool contains(const Point& pos) const + { + return contains(pos.getX(), pos.getY()); + } + + /** + Tell this widget's window to repaint itself. + */ + void repaint() + { + redraw(); } protected: diff --git a/dgl/ntk/NtkWindow.hpp b/dgl/ntk/NtkWindow.hpp index 7e4ad95f..81ad45b6 100644 --- a/dgl/ntk/NtkWindow.hpp +++ b/dgl/ntk/NtkWindow.hpp @@ -19,6 +19,8 @@ #include "NtkApp.hpp" +#include "../Geometry.hpp" + START_NAMESPACE_DGL class NtkWidget; @@ -31,59 +33,147 @@ public: explicit NtkWindow(NtkApp& app) : Fl_Double_Window(100, 100), fApp(app), + fIsVisible(false), fUsingEmbed(false), - fParent(nullptr), - fWidgets() {} + fParent(nullptr) {} explicit NtkWindow(NtkApp& app, NtkWindow& parent) : Fl_Double_Window(100, 100), fApp(app), + fIsVisible(false), fUsingEmbed(false), - fParent(&parent), - fWidgets() {} + fParent(&parent) {} explicit NtkWindow(NtkApp& app, intptr_t parentId) : Fl_Double_Window(100, 100), fApp(app), + fIsVisible(parentId != 0), fUsingEmbed(parentId != 0), - fParent(nullptr), - fWidgets() + fParent(nullptr) { if (fUsingEmbed) { fl_embed(this, (Window)parentId); Fl_Double_Window::show(); + fApp.addWindow(this); } } ~NtkWindow() override { - fWidgets.clear(); - if (fUsingEmbed) + { + fApp.removeWindow(this); Fl_Double_Window::hide(); + } } - void show() + void show() override { + if (fUsingEmbed || fIsVisible) + return; + Fl_Double_Window::show(); + fApp.addWindow(this); + fIsVisible = true; -#ifdef DISTRHO_OS_LINUX - if (fParent == nullptr) + if (fParent != nullptr) + setTransientWinId((intptr_t)fl_xid(fParent)); + } + + void hide() override + { + if (fUsingEmbed || ! fIsVisible) return; + fIsVisible = false; + fApp.removeWindow(this); + Fl_Double_Window::hide(); + } + + void close() + { + hide(); + } + + bool isVisible() const + { + return visible(); + } + + void setVisible(bool yesNo) + { + if (yesNo) + show(); + else + hide(); + } + + bool isResizable() const + { + // TODO + return false; + } + + void setResizable(bool /*yesNo*/) + { + // TODO + } + + int getWidth() const noexcept + { + return w(); + } + + int getHeight() const noexcept + { + return h(); + } + + Size getSize() const noexcept + { + return Size(w(), h()); + } + + void setSize(uint width, uint height) + { + resize(x(), y(), width, height); + } + + void setSize(Size size) + { + resize(x(), y(), size.getWidth(), size.getHeight()); + } + + void setTitle(const char* title) + { + label(title); + } + + void setTransientWinId(intptr_t winId) + { + DISTRHO_SAFE_ASSERT_RETURN(winId != 0,); + +#ifdef DISTRHO_OS_LINUX DISTRHO_SAFE_ASSERT_RETURN(fl_display != nullptr,); - const ::Window ourWindow(fl_xid_(this)); + const ::Window ourWindow(fl_xid(this)); DISTRHO_SAFE_ASSERT_RETURN(ourWindow != 0,); - const ::Window parentWindow(fl_xid_(fParent)); - DISTRHO_SAFE_ASSERT_RETURN(parentWindow != 0,); - - XSetTransientForHint(fl_display, ourWindow, parentWindow); + XSetTransientForHint(fl_display, ourWindow, winId); #endif } + NtkApp& getApp() const noexcept + { + return fApp; + } + + intptr_t getWindowId() const + { + return (intptr_t)fl_xid(this); + } + void addIdleCallback(IdleCallback* const callback) { DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,); @@ -106,12 +196,12 @@ public: private: NtkApp& fApp; + bool fIsVisible; bool fUsingEmbed; // transient parent, may be null NtkWindow* const fParent; - std::list fWidgets; std::list fIdleCallbacks; friend class NtkWidget; diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp index 3901067d..7c34f0a0 100644 --- a/distrho/DistrhoUI.hpp +++ b/distrho/DistrhoUI.hpp @@ -95,7 +95,11 @@ protected: // UI Callbacks (optional) virtual void d_uiIdle() {} + +#if ! DISTRHO_UI_USE_NTK + // updates window openGL state virtual void d_uiReshape(int width, int height); +#endif // ------------------------------------------------------------------- @@ -106,6 +110,7 @@ private: friend class UIExporterWindow; // these should not be used + void position(int, int) noexcept {} void setAbsoluteX(int) const noexcept {} void setAbsoluteY(int) const noexcept {} void setAbsolutePos(int, int) const noexcept {} diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index 7d2951ff..1295dc7d 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -98,9 +98,9 @@ void UI::d_sampleRateChanged(double) {} // ----------------------------------------------------------------------- // UI Callbacks (optional) +#if ! DISTRHO_UI_USE_NTK void UI::d_uiReshape(int width, int height) { -#if ! DISTRHO_UI_USE_NTK glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); @@ -109,10 +109,8 @@ void UI::d_uiReshape(int width, int height) glViewport(0, 0, width, height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); -#else - (void)width; (void)height; -#endif } +#endif // ----------------------------------------------------------------------- diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp index 1eaca647..dd114918 100644 --- a/distrho/src/DistrhoUIInternal.hpp +++ b/distrho/src/DistrhoUIInternal.hpp @@ -157,17 +157,15 @@ public: { DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); -#if ! DISTRHO_UI_USE_NTK const int width = fUI->d_getWidth(); const int height = fUI->d_getHeight(); // set widget size fUI->setSize(width, height); - // set this window size + // set window size setResizable(false); setSize(width, height); -#endif } ~UIExporterWindow() @@ -185,8 +183,14 @@ public: return fIsReady; } -#if ! DISTRHO_UI_USE_NTK protected: +#if DISTRHO_UI_USE_NTK + void resize(int x, int y, int width, int height) override + { + UIWindow::resize(x, y, width, height); + fIsReady = true; + } +#else void onReshape(int width, int height) override { DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); @@ -292,7 +296,6 @@ public: } #endif -#if ! DISTRHO_UI_USE_NTK // ------------------------------------------------------------------- void exec(IdleCallback* const cb) @@ -355,7 +358,6 @@ public: return ! glApp.isQuiting(); } -#endif void setSampleRate(const double sampleRate, const bool doCallback = false) {