📄 fl_file_chooser.cxx
字号:
//// "$Id: fl_file_chooser.cxx,v 1.1.1.1 2003/08/07 21:18:41 jasonk Exp $"//// File chooser widget for the Fast Light Tool Kit (FLTK).//// Copyright 1998-1999 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__) case '\\':#endif case '/': bufdirend=c-buf; break; }#if defined(WIN32) || defined(__EMX__) 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;#ifdef WIN32 while (*b && tolower(*a)==tolower(*b)) {a++; b++;}#else while (*b && *a==*b) {a++; b++;}#endif if (!*b && (*a==0 || /* *a=='/' ||*/ *a==1)) break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -