| @@ -42,7 +42,7 @@ public: | |||||
| Constructor. | Constructor. | ||||
| */ | */ | ||||
| NtkApp() | NtkApp() | ||||
| : fIsRunning(false), | |||||
| : fIsRunning(true), | |||||
| fWindows() | fWindows() | ||||
| { | { | ||||
| static bool initialized = false; | static bool initialized = false; | ||||
| @@ -51,7 +51,9 @@ public: | |||||
| { | { | ||||
| initialized = true; | initialized = true; | ||||
| fl_register_images(); | fl_register_images(); | ||||
| #ifdef DISTRHO_OS_LINUX | |||||
| fl_open_display(); | fl_open_display(); | ||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| @@ -67,7 +69,7 @@ public: | |||||
| /** | /** | ||||
| Idle function. | Idle function. | ||||
| This calls the NTK event-loop once. | |||||
| This calls the NTK event-loop once (and all idle callbacks). | |||||
| */ | */ | ||||
| void idle() | void idle() | ||||
| { | { | ||||
| @@ -115,6 +117,28 @@ private: | |||||
| friend class NtkWindow; | 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) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp) | ||||
| }; | }; | ||||
| @@ -19,8 +19,6 @@ | |||||
| #include "NtkWindow.hpp" | #include "NtkWindow.hpp" | ||||
| #include "../Geometry.hpp" | |||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -29,16 +27,18 @@ START_NAMESPACE_DGL | |||||
| DGL compatible Widget class that uses NTK instead of OpenGL. | DGL compatible Widget class that uses NTK instead of OpenGL. | ||||
| @see Widget | @see Widget | ||||
| */ | */ | ||||
| class NtkWidget : public Fl_Group | |||||
| class NtkWidget : public Fl_Double_Window | |||||
| { | { | ||||
| public: | public: | ||||
| /** | /** | ||||
| Constructor. | Constructor. | ||||
| */ | */ | ||||
| explicit NtkWidget(NtkWindow& parent) | explicit NtkWidget(NtkWindow& parent) | ||||
| : Fl_Group(0, 0, 0, 0), | |||||
| : Fl_Double_Window(100, 100), | |||||
| fParent(parent) | fParent(parent) | ||||
| { | { | ||||
| fParent.add(this); | |||||
| show(); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -46,6 +46,181 @@ public: | |||||
| */ | */ | ||||
| ~NtkWidget() override | ~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<int> getSize() const | |||||
| { | |||||
| return Size<int>(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<int>& 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<int> getAbsolutePos() const | |||||
| { | |||||
| return Point<int>(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<int>& 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<int>& pos) const | |||||
| { | |||||
| return contains(pos.getX(), pos.getY()); | |||||
| } | |||||
| /** | |||||
| Tell this widget's window to repaint itself. | |||||
| */ | |||||
| void repaint() | |||||
| { | |||||
| redraw(); | |||||
| } | } | ||||
| protected: | protected: | ||||
| @@ -19,6 +19,8 @@ | |||||
| #include "NtkApp.hpp" | #include "NtkApp.hpp" | ||||
| #include "../Geometry.hpp" | |||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| class NtkWidget; | class NtkWidget; | ||||
| @@ -31,59 +33,147 @@ public: | |||||
| explicit NtkWindow(NtkApp& app) | explicit NtkWindow(NtkApp& app) | ||||
| : Fl_Double_Window(100, 100), | : Fl_Double_Window(100, 100), | ||||
| fApp(app), | fApp(app), | ||||
| fIsVisible(false), | |||||
| fUsingEmbed(false), | fUsingEmbed(false), | ||||
| fParent(nullptr), | |||||
| fWidgets() {} | |||||
| fParent(nullptr) {} | |||||
| explicit NtkWindow(NtkApp& app, NtkWindow& parent) | explicit NtkWindow(NtkApp& app, NtkWindow& parent) | ||||
| : Fl_Double_Window(100, 100), | : Fl_Double_Window(100, 100), | ||||
| fApp(app), | fApp(app), | ||||
| fIsVisible(false), | |||||
| fUsingEmbed(false), | fUsingEmbed(false), | ||||
| fParent(&parent), | |||||
| fWidgets() {} | |||||
| fParent(&parent) {} | |||||
| explicit NtkWindow(NtkApp& app, intptr_t parentId) | explicit NtkWindow(NtkApp& app, intptr_t parentId) | ||||
| : Fl_Double_Window(100, 100), | : Fl_Double_Window(100, 100), | ||||
| fApp(app), | fApp(app), | ||||
| fIsVisible(parentId != 0), | |||||
| fUsingEmbed(parentId != 0), | fUsingEmbed(parentId != 0), | ||||
| fParent(nullptr), | |||||
| fWidgets() | |||||
| fParent(nullptr) | |||||
| { | { | ||||
| if (fUsingEmbed) | if (fUsingEmbed) | ||||
| { | { | ||||
| fl_embed(this, (Window)parentId); | fl_embed(this, (Window)parentId); | ||||
| Fl_Double_Window::show(); | Fl_Double_Window::show(); | ||||
| fApp.addWindow(this); | |||||
| } | } | ||||
| } | } | ||||
| ~NtkWindow() override | ~NtkWindow() override | ||||
| { | { | ||||
| fWidgets.clear(); | |||||
| if (fUsingEmbed) | if (fUsingEmbed) | ||||
| { | |||||
| fApp.removeWindow(this); | |||||
| Fl_Double_Window::hide(); | Fl_Double_Window::hide(); | ||||
| } | |||||
| } | } | ||||
| void show() | |||||
| void show() override | |||||
| { | { | ||||
| if (fUsingEmbed || fIsVisible) | |||||
| return; | |||||
| Fl_Double_Window::show(); | 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; | 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<uint> getSize() const noexcept | |||||
| { | |||||
| return Size<uint>(w(), h()); | |||||
| } | |||||
| void setSize(uint width, uint height) | |||||
| { | |||||
| resize(x(), y(), width, height); | |||||
| } | |||||
| void setSize(Size<uint> 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,); | 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,); | 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 | #endif | ||||
| } | } | ||||
| NtkApp& getApp() const noexcept | |||||
| { | |||||
| return fApp; | |||||
| } | |||||
| intptr_t getWindowId() const | |||||
| { | |||||
| return (intptr_t)fl_xid(this); | |||||
| } | |||||
| void addIdleCallback(IdleCallback* const callback) | void addIdleCallback(IdleCallback* const callback) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,); | ||||
| @@ -106,12 +196,12 @@ public: | |||||
| private: | private: | ||||
| NtkApp& fApp; | NtkApp& fApp; | ||||
| bool fIsVisible; | |||||
| bool fUsingEmbed; | bool fUsingEmbed; | ||||
| // transient parent, may be null | // transient parent, may be null | ||||
| NtkWindow* const fParent; | NtkWindow* const fParent; | ||||
| std::list<Fl_Group*> fWidgets; | |||||
| std::list<IdleCallback*> fIdleCallbacks; | std::list<IdleCallback*> fIdleCallbacks; | ||||
| friend class NtkWidget; | friend class NtkWidget; | ||||
| @@ -95,7 +95,11 @@ protected: | |||||
| // UI Callbacks (optional) | // UI Callbacks (optional) | ||||
| virtual void d_uiIdle() {} | virtual void d_uiIdle() {} | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| // updates window openGL state | |||||
| virtual void d_uiReshape(int width, int height); | virtual void d_uiReshape(int width, int height); | ||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -106,6 +110,7 @@ private: | |||||
| friend class UIExporterWindow; | friend class UIExporterWindow; | ||||
| // these should not be used | // these should not be used | ||||
| void position(int, int) noexcept {} | |||||
| void setAbsoluteX(int) const noexcept {} | void setAbsoluteX(int) const noexcept {} | ||||
| void setAbsoluteY(int) const noexcept {} | void setAbsoluteY(int) const noexcept {} | ||||
| void setAbsolutePos(int, int) const noexcept {} | void setAbsolutePos(int, int) const noexcept {} | ||||
| @@ -98,9 +98,9 @@ void UI::d_sampleRateChanged(double) {} | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // UI Callbacks (optional) | // UI Callbacks (optional) | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| void UI::d_uiReshape(int width, int height) | void UI::d_uiReshape(int width, int height) | ||||
| { | { | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| glEnable(GL_BLEND); | glEnable(GL_BLEND); | ||||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| glMatrixMode(GL_PROJECTION); | glMatrixMode(GL_PROJECTION); | ||||
| @@ -109,10 +109,8 @@ void UI::d_uiReshape(int width, int height) | |||||
| glViewport(0, 0, width, height); | glViewport(0, 0, width, height); | ||||
| glMatrixMode(GL_MODELVIEW); | glMatrixMode(GL_MODELVIEW); | ||||
| glLoadIdentity(); | glLoadIdentity(); | ||||
| #else | |||||
| (void)width; (void)height; | |||||
| #endif | |||||
| } | } | ||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -157,17 +157,15 @@ public: | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| const int width = fUI->d_getWidth(); | const int width = fUI->d_getWidth(); | ||||
| const int height = fUI->d_getHeight(); | const int height = fUI->d_getHeight(); | ||||
| // set widget size | // set widget size | ||||
| fUI->setSize(width, height); | fUI->setSize(width, height); | ||||
| // set this window size | |||||
| // set window size | |||||
| setResizable(false); | setResizable(false); | ||||
| setSize(width, height); | setSize(width, height); | ||||
| #endif | |||||
| } | } | ||||
| ~UIExporterWindow() | ~UIExporterWindow() | ||||
| @@ -185,8 +183,14 @@ public: | |||||
| return fIsReady; | return fIsReady; | ||||
| } | } | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| protected: | 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 | void onReshape(int width, int height) override | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| @@ -292,7 +296,6 @@ public: | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if ! DISTRHO_UI_USE_NTK | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| void exec(IdleCallback* const cb) | void exec(IdleCallback* const cb) | ||||
| @@ -355,7 +358,6 @@ public: | |||||
| return ! glApp.isQuiting(); | return ! glApp.isQuiting(); | ||||
| } | } | ||||
| #endif | |||||
| void setSampleRate(const double sampleRate, const bool doCallback = false) | void setSampleRate(const double sampleRate, const bool doCallback = false) | ||||
| { | { | ||||