commit f84486802f8f46648b84fe089d3971a778eca67c
parent 0a3eb0fba0d150c3bbcdf435ece34a0e62923666
Author: falkTX <falktx@gmail.com>
Date: Mon, 16 Feb 2015 15:11:50 +0000
Initial code for file-browser support (X11 only)
Diffstat:
5 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/dgl/Window.hpp b/dgl/Window.hpp
@@ -25,10 +25,48 @@ START_NAMESPACE_DGL
class App;
class Widget;
+class StandaloneWindow;
class Window
{
public:
+ /**
+ File browser options.
+ */
+ struct FileBrowserOptions {
+ const char* startDir;
+ const char* title;
+ uint width;
+ uint height;
+
+ /**
+ File browser buttons.
+
+ 0 means hidden.
+ 1 means visible and unchecked.
+ 2 means visible and checked.
+ */
+ struct Buttons {
+ uint listAllFiles;
+ uint showHidden;
+ uint showPlaces;
+
+ /** Constuctor for default values */
+ Buttons()
+ : listAllFiles(2),
+ showHidden(1),
+ showPlaces(1) {}
+ } buttons;
+
+ /** Constuctor for default values */
+ FileBrowserOptions()
+ : startDir(nullptr),
+ title(nullptr),
+ width(0),
+ height(0),
+ buttons() {}
+ };
+
explicit Window(App& app);
explicit Window(App& app, Window& parent);
explicit Window(App& app, intptr_t parentId);
@@ -42,6 +80,8 @@ public:
void focus();
void repaint() noexcept;
+ bool openFileBrowser(const FileBrowserOptions& options);
+
bool isVisible() const noexcept;
void setVisible(bool yesNo);
@@ -54,6 +94,7 @@ public:
void setSize(uint width, uint height);
void setSize(Size<uint> size);
+ const char* getTitle() const noexcept;
void setTitle(const char* title);
void setTransientWinId(uintptr_t winId);
@@ -70,6 +111,8 @@ protected:
virtual void onReshape(uint width, uint height);
virtual void onClose();
+ virtual void fileBrowserSelected(const char* filename);
+
private:
struct PrivateData;
PrivateData* const pData;
diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp
@@ -20,6 +20,7 @@
#include "AppPrivateData.hpp"
#include "../Widget.hpp"
#include "../Window.hpp"
+#include "../../distrho/extra/d_string.hpp"
#include "pugl/pugl.h"
@@ -69,6 +70,7 @@ struct Window::PrivateData {
fUsingEmbed(false),
fWidth(1),
fHeight(1),
+ fTitle(nullptr),
fWidgets(),
fModal(),
#if defined(DISTRHO_OS_WINDOWS)
@@ -97,6 +99,7 @@ struct Window::PrivateData {
fUsingEmbed(false),
fWidth(1),
fHeight(1),
+ fTitle(nullptr),
fWidgets(),
fModal(parent.pData),
#if defined(DISTRHO_OS_WINDOWS)
@@ -135,6 +138,7 @@ struct Window::PrivateData {
fUsingEmbed(parentId != 0),
fWidth(1),
fHeight(1),
+ fTitle(nullptr),
fWidgets(),
fModal(),
#if defined(DISTRHO_OS_WINDOWS)
@@ -190,6 +194,7 @@ struct Window::PrivateData {
puglSetSpecialFunc(fView, onSpecialCallback);
puglSetReshapeFunc(fView, onReshapeCallback);
puglSetCloseFunc(fView, onCloseCallback);
+ puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback);
puglCreateWindow(fView, nullptr);
@@ -535,10 +540,22 @@ struct Window::PrivateData {
// -------------------------------------------------------------------
+ const char* getTitle() const noexcept
+ {
+ static const char* const kFallback = "";
+
+ return fTitle != nullptr ? fTitle : kFallback;
+ }
+
void setTitle(const char* const title)
{
DBGp("Window setTitle \"%s\"\n", title);
+ if (fTitle != nullptr)
+ std::free(fTitle);
+
+ fTitle = strdup(title);
+
#if defined(DISTRHO_OS_WINDOWS)
SetWindowTextA(hwnd, title);
#elif defined(DISTRHO_OS_MAC)
@@ -840,6 +857,7 @@ struct Window::PrivateData {
bool fUsingEmbed;
uint fWidth;
uint fHeight;
+ char* fTitle;
std::list<Widget*> fWidgets;
struct Modal {
@@ -922,6 +940,11 @@ struct Window::PrivateData {
handlePtr->onPuglClose();
}
+ static void fileBrowserSelectedCallback(PuglView* view, const char* filename)
+ {
+ handlePtr->fSelf->fileBrowserSelected(filename);
+ }
+
#undef handlePtr
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
@@ -977,6 +1000,73 @@ void Window::repaint() noexcept
puglPostRedisplay(pData->fView);
}
+// static int fib_filter_filename_filter(const char* const name)
+// {
+// return 1;
+// (void)name;
+// }
+
+bool Window::openFileBrowser(const FileBrowserOptions& options)
+{
+ using DISTRHO_NAMESPACE::d_string;
+
+ // --------------------------------------------------------------------------
+ // configure start dir
+
+ // TODO: get abspath if needed
+ // TODO: cross-platform
+
+ d_string startDir(options.startDir);
+
+ if (startDir.isEmpty())
+ {
+ if (char* const dir_name = get_current_dir_name())
+ {
+ startDir = dir_name;
+ std::free(dir_name);
+ }
+ }
+
+ DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false);
+
+ if (! startDir.endsWith('/'))
+ startDir += "/";
+
+ DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false);
+
+ // --------------------------------------------------------------------------
+ // configure title
+
+ d_string title(options.title);
+
+ if (title.isEmpty())
+ {
+ title = pData->getTitle();
+
+ if (title.isEmpty())
+ title = "FileBrowser";
+ }
+
+ DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false);
+
+ // --------------------------------------------------------------------------
+ // configure filters
+
+ x_fib_cfg_filter_callback(nullptr); //fib_filter_filename_filter);
+
+ // --------------------------------------------------------------------------
+ // configure buttons
+
+ x_fib_cfg_buttons(3, options.buttons.listAllFiles-1);
+ x_fib_cfg_buttons(1, options.buttons.showHidden-1);
+ x_fib_cfg_buttons(2, options.buttons.showPlaces-1);
+
+ // --------------------------------------------------------------------------
+ // show
+
+ return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0);
+}
+
bool Window::isVisible() const noexcept
{
return pData->fVisible;
@@ -1022,6 +1112,11 @@ void Window::setSize(Size<uint> size)
pData->setSize(size.getWidth(), size.getHeight());
}
+const char* Window::getTitle() const noexcept
+{
+ return pData->getTitle();
+}
+
void Window::setTitle(const char* title)
{
pData->setTitle(title);
@@ -1101,6 +1196,10 @@ void Window::onClose()
{
}
+void Window::fileBrowserSelected(const char*)
+{
+}
+
// -----------------------------------------------------------------------
END_NAMESPACE_DGL
diff --git a/dgl/src/pugl/pugl.h b/dgl/src/pugl/pugl.h
@@ -220,6 +220,14 @@ typedef void (*PuglScrollFunc)(PuglView* view, int x, int y, float dx, float dy)
typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key);
/**
+ A function called when a filename is selected via file-browser.
+
+ @param view The view the event occured in.
+ @param filename The selected file name or NULL if the dialog was canceled.
+*/
+typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename);
+
+/**
Create a Pugl context.
To create a window, call the various puglInit* functions as necessary, then
@@ -353,6 +361,12 @@ PUGL_API void
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc);
/**
+ Set the function to call on file-browser selections.
+*/
+PUGL_API void
+puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc);
+
+/**
Return the native window handle.
*/
PUGL_API PuglNativeWindow
diff --git a/dgl/src/pugl/pugl_internal.h b/dgl/src/pugl/pugl_internal.h
@@ -51,6 +51,7 @@ struct PuglViewImpl {
PuglReshapeFunc reshapeFunc;
PuglScrollFunc scrollFunc;
PuglSpecialFunc specialFunc;
+ PuglFileSelectedFunc fileSelectedFunc;
PuglInternals* impl;
PuglNativeWindow parent;
@@ -200,3 +201,9 @@ puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc)
{
view->specialFunc = specialFunc;
}
+
+void
+puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc)
+{
+ view->fileSelectedFunc = fileSelectedFunc;
+}
diff --git a/dgl/src/pugl/pugl_x11.c b/dgl/src/pugl/pugl_x11.c
@@ -32,6 +32,10 @@
#include "pugl_internal.h"
+#define SOFD_HAVE_X11
+#include "../sofd/libsofd.h"
+#include "../sofd/libsofd.c"
+
struct PuglInternalsImpl {
Display* display;
int screen;
@@ -96,7 +100,7 @@ puglCreateWindow(PuglView* view, const char* title)
{
PuglInternals* impl = view->impl;
- impl->display = XOpenDisplay(0);
+ impl->display = XOpenDisplay(NULL);
impl->screen = DefaultScreen(impl->display);
impl->doubleBuffered = True;
@@ -322,6 +326,26 @@ puglProcessEvents(PuglView* view)
XEvent event;
while (XPending(view->impl->display) > 0) {
XNextEvent(view->impl->display, &event);
+
+ if (x_fib_handle_events(view->impl->display, &event)) {
+ const int status = x_fib_status();
+
+ if (status > 0) {
+ char* const filename = x_fib_filename();
+ x_fib_close(view->impl->display);
+ if (view->fileSelectedFunc) {
+ view->fileSelectedFunc(view, filename);
+ }
+ free(filename);
+ } else if (status < 0) {
+ x_fib_close(view->impl->display);
+ if (view->fileSelectedFunc) {
+ view->fileSelectedFunc(view, NULL);
+ }
+ }
+ break;
+ }
+
switch (event.type) {
case MapNotify:
puglReshape(view, view->width, view->height);