@@ -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) | |||
}; | |||
@@ -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<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: | |||
@@ -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<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,); | |||
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<Fl_Group*> fWidgets; | |||
std::list<IdleCallback*> fIdleCallbacks; | |||
friend class NtkWidget; | |||
@@ -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 {} | |||
@@ -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 | |||
// ----------------------------------------------------------------------- | |||
@@ -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) | |||
{ | |||