STR #3088: make Fl_Native_File_Chooser use the standard GTK file dialog when available.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10186 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
460544455d
commit
baebff2227
5
CHANGES
5
CHANGES
@ -1,7 +1,10 @@
|
||||
CHANGES IN FLTK 1.3.3 RELEASED: MMM DD YYYY
|
||||
|
||||
- on Linux/Unix, class Fl_Native_File_Chooser uses file dialogs of the Gnome
|
||||
environment (provided by the libgtk dynamic library), when this is available,
|
||||
and falls back to FLTK's Fl_File_Chooser, when it's not (STR #3088).
|
||||
- added class Fl_Copy_Surface allowing to copy graphical data to the clipboard
|
||||
in a cross-platform way.
|
||||
in a cross-platform way (STR #3058).
|
||||
- added support for pasting graphical data from the clipboard to an FLTK widget.
|
||||
- added class Fl_Image_Surface allowing to draw into an Fl_Image object.
|
||||
- removed constraint that lines are limited to 1024 chars in widget labels and browser lines (STR #2990).
|
||||
|
12
FL/Fl.H
12
FL/Fl.H
@ -173,7 +173,7 @@ public:
|
||||
/// a text in a text widget will change focus to the next text widget.
|
||||
/// (This is considered 'old' behavior)
|
||||
///
|
||||
/// When switched off, the cursor will stop at the end of the text.
|
||||
/// When switched off (default), the cursor will stop at the end of the text.
|
||||
/// Pressing Tab or Ctrl-Tab will advance the keyboard focus.
|
||||
///
|
||||
/// See also: Fl_Input_::tab_nav()
|
||||
@ -189,19 +189,23 @@ public:
|
||||
// decides to choose the file.
|
||||
// \todo implement me
|
||||
//OPTION_FILECHOOSER_PREVIEW,
|
||||
/// If visible focus is switched on, FLTK will draw a dotted rectangle
|
||||
/// If visible focus is switched on (default), FLTK will draw a dotted rectangle
|
||||
/// inside the widget that will receive the next keystroke. If switched
|
||||
/// off, no such indicator will be drawn and keyboard navigation
|
||||
/// is disabled.
|
||||
OPTION_VISIBLE_FOCUS,
|
||||
/// If text drag-and-drop is enabled, the user can select and drag text
|
||||
/// If text drag-and-drop is enabled (default), the user can select and drag text
|
||||
/// from any text widget. If disabled, no dragging is possible, however
|
||||
/// dropping text from other applications still works.
|
||||
OPTION_DND_TEXT,
|
||||
/// If tooltips are enabled, hovering the mouse over a widget with a
|
||||
/// If tooltips are enabled (default), hovering the mouse over a widget with a
|
||||
/// tooltip text will open a little tooltip window until the mouse leaves
|
||||
/// the widget. If disabled, no tooltip is shown.
|
||||
OPTION_SHOW_TOOLTIPS,
|
||||
/// When switched on (default), Fl_Native_File_Chooser runs GTK file dialogs
|
||||
/// if the GTK library is available on the platform (linux/unix only).
|
||||
/// When switched off, GTK file dialogs aren't used even if the GTK library is available.
|
||||
OPTION_FNFC_USES_GTK,
|
||||
// don't change this, leave it always as the last element
|
||||
/// For internal use only.
|
||||
OPTION_LAST
|
||||
|
@ -3,7 +3,7 @@
|
||||
//
|
||||
// FLTK native OS file chooser widget
|
||||
//
|
||||
// Copyright 1998-2010 by Bill Spitzak and others.
|
||||
// Copyright 1998-2014 by Bill Spitzak and others.
|
||||
// Copyright 2004 Greg Ercolano.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
@ -23,47 +23,46 @@
|
||||
#ifndef FL_NATIVE_FILE_CHOOSER_H
|
||||
#define FL_NATIVE_FILE_CHOOSER_H
|
||||
|
||||
/* \file
|
||||
Fl_Native_File_Chooser widget. */
|
||||
|
||||
// Use Windows' chooser
|
||||
#ifdef WIN32
|
||||
// #define _WIN32_WINNT 0x0501 // needed for OPENFILENAME's 'FlagsEx'
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // malloc
|
||||
#include <windows.h>
|
||||
#include <commdlg.h> // OPENFILENAME, GetOpenFileName()
|
||||
#include <shlobj.h> // BROWSEINFO, SHBrowseForFolder()
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h> // malloc
|
||||
# include <windows.h>
|
||||
# include <commdlg.h> // OPENFILENAME, GetOpenFileName()
|
||||
# include <shlobj.h> // BROWSEINFO, SHBrowseForFolder()
|
||||
#endif
|
||||
|
||||
// Use Apple's chooser
|
||||
#ifdef __APPLE__
|
||||
#define MAXFILTERS 80
|
||||
# define MAXFILTERS 80
|
||||
#endif
|
||||
|
||||
// All else falls back to FLTK's own chooser
|
||||
#if ! defined(__APPLE__) && !defined(WIN32)
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
#include <unistd.h> // _POSIX_NAME_MAX
|
||||
# include <FL/Fl_File_Chooser.H>
|
||||
# include <unistd.h> // _POSIX_NAME_MAX
|
||||
#else
|
||||
#include <FL/filename.H> // FL_EXPORT
|
||||
# include <FL/filename.H> // FL_EXPORT
|
||||
#endif
|
||||
|
||||
class Fl_FLTK_File_Chooser;
|
||||
class Fl_GTK_File_Chooser;
|
||||
|
||||
/**
|
||||
This class lets an FLTK application easily and consistently access
|
||||
the operating system's native file chooser. Some operating systems
|
||||
have very complex and specific file choosers that many users want
|
||||
access to specifically, instead of FLTK's default file chooser(s).
|
||||
|
||||
This class lets an FLTK application easily and consistently access
|
||||
the operating system's native file chooser. Some operating systems
|
||||
have very complex and specific file choosers that many users want
|
||||
access to specifically, instead of FLTK's default file chooser(s).
|
||||
|
||||
In cases where there is no native file browser, FLTK's own file browser
|
||||
is used instead.
|
||||
|
||||
|
||||
To use this widget, use the following include in your code:
|
||||
\code
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
\endcode
|
||||
|
||||
|
||||
The following example shows how to pick a single file:
|
||||
\code
|
||||
// Create and post the local native file chooser
|
||||
@ -82,25 +81,28 @@
|
||||
default: printf("PICKED: %s\n", fnfc.filename()); break; // FILE CHOSEN
|
||||
}
|
||||
\endcode
|
||||
|
||||
|
||||
The Fl_Native_File_Chooser widget transmits UTF-8 encoded filenames to its user. It is
|
||||
recommended to open files that may have non-ASCII names with the fl_fopen() or
|
||||
fl_open() utility functions that handle these names in a cross-platform way
|
||||
(whereas the standard fopen()/open() functions fail on the MSWindows platform
|
||||
fl_open() utility functions that handle these names in a cross-platform way
|
||||
(whereas the standard fopen()/open() functions fail on the MSWindows platform
|
||||
to open files with a non-ASCII name).
|
||||
|
||||
|
||||
<B>Platform Specific Caveats</B>
|
||||
|
||||
- Under X windows, it's best if you call Fl_File_Icon::load_system_icons()
|
||||
|
||||
- Under X windows, and if Fl::OPTION_FNFC_USES_GTK has not been switched off,
|
||||
the widget attempts to use standard GTK file chooser dialogs if they are
|
||||
available at run-time on the platform, and falls back to use FLTK's Fl_File_Chooser if they are not.
|
||||
In the latter case, it's best if you call Fl_File_Icon::load_system_icons()
|
||||
at the start of main(), to enable the nicer looking file browser widgets.
|
||||
Use the static public attributes of class Fl_File_Chooser to localize
|
||||
the browser.
|
||||
- Some operating systems support certain OS specific options; see
|
||||
- Some operating systems support certain OS specific options; see
|
||||
Fl_Native_File_Chooser::options() for a list.
|
||||
|
||||
|
||||
\image html Fl_Native_File_Chooser.png "The Fl_Native_File_Chooser on different platforms."
|
||||
\image latex Fl_Native_File_Chooser.png "The Fl_Native_File_Chooser on different platforms" width=14cm
|
||||
|
||||
|
||||
*/
|
||||
class FL_EXPORT Fl_Native_File_Chooser {
|
||||
public:
|
||||
@ -121,39 +123,39 @@ public:
|
||||
};
|
||||
/** Localizable message */
|
||||
static const char *file_exists_message;
|
||||
|
||||
|
||||
public:
|
||||
Fl_Native_File_Chooser(int val=BROWSE_FILE);
|
||||
~Fl_Native_File_Chooser();
|
||||
|
||||
|
||||
// Public methods
|
||||
void type(int);
|
||||
int type() const;
|
||||
void options(int);
|
||||
void type(int t);
|
||||
int type() const ;
|
||||
void options(int o);
|
||||
int options() const;
|
||||
int count() const;
|
||||
const char *filename() const;
|
||||
const char *filename(int i) const;
|
||||
void directory(const char *val);
|
||||
const char *filename() const ;
|
||||
const char *filename(int i) const ;
|
||||
void directory(const char *val) ;
|
||||
const char *directory() const;
|
||||
void title(const char *);
|
||||
void title(const char *t);
|
||||
const char* title() const;
|
||||
const char *filter() const;
|
||||
void filter(const char *);
|
||||
int filters() const;
|
||||
void filter_value(int i);
|
||||
int filter_value() const;
|
||||
void preset_file(const char*);
|
||||
const char *filter() const ;
|
||||
void filter(const char *f);
|
||||
int filters() const ;
|
||||
void filter_value(int i) ;
|
||||
int filter_value() const ;
|
||||
void preset_file(const char*f) ;
|
||||
const char* preset_file() const;
|
||||
const char *errmsg() const;
|
||||
int show();
|
||||
|
||||
const char *errmsg() const ;
|
||||
int show() ;
|
||||
|
||||
#ifdef WIN32
|
||||
private:
|
||||
int _btype; // kind-of browser to show()
|
||||
int _options; // general options
|
||||
OPENFILENAMEW _ofn; // GetOpenFileName() & GetSaveFileName() struct
|
||||
BROWSEINFOW _binf; // SHBrowseForFolder() struct
|
||||
BROWSEINFOW _binf; // SHBrowseForFolder() struct
|
||||
char **_pathnames; // array of pathnames
|
||||
int _tpathnames; // total pathnames
|
||||
char *_directory; // default pathname to use
|
||||
@ -163,14 +165,14 @@ private:
|
||||
int _nfilters; // number of filters parse_filter counted
|
||||
char *_preset_file; // the file to preselect
|
||||
char *_errmsg; // error message
|
||||
|
||||
|
||||
// Private methods
|
||||
void errmsg(const char *msg);
|
||||
|
||||
|
||||
void clear_pathnames();
|
||||
void set_single_pathname(const char *s);
|
||||
void add_pathname(const char *s);
|
||||
|
||||
|
||||
void FreePIDL(LPITEMIDLIST pidl);
|
||||
void ClearOFN();
|
||||
void ClearBINF();
|
||||
@ -179,7 +181,7 @@ private:
|
||||
int showfile();
|
||||
static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data);
|
||||
int showdir();
|
||||
|
||||
|
||||
void parse_filter(const char *);
|
||||
void clear_filters();
|
||||
void add_filter(const char *, const char *);
|
||||
@ -195,22 +197,22 @@ private:
|
||||
char *_directory; // default pathname to use
|
||||
char *_title; // title for window
|
||||
char *_preset_file; // the 'save as' filename
|
||||
|
||||
|
||||
char *_filter; // user-side search filter, eg:
|
||||
// C Files\t*.[ch]\nText Files\t*.txt"
|
||||
|
||||
// C Files\t*.[ch]\nText Files\t*.txt"
|
||||
|
||||
char *_filt_names; // filter names (tab delimited)
|
||||
// eg. "C Files\tText Files"
|
||||
|
||||
// eg. "C Files\tText Files"
|
||||
|
||||
char *_filt_patt[MAXFILTERS];
|
||||
// array of filter patterns, eg:
|
||||
// _filt_patt[0]="*.{cxx,h}"
|
||||
// _filt_patt[1]="*.txt"
|
||||
|
||||
|
||||
int _filt_total; // parse_filter() # of filters loaded
|
||||
int _filt_value; // index of the selected filter
|
||||
char *_errmsg; // error message
|
||||
|
||||
|
||||
// Private methods
|
||||
void errmsg(const char *msg);
|
||||
void clear_pathnames();
|
||||
@ -225,6 +227,7 @@ private:
|
||||
|
||||
#if ! defined(__APPLE__) && !defined(WIN32)
|
||||
private:
|
||||
#if FLTK_ABI_VERSION <= 10302
|
||||
int _btype; // kind-of browser to show()
|
||||
int _options; // general options
|
||||
int _nfilters;
|
||||
@ -235,17 +238,100 @@ private:
|
||||
char *_prevvalue; // Returned filename
|
||||
char *_directory;
|
||||
char *_errmsg; // error message
|
||||
Fl_File_Chooser *_file_chooser;
|
||||
|
||||
// Private methods
|
||||
void errmsg(const char *msg);
|
||||
int type_fl_file(int);
|
||||
void parse_filter();
|
||||
void keeplocation();
|
||||
int exist_dialog();
|
||||
#endif
|
||||
static int have_looked_for_GTK_libs;
|
||||
union {
|
||||
Fl_FLTK_File_Chooser *_x11_file_chooser;
|
||||
Fl_GTK_File_Chooser *_gtk_file_chooser;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined(__APPLE__) && !defined(WIN32)
|
||||
class Fl_FLTK_File_Chooser {
|
||||
friend class Fl_Native_File_Chooser;
|
||||
protected:
|
||||
int _btype; // kind-of browser to show()
|
||||
int _options; // general options
|
||||
int _nfilters;
|
||||
char *_filter; // user supplied filter
|
||||
char *_parsedfilt; // parsed filter
|
||||
int _filtvalue; // selected filter
|
||||
char *_preset_file;
|
||||
char *_prevvalue; // Returned filename
|
||||
char *_directory;
|
||||
char *_errmsg; // error message
|
||||
Fl_FLTK_File_Chooser(int val);
|
||||
virtual ~Fl_FLTK_File_Chooser();
|
||||
void errmsg(const char *msg);
|
||||
int type_fl_file(int);
|
||||
void parse_filter();
|
||||
int exist_dialog();
|
||||
Fl_File_Chooser *_file_chooser;
|
||||
virtual void type(int);
|
||||
int type() const;
|
||||
void options(int);
|
||||
int options() const;
|
||||
virtual int count() const;
|
||||
virtual const char *filename() const;
|
||||
virtual const char *filename(int i) const;
|
||||
void directory(const char *val);
|
||||
const char *directory() const;
|
||||
virtual void title(const char *);
|
||||
virtual const char* title() const;
|
||||
const char *filter() const;
|
||||
void filter(const char *);
|
||||
int filters() const;
|
||||
void filter_value(int i);
|
||||
int filter_value() const;
|
||||
void preset_file(const char*);
|
||||
const char* preset_file() const;
|
||||
const char *errmsg() const;
|
||||
virtual int show();
|
||||
};
|
||||
|
||||
|
||||
class Fl_GTK_File_Chooser : public Fl_FLTK_File_Chooser {
|
||||
friend class Fl_Native_File_Chooser;
|
||||
private:
|
||||
typedef struct _GtkWidget GtkWidget;
|
||||
typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
|
||||
struct pair {
|
||||
Fl_GTK_File_Chooser* running; // the running Fl_GTK_File_Chooser
|
||||
const char *filter; // a filter string of the chooser
|
||||
pair(Fl_GTK_File_Chooser* c, const char *f) {
|
||||
running = c;
|
||||
filter = strdup(f);
|
||||
};
|
||||
~pair() {
|
||||
free((char*)filter);
|
||||
};
|
||||
};
|
||||
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
|
||||
const char *previous_filter;
|
||||
|
||||
int fl_gtk_chooser_wrapper(); // method that wraps the GTK widget
|
||||
Fl_GTK_File_Chooser(int val);
|
||||
virtual ~Fl_GTK_File_Chooser();
|
||||
static int did_find_GTK_libs;
|
||||
static void probe_for_GTK_libs(void);
|
||||
virtual void type(int);
|
||||
virtual int count() const;
|
||||
virtual const char *filename() const;
|
||||
virtual const char *filename(int i) const;
|
||||
virtual void title(const char *);
|
||||
virtual const char* title() const;
|
||||
virtual int show();
|
||||
void changed_output_type(const char *filter);
|
||||
|
||||
static int custom_gtk_filter_function(const GtkFileFilterInfo*, Fl_GTK_File_Chooser::pair*);
|
||||
static void free_pair(pair *p);
|
||||
};
|
||||
#endif // !defined(__APPLE__) && !defined(WIN32)
|
||||
|
||||
#endif /*FL_NATIVE_FILE_CHOOSER_H*/
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 401 KiB |
@ -2069,6 +2069,8 @@ bool Fl::option(Fl_Option opt)
|
||||
options_[OPTION_DND_TEXT] = tmp;
|
||||
opt_prefs.get("ShowTooltips", tmp, 1); // default: on
|
||||
options_[OPTION_SHOW_TOOLTIPS] = tmp;
|
||||
opt_prefs.get("FNFCUsesGTK", tmp, 1); // default: on
|
||||
options_[OPTION_FNFC_USES_GTK] = tmp;
|
||||
}
|
||||
{ // next, check the user preferences
|
||||
// override system options only, if the option is set ( >= 0 )
|
||||
@ -2086,6 +2088,8 @@ bool Fl::option(Fl_Option opt)
|
||||
if (tmp >= 0) options_[OPTION_DND_TEXT] = tmp;
|
||||
opt_prefs.get("ShowTooltips", tmp, -1);
|
||||
if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
|
||||
opt_prefs.get("FNFCUsesGTK", tmp, -1);
|
||||
if (tmp >= 0) options_[OPTION_FNFC_USES_GTK] = tmp;
|
||||
}
|
||||
{ // now, if the developer has registered this app, we could as for per-application preferences
|
||||
}
|
||||
|
@ -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-2014 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
|
||||
@ -25,24 +24,20 @@
|
||||
#define FLTK_CHOOSER_CREATE Fl_File_Chooser::CREATE
|
||||
|
||||
#include "Fl_Native_File_Chooser_common.cxx"
|
||||
#include "Fl_Native_File_Chooser_GTK.cxx"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
int Fl_Native_File_Chooser::have_looked_for_GTK_libs = 0;
|
||||
|
||||
/**
|
||||
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().
|
||||
*/
|
||||
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;
|
||||
//// }
|
||||
#if FLTK_ABI_VERSION <= 10302
|
||||
_btype = val;
|
||||
_options = NO_OPTIONS;
|
||||
_filter = NULL;
|
||||
@ -52,17 +47,201 @@ Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
|
||||
_prevvalue = NULL;
|
||||
_directory = NULL;
|
||||
_errmsg = NULL;
|
||||
_file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
|
||||
type(val); // do this after _file_chooser created
|
||||
#endif // FLTK_ABI_VERSION
|
||||
if (have_looked_for_GTK_libs == 0) {
|
||||
// First Time here, try to find the GTK libs if they are installed
|
||||
if (Fl::option(Fl::OPTION_FNFC_USES_GTK)) {
|
||||
Fl_GTK_File_Chooser::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 (Fl_GTK_File_Chooser::did_find_GTK_libs) _gtk_file_chooser = new Fl_GTK_File_Chooser(val);
|
||||
else _x11_file_chooser = new Fl_FLTK_File_Chooser(val);
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor.
|
||||
Deallocates any resources allocated to this widget.
|
||||
*/
|
||||
Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
|
||||
delete _x11_file_chooser;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the current Fl_Native_File_Chooser::Type of browser.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::type(int t) { return _x11_file_chooser->type(t); }
|
||||
/**
|
||||
Gets the current Fl_Native_File_Chooser::Type of browser.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::type() const { return _x11_file_chooser->type(); }
|
||||
/**
|
||||
Sets the platform specific chooser options to \p val.
|
||||
\p val is expected to be one or more Fl_Native_File_Chooser::Option flags ORed together.
|
||||
Some platforms have OS-specific functions that can be enabled/disabled via this method.
|
||||
<P>
|
||||
\code
|
||||
Flag Description Win Mac Other
|
||||
-------------- ----------------------------------------------- ------- ------- -------
|
||||
NEW_FOLDER Shows the 'New Folder' button. Ignored Used Used
|
||||
PREVIEW Enables the 'Preview' mode by default. Ignored Ignored Used
|
||||
SAVEAS_CONFIRM Confirm dialog if BROWSE_SAVE_FILE file exists. Used Used Used
|
||||
USE_FILTER_EXT Chooser filter pilots the output file extension. Ignored Used Ignored
|
||||
\endcode
|
||||
*/
|
||||
void Fl_Native_File_Chooser::options(int o) { _x11_file_chooser->options(o); }
|
||||
/**
|
||||
Gets the platform specific Fl_Native_File_Chooser::Option flags.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::options() const { return _x11_file_chooser->options(); }
|
||||
|
||||
/**
|
||||
Returns the number of filenames (or directory names) the user selected.
|
||||
<P>
|
||||
\b Example:
|
||||
\code
|
||||
if ( fnfc->show() == 0 ) {
|
||||
// Print all filenames user selected
|
||||
for (int n=0; n<fnfc->count(); n++ ) {
|
||||
printf("%d) '%s'\n", n, fnfc->filename(n));
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
int Fl_Native_File_Chooser::count() const { return _x11_file_chooser->count(); }
|
||||
/**
|
||||
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 { return _x11_file_chooser->filename(); }
|
||||
/**
|
||||
Return one of the filenames the user selected.
|
||||
Use count() to determine how many filenames the user selected.
|
||||
<P>
|
||||
\b Example:
|
||||
\code
|
||||
if ( fnfc->show() == 0 ) {
|
||||
// Print all filenames user selected
|
||||
for (int n=0; n<fnfc->count(); n++ ) {
|
||||
printf("%d) '%s'\n", n, fnfc->filename(n));
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::filename(int i) const { return _x11_file_chooser->filename(i); }
|
||||
/**
|
||||
Preset the directory the browser will show when opened.
|
||||
If \p val is NULL, or no directory is specified, the chooser will attempt
|
||||
to use the last non-cancelled folder.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::directory(const char *val) { _x11_file_chooser->directory(val); }
|
||||
/**
|
||||
Returns the current preset directory() value.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::directory() const { return _x11_file_chooser->directory(); }
|
||||
/**
|
||||
Set the title of the file chooser's dialog window.
|
||||
Can be NULL if no title desired.
|
||||
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 *t) { _x11_file_chooser->title(t); }
|
||||
/**
|
||||
Get the title of the file chooser's dialog window.
|
||||
Return value may be NULL if no title was set.
|
||||
*/
|
||||
const char* Fl_Native_File_Chooser::title() const { return _x11_file_chooser->title(); }
|
||||
/**
|
||||
Returns the filter string last set.
|
||||
Can be NULL if no filter was set.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::filter() const { return _x11_file_chooser->filter(); }
|
||||
/**
|
||||
Sets the filename filters used for browsing.
|
||||
The default is NULL, which browses all files.
|
||||
<P>
|
||||
The filter string can be any of:
|
||||
<P>
|
||||
- A single wildcard (eg. "*.txt")
|
||||
- Multiple wildcards (eg. "*.{cxx,h,H}")
|
||||
- A descriptive name followed by a "\t" and a wildcard (eg. "Text Files\t*.txt")
|
||||
- A list of separate wildcards with a "\n" between each (eg. "*.{cxx,H}\n*.txt")
|
||||
- A list of descriptive names and wildcards (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
|
||||
<P>
|
||||
The format of each filter is a wildcard, or an optional user description
|
||||
followed by '\\t' and the wildcard.
|
||||
<P>
|
||||
On most platforms, each filter is available to the user via a pulldown menu
|
||||
in the file chooser. The 'All Files' option is always available to the user.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::filter(const char *f) { _x11_file_chooser->filter(f); }
|
||||
/**
|
||||
Gets how many filters were available, not including "All Files"
|
||||
*/
|
||||
int Fl_Native_File_Chooser::filters() const { return _x11_file_chooser->filters(); }
|
||||
/**
|
||||
Sets which filter will be initially selected.
|
||||
|
||||
The first filter is indexed as 0.
|
||||
If filter_value()==filters(), then "All Files" was chosen.
|
||||
If filter_value() > filters(), then a custom filter was set.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::filter_value(int i) { _x11_file_chooser->filter_value(i); }
|
||||
/**
|
||||
Returns which filter value was last selected by the user.
|
||||
This is only valid if the chooser returns success.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::filter_value() const { return _x11_file_chooser->filter_value(); }
|
||||
/**
|
||||
Sets the default filename for the chooser.
|
||||
Use directory() to set the default directory.
|
||||
Mainly used to preset the filename for save dialogs,
|
||||
and on most platforms can be used for opening files as well.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::preset_file(const char* f) { _x11_file_chooser->preset_file(f); }
|
||||
/**
|
||||
Get the preset filename.
|
||||
*/
|
||||
const char* Fl_Native_File_Chooser::preset_file() const { return _x11_file_chooser->preset_file(); }
|
||||
/**
|
||||
Returns a system dependent error message for the last method that failed.
|
||||
This message should at least be flagged to the user in a dialog box, or to some kind of error log.
|
||||
Contents will be valid only for methods that document errmsg() will have info on failures.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::errmsg() const { return _x11_file_chooser->errmsg(); }
|
||||
/**
|
||||
Post the chooser's dialog. Blocks until dialog has been completed or cancelled.
|
||||
\returns
|
||||
- 0 -- user picked a file
|
||||
- 1 -- user cancelled
|
||||
- -1 -- failed; errmsg() has reason
|
||||
*/
|
||||
int Fl_Native_File_Chooser::show() { return _x11_file_chooser->show(); }
|
||||
|
||||
|
||||
Fl_FLTK_File_Chooser::Fl_FLTK_File_Chooser(int val) {
|
||||
_btype = 0;
|
||||
_options = 0;
|
||||
_filter = NULL;
|
||||
_filtvalue = 0;
|
||||
_parsedfilt = NULL;
|
||||
_preset_file = NULL;
|
||||
_prevvalue = NULL;
|
||||
_directory = NULL;
|
||||
_errmsg = NULL;
|
||||
_file_chooser= NULL;
|
||||
if (val >= 0) {
|
||||
_file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
|
||||
type(val); // do this after _file_chooser created
|
||||
}
|
||||
_nfilters = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor.
|
||||
Deallocates any resources allocated to this widget.
|
||||
*/
|
||||
Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
|
||||
Fl_FLTK_File_Chooser::~Fl_FLTK_File_Chooser() {
|
||||
delete _file_chooser;
|
||||
_file_chooser = NULL;
|
||||
_filter = strfree(_filter);
|
||||
_parsedfilt = strfree(_parsedfilt);
|
||||
_preset_file = strfree(_preset_file);
|
||||
@ -71,286 +250,169 @@ Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
|
||||
_errmsg = strfree(_errmsg);
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE: SET ERROR MESSAGE
|
||||
void Fl_Native_File_Chooser::errmsg(const char *msg) {
|
||||
void Fl_FLTK_File_Chooser::errmsg(const char *msg) {
|
||||
_errmsg = strfree(_errmsg);
|
||||
_errmsg = strnew(msg);
|
||||
}
|
||||
|
||||
// PRIVATE: translate Native types to Fl_File_Chooser types
|
||||
int Fl_Native_File_Chooser::type_fl_file(int val) {
|
||||
int Fl_FLTK_File_Chooser::type_fl_file(int val) {
|
||||
switch (val) {
|
||||
case BROWSE_FILE:
|
||||
return(FLTK_CHOOSER_SINGLE);
|
||||
case BROWSE_DIRECTORY:
|
||||
return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
|
||||
case BROWSE_MULTI_FILE:
|
||||
return(FLTK_CHOOSER_MULTI);
|
||||
case BROWSE_MULTI_DIRECTORY:
|
||||
return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
|
||||
case BROWSE_SAVE_FILE:
|
||||
return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
|
||||
case BROWSE_SAVE_DIRECTORY:
|
||||
return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
|
||||
case Fl_Native_File_Chooser::BROWSE_FILE:
|
||||
return(Fl_File_Chooser::SINGLE);
|
||||
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
|
||||
return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::DIRECTORY);
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
|
||||
return(Fl_File_Chooser::MULTI);
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
|
||||
return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::MULTI);
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
|
||||
return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::CREATE);
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
|
||||
return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::MULTI | Fl_File_Chooser::CREATE);
|
||||
default:
|
||||
return(FLTK_CHOOSER_SINGLE);
|
||||
return(Fl_File_Chooser::SINGLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the current Fl_Native_File_Chooser::Type of browser.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::type(int val) {
|
||||
void Fl_FLTK_File_Chooser::type(int val) {
|
||||
_btype = val;
|
||||
_file_chooser->type(type_fl_file(val));
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the current Fl_Native_File_Chooser::Type of browser.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::type() const {
|
||||
int Fl_FLTK_File_Chooser::type() const {
|
||||
return(_btype);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the platform specific chooser options to \p val.
|
||||
\p val is expected to be one or more Fl_Native_File_Chooser::Option flags ORed together.
|
||||
Some platforms have OS-specific functions that can be enabled/disabled via this method.
|
||||
<P>
|
||||
\code
|
||||
Flag Description Win Mac Other
|
||||
-------------- ----------------------------------------------- ------- ------- -------
|
||||
NEW_FOLDER Shows the 'New Folder' button. Ignored Used Used
|
||||
PREVIEW Enables the 'Preview' mode by default. Ignored Ignored Used
|
||||
SAVEAS_CONFIRM Confirm dialog if BROWSE_SAVE_FILE file exists. Used Used Used
|
||||
USE_FILTER_EXT Chooser filter pilots the output file extension. Ignored Used Ignored
|
||||
\endcode
|
||||
*/
|
||||
void Fl_Native_File_Chooser::options(int val) {
|
||||
void Fl_FLTK_File_Chooser::options(int val) {
|
||||
_options = val;
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the platform specific Fl_Native_File_Chooser::Option flags.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::options() const {
|
||||
int Fl_FLTK_File_Chooser::options() const {
|
||||
return(_options);
|
||||
}
|
||||
|
||||
/**
|
||||
Post the chooser's dialog. Blocks until dialog has been completed or cancelled.
|
||||
\returns
|
||||
- 0 -- user picked a file
|
||||
- 1 -- user cancelled
|
||||
- -1 -- failed; errmsg() has reason
|
||||
*/
|
||||
int Fl_Native_File_Chooser::show() {
|
||||
int Fl_FLTK_File_Chooser::show() {
|
||||
|
||||
// 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() & Fl_Native_File_Chooser::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() & Fl_Native_File_Chooser::NEW_FOLDER )
|
||||
_file_chooser->type(_file_chooser->type() | Fl_File_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() & Fl_Native_File_Chooser::SAVEAS_CONFIRM && type() == Fl_Native_File_Chooser::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);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a system dependent error message for the last method that failed.
|
||||
This message should at least be flagged to the user in a dialog box, or to some kind of error log.
|
||||
Contents will be valid only for methods that document errmsg() will have info on failures.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::errmsg() const {
|
||||
const char *Fl_FLTK_File_Chooser::errmsg() const {
|
||||
return(_errmsg ? _errmsg : "No error");
|
||||
}
|
||||
|
||||
/**
|
||||
Return the filename the user choose.
|
||||
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());
|
||||
return("");
|
||||
}
|
||||
|
||||
/**
|
||||
Return one of the filenames the user selected.
|
||||
Use count() to determine how many filenames the user selected.
|
||||
<P>
|
||||
\b Example:
|
||||
\code
|
||||
if ( fnfc->show() == 0 ) {
|
||||
// Print all filenames user selected
|
||||
for (int n=0; n<fnfc->count(); n++ ) {
|
||||
printf("%d) '%s'\n", n, fnfc->filename(n));
|
||||
}
|
||||
const char* Fl_FLTK_File_Chooser::filename() const {
|
||||
if ( _file_chooser->count() > 0 ) {
|
||||
return(_file_chooser->value());
|
||||
}
|
||||
\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
|
||||
return("");
|
||||
}
|
||||
|
||||
/**
|
||||
Set the title of the file chooser's dialog window.
|
||||
Can be NULL if no title desired.
|
||||
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) {
|
||||
const char* Fl_FLTK_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
|
||||
return("");
|
||||
}
|
||||
|
||||
void Fl_FLTK_File_Chooser::title(const char *val) {
|
||||
_file_chooser->label(val);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the title of the file chooser's dialog window.
|
||||
Return value may be NULL if no title was set.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::title() const {
|
||||
return(_file_chooser->label());
|
||||
const char *Fl_FLTK_File_Chooser::title() const {
|
||||
return(_file_chooser->label());
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the filename filters used for browsing.
|
||||
The default is NULL, which browses all files.
|
||||
<P>
|
||||
The filter string can be any of:
|
||||
<P>
|
||||
- A single wildcard (eg. "*.txt")
|
||||
- Multiple wildcards (eg. "*.{cxx,h,H}")
|
||||
- A descriptive name followed by a "\t" and a wildcard (eg. "Text Files\t*.txt")
|
||||
- A list of separate wildcards with a "\n" between each (eg. "*.{cxx,H}\n*.txt")
|
||||
- A list of descriptive names and wildcards (eg. "C++ Files\t*.{cxx,H}\nTxt Files\t*.txt")
|
||||
<P>
|
||||
The format of each filter is a wildcard, or an optional user description
|
||||
followed by '\\t' and the wildcard.
|
||||
<P>
|
||||
On most platforms, each filter is available to the user via a pulldown menu
|
||||
in the file chooser. The 'All Files' option is always available to the user.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::filter(const char *val) {
|
||||
void Fl_FLTK_File_Chooser::filter(const char *val) {
|
||||
_filter = strfree(_filter);
|
||||
_filter = strnew(val);
|
||||
parse_filter();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the filter string last set.
|
||||
Can be NULL if no filter was set.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::filter() const {
|
||||
const char *Fl_FLTK_File_Chooser::filter() const {
|
||||
return(_filter);
|
||||
}
|
||||
|
||||
/**
|
||||
Gets how many filters were available, not including "All Files"
|
||||
*/
|
||||
int Fl_Native_File_Chooser::filters() const {
|
||||
int Fl_FLTK_File_Chooser::filters() const {
|
||||
return(_nfilters);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets which filter will be initially selected.
|
||||
|
||||
The first filter is indexed as 0.
|
||||
If filter_value()==filters(), then "All Files" was chosen.
|
||||
If filter_value() > filters(), then a custom filter was set.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::filter_value(int val) {
|
||||
void Fl_FLTK_File_Chooser::filter_value(int val) {
|
||||
_filtvalue = val;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns which filter value was last selected by the user.
|
||||
This is only valid if the chooser returns success.
|
||||
*/
|
||||
int Fl_Native_File_Chooser::filter_value() const {
|
||||
return(_filtvalue);
|
||||
int Fl_FLTK_File_Chooser::filter_value() const {
|
||||
return _filtvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of filenames (or directory names) the user selected.
|
||||
<P>
|
||||
\b Example:
|
||||
\code
|
||||
if ( fnfc->show() == 0 ) {
|
||||
// Print all filenames user selected
|
||||
for (int n=0; n<fnfc->count(); n++ ) {
|
||||
printf("%d) '%s'\n", n, fnfc->filename(n));
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
int Fl_Native_File_Chooser::count() const {
|
||||
return(_file_chooser->count());
|
||||
int Fl_FLTK_File_Chooser::count() const {
|
||||
return _file_chooser->count();
|
||||
}
|
||||
|
||||
/**
|
||||
Preset the directory the browser will show when opened.
|
||||
If \p val is NULL, or no directory is specified, the chooser will attempt
|
||||
to use the last non-cancelled folder.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::directory(const char *val) {
|
||||
void Fl_FLTK_File_Chooser::directory(const char *val) {
|
||||
_directory = strfree(_directory);
|
||||
_directory = strnew(val);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the current preset directory() value.
|
||||
*/
|
||||
const char *Fl_Native_File_Chooser::directory() const {
|
||||
return(_directory);
|
||||
const char *Fl_FLTK_File_Chooser::directory() const {
|
||||
return _directory;
|
||||
}
|
||||
|
||||
// PRIVATE: Convert our filter format to fltk's chooser format
|
||||
@ -363,7 +425,7 @@ const char *Fl_Native_File_Chooser::directory() const {
|
||||
// Returns a modified version of the filter that the caller is responsible
|
||||
// for freeing with strfree().
|
||||
//
|
||||
void Fl_Native_File_Chooser::parse_filter() {
|
||||
void Fl_FLTK_File_Chooser::parse_filter() {
|
||||
_parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any)
|
||||
_nfilters = 0;
|
||||
char *in = _filter;
|
||||
@ -426,27 +488,17 @@ void Fl_Native_File_Chooser::parse_filter() {
|
||||
//NOTREACHED
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the default filename for the chooser.
|
||||
Use directory() to set the default directory.
|
||||
Mainly used to preset the filename for save dialogs,
|
||||
and on most platforms can be used for opening files as well.
|
||||
*/
|
||||
void Fl_Native_File_Chooser::preset_file(const char* val) {
|
||||
void Fl_FLTK_File_Chooser::preset_file(const char* val) {
|
||||
_preset_file = strfree(_preset_file);
|
||||
_preset_file = strnew(val);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the preset filename.
|
||||
*/
|
||||
const char* Fl_Native_File_Chooser::preset_file() const {
|
||||
return(_preset_file);
|
||||
const char* Fl_FLTK_File_Chooser::preset_file() const {
|
||||
return _preset_file;
|
||||
}
|
||||
|
||||
|
||||
int Fl_Native_File_Chooser::exist_dialog() {
|
||||
return(fl_choice("%s", fl_cancel, fl_ok, NULL, file_exists_message));
|
||||
int Fl_FLTK_File_Chooser::exist_dialog() {
|
||||
return fl_choice("%s", fl_cancel, fl_ok, NULL, Fl_Native_File_Chooser::file_exists_message);
|
||||
}
|
||||
|
||||
//
|
||||
|
700
src/Fl_Native_File_Chooser_GTK.cxx
Normal file
700
src/Fl_Native_File_Chooser_GTK.cxx
Normal file
@ -0,0 +1,700 @@
|
||||
// "$Id$"
|
||||
//
|
||||
// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
|
||||
//
|
||||
// Copyright 1998-2014 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
|
||||
// file is missing or damaged, see the license at:
|
||||
//
|
||||
// http://www.fltk.org/COPYING.php
|
||||
//
|
||||
// Please report all bugs and problems to:
|
||||
//
|
||||
// http://www.fltk.org/str.php
|
||||
//
|
||||
|
||||
#include <FL/x.H>
|
||||
#include <dlfcn.h> // for dlopen et al
|
||||
#include <locale.h> // for setlocale
|
||||
|
||||
/* --------------------- 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 _GdkDrawable GdkWindow;
|
||||
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_NONE = -1;
|
||||
const int GTK_RESPONSE_ACCEPT = -3;
|
||||
const int GTK_RESPONSE_DELETE_EVENT = -4;
|
||||
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 --------------------- */
|
||||
|
||||
int Fl_GTK_File_Chooser::did_find_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;
|
||||
|
||||
// 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_now(GtkWidget *);
|
||||
typedef void (*XX_gtk_widget_show_now)(GtkWidget *);
|
||||
static XX_gtk_widget_show_now fl_gtk_widget_show_now = NULL;
|
||||
|
||||
// GdkWindow* gtk_widget_get_window(GtkWidget *);
|
||||
typedef GdkWindow* (*XX_gtk_widget_get_window)(GtkWidget *);
|
||||
static XX_gtk_widget_get_window fl_gtk_widget_get_window = NULL;
|
||||
|
||||
// Window gdk_x11_drawable_get_xid(GdkWindow *);
|
||||
typedef Window (*XX_gdk_x11_drawable_get_xid)(GdkWindow *);
|
||||
static XX_gdk_x11_drawable_get_xid fl_gdk_x11_drawable_get_xid = 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;
|
||||
|
||||
|
||||
Fl_GTK_File_Chooser::Fl_GTK_File_Chooser(int val) : Fl_FLTK_File_Chooser(-1)
|
||||
{
|
||||
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
|
||||
_btype = val;
|
||||
previous_filter = NULL;
|
||||
}
|
||||
|
||||
Fl_GTK_File_Chooser::~Fl_GTK_File_Chooser()
|
||||
{
|
||||
// Should free up resources taken for...
|
||||
if(gtkw_ptr) {
|
||||
fl_gtk_widget_destroy (gtkw_ptr);
|
||||
gtkw_ptr = NULL;
|
||||
}
|
||||
if(gtkw_filename) {
|
||||
fl_g_free(gtkw_filename);
|
||||
gtkw_filename = NULL;
|
||||
}
|
||||
if(gtkw_slist) {
|
||||
GSList *iter = (GSList *)gtkw_slist;
|
||||
while(iter) {
|
||||
if(iter->data) fl_g_free(iter->data);
|
||||
iter = g_slist_next(iter);
|
||||
}
|
||||
fl_g_slist_free((GSList *)gtkw_slist);
|
||||
gtkw_slist = NULL;
|
||||
}
|
||||
gtkw_count = 0; // assume we have no files selected now
|
||||
gtkw_title = strfree(gtkw_title);
|
||||
}
|
||||
|
||||
void Fl_GTK_File_Chooser::type(int val) {
|
||||
_btype = val;
|
||||
}
|
||||
|
||||
int Fl_GTK_File_Chooser::count() const {
|
||||
return gtkw_count;
|
||||
}
|
||||
|
||||
const char *Fl_GTK_File_Chooser::filename() const
|
||||
{
|
||||
if(gtkw_ptr) {
|
||||
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
|
||||
return gtkw_filename;
|
||||
}
|
||||
else {
|
||||
GSList *iter = (GSList *)gtkw_slist;
|
||||
char *nm = (char *)iter->data;
|
||||
return nm;
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
const char *Fl_GTK_File_Chooser::filename(int i) const
|
||||
{
|
||||
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
|
||||
return gtkw_filename;
|
||||
}
|
||||
else {
|
||||
if ((unsigned)i < gtkw_count) {
|
||||
GSList *iter = (GSList *)gtkw_slist;
|
||||
char *nm = (char *)fl_g_slist_nth_data(iter, i);
|
||||
return nm;
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
void Fl_GTK_File_Chooser::title(const char *val)
|
||||
{
|
||||
strfree(gtkw_title);
|
||||
gtkw_title = strnew(val);
|
||||
}
|
||||
|
||||
const char* Fl_GTK_File_Chooser::title() const
|
||||
{
|
||||
return gtkw_title;
|
||||
}
|
||||
|
||||
/* changes the extension of the outfile in the chooser according to newly selected filter */
|
||||
void Fl_GTK_File_Chooser::changed_output_type(const char *filter)
|
||||
{
|
||||
if ( !(options()&Fl_Native_File_Chooser::USE_FILTER_EXT) ) return;
|
||||
if (strchr(filter, '(') || strchr(filter, '{') || strchr(filter+1, '*') || strncmp(filter, "*.", 2)) return;
|
||||
const char *p = fl_gtk_file_chooser_get_filename((GtkFileChooser*)gtkw_ptr);
|
||||
if (!p) return;
|
||||
p = fl_filename_name(p);
|
||||
const char *q = strrchr(p, '.');
|
||||
if (!q) q = p + strlen(p);
|
||||
char *r = new char[strlen(p) + strlen(filter)];
|
||||
strcpy(r, p);
|
||||
strcpy(r + (q - p), filter + 1);
|
||||
fl_gtk_file_chooser_set_current_name((GtkFileChooser*)gtkw_ptr, r);
|
||||
delete[] r;
|
||||
}
|
||||
|
||||
/* Filters files before display in chooser.
|
||||
Also used to detect when the filter just changed */
|
||||
gboolean Fl_GTK_File_Chooser::custom_gtk_filter_function(const GtkFileFilterInfo *info, Fl_GTK_File_Chooser::pair* p)
|
||||
{
|
||||
if (p->running->previous_filter != p->filter) {
|
||||
p->running->changed_output_type(p->filter);
|
||||
p->running->previous_filter = p->filter;
|
||||
}
|
||||
return (gboolean)fl_filename_match(info->filename, p->filter);
|
||||
}
|
||||
|
||||
void Fl_GTK_File_Chooser::free_pair(Fl_GTK_File_Chooser::pair *p)
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int Fl_GTK_File_Chooser::show()
|
||||
{
|
||||
// The point here is that after running a GTK dialog, the calling program's current locale is modified.
|
||||
// To avoid that, we memorize the calling program's current locale, and the locale as modified
|
||||
// by GTK after the first dialog use. We restore the calling program's current locale
|
||||
// before returning, and we set the locale as modified by GTK before subsequent GTK dialog uses.
|
||||
static bool first = true;
|
||||
char *p;
|
||||
char *before = NULL;
|
||||
static char *gtk_wants = NULL;
|
||||
// record in before the calling program's current locale
|
||||
p = setlocale(LC_ALL, NULL);
|
||||
if (p) before = strdup(p);
|
||||
if (gtk_wants) { // set the locale as GTK 'wants it'
|
||||
setlocale(LC_ALL, gtk_wants);
|
||||
}
|
||||
int retval = fl_gtk_chooser_wrapper(); // may change the locale
|
||||
if (first) {
|
||||
first = false;
|
||||
// record in gtk_wants the locale as modified by the GTK dialog
|
||||
p = setlocale(LC_ALL, NULL);
|
||||
if (p) gtk_wants = strdup(p);
|
||||
}
|
||||
if (before) {
|
||||
setlocale(LC_ALL, before); // restore calling program's current locale
|
||||
free(before);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void run_response_handler(GtkDialog *dialog, gint response_id, gpointer data)
|
||||
{
|
||||
gint *ri = (gint *)data;
|
||||
*ri = response_id;
|
||||
}
|
||||
|
||||
|
||||
int Fl_GTK_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(gtkw_ptr) { // discard the previous dialog widget
|
||||
fl_gtk_widget_destroy (gtkw_ptr);
|
||||
gtkw_ptr = NULL;
|
||||
}
|
||||
|
||||
// set the dialog action type
|
||||
GtkFileChooserAction gtw_action_type;
|
||||
switch (_btype) {
|
||||
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
|
||||
gtw_action_type = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
|
||||
gtw_action_type = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
|
||||
gtw_action_type = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
|
||||
case Fl_Native_File_Chooser::BROWSE_FILE:
|
||||
default:
|
||||
gtw_action_type = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
break;
|
||||
}
|
||||
// create a new dialog
|
||||
gtkw_ptr = fl_gtk_file_chooser_dialog_new (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(!gtkw_ptr) {
|
||||
// fail
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set the dialog properties
|
||||
switch (_btype) {
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY:
|
||||
case Fl_Native_File_Chooser::BROWSE_MULTI_FILE:
|
||||
fl_gtk_file_chooser_set_select_multiple((GtkFileChooser *)gtkw_ptr, TRUE);
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
|
||||
if (_preset_file)fl_gtk_file_chooser_set_current_name ((GtkFileChooser *)gtkw_ptr, fl_filename_name(_preset_file));
|
||||
/* FALLTHROUGH */
|
||||
case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
|
||||
fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtkw_ptr, TRUE);
|
||||
fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser *)gtkw_ptr, (_options & Fl_Native_File_Chooser::SAVEAS_CONFIRM)?TRUE:FALSE);
|
||||
break;
|
||||
|
||||
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
|
||||
case Fl_Native_File_Chooser::BROWSE_FILE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_directory && _directory[0]) fl_gtk_file_chooser_set_current_folder((GtkFileChooser *)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,
|
||||
(GtkFileFilterFunc)Fl_GTK_File_Chooser::custom_gtk_filter_function,
|
||||
new Fl_GTK_File_Chooser::pair(this, p),
|
||||
(GDestroyNotify)Fl_GTK_File_Chooser::free_pair);
|
||||
fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtkw_ptr, filter_tab[count]);
|
||||
p = strtok(NULL, "\t");
|
||||
count++;
|
||||
}
|
||||
free(filter);
|
||||
fl_gtk_file_chooser_set_filter((GtkFileChooser *)gtkw_ptr, filter_tab[_filtvalue]);
|
||||
previous_filter = NULL;
|
||||
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 *)gtkw_ptr, gfilter);
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *toggle = fl_gtk_check_button_new_with_label(Fl_File_Chooser::hidden_label);
|
||||
fl_gtk_file_chooser_set_extra_widget((GtkFileChooser *)gtkw_ptr, toggle);
|
||||
fl_g_signal_connect_data(toggle, "toggled", G_CALLBACK(hidden_files_cb), gtkw_ptr, NULL, (GConnectFlags) 0);
|
||||
Fl_Window* firstw = Fl::first_window();
|
||||
fl_gtk_widget_show_now(gtkw_ptr); // map the GTK window on screen
|
||||
if (firstw) {
|
||||
GdkWindow* gdkw = fl_gtk_widget_get_window(gtkw_ptr);
|
||||
Window xw = fl_gdk_x11_drawable_get_xid(gdkw); // get the X11 ref of the GTK window
|
||||
XSetTransientForHint(fl_display, xw, fl_xid(firstw)); // set the GTK window transient for the last FLTK win
|
||||
}
|
||||
gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser *)gtkw_ptr);
|
||||
fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
|
||||
|
||||
gint response_id = GTK_RESPONSE_NONE;
|
||||
fl_g_signal_connect_data(gtkw_ptr, "response", G_CALLBACK(run_response_handler), &response_id, NULL, (GConnectFlags) 0);
|
||||
while (response_id == GTK_RESPONSE_NONE) { // loop that shows the GTK dialog window
|
||||
fl_gtk_main_iteration(); // one iteration of the GTK event loop
|
||||
while (XEventsQueued(fl_display, QueuedAfterReading)) { // emulate modal dialog
|
||||
XEvent xevent;
|
||||
XNextEvent(fl_display, &xevent);
|
||||
Window xid = xevent.xany.window;
|
||||
if (xevent.type == ConfigureNotify) xid = xevent.xmaprequest.window;
|
||||
if (!fl_find(xid)) continue; // skip events to non-FLTK windows
|
||||
// process Expose and ConfigureNotify events
|
||||
if ( xevent.type == Expose || xevent.type == ConfigureNotify ) fl_handle(xevent);
|
||||
}
|
||||
Fl::flush(); // do the drawings needed after Expose events
|
||||
}
|
||||
|
||||
if (response_id == GTK_RESPONSE_ACCEPT) {
|
||||
if (_parsedfilt) {
|
||||
GtkFileFilter *gfilter = fl_gtk_file_chooser_get_filter((GtkFileChooser *)gtkw_ptr);
|
||||
for (_filtvalue = 0; _filtvalue < _nfilters; _filtvalue++) {
|
||||
if (filter_tab[_filtvalue] == gfilter) break;
|
||||
}
|
||||
}
|
||||
|
||||
// discard any filenames or lists from previous calls
|
||||
if(gtkw_filename) {
|
||||
fl_g_free(gtkw_filename);
|
||||
gtkw_filename = NULL;
|
||||
}
|
||||
if(gtkw_slist) {
|
||||
GSList *iter = (GSList *)gtkw_slist;
|
||||
while(iter) {
|
||||
if(iter->data) fl_g_free(iter->data);
|
||||
iter = g_slist_next(iter);
|
||||
}
|
||||
fl_g_slist_free((GSList *)gtkw_slist);
|
||||
gtkw_slist = NULL;
|
||||
}
|
||||
gtkw_count = 0; // assume we have no files selected now
|
||||
|
||||
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtkw_ptr) == FALSE) {
|
||||
gtkw_filename = fl_gtk_file_chooser_get_filename ((GtkFileChooser *)gtkw_ptr);
|
||||
if (gtkw_filename) {
|
||||
gtkw_count = 1;
|
||||
result = 0;
|
||||
//printf("single: %s\n", gtkw_filename);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gtkw_slist = fl_gtk_file_chooser_get_filenames((GtkFileChooser *)gtkw_ptr);
|
||||
gtkw_count = fl_g_slist_length((GSList *)gtkw_slist);
|
||||
if(gtkw_count) result = 0;
|
||||
|
||||
// puts("multiple");
|
||||
// GSList *iter = (GSList *)gtkw_slist;
|
||||
// printf ("Selected %d files\n", gtkw_count);
|
||||
// while(iter) {
|
||||
// char *nm = (char *)iter->data;
|
||||
// printf("%s\n", nm);
|
||||
// iter = g_slist_next(iter);
|
||||
// }
|
||||
}
|
||||
}
|
||||
delete[] filter_tab;
|
||||
if ( response_id == GTK_RESPONSE_DELETE_EVENT) gtkw_ptr = NULL;
|
||||
else fl_gtk_widget_hide (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
|
||||
|
||||
// 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.
|
||||
*/
|
||||
void Fl_GTK_File_Chooser::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 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
|
||||
if (ptr_gtk && ptr_glib) {
|
||||
#ifdef DEBUG
|
||||
puts("selected GTK-2\n");
|
||||
#endif
|
||||
}
|
||||
else {// Try then with GTK3
|
||||
ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
|
||||
#ifdef DEBUG
|
||||
if (ptr_gtk && ptr_glib) {
|
||||
puts("selected GTK-3\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if((!ptr_glib) || (!ptr_gtk)) {
|
||||
#ifdef DEBUG
|
||||
puts("Failure to load libglib or libgtk");
|
||||
#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_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_now, ptr_gtk);
|
||||
GET_SYM(gtk_widget_get_window, ptr_gtk);
|
||||
GET_SYM(gdk_x11_drawable_get_xid, 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 = 1;
|
||||
} // probe_for_GTK_libs
|
||||
|
||||
//
|
||||
// End of "$Id$".
|
||||
//
|
Loading…
Reference in New Issue
Block a user