4b561b6e90
Updated the configure script for *BSD and GCC 2.95 (-fno-exceptions) Added install rule to documentation directory. Dumped old packages directory; added traditional RPM spec file and EPM list file (that replace all of the packages stuff) The FLUID man page is now "fluid.1" for the formatted page and "fluid.man" for the non-formatted page, since only IRIX uses pack'd formatted man pages. Whew! git-svn-id: file:///fltk/svn/fltk/branches/branch-1.0@1090 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
627 lines
18 KiB
C++
627 lines
18 KiB
C++
//
|
|
// "$Id: fl_file_chooser.cxx,v 1.10.2.3 2000/04/25 22:16:41 mike Exp $"
|
|
//
|
|
// File chooser widget for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 1998-2000 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
// USA.
|
|
//
|
|
// Please report all bugs and problems to "fltk-bugs@easysw.com".
|
|
//
|
|
|
|
#include <config.h>
|
|
#include <FL/fl_file_chooser.H>
|
|
|
|
#include <FL/Fl.H>
|
|
#include <FL/Fl_Window.H>
|
|
#include <FL/Fl_Box.H>
|
|
#include <FL/Fl_Button.H>
|
|
#include <FL/Fl_Return_Button.H>
|
|
#include <FL/Fl_Browser_.H>
|
|
#include <FL/Fl_Input.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <FL/filename.H>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
|
|
static void default_callback(const char*) {}
|
|
static void (*current_callback)(const char*) = default_callback;
|
|
void fl_file_chooser_callback(void (*cb)(const char*)) {
|
|
current_callback = cb ? cb : default_callback;
|
|
}
|
|
|
|
// "File Chooser Browser" widget:
|
|
class FCB : public Fl_Browser_ {
|
|
void* item_first() const ;
|
|
void* item_next(void*) const ;
|
|
void* item_prev(void*) const ;
|
|
int item_height(const dirent*, int) const ;
|
|
int item_height(void*) const ;
|
|
int item_width(const dirent*) const ;
|
|
int item_width(void*) const ;
|
|
int item_quick_height(void*) const ;
|
|
int incr_height() const ;
|
|
void item_draw(void*, int, int, int, int) const ;
|
|
int checkdir(const dirent*, char*) const ;
|
|
void draw();
|
|
void clear_prev();
|
|
public:
|
|
char listed[FL_PATH_MAX];// current dir & starname
|
|
int dirend; // points after last / before starname
|
|
int nameend; // length to trailing '*' or '\0'
|
|
const char* pattern; // default pattern
|
|
dirent** list; // the file names
|
|
dirent** last; // pointer after end of list
|
|
const char* message; // message if no file names
|
|
char preved[FL_PATH_MAX];// directory listed in prev
|
|
dirent** prev; // cached list of another directory
|
|
dirent** prev_last; // end of that list
|
|
int prev_count;
|
|
FCB(int x, int y, int w, int h) : Fl_Browser_(x, y, w, h, 0) {
|
|
type(FL_HOLD_BROWSER);
|
|
listed[0] = 0;
|
|
dirend = nameend = 1;
|
|
pattern = 0;
|
|
list = prev = 0;
|
|
message = 0;
|
|
}
|
|
// ~FCB nyi
|
|
void clear();
|
|
void set(const char*);
|
|
int get(char*);
|
|
};
|
|
|
|
// "File Chooser Window" widget:
|
|
class FCW : public Fl_Window {
|
|
public:
|
|
int handle(int);
|
|
Fl_Input input;
|
|
Fl_Button* ok_button;
|
|
Fl_Button* cancel_button;
|
|
Fl_Button* normal_button;
|
|
FCB browser;
|
|
FCW();
|
|
};
|
|
|
|
/* Files are marked as being directories by replacing the trailing null
|
|
with a '/' if it is a directory, a '\001' if it is *not* a directory.
|
|
An item has height (and is thus selectable) if it is either a directory
|
|
or if it matches the pattern. Quick-height assummes all unknown files
|
|
are directories, and thus saves the time needed to do a stat().
|
|
*/
|
|
|
|
// return pointer to last character:
|
|
static const char* end_of_name(const dirent* d) {
|
|
#if HAVE_DIRENT_H
|
|
const char* e;
|
|
for (e = d->d_name; ;e++) switch (*e) {
|
|
case 0: case 1: case '/': return e;
|
|
}
|
|
#else
|
|
// warning: clobbers byte after end of name
|
|
return d->d_name + d->d_namelen;
|
|
#endif
|
|
}
|
|
|
|
// return true if item is directory, when given pointer to last character:
|
|
int FCB::checkdir(const dirent* d, char* e) const {
|
|
if (*e == 1) return 0;
|
|
if (*e == '/') return 1;
|
|
char buf[FL_PATH_MAX];
|
|
memcpy(buf, listed, dirend);
|
|
memcpy(buf+dirend, d->d_name, e-d->d_name);
|
|
*(buf+dirend+(e-d->d_name)) = 0;
|
|
if (filename_isdir(buf)) {
|
|
*e = '/'; return 1;
|
|
} else {
|
|
*e = 1; return 0;
|
|
}
|
|
}
|
|
|
|
void* FCB::item_first() const {return list;}
|
|
|
|
void* FCB::item_next(void* p) const {
|
|
if ((dirent**)p+1 >= last) return 0;
|
|
return (dirent**)p+1;
|
|
}
|
|
|
|
void* FCB::item_prev(void* p) const {
|
|
if ((dirent**)p <= list) return 0;
|
|
return ((dirent**)p)-1;
|
|
}
|
|
|
|
static int ido_matching(const dirent* p, const char* e, const char* n) {
|
|
// replace / or 1 at end with 0 and do match, then put back. yukko
|
|
int save = *e; *(char*)e = 0;
|
|
int r = filename_match(p->d_name, n);
|
|
*(char*)e = save;
|
|
return(r);
|
|
}
|
|
|
|
int FCB::incr_height() const {return textsize()+2;}
|
|
|
|
int FCB::item_height(const dirent* p, int slow) const {
|
|
const char* e = end_of_name(p);
|
|
if (listed[dirend]) {
|
|
// if (p->d_name[0]=='.' && listed[dirend]!='.') return 0;
|
|
if (listed[nameend-1]=='/') {
|
|
if (slow ? !checkdir(p, (char*)e) : *e==1) return 0;
|
|
((char*)listed)[nameend-1] = 0;
|
|
int r = ido_matching(p, e, listed+dirend);
|
|
((char*)listed)[nameend-1] = '/';
|
|
if (!r) return 0;
|
|
} else {
|
|
if (!ido_matching(p, e, listed+dirend)) return 0;
|
|
}
|
|
} else {
|
|
if (p->d_name[0]=='.') return 0;
|
|
if (pattern && (slow ? !checkdir(p, (char*)e) : *e==1) &&
|
|
!ido_matching(p, e, pattern)) return 0;
|
|
}
|
|
return textsize()+2;
|
|
}
|
|
|
|
int FCB::item_height(void* x) const {
|
|
return item_height(*(const dirent**)x, 1);
|
|
}
|
|
|
|
int FCB::item_quick_height(void* x) const {
|
|
return item_height(*(const dirent**)x, 0);
|
|
}
|
|
|
|
void FCB::item_draw(void* v, int x, int y, int, int h) const {
|
|
const dirent* p = *(const dirent**)v;
|
|
const char* e = end_of_name(p);
|
|
if (checkdir(p, (char*)e)) e++;
|
|
if (v == selection()) fl_color(contrast(textcolor(), selection_color()));
|
|
else fl_color(textcolor());
|
|
fl_font(textfont(), textsize());
|
|
fl_draw(p->d_name, e-p->d_name, x+4, y+h-3);
|
|
}
|
|
|
|
int FCB::item_width(const dirent* p) const {
|
|
const char* e = end_of_name(p); if (*e == '/') e++;
|
|
fl_font(textfont(), textsize());
|
|
return (int)fl_width(p->d_name, e-p->d_name)+4;
|
|
}
|
|
|
|
int FCB::item_width(void* x) const {
|
|
return item_width(*(const dirent**)x);
|
|
}
|
|
|
|
// "get" the current value by copying the name of the selected file
|
|
// or if none are selected, by copying as many common letters as
|
|
// possible of the matched file list:
|
|
int FCB::get(char* buf) {
|
|
dirent** q = (dirent**)selection(); // the file to copy from
|
|
int n = 0; // number of letters
|
|
if (q) { // a file is selected
|
|
const char* e = end_of_name(*q);
|
|
n = e - (*q)->d_name;
|
|
if (*e == '/') n++;
|
|
} else { // do filename completion
|
|
for (q = list; q < last && !item_height(*q, 0); q++);
|
|
if (q < last) {
|
|
const char* e = end_of_name(*q);
|
|
n = e - (*q)->d_name;
|
|
if (*e == '/') n++;
|
|
for (dirent** r = q+1; n && r < last; r++) {
|
|
if (!item_height(*r, 0)) continue;
|
|
int i;
|
|
for (i=0; i<n && (*q)->d_name[i]==(*r)->d_name[i]; i++);
|
|
n = i;
|
|
}
|
|
}
|
|
}
|
|
if (n) {
|
|
memcpy(buf, listed, dirend);
|
|
memcpy(buf+dirend, (*q)->d_name, n);
|
|
buf[dirend+n]=0;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// "set" the current value by changing the directory being listed and
|
|
// changing the highlighted item, if possible:
|
|
void FCB::set(const char* buf) {
|
|
|
|
int bufdirend;
|
|
int ispattern = 0;
|
|
const char* c = buf;
|
|
for (bufdirend=0; *c;) switch(*c++) {
|
|
case '?': case '[': case '*': case '{': ispattern = 1; goto BREAK;
|
|
#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
|
|
case '\\':
|
|
#endif
|
|
case '/': bufdirend=c-buf; break;
|
|
}
|
|
#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
|
|
if ((!bufdirend) && isalpha(buf[0]) && (buf[1]==':')) bufdirend = 2;
|
|
#endif
|
|
BREAK:
|
|
int bufend = strlen(buf);
|
|
if (bufend<=bufdirend) ispattern = 1;
|
|
|
|
// if directory is different, change list to xxx/ :
|
|
if (bufdirend != dirend || strncmp(buf, listed, bufdirend)) {
|
|
if (prev &&
|
|
preved[bufdirend]==0 && !strncmp(buf, preved, bufdirend)) {
|
|
strcpy(preved, listed); preved[dirend] = 0;
|
|
dirent** t;
|
|
t = prev; prev = list; list = t;
|
|
t = prev_last; prev_last = last; last = t;
|
|
strcpy(listed, buf);
|
|
dirend = nameend = bufdirend;
|
|
message = 0;
|
|
} else {
|
|
if (list) {
|
|
clear_prev();
|
|
strcpy(preved, listed); preved[dirend]=0;
|
|
prev = list;
|
|
prev_last = last;
|
|
}
|
|
list = last = 0;
|
|
message = "reading..."; redraw(); Fl::flush(); redraw();
|
|
strcpy(listed, buf);
|
|
dirend = nameend = bufdirend;
|
|
listed[dirend] = listed[dirend+1] = 0;
|
|
int n = filename_list(dirend ? listed : ".", &list);
|
|
if (n < 0) {
|
|
if (errno==ENOENT) message = "No such directory";
|
|
else message = strerror(errno);
|
|
n = 0; list = 0;
|
|
} else message = 0;
|
|
last = list+n;
|
|
}
|
|
if (list && last <= list+2) message = "Empty directory";
|
|
new_list();
|
|
}
|
|
|
|
dirent** q = 0; // will point to future selection
|
|
int any = 0; // true if any names shown
|
|
|
|
// do we match one item in the previous list?
|
|
if (!ispattern && bufend >= nameend) {
|
|
for (q = list; ; q++) {
|
|
if (q >= last) {q = 0; break;}
|
|
if (item_height(*q, 0)==0) continue;
|
|
any = 1;
|
|
const char* a = (*q)->d_name;
|
|
const char* b = buf+bufdirend;
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
while (*b && tolower(*a)==tolower(*b)) {a++; b++;}
|
|
#else
|
|
while (*b && *a==*b) {a++; b++;}
|
|
#endif
|
|
if (!*b && (*a==0 || /* *a=='/' ||*/ *a==1)) break;
|
|
}
|
|
}
|
|
|
|
// no, change the list pattern to the new text + a star:
|
|
if (!q) {
|
|
strcpy(listed+dirend, buf+bufdirend);
|
|
nameend = bufend;
|
|
if (!ispattern) {listed[nameend]='*'; listed[nameend+1]=0;}
|
|
any = 0;
|
|
// search again for an exact match:
|
|
for (q = list; ; q++) {
|
|
if (q >= last) {q = 0; break;}
|
|
if (item_height(*q, 0)==0) continue;
|
|
any = 1;
|
|
const char* a = (*q)->d_name;
|
|
const char* b = buf+bufdirend;
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
while (*b && tolower(*a)==tolower(*b)) {a++; b++;}
|
|
#else
|
|
while (*b && *a==*b) {a++; b++;}
|
|
#endif
|
|
if (!*b && (*a==0 || /* *a=='/' ||*/ *a==1)) break;
|
|
}
|
|
new_list();
|
|
}
|
|
|
|
if (any) message = 0;
|
|
else if (!message) message = "No matching files";
|
|
select_only(q);
|
|
if (q) current_callback(buf);
|
|
}
|
|
|
|
void FCB::draw() {
|
|
if (!message) {
|
|
Fl_Browser_::draw();
|
|
if (full_height() > 0) return;
|
|
message = "No matching files";
|
|
}
|
|
Fl_Boxtype b = box(); if (!b) b = FL_DOWN_BOX;
|
|
draw_box(b,color());
|
|
fl_color(FL_INACTIVE_COLOR);
|
|
fl_font(textfont(), textsize());
|
|
fl_draw(message, x()+7, y()+3, w(), h()-3, FL_ALIGN_TOP_LEFT);
|
|
// insure scrollbars are redrawn if error message goes away:
|
|
scrollbar.redraw();
|
|
hscrollbar.redraw();
|
|
}
|
|
|
|
void FCB::clear_prev() {
|
|
if (prev) {
|
|
for (dirent**p=prev_last-1; p>=prev; p--) free((void*)*p);
|
|
free((void*)prev);
|
|
prev = prev_last = 0;
|
|
}
|
|
}
|
|
|
|
void FCB::clear() {
|
|
if (list) {
|
|
for (dirent**p=last-1; p>=list; p--) free((void*)*p);
|
|
free((void*)list);
|
|
list = last = 0;
|
|
}
|
|
clear_prev();
|
|
listed[0] = 0; dirend = 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static void fcb_cb(Fl_Widget*, void* v) {
|
|
FCW* w = (FCW*)v;
|
|
char buf[FL_PATH_MAX];
|
|
if (w->browser.get(buf)) {
|
|
w->input.value(buf);
|
|
w->input.position(10000);
|
|
// w->input.position(10000, w->browser.dirend);
|
|
if (Fl::event_button()==1) {
|
|
if (Fl::event_clicks()) w->ok_button->do_callback();
|
|
else w->browser.set(buf);
|
|
} else {
|
|
current_callback(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void tab_cb(Fl_Widget*, void* v) {
|
|
FCW* w = (FCW*)v;
|
|
char buf[FL_PATH_MAX];
|
|
if (w->browser.get(buf)) {
|
|
w->input.value(buf);
|
|
w->input.position(10000);
|
|
w->browser.set(buf);
|
|
}
|
|
}
|
|
|
|
#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
|
|
// ':' needs very special handling!
|
|
static inline int isdirsep(char c) {return c=='/' || c=='\\';}
|
|
#else
|
|
#define isdirsep(c) ((c)=='/')
|
|
#endif
|
|
|
|
static void input_cb(Fl_Widget*, void* v) {
|
|
FCW* w = (FCW*)v;
|
|
const char* buf = w->input.value();
|
|
char localbuf[FL_PATH_MAX];
|
|
if (buf[0] && isdirsep(buf[w->input.size()-1])
|
|
&& filename_expand(localbuf, buf)) {
|
|
buf = localbuf;
|
|
w->input.value(localbuf);
|
|
w->input.position(10000);
|
|
}
|
|
w->browser.set(buf);
|
|
}
|
|
|
|
static void up_cb(Fl_Widget*, void* v) { // the .. button
|
|
FCW* w = (FCW*)v;
|
|
char* p;
|
|
char* newname;
|
|
char buf[FL_PATH_MAX];
|
|
p = w->browser.listed+w->browser.dirend-1; // point right before last '/'
|
|
if (p < w->browser.listed)
|
|
newname = "../"; // go up from current directory
|
|
else {
|
|
for (; p>w->browser.listed; p--) if (isdirsep(*(p-1))) break;
|
|
if (isdirsep(*p) || *p=='.' &&
|
|
(isdirsep(p[1]) || p[1]=='.' && isdirsep(p[2]))) {
|
|
p = w->browser.listed+w->browser.dirend;
|
|
memcpy(buf, w->browser.listed, p-w->browser.listed);
|
|
strcpy(buf+(p-w->browser.listed), "../");
|
|
} else {
|
|
memcpy(buf, w->browser.listed, p-w->browser.listed);
|
|
buf[p-w->browser.listed] = 0;
|
|
}
|
|
newname = buf;
|
|
}
|
|
w->input.value(newname);
|
|
w->input.position(10000);
|
|
w->browser.set(newname);
|
|
}
|
|
|
|
static void dir_cb(Fl_Widget* obj, void* v) { // directory buttons
|
|
FCW* w = (FCW*)v;
|
|
const char* p = obj->label(); if (*p=='&') p++;
|
|
char buf[FL_PATH_MAX];
|
|
char* q; for (q=buf; *p && *p!=' '; *q++ = *p++); *q = 0;
|
|
filename_expand(buf, buf);
|
|
w->input.value(buf);
|
|
w->input.position(10000);
|
|
w->browser.set(buf);
|
|
}
|
|
|
|
static void working_cb(Fl_Widget*, void* v) { // directory buttons
|
|
FCW*w = (FCW*)v;
|
|
char buf[FL_PATH_MAX];
|
|
filename_absolute(buf, "");
|
|
w->input.value(buf);
|
|
w->input.position(10000);
|
|
w->browser.set(buf);
|
|
}
|
|
|
|
static void files_cb(Fl_Widget* obj, void* v) { // file pattern buttons
|
|
FCW* w = (FCW*)v;
|
|
char buf[FL_PATH_MAX];
|
|
strcpy(buf, w->input.value());
|
|
char* q = buf+w->browser.dirend;
|
|
if (obj != w->normal_button) { // tack on first word of label
|
|
const char* p = obj->label(); if (*p=='&') p++;
|
|
for (; *p && *p!=' '; *q++ = *p++);
|
|
}
|
|
*q = 0;
|
|
w->input.value(buf);
|
|
w->input.position(10000, w->browser.dirend);
|
|
w->browser.set(buf);
|
|
}
|
|
|
|
/*----------------------- The Main Routine ----------------------*/
|
|
#define HEIGHT_BOX (4*WIDTH_SPC+HEIGHT_BUT+HEIGHT_INPUT+HEIGHT_BROWSER)
|
|
#define HEIGHT_BUT 23
|
|
#define HEIGHT_INPUT 23
|
|
#define HEIGHT_BROWSER (9*HEIGHT_BUT+2) // must be > buttons*HEIGHT_BUT
|
|
#define WIDTH_BOX (3*WIDTH_SPC+WIDTH_BUT+WIDTH_BROWSER)
|
|
#define WIDTH_BROWSER 350
|
|
#define WIDTH_BUT 125
|
|
#define WIDTH_OK 60
|
|
#define WIDTH_SPC 5
|
|
|
|
int FCW::handle(int event) {
|
|
if (Fl_Window::handle(event)) return 1;
|
|
if (event==FL_KEYBOARD && Fl::event_key()==FL_Tab) {
|
|
tab_cb(this, this);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// set this to make extra directory-jumping button:
|
|
const char* fl_file_chooser_button;
|
|
extern const char* fl_ok;
|
|
extern const char* fl_cancel;
|
|
|
|
FCW::FCW() : Fl_Window(WIDTH_BOX, HEIGHT_BOX),
|
|
input(WIDTH_SPC, HEIGHT_BOX-HEIGHT_BUT-2*WIDTH_SPC-HEIGHT_INPUT,
|
|
WIDTH_BOX-2*WIDTH_SPC, HEIGHT_INPUT, 0),
|
|
browser(2*WIDTH_SPC+WIDTH_BUT, WIDTH_SPC,
|
|
WIDTH_BROWSER, HEIGHT_BROWSER)
|
|
{
|
|
int but_y = WIDTH_SPC;
|
|
input.callback(input_cb, this);
|
|
input.when(FL_WHEN_CHANGED);
|
|
// add(browser);
|
|
browser.callback(fcb_cb, this);
|
|
|
|
begin();
|
|
Fl_Widget* obj;
|
|
obj = ok_button = new Fl_Return_Button(
|
|
WIDTH_BOX-2*(WIDTH_SPC+WIDTH_OK), HEIGHT_BOX-WIDTH_SPC-HEIGHT_BUT,
|
|
WIDTH_OK, HEIGHT_BUT, fl_ok);
|
|
obj = cancel_button = new Fl_Button(
|
|
WIDTH_BOX-WIDTH_SPC-WIDTH_OK, HEIGHT_BOX-WIDTH_SPC-HEIGHT_BUT,
|
|
WIDTH_OK, HEIGHT_BUT, fl_cancel);
|
|
cancel_button->shortcut("^[");
|
|
|
|
obj=new Fl_Button(WIDTH_SPC,but_y,WIDTH_BUT,HEIGHT_BUT, "&Up one directory");
|
|
obj->callback(up_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj = new Fl_Button(WIDTH_SPC, but_y, WIDTH_BUT, HEIGHT_BUT, "&~/ Home");
|
|
obj->callback(dir_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj = new Fl_Button(WIDTH_SPC, but_y, WIDTH_BUT, HEIGHT_BUT, "&/ Root");
|
|
obj->callback(dir_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj=new Fl_Button(WIDTH_SPC, but_y, WIDTH_BUT, HEIGHT_BUT, "&Current dir");
|
|
obj->callback(working_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
if (fl_file_chooser_button) {
|
|
obj=new Fl_Button(WIDTH_SPC,but_y,WIDTH_BUT,HEIGHT_BUT,fl_file_chooser_button);
|
|
obj->callback(dir_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
}
|
|
|
|
normal_button = new Fl_Button(WIDTH_SPC, but_y, WIDTH_BUT, HEIGHT_BUT, "");
|
|
normal_button->callback(files_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj = new Fl_Button(WIDTH_SPC,but_y, WIDTH_BUT, HEIGHT_BUT, "* &All files");
|
|
obj->callback(files_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj = new Fl_Button(WIDTH_SPC,but_y,WIDTH_BUT,HEIGHT_BUT, ". &Hidden files");
|
|
obj->callback(files_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
obj = new Fl_Button(WIDTH_SPC,but_y,WIDTH_BUT,HEIGHT_BUT, "*/ &Directories");
|
|
obj->callback(files_cb, this);
|
|
but_y += HEIGHT_BUT;
|
|
|
|
resizable(new Fl_Box(browser.x(), but_y,
|
|
ok_button->x()-browser.x(),
|
|
browser.y()+browser.h()-but_y));
|
|
// add(input); // put last for better draw() speed
|
|
end();
|
|
set_modal();
|
|
}
|
|
|
|
char* fl_file_chooser(const char* message, const char* pat, const char* fname)
|
|
{
|
|
static FCW* f; if (!f) f = new FCW();
|
|
f->ok_button->label(fl_ok);
|
|
f->cancel_button->label(fl_cancel);
|
|
|
|
if (pat && !*pat) pat = 0;
|
|
if (fname && *fname) {
|
|
f->input.value(fname);
|
|
} else if (f->browser.pattern != pat && (!pat || !f->browser.pattern ||
|
|
strcmp(pat,f->browser.pattern))) {
|
|
// if pattern is different, remove name but leave old directory:
|
|
const char* p = f->input.value();
|
|
const char* q = filename_name(p);
|
|
f->input.value(p, q-p);
|
|
}
|
|
f->browser.pattern = pat;
|
|
f->normal_button->label(pat ? pat : "visible files");
|
|
f->browser.set(f->input.value());
|
|
f->input.position(10000, f->browser.dirend);
|
|
|
|
f->label(message);
|
|
f->hotspot(f);
|
|
f->show();
|
|
int ok = 0;
|
|
for (;;) {
|
|
Fl::wait();
|
|
Fl_Widget* o = Fl::readqueue();
|
|
if (o == f->ok_button) {ok = 1; break;}
|
|
else if (o == f->cancel_button || o == f) break;
|
|
}
|
|
f->hide();
|
|
f->browser.clear();
|
|
|
|
if (!ok) return 0;
|
|
const char* r = f->input.value();
|
|
const char* p;
|
|
for (p=r+f->browser.dirend; *p; p++)
|
|
if (*p=='*' || *p=='?' || *p=='[' || *p=='{') return 0;
|
|
return (char*)r;
|
|
}
|
|
|
|
//
|
|
// End of "$Id: fl_file_chooser.cxx,v 1.10.2.3 2000/04/25 22:16:41 mike Exp $".
|
|
//
|