DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.
[STR New]
Link: http://www.fltk.org/str.php?L2904
Version: 1.3-feature
Attached file "gtk-browser.patch"...
Link: http://www.fltk.org/str.php?L2904
Version: 1.3-feature
Index: src/fl_gtk.h
===================================================================
--- src/fl_gtk.h (revision 0)
+++ src/fl_gtk.h (revision 0)
@@ -0,0 +1,66 @@
+/* --------------------- Type definitions from GLIB and GTK
--------------------- */
+/* all of this is from the public gnome API, so unlikely to change */
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+typedef void* gpointer;
+typedef int gint;
+typedef unsigned int guint;
+typedef unsigned long gulong;
+typedef gint gboolean;
+typedef char gchar;
+typedef struct _GSList GSList;
+struct _GSList
+{
+ gpointer data;
+ GSList *next;
+};
+#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next)
: NULL)
+typedef struct _GtkWidget GtkWidget;
+typedef struct _GtkFileChooser GtkFileChooser;
+typedef struct _GtkDialog GtkDialog;
+typedef struct _GtkWindow GtkWindow;
+typedef struct _GtkFileFilter GtkFileFilter;
+typedef struct _GtkToggleButton GtkToggleButton;
+typedef enum {
+ GTK_FILE_FILTER_FILENAME = 1 << 0,
+ GTK_FILE_FILTER_URI = 1 << 1,
+ GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
+ GTK_FILE_FILTER_MIME_TYPE = 1 << 3
+} GtkFileFilterFlags;
+struct _GtkFileFilterInfo
+{
+ GtkFileFilterFlags contains;
+
+ const gchar *filename;
+ const gchar *uri;
+ const gchar *display_name;
+ const gchar *mime_type;
+};
+typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
+typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info,
gpointer data);
+typedef void (*GDestroyNotify)(gpointer data);
+typedef enum
+{
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+} GtkFileChooserAction;
+#define GTK_STOCK_CANCEL "gtk-cancel"
+#define GTK_STOCK_SAVE "gtk-save"
+#define GTK_STOCK_OPEN "gtk-open"
+const int GTK_RESPONSE_ACCEPT = -3;
+const int GTK_RESPONSE_CANCEL = -6;
+typedef void (*GCallback)(void);
+#define G_CALLBACK(f) ((GCallback) (f))
+typedef int GConnectFlags;
+typedef struct _GClosure GClosure;
+typedef void (*GClosureNotify)(gpointer data, GClosure *closure);
+
+/* --------------------- End of Type definitions from GLIB and GTK
--------------------- */
+
+
Index: src/Fl_Native_File_Chooser_FLTK.cxx
===================================================================
--- src/Fl_Native_File_Chooser_FLTK.cxx (revision 9729)
+++ src/Fl_Native_File_Chooser_FLTK.cxx (working copy)
@@ -1,10 +1,9 @@
// "$Id$"
//
-// FLTK native OS file chooser widget
+// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
//
-// Copyright 1998-2010 by Bill Spitzak and others.
-// Copyright 2004 Greg Ercolano.
-// API changes + filter improvements by Nathan Vander Wilt 2005
+// Copyright 1998-2013 by Bill Spitzak and others.
+// Copyright 2012 IMM
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -28,21 +27,272 @@
#include <sys/stat.h>
#include <string.h>
+static int did_find_GTK_libs = 0;
+
+#ifdef _TEST_GTK_FILE_CHOOSER
+# warning Test code for GTK file chooser
+# include "fl_gtk.h"
+# include <dlfcn.h> // for dlopen et al
+# include <locale.h> // for setlocale
+
+
+static int have_looked_for_GTK_libs = 0;
+
+/* These are the GTK/GLib methods we want to load, but not call by name...! */
+
+// void g_free (gpointer mem);
+typedef void (*XX_g_free)(gpointer);
+static XX_g_free fl_g_free = NULL;
+
+// gpointer g_slist_nth_data (GSList *list, guint n);
+typedef gpointer (*XX_g_slist_nth_data) (GSList *, guint);
+static XX_g_slist_nth_data fl_g_slist_nth_data = NULL;
+
+// guint g_slist_length (GSList *list);
+typedef guint (*XX_g_slist_length) (GSList *);
+static XX_g_slist_length fl_g_slist_length = NULL;
+
+// void g_slist_free (GSList *list);
+typedef void (*XX_g_slist_free) (GSList *);
+static XX_g_slist_free fl_g_slist_free = NULL;
+
+// gboolean gtk_init_check (int *argc, char ***argv);
+typedef gboolean (*XX_gtk_init_check)(int *, char ***);
+static XX_gtk_init_check fl_gtk_init_check = NULL;
+
+// void gtk_widget_destroy (GtkWidget *widget);
+typedef void (*XX_gtk_widget_destroy) (GtkWidget *);
+static XX_gtk_widget_destroy fl_gtk_widget_destroy = NULL;
+
+// void gtk_file_chooser_set_select_multiple(GtkFileChooser *chooser, gboolean
select_multiple);
+typedef void (*XX_gtk_file_chooser_set_select_multiple)(GtkFileChooser *,
gboolean);
+static XX_gtk_file_chooser_set_select_multiple
fl_gtk_file_chooser_set_select_multiple = NULL;
+
+// void gtk_file_chooser_set_do_overwrite_confirmation(GtkFileChooser
*chooser, gboolean do_overwrite_confirmation);
+typedef void
(*XX_gtk_file_chooser_set_do_overwrite_confirmation)(GtkFileChooser *,
gboolean);
+static XX_gtk_file_chooser_set_do_overwrite_confirmation
fl_gtk_file_chooser_set_do_overwrite_confirmation = NULL;
+
+// void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const
gchar *name);
+typedef void (*XX_gtk_file_chooser_set_current_name)(GtkFileChooser *, const
gchar *);
+static XX_gtk_file_chooser_set_current_name
fl_gtk_file_chooser_set_current_name = NULL;
+
+// void gtk_file_chooser_set_current_folder (GtkFileChooser *chooser, const
gchar *name);
+typedef void (*XX_gtk_file_chooser_set_current_folder)(GtkFileChooser *, const
gchar *);
+static XX_gtk_file_chooser_set_current_folder
fl_gtk_file_chooser_set_current_folder = NULL;
+
+// void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser, gboolean
create_folders);
+typedef void (*XX_gtk_file_chooser_set_create_folders) (GtkFileChooser *,
gboolean);
+static XX_gtk_file_chooser_set_create_folders
fl_gtk_file_chooser_set_create_folders = NULL;
+
+// gboolean gtk_file_chooser_get_select_multiple(GtkFileChooser *chooser);
+typedef gboolean (*XX_gtk_file_chooser_get_select_multiple)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_select_multiple
fl_gtk_file_chooser_get_select_multiple = NULL;
+
+// void gtk_widget_hide(GtkWidget *widget);
+typedef void (*XX_gtk_widget_hide)(GtkWidget *);
+static XX_gtk_widget_hide fl_gtk_widget_hide = NULL;
+
+// gint gtk_dialog_run(GtkDialog *dialog);
+typedef gint (*XX_gtk_dialog_run)(GtkDialog *dialog);
+static XX_gtk_dialog_run fl_gtk_dialog_run = NULL;
+
+// gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser);
+typedef gchar* (*XX_gtk_file_chooser_get_filename)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_filename fl_gtk_file_chooser_get_filename =
NULL;
+
+// GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser);
+typedef GSList* (*XX_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser);
+static XX_gtk_file_chooser_get_filenames fl_gtk_file_chooser_get_filenames =
NULL;
+
+// gboolean gtk_main_iteration(void);
+typedef gboolean (*XX_gtk_main_iteration)(void);
+static XX_gtk_main_iteration fl_gtk_main_iteration = NULL;
+
+// gboolean gtk_events_pending(void);
+typedef gboolean (*XX_gtk_events_pending)(void);
+static XX_gtk_events_pending fl_gtk_events_pending = NULL;
+
+// GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow
*parent, GtkFileChooserAction action, const gchar *first_button_text, ...);
+typedef GtkWidget* (*XX_gtk_file_chooser_dialog_new)(const gchar *, GtkWindow
*, GtkFileChooserAction, const gchar *, ...);
+static XX_gtk_file_chooser_dialog_new fl_gtk_file_chooser_dialog_new = NULL;
+
+// void gtk_file_chooser_add_filter(GtkFileChooser*, GtkFileFilter*);
+typedef void (*XX_gtk_file_chooser_add_filter)(GtkFileChooser*,
GtkFileFilter*);
+static XX_gtk_file_chooser_add_filter fl_gtk_file_chooser_add_filter = NULL;
+
+// GtkFileFilter* gtk_file_chooser_get_filter(GtkFileChooser*);
+typedef GtkFileFilter* (*XX_gtk_file_chooser_get_filter)(GtkFileChooser*);
+static XX_gtk_file_chooser_get_filter fl_gtk_file_chooser_get_filter = NULL;
+
+// void gtk_file_chooser_set_filter(GtkFileChooser*, GtkFileFilter*);
+typedef void (*XX_gtk_file_chooser_set_filter)(GtkFileChooser*,
GtkFileFilter*);
+static XX_gtk_file_chooser_set_filter fl_gtk_file_chooser_set_filter = NULL;
+
+// GtkFileFilter * gtk_file_filter_new();
+typedef GtkFileFilter* (*XX_gtk_file_filter_new)(void);
+static XX_gtk_file_filter_new fl_gtk_file_filter_new = NULL;
+
+// void gtk_file_filter_add_pattern(GtkFileFilter*, const gchar*);
+typedef void (*XX_gtk_file_filter_add_pattern)(GtkFileFilter*, const gchar*);
+static XX_gtk_file_filter_add_pattern fl_gtk_file_filter_add_pattern = NULL;
+
+// void gtk_file_filter_add_custom(GtkFileFilter *filter, GtkFileFilterFlags
needed,
+// GtkFileFilterFunc func, gpointer data, GDestroyNotify notify);
+typedef void (*XX_gtk_file_filter_add_custom)(GtkFileFilter *filter,
GtkFileFilterFlags needed,
+ GtkFileFilterFunc func, gpointer
data,
+ GDestroyNotify notify);
+static XX_gtk_file_filter_add_custom fl_gtk_file_filter_add_custom = NULL;
+
+// void gtk_file_filter_set_name(GtkFileFilter*, const gchar*);
+typedef void (*XX_gtk_file_filter_set_name)(GtkFileFilter*, const gchar*);
+static XX_gtk_file_filter_set_name fl_gtk_file_filter_set_name = NULL;
+
+// const gchar* gtk_file_filter_get_name(GtkFileFilter*);
+typedef const gchar* (*XX_gtk_file_filter_get_name)(GtkFileFilter*);
+static XX_gtk_file_filter_get_name fl_gtk_file_filter_get_name = NULL;
+
+// void gtk_file_chooser_set_extra_widget(GtkFileChooser *, GtkWidget *);
+typedef void (*XX_gtk_file_chooser_set_extra_widget)(GtkFileChooser *,
GtkWidget *);
+static XX_gtk_file_chooser_set_extra_widget
fl_gtk_file_chooser_set_extra_widget = NULL;
+
+// void gtk_widget_show(GtkWidget *);
+typedef void (*XX_gtk_widget_show)(GtkWidget *);
+static XX_gtk_widget_show fl_gtk_widget_show = NULL;
+
+// GtkWidget *gtk_check_button_new_with_label(const gchar *);
+typedef GtkWidget* (*XX_gtk_check_button_new_with_label)(const gchar *);
+static XX_gtk_check_button_new_with_label fl_gtk_check_button_new_with_label =
NULL;
+
+// gulong g_signal_connect_data(gpointer, const gchar *, GCallback, gpointer,
GClosureNotify, GConnectFlags);
+typedef gulong (*XX_g_signal_connect_data)(gpointer, const gchar *, GCallback,
gpointer, GClosureNotify, GConnectFlags);
+static XX_g_signal_connect_data fl_g_signal_connect_data = NULL;
+
+// gboolean gtk_toggle_button_get_active(GtkToggleButton *);
+typedef gboolean (*XX_gtk_toggle_button_get_active)(GtkToggleButton*);
+static XX_gtk_toggle_button_get_active fl_gtk_toggle_button_get_active = NULL;
+
+// void gtk_file_chooser_set_show_hidden(GtkFileChooser *, gboolean);
+typedef void (*XX_gtk_file_chooser_set_show_hidden)(GtkFileChooser *,
gboolean);
+static XX_gtk_file_chooser_set_show_hidden fl_gtk_file_chooser_set_show_hidden
= NULL;
+
+// gboolean gtk_file_chooser_get_show_hidden(GtkFileChooser *);
+typedef gboolean (*XX_gtk_file_chooser_get_show_hidden)(GtkFileChooser *);
+static XX_gtk_file_chooser_get_show_hidden fl_gtk_file_chooser_get_show_hidden
= NULL;
+
+// void gtk_toggle_button_set_active(GtkToggleButton *, gboolean);
+typedef void (*XX_gtk_toggle_button_set_active)(GtkToggleButton *, gboolean);
+static XX_gtk_toggle_button_set_active fl_gtk_toggle_button_set_active = NULL;
+
+
+// macro to help with the symbol loading boilerplate...
+#define GET_SYM(SSS, LLL) \
+ dlerror(); /* Clear any existing error */ \
+ fl_##SSS = (XX_##SSS)dlsym(LLL, #SSS); \
+ if ((pc_dl_error = dlerror()) != NULL) { \
+ fprintf(stderr, "%s\n", pc_dl_error); \
+ did_find_GTK_libs = 0; \
+ return; }
+
+
+static void* fl_dlopen(const char *filename1, const char *filename2)
+{
+ void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
+ if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
+ return ptr;
+}
+
+/*
+ * Use dlopen to see if we can load the gtk dynamic libraries that
+ * will allow us to create a GtkFileChooserDialog() on the fly,
+ * without linking to the GTK libs at compile time.
+ */
+static void probe_for_GTK_libs(void) {
+ void *ptr_glib = NULL;
+ void *ptr_gtk = NULL;
+
+# ifdef __APPLE_CC__ // allows testing on Darwin + X11
+ ptr_glib = dlopen("/sw/lib/libglib-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
+# else
+ ptr_glib = fl_dlopen("libglib-2.0.so", "libglib-2.0.so.0");
+# endif
+ // Try first with GTK3
+ ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
+ if (ptr_gtk && ptr_glib) {
+#ifdef DEBUG
+ puts("selected GTK-3\n");
+#endif
+ }
+ else {// Try then with GTK2
+# ifdef __APPLE_CC__ // allows testing on Darwin + X11
+ ptr_gtk = dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY |
RTLD_GLOBAL);
+#else
+ ptr_gtk = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
+#endif
+#ifdef DEBUG
+ if (ptr_gtk && ptr_glib) {
+ puts("selected GTK-2\n");
+ }
+#endif
+ }
+
+ if((!ptr_glib) || (!ptr_gtk)) {
+#ifdef DEBUG
+ puts("Failure to load");
+#endif
+ did_find_GTK_libs = 0;
+ return;
+ }
+
+ char *pc_dl_error; // used to report errors by the GET_SYM macro...
+ // items we need from GLib
+ GET_SYM(g_free, ptr_glib);
+ GET_SYM(g_slist_nth_data, ptr_glib);
+ GET_SYM(g_slist_length, ptr_glib);
+ GET_SYM(g_slist_free, ptr_glib);
+ // items we need from GTK
+ GET_SYM(gtk_init_check, ptr_gtk);
+ GET_SYM(gtk_widget_destroy, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_select_multiple, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_do_overwrite_confirmation, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_current_name, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_current_folder, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_create_folders, ptr_gtk);
+ GET_SYM(gtk_file_chooser_get_select_multiple, ptr_gtk);
+ GET_SYM(gtk_widget_hide, ptr_gtk);
+ GET_SYM(gtk_dialog_run, ptr_gtk);
+ GET_SYM(gtk_file_chooser_get_filename, ptr_gtk);
+ GET_SYM(gtk_file_chooser_get_filenames, ptr_gtk);
+ GET_SYM(gtk_main_iteration, ptr_gtk);
+ GET_SYM(gtk_events_pending, ptr_gtk);
+ GET_SYM(gtk_file_chooser_dialog_new, ptr_gtk);
+ GET_SYM(gtk_file_chooser_add_filter, ptr_gtk);
+ GET_SYM(gtk_file_chooser_get_filter, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_filter, ptr_gtk);
+ GET_SYM(gtk_file_filter_new, ptr_gtk);
+ GET_SYM(gtk_file_filter_add_pattern, ptr_gtk);
+ GET_SYM(gtk_file_filter_add_custom, ptr_gtk);
+ GET_SYM(gtk_file_filter_set_name, ptr_gtk);
+ GET_SYM(gtk_file_filter_get_name, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_extra_widget, ptr_gtk);
+ GET_SYM(gtk_widget_show, ptr_gtk);
+ GET_SYM(gtk_check_button_new_with_label, ptr_gtk);
+ GET_SYM(g_signal_connect_data, ptr_gtk);
+ GET_SYM(gtk_toggle_button_get_active, ptr_gtk);
+ GET_SYM(gtk_file_chooser_set_show_hidden, ptr_gtk);
+ GET_SYM(gtk_file_chooser_get_show_hidden, ptr_gtk);
+ GET_SYM(gtk_toggle_button_set_active, ptr_gtk);
+
+ did_find_GTK_libs = _TEST_GTK_FILE_CHOOSER;
+} // probe_for_GTK_libs
+
+#endif /* _TEST_GTK_FILE_CHOOSER */
+
/**
The constructor. Internally allocates the native widgets.
Optional \p val presets the type of browser this will be,
which can also be changed with type().
*/
Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
- //// CANT USE THIS -- MESSES UP LINKING/CREATES DEPENDENCY ON fltk_images.
- //// Have app call this from main() instead.
- ////
- //// static int init = 0; // 'first time' initialize flag
- //// if ( init == 0 ) {
- //// // Initialize when instanced for first time
- //// Fl_File_Icon::load_system_icons();
- //// init = 1;
- //// }
_btype = val;
_options = NO_OPTIONS;
_filter = NULL;
@@ -52,7 +302,30 @@
_prevvalue = NULL;
_directory = NULL;
_errmsg = NULL;
- _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
+ _file_chooser = NULL;
+
+ // My plan - such as it is - is to allocate _file_chooser ONLY if I can not
+ // make a GtkFileChooserDialog, which I'll deal with... somehow...
+ // Anyway, the idea is to have some global static state in this file, such
that
+ // the first time in, we probe for the GTK libs we need, and if found we use
them.
+ // Otherwise, we just create a stock FLTK file chooser, and from thereon
this file
+ // would behave exactly like Fl_Native_File_Chooser_FLTK.
+
+#ifdef _TEST_GTK_FILE_CHOOSER
+
+ if(have_looked_for_GTK_libs == 0) {
+ // First Time here, try to find the GTK libs if they are installed
+ probe_for_GTK_libs();
+ have_looked_for_GTK_libs = -1;
+ }
+
+ // if we found all the GTK functions we need, we will use the
GtkFileChooserDialog
+ if (did_find_GTK_libs) {
+ _gtk_file_chooser = new _Fl_GTK_File_Chooser();
+ }
+#endif // _TEST_GTK_FILE_CHOOSER
+ if (!_file_chooser) _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
+
type(val); // do this after _file_chooser created
_nfilters = 0;
}
@@ -62,13 +335,40 @@
Deallocates any resources allocated to this widget.
*/
Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
- delete _file_chooser;
+ if (!did_find_GTK_libs) {
+ delete _file_chooser;
+ _file_chooser = NULL;
+ }
_filter = strfree(_filter);
_parsedfilt = strfree(_parsedfilt);
_preset_file = strfree(_preset_file);
_prevvalue = strfree(_prevvalue);
_directory = strfree(_directory);
_errmsg = strfree(_errmsg);
+#ifdef _TEST_GTK_FILE_CHOOSER
+ if (did_find_GTK_libs) {
+ // Should free up resources taken for...
+ if(_gtk_file_chooser->gtkw_ptr) {
+ fl_gtk_widget_destroy (_gtk_file_chooser->gtkw_ptr);
+ _gtk_file_chooser->gtkw_ptr = NULL;
+ }
+ if(_gtk_file_chooser->gtkw_filename) {
+ fl_g_free(_gtk_file_chooser->gtkw_filename);
+ _gtk_file_chooser->gtkw_filename = NULL;
+ }
+ if(_gtk_file_chooser->gtkw_slist) {
+ GSList *iter = (GSList *)_gtk_file_chooser->gtkw_slist;
+ while(iter) {
+ if(iter->data) fl_g_free(iter->data);
+ iter = g_slist_next(iter);
+ }
+ fl_g_slist_free((GSList *)_gtk_file_chooser->gtkw_slist);
+ _gtk_file_chooser->gtkw_slist = NULL;
+ }
+ _gtk_file_chooser->gtkw_count = 0; // assume we have no files selected now
+ _gtk_file_chooser->gtkw_title = strfree(_gtk_file_chooser->gtkw_title);
+ }
+#endif // _TEST_GTK_FILE_CHOOSER
}
// PRIVATE: SET ERROR MESSAGE
@@ -102,7 +402,7 @@
*/
void Fl_Native_File_Chooser::type(int val) {
_btype = val;
- _file_chooser->type(type_fl_file(val));
+ if (!did_find_GTK_libs) _file_chooser->type(type_fl_file(val));
}
/**
@@ -136,6 +436,197 @@
return(_options);
}
+#ifdef _TEST_GTK_FILE_CHOOSER
+static gboolean fl_custom_gtk_filter_function(const GtkFileFilterInfo *info,
gpointer data)
+{
+ return (gboolean)fl_filename_match(info->filename, (const char*)data);
+}
+
+static void hidden_files_cb(GtkToggleButton *togglebutton, gpointer user_data)
+{
+ gboolean state = fl_gtk_toggle_button_get_active(togglebutton);
+ fl_gtk_file_chooser_set_show_hidden((GtkFileChooser*)user_data, state);
+}
+
+static const char *extract_filename(const char *in)
+{
+ const char *p = strrchr(in, '/');
+ return p ? p + 1 : in;
+}
+
+// Implements a wrapper for the GtkFileChooserDialog
+int Fl_Native_File_Chooser::fl_gtk_chooser_wrapper()
+{
+ int result = 1;
+ static int have_gtk_init = 0;
+ if(!have_gtk_init) {
+ have_gtk_init = -1;
+ int ac = 0;
+ fl_gtk_init_check(&ac, NULL);
+ }
+
+ if(_gtk_file_chooser->gtkw_ptr) { // discard the previous dialog widget
+ fl_gtk_widget_destroy (_gtk_file_chooser->gtkw_ptr);
+ _gtk_file_chooser->gtkw_ptr = NULL;
+ }
+
+ // set the dialog action type
+ GtkFileChooserAction gtw_action_type;
+ switch (_btype) {
+ case BROWSE_DIRECTORY:
+ case BROWSE_MULTI_DIRECTORY:
+ gtw_action_type = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ break;
+
+ case BROWSE_SAVE_FILE:
+ gtw_action_type = GTK_FILE_CHOOSER_ACTION_SAVE;
+ break;
+
+ case BROWSE_SAVE_DIRECTORY:
+ gtw_action_type = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
+ break;
+
+ case BROWSE_MULTI_FILE:
+ case BROWSE_FILE:
+ default:
+ gtw_action_type = GTK_FILE_CHOOSER_ACTION_OPEN;
+ break;
+ }
+ // create a new dialog
+ _gtk_file_chooser->gtkw_ptr = fl_gtk_file_chooser_dialog_new
(_gtk_file_chooser->gtkw_title,
+ NULL, /* parent_window */
+ gtw_action_type,
+ GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
+ gtw_action_type == GTK_FILE_CHOOSER_ACTION_SAVE ||
gtw_action_type == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ?
+ GTK_STOCK_SAVE
: GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ // did we create a valid dialog widget?
+ if(!_gtk_file_chooser->gtkw_ptr) {
+ // fail
+ return -1;
+ }
+
+ // set the dialog properties
+ switch (_btype) {
+ case BROWSE_MULTI_DIRECTORY:
+ case BROWSE_MULTI_FILE:
+ fl_gtk_file_chooser_set_select_multiple((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, TRUE);
+ break;
+
+ case BROWSE_SAVE_FILE:
+ if((_options & SAVEAS_CONFIRM) != 0)
fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, TRUE);
+ fl_gtk_file_chooser_set_current_name ((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, extract_filename(_preset_file));
+ if((_options & NEW_FOLDER) != 0)
fl_gtk_file_chooser_set_create_folders((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, TRUE);
+ break;
+
+ case BROWSE_SAVE_DIRECTORY:
+ if((_options & NEW_FOLDER) != 0)
fl_gtk_file_chooser_set_create_folders((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, TRUE);
+ if((_options & SAVEAS_CONFIRM) != 0)
+ fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, TRUE);
+ break;
+
+ case BROWSE_DIRECTORY:
+ case BROWSE_FILE:
+ default:
+ break;
+ }
+
+ if (_directory && _directory[0])
fl_gtk_file_chooser_set_current_folder((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, _directory);
+
+ GtkFileFilter **filter_tab = NULL;
+ if (_parsedfilt) {
+ filter_tab = new GtkFileFilter*[_nfilters];
+ char *filter = strdup(_parsedfilt);
+ char *p = strtok(filter, "\t");
+ int count = 0;
+ while (p) {
+ filter_tab[count] = fl_gtk_file_filter_new();
+ fl_gtk_file_filter_set_name(filter_tab[count], p);
+ p = strchr(p, '(') + 1;
+ char *q = strchr(p, ')'); *q = 0;
+ fl_gtk_file_filter_add_custom(filter_tab[count],
GTK_FILE_FILTER_FILENAME,
+ fl_custom_gtk_filter_function, strdup(p),
free);
+ fl_gtk_file_chooser_add_filter((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, filter_tab[count]);
+ p = strtok(NULL, "\t");
+ count++;
+ }
+ free(filter);
+ fl_gtk_file_chooser_set_filter((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, filter_tab[_filtvalue]);
+ if (gtw_action_type == GTK_FILE_CHOOSER_ACTION_OPEN) {
+ GtkFileFilter* gfilter = fl_gtk_file_filter_new();
+ fl_gtk_file_filter_set_name(gfilter, Fl_File_Chooser::all_files_label);
+ fl_gtk_file_filter_add_pattern(gfilter, "*");
+ fl_gtk_file_chooser_add_filter((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, gfilter);
+ }
+ }
+
+ GtkWidget *toggle =
fl_gtk_check_button_new_with_label(Fl_File_Chooser::hidden_label);
+ fl_gtk_widget_show(toggle);
+ fl_gtk_file_chooser_set_extra_widget((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr, toggle);
+ fl_g_signal_connect_data(toggle, "toggled", G_CALLBACK(hidden_files_cb),
_gtk_file_chooser->gtkw_ptr, NULL, (GConnectFlags) 0);
+ fl_gtk_widget_show(_gtk_file_chooser->gtkw_ptr);
+ gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr);
+ fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
+
+ if (fl_gtk_dialog_run ((GtkDialog *)_gtk_file_chooser->gtkw_ptr) ==
GTK_RESPONSE_ACCEPT) {
+ if (_parsedfilt) {
+ GtkFileFilter *gfilter = fl_gtk_file_chooser_get_filter((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr);
+ for (_filtvalue = 0; _filtvalue < _nfilters; _filtvalue++) {
+ if (filter_tab[_filtvalue] == gfilter) break;
+ }
+ }
+
+ // discard any filenames or lists from previous calls
+ if(_gtk_file_chooser->gtkw_filename) {
+ fl_g_free(_gtk_file_chooser->gtkw_filename);
+ _gtk_file_chooser->gtkw_filename = NULL;
+ }
+ if(_gtk_file_chooser->gtkw_slist) {
+ GSList *iter = (GSList *)_gtk_file_chooser->gtkw_slist;
+ while(iter) {
+ if(iter->data) fl_g_free(iter->data);
+ iter = g_slist_next(iter);
+ }
+ fl_g_slist_free((GSList *)_gtk_file_chooser->gtkw_slist);
+ _gtk_file_chooser->gtkw_slist = NULL;
+ }
+ _gtk_file_chooser->gtkw_count = 0; // assume we have no files selected now
+
+ if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr) == FALSE) {
+ _gtk_file_chooser->gtkw_filename = fl_gtk_file_chooser_get_filename
((GtkFileChooser *)_gtk_file_chooser->gtkw_ptr);
+ if (_gtk_file_chooser->gtkw_filename) {
+ _gtk_file_chooser->gtkw_count = 1;
+ result = 0;
+ //printf("single: %s\n", gtkw_filename);
+ }
+ }
+ else {
+ _gtk_file_chooser->gtkw_slist =
fl_gtk_file_chooser_get_filenames((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr);
+ _gtk_file_chooser->gtkw_count = fl_g_slist_length((GSList
*)_gtk_file_chooser->gtkw_slist);
+ if(_gtk_file_chooser->gtkw_count) result = 0;
+
+// puts("multiple");
+// GSList *iter = (GSList *)_gtk_file_chooser->gtkw_slist;
+// printf ("Selected %d files\n", _gtk_file_chooser->gtkw_count);
+// while(iter) {
+// char *nm = (char *)iter->data;
+// printf("%s\n", nm);
+// iter = g_slist_next(iter);
+// }
+ }
+ }
+ delete[] filter_tab;
+ fl_gtk_widget_hide (_gtk_file_chooser->gtkw_ptr);
+
+ // I think this is analogus to doing an Fl::check() - we need this here to
make sure
+ // the GtkFileChooserDialog is removed from the display correctly
+ while (fl_gtk_events_pending ()) fl_gtk_main_iteration ();
+
+ return result;
+} // fl_gtk_chooser_wrapper
+#endif // _TEST_GTK_FILE_CHOOSER
+
/**
Post the chooser's dialog. Blocks until dialog has been completed or
cancelled.
\returns
@@ -144,63 +635,90 @@
- -1 -- failed; errmsg() has reason
*/
int Fl_Native_File_Chooser::show() {
+
+ if(!did_find_GTK_libs) { // use FLTK built-in file chooser
// FILTER
- if ( _parsedfilt ) {
- _file_chooser->filter(_parsedfilt);
- }
+ if ( _parsedfilt ) {
+ _file_chooser->filter(_parsedfilt);
+ }
- // FILTER VALUE
- // Set this /after/ setting the filter
- //
- _file_chooser->filter_value(_filtvalue);
+ // FILTER VALUE
+ // Set this /after/ setting the filter
+ //
+ _file_chooser->filter_value(_filtvalue);
- // DIRECTORY
- if ( _directory && _directory[0] ) {
- _file_chooser->directory(_directory);
- } else {
- _file_chooser->directory(_prevvalue);
- }
+ // DIRECTORY
+ if ( _directory && _directory[0] ) {
+ _file_chooser->directory(_directory);
+ } else {
+ _file_chooser->directory(_prevvalue);
+ }
- // PRESET FILE
- if ( _preset_file ) {
- _file_chooser->value(_preset_file);
- }
+ // PRESET FILE
+ if ( _preset_file ) {
+ _file_chooser->value(_preset_file);
+ }
- // OPTIONS: PREVIEW
- _file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
+ // OPTIONS: PREVIEW
+ _file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
- // OPTIONS: NEW FOLDER
- if ( options() & NEW_FOLDER )
- _file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE); // on
+ // OPTIONS: NEW FOLDER
+ if ( options() & NEW_FOLDER )
+ _file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE); // on
- // SHOW
- _file_chooser->show();
+ // SHOW
+ _file_chooser->show();
- // BLOCK WHILE BROWSER SHOWN
- while ( _file_chooser->shown() ) {
- Fl::wait();
- }
+ // BLOCK WHILE BROWSER SHOWN
+ while ( _file_chooser->shown() ) {
+ Fl::wait();
+ }
- if ( _file_chooser->value() && _file_chooser->value()[0] ) {
- _prevvalue = strfree(_prevvalue);
- _prevvalue = strnew(_file_chooser->value());
- _filtvalue = _file_chooser->filter_value(); // update filter value
+ if ( _file_chooser->value() && _file_chooser->value()[0] ) {
+ _prevvalue = strfree(_prevvalue);
+ _prevvalue = strnew(_file_chooser->value());
+ _filtvalue = _file_chooser->filter_value(); // update filter value
- // HANDLE SHOWING 'SaveAs' CONFIRM
- if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
- struct stat buf;
- if ( stat(_file_chooser->value(), &buf) != -1 ) {
- if ( buf.st_mode & S_IFREG ) { // Regular file + exists?
- if ( exist_dialog() == 0 ) {
- return(1);
- }
- }
+ // HANDLE SHOWING 'SaveAs' CONFIRM
+ if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
+ struct stat buf;
+ if ( stat(_file_chooser->value(), &buf) != -1 ) {
+ if ( buf.st_mode & S_IFREG ) { // Regular file + exists?
+ if ( exist_dialog() == 0 ) {
+ return(1);
+ }
+ }
+ }
}
}
+
+ if ( _file_chooser->count() ) return(0);
+ else return(1);
}
-
- if ( _file_chooser->count() ) return(0);
- else return(1);
+#ifdef _TEST_GTK_FILE_CHOOSER
+ else { // use GtkFileChooserDialog
+ char *p, **before = new char*[20];
+ int val;
+ for (val = 0; val < 20; val++) { // memorize the state of all components
of the current locale
+ if (val == LC_ALL) continue;
+ p = setlocale(val, NULL);
+ if (!p) break;
+ before[val] = strdup(p);
+ }
+ int retval = fl_gtk_chooser_wrapper(); // may change the locale
+ for (int i = 0; i < val; i++) { // set all components of the locale to
their previous state
+ if (i == LC_ALL) continue;
+ if (before[i]) {
+ setlocale(i, before[i]);
+ free(before[i]);
+ }
+ }
+ delete[] before;
+ return retval;
+ }
+#else
+ return -1; //error
+#endif // _TEST_GTK_FILE_CHOOSER
}
/**
@@ -213,13 +731,33 @@
}
/**
- Return the filename the user choose.
+ Return the filename the user chose.
Use this if only expecting a single filename.
If more than one filename is expected, use filename(int) instead.
Return value may be "" if no filename was chosen (eg. user cancelled).
*/
const char* Fl_Native_File_Chooser::filename() const {
- if ( _file_chooser->count() > 0 ) return(_file_chooser->value());
+ if ((!did_find_GTK_libs) && ( _file_chooser->count() > 0 )) {
+ return(_file_chooser->value());
+ }
+
+#ifdef _TEST_GTK_FILE_CHOOSER
+ // else...
+ if (did_find_GTK_libs) {
+ if(_gtk_file_chooser->gtkw_ptr) {
+ if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr) == FALSE) {
+ return _gtk_file_chooser->gtkw_filename;
+ }
+ else {
+ GSList *iter = (GSList *)_gtk_file_chooser->gtkw_slist;
+ char *nm = (char *)iter->data;
+ return nm;
+ }
+ }
+ }
+#endif // _TEST_GTK_FILE_CHOOSER
+
+ // else...
return("");
}
@@ -238,8 +776,26 @@
\endcode
*/
const char* Fl_Native_File_Chooser::filename(int i) const {
- if ( i < _file_chooser->count() )
- return(_file_chooser->value(i+1)); // convert fltk 1 based to our 0 based
+ if(!did_find_GTK_libs) {
+ if ( i < _file_chooser->count() )
+ return(_file_chooser->value(i+1)); // convert fltk 1 based to our 0
based
+ }
+#ifdef _TEST_GTK_FILE_CHOOSER
+ else {
+ if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser
*)_gtk_file_chooser->gtkw_ptr) == FALSE) {
+ return _gtk_file_chooser->gtkw_filename;
+ }
+ else {
+ if ((unsigned)i < _gtk_file_chooser->gtkw_count) {
+ GSList *iter = (GSList *)_gtk_file_chooser->gtkw_slist;
+ char *nm = (char *)fl_g_slist_nth_data(iter, i);
+ return nm;
+ }
+ }
+ }
+#endif // _TEST_GTK_FILE_CHOOSER
+
+ // else...
return("");
}
@@ -249,7 +805,15 @@
The default title varies according to the platform, so you are advised to
set the title explicitly.
*/
void Fl_Native_File_Chooser::title(const char *val) {
- _file_chooser->label(val);
+ if(!did_find_GTK_libs) {
+ _file_chooser->label(val);
+ }
+#ifdef _TEST_GTK_FILE_CHOOSER
+ else { // gtk version...
+ strfree(_gtk_file_chooser->gtkw_title);
+ _gtk_file_chooser->gtkw_title = strnew(val);
+ }
+#endif // _TEST_GTK_FILE_CHOOSER
}
/**
@@ -257,7 +821,16 @@
Return value may be NULL if no title was set.
*/
const char *Fl_Native_File_Chooser::title() const {
- return(_file_chooser->label());
+ if(!did_find_GTK_libs) {
+ return(_file_chooser->label());
+ }
+#ifdef _TEST_GTK_FILE_CHOOSER
+ else {
+ return _gtk_file_chooser->gtkw_title;
+ }
+#else
+ return "";
+#endif // _TEST_GTK_FILE_CHOOSER
}
/**
@@ -332,7 +905,13 @@
\endcode
*/
int Fl_Native_File_Chooser::count() const {
- return(_file_chooser->count());
+ if(!did_find_GTK_libs) return(_file_chooser->count());
+
+#ifdef _TEST_GTK_FILE_CHOOSER
+ if (_gtk_file_chooser->gtkw_ptr) { return _gtk_file_chooser->gtkw_count; }
+#endif // _TEST_GTK_FILE_CHOOSER
+
+ else return 0;
}
/**
Index: FL/Fl_Native_File_Chooser.H
===================================================================
--- FL/Fl_Native_File_Chooser.H (revision 9729)
+++ FL/Fl_Native_File_Chooser.H (working copy)
@@ -23,6 +23,8 @@
#ifndef FL_NATIVE_FILE_CHOOSER_H
#define FL_NATIVE_FILE_CHOOSER_H
+#define _TEST_GTK_FILE_CHOOSER 1 /* forces use of GTK browser when available */
+
/* \file
Fl_Native_File_Chooser widget. */
@@ -49,7 +51,6 @@
#include <FL/filename.H> // FL_EXPORT
#endif
-
/**
This class lets an FLTK application easily and consistently access
the operating system's native file chooser. Some operating systems
@@ -103,6 +104,27 @@
*/
class FL_EXPORT Fl_Native_File_Chooser {
+# ifdef _TEST_GTK_FILE_CHOOSER
+ typedef struct _GtkWidget GtkWidget;
+ class _Fl_GTK_File_Chooser {
+ friend class Fl_Native_File_Chooser;
+ private:
+ GtkWidget *gtkw_ptr; // used to hold a GtkWidget* without pulling GTK into
everything...
+ void *gtkw_slist; // used to hold a GLib GSList...
+ unsigned gtkw_count; // number of files read back - if any
+ mutable char *gtkw_filename; // last name we read back
+ char *gtkw_title; // the title to be applied to the dialog
+ public:
+ _Fl_GTK_File_Chooser() {
+ gtkw_ptr = NULL; // used to hold a GtkWidget*
+ gtkw_slist = NULL; // will hold the returned file names in a
multi-selection...
+ gtkw_count = 0; // How many items were selected?
+ gtkw_filename = NULL; // holds the last name we read back in a single
file selection...
+ gtkw_title = NULL; // dialog title
+ }
+ };
+#endif
+
public:
enum Type {
BROWSE_FILE = 0, ///< browse files (lets user choose one
file)
@@ -234,7 +256,14 @@
char *_prevvalue; // Returned filename
char *_directory;
char *_errmsg; // error message
+# ifdef _TEST_GTK_FILE_CHOOSER
+ union {
+ Fl_File_Chooser *_file_chooser;
+ _Fl_GTK_File_Chooser *_gtk_file_chooser;
+ };
+#else
Fl_File_Chooser *_file_chooser;
+#endif
// Private methods
void errmsg(const char *msg);
@@ -242,6 +271,12 @@
void parse_filter();
void keeplocation();
int exist_dialog();
+
+ // Extra method to help with the GtkFileChooserDialog based tests
+# ifdef _TEST_GTK_FILE_CHOOSER
+ int fl_gtk_chooser_wrapper(); // method that wraps the GTK widget
+# endif // _TEST_GTK_FILE_CHOOSER
+
#endif
};
Index: test/native-filechooser.cxx
===================================================================
--- test/native-filechooser.cxx (revision 9729)
+++ test/native-filechooser.cxx (working copy)
@@ -3,7 +3,7 @@
//
// Simple test of the Fl_Native_File_Chooser.
//
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2013 by Bill Spitzak and others.
// Copyright 2004 Greg Ercolano.
//
// This library is free software. Distribution and use rights are outlined in
@@ -28,14 +28,68 @@
// GLOBALS
Fl_Input *G_filename = NULL;
-void Butt_CB(Fl_Widget*, void*) {
+void Butt_CB(Fl_Widget* butt, void*) {
// Create native chooser
+ static int test_mode = 0;
Fl_Native_File_Chooser native;
- native.title("Pick a file");
- native.type(Fl_Native_File_Chooser::BROWSE_FILE);
+
+ native.options(Fl_Native_File_Chooser::NO_OPTIONS);
+
+ switch(test_mode) {
+ default:
+ case 0:
+ native.title("Open Single file");
+ native.type(Fl_Native_File_Chooser::BROWSE_FILE);
+ break;
+
+ case 1:
+ native.title("Open Single Directory");
+ native.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY);
+ break;
+
+ case 2:
+ native.title("BROWSE_MULTI_FILE");
+ native.type(Fl_Native_File_Chooser::BROWSE_MULTI_FILE);
+ break;
+
+ case 3:
+ native.title("BROWSE_MULTI_DIRECTORY");
+ native.type(Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY);
+ break;
+
+ case 4:
+ native.title("BROWSE_SAVE_FILE");
+ native.options(Fl_Native_File_Chooser::NEW_FOLDER);
+ native.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
+ break;
+
+ case 5:
+ native.title("BROWSE_SAVE_FILE - warn overwrite");
+ native.options(Fl_Native_File_Chooser::NEW_FOLDER |
Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+ native.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
+ break;
+
+ case 6:
+ native.title("BROWSE_SAVE_DIRECTORY");
+ native.options(Fl_Native_File_Chooser::NEW_FOLDER);
+ native.type(Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY);
+ break;
+
+ case 7:
+ native.title("BROWSE_SAVE_DIRECTORY - warn overwrite");
+ native.options(Fl_Native_File_Chooser::NEW_FOLDER |
Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+ native.type(Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY);
+ break;
+
+ }
+ test_mode ++;
+ if(test_mode > 7) test_mode = 0;
+
+ butt->label("Pick File again");
+
native.filter("Text\t*.txt\n"
"C Files\t*.{cxx,h,c}\n"
- "Apps\t*.{app}\n"); // TODO: need to add
kNavSupportPackages to non-cocoa <FNFC>_MAC.cxx
+ "PDF\t*.{pdf}\n");
native.preset_file(G_filename->value());
// Show native chooser
switch ( native.show() ) {
@@ -49,6 +103,14 @@
}
break;
}
+
+ int items_selected = native.count();
+ if(items_selected) {
+ printf("\nRead %d items\n", items_selected);
+ for(int idx = 0; idx < items_selected; idx++) {
+ puts(native.filename(idx));
+ }
+ }
}
int main(int argc, char **argv) {
@@ -78,7 +140,7 @@
G_filename->value(argc <= argn ? "." : argv[argn]);
G_filename->tooltip("Default filename");
y += G_filename->h() + 5;
- Fl_Button *but = new Fl_Button(win->w()-80-10, win->h()-25-10, 80, 25,
"Pick File");
+ Fl_Button *but = new Fl_Button(win->w()-110-10, win->h()-25-10, 110, 25,
"Pick File");
but->callback(Butt_CB);
Fl_Box *dummy = new Fl_Box(80, 0, 430, 100);
dummy->hide();
_______________________________________________
fltk-dev mailing list
fltk-dev@easysw.com
http://lists.easysw.com/mailman/listinfo/fltk-dev