Logo Search packages:      
Sourcecode: csound version File versions  Download package

Fl_Native_File_Chooser_WIN32.cxx

//
// Fl_Native_File_Chooser_WINDOWS.cxx -- FLTK native OS file chooser widget
//
// Copyright 2004 by Greg Ercolano.
// April 2005 - API changes, improved filter processing by Nathan Vander Wilt
//
// 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 keep code 80 column compliant.
//
//      10        20        30        40        50        60        70
//       |         |         |         |         |         |         |
// 4567890123456789012345678901234567890123456789012345678901234567890123456789
//

// http://www.codeproject.com/dialog/selectfolder.asp - any application to multi-folder implementation?

#include "Fl_Native_File_Chooser.H"
#include <stdio.h>            // debugging
#include "common.cxx"         // strnew/strfree/strapp/chrcat

#define LCURLY_CHR    '{'
#define RCURLY_CHR    '}'
#define LBRACKET_CHR  '['
#define RBRACKET_CHR  ']'

// STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG)
static void dnullprint(char *wp) {
    if ( ! wp ) return;
    for ( int t=0; true; t++ ) {
        if ( wp[t] == '\0' && wp[t+1] == '\0' ) {
          printf("\\0\\0");
          fflush(stdout);
          return;
      } else if ( wp[t] == '\0' ) {
          printf("\\0");
      } else { 
          printf("%c",wp[t]);
      }
    }
}

// RETURN LENGTH OF DOUBLENULL STRING
//    Includes single nulls in count, excludes trailing doublenull.
//
//         1234 567
//         |||/\|||
//    IN: "one\0two\0\0"
//   OUT: 7
//
static int dnulllen(const char *wp) {
    int len = 0;
    while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) )
        { ++wp; ++len; }
    return(len);
}

// STATIC: Append a string to another, leaving terminated with DOUBLE NULL.
//     Automatically handles extending length of string.
//     wp can be NULL (a new wp will be allocated and initialized).
//     string must be NULL terminated.
//     The pointer wp may be modified on return.
//
static void dnullcat(char*&wp, const char *string, int n = -1 ) {
    //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n");
    int inlen = ( n < 0 ) ? strlen(string) : n;
    if ( ! wp ) {
        wp = new char[inlen + 4];
      *(wp+0) = '\0';
      *(wp+1) = '\0';
    } else {
        int wplen = dnulllen(wp);
      // Make copy of wp into larger buffer
      char *tmp = new char[wplen + inlen + 4];
      memcpy(tmp, wp, wplen+2);     // copy of wp plus doublenull
      delete [] wp;                 // delete old wp
      wp = tmp;               // use new copy
      //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen);
    }

    // Find end of double null string
    //     *wp2 is left pointing at second null.
    //
    char *wp2 = wp;
    if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) {
      for ( ; 1; wp2++ )
          if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' )
            { wp2++; break; }
    }

    if ( n == -1 ) n = strlen(string);
    strncpy(wp2, string, n);

    // Leave string double-null terminated
    *(wp2+n+0) = '\0';
    *(wp2+n+1) = '\0';
    //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n");
}

// CTOR
Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
    _btype           = val;
    _options         = NO_OPTIONS;
    memset((void*)&_ofn, 0, sizeof(OPENFILENAME));
    _ofn.lStructSize = sizeof(OPENFILENAME);
    _ofn.hwndOwner   = NULL;
    memset((void*)&_binf, 0, sizeof(BROWSEINFO));
    _pathnames       = NULL;
    _tpathnames      = 0;
    _directory       = NULL;
    _title           = NULL;
    _filter          = NULL;
    _parsedfilt      = NULL;
    _nfilters        = 0;
    _preset_file     = NULL;
    _errmsg          = NULL;
}

// DTOR
Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
    //_pathnames                // managed by clear_pathnames()
    //_tpathnames               // managed by clear_pathnames()
    _directory   = strfree(_directory);
    _title       = strfree(_title);
    _filter      = strfree(_filter);
    //_parsedfilt               // managed by clear_filters()
    //_nfilters                 // managed by clear_filters()
    _preset_file = strfree(_preset_file);
    _errmsg      = strfree(_errmsg);
    clear_filters();
    clear_pathnames();
    ClearOFN();
    ClearBINF();
}

// SET TYPE OF BROWSER
void Fl_Native_File_Chooser::type(int val) {
    _btype = val;
}

// GET TYPE OF BROWSER
int Fl_Native_File_Chooser::type() const {
    return( _btype );
}

// SET OPTIONS
void Fl_Native_File_Chooser::options(int val) {
    _options = val;
}

// GET OPTIONS
int Fl_Native_File_Chooser::options() const {
    return(_options);
}

// PRIVATE: SET ERROR MESSAGE
void Fl_Native_File_Chooser::errmsg(const char *val) {
    _errmsg = strfree(_errmsg);
    _errmsg = strnew(val);
}

// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
void Fl_Native_File_Chooser::clear_pathnames() {
    if ( _pathnames ) {
      while ( --_tpathnames >= 0 ) {
          _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
      }
      delete [] _pathnames;
      _pathnames = NULL;
    }
    _tpathnames = 0;
}

// SET A SINGLE PATHNAME
void Fl_Native_File_Chooser::set_single_pathname(const char *s) {
    clear_pathnames();
    _pathnames = new char*[1];
    _pathnames[0] = strnew(s);
    _tpathnames = 1;
}

// ADD PATHNAME TO EXISTING ARRAY
void Fl_Native_File_Chooser::add_pathname(const char *s) {
    if ( ! _pathnames ) {
        // Create first element in array
      ++_tpathnames;
      _pathnames = new char*[_tpathnames];
    } else {
        // Grow array by 1
        char **tmp = new char*[_tpathnames+1];        // create new buffer
      memcpy((void*)tmp, (void*)_pathnames, sizeof(char*)*_tpathnames); // copy old
      delete [] _pathnames;                     // delete old
      _pathnames = tmp;                   // use new
      ++_tpathnames;
    }
    _pathnames[_tpathnames-1] = strnew(s);
}

// FREE A PIDL (Pointer to IDentity List)
void Fl_Native_File_Chooser::FreePIDL(ITEMIDLIST *pidl) {
    IMalloc *imalloc = NULL;
    if ( SUCCEEDED(SHGetMalloc(&imalloc)) )
      { imalloc->Free(pidl); imalloc->Release(); imalloc = NULL; }
}

// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS
void Fl_Native_File_Chooser::ClearOFN() {
    int temp;
    // Free any previously allocated lpstrFile before zeroing out _ofn
    if ( _ofn.lpstrFile ) 
      { _ofn.lpstrFile = strfree((char*)_ofn.lpstrFile); }
    if ( _ofn.lpstrInitialDir ) 
      { _ofn.lpstrInitialDir = (LPCSTR)strfree((char*)_ofn.lpstrInitialDir); }
    if ( _ofn.lpstrFile ) 
      { _ofn.lpstrFile = strfree(_ofn.lpstrFile); }
    _ofn.lpstrFilter = NULL;        // (deleted elsewhere)
    temp = _ofn.nFilterIndex;       // keep the filter_value
    memset((void*)&_ofn, 0, sizeof(_ofn));
    _ofn.lStructSize = sizeof(OPENFILENAME);
    _ofn.nFilterIndex = temp;
}

// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS
void Fl_Native_File_Chooser::ClearBINF() {
    if ( _binf.pidlRoot ) {
      FreePIDL((ITEMIDLIST*)_binf.pidlRoot);
      _binf.pidlRoot = NULL;
    }
    memset((void*)&_binf, 0, sizeof(_binf));
}

// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
void Fl_Native_File_Chooser::Win2Unix(char *s) {
    for ( ; *s; s++ )
      if ( *s == '\\' ) *s = '/';
}

// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
void Fl_Native_File_Chooser::Unix2Win(char *s) {
    for ( ; *s; s++ )
      if ( *s == '/' ) *s = '\\';
}

// SHOW FILE BROWSER
int Fl_Native_File_Chooser::showfile() {
    ClearOFN();
    clear_pathnames();
    size_t fsize = 2048;
    _ofn.Flags |= OFN_NOVALIDATE;   // prevent disabling of front slashes
    _ofn.Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag
    // USE NEW BROWSER
    _ofn.Flags |= OFN_EXPLORER;           // use newer explorer windows
//  // USE OLD BROWSER
//  _ofn.lpfnHook = MyHook;
//  _ofn.Flags |= OFN_ENABLEHOOK;
    _ofn.Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?)

    switch ( _btype ) {
      case BROWSE_DIRECTORY:
      case BROWSE_MULTI_DIRECTORY:
      case BROWSE_SAVE_DIRECTORY:
          abort();                  // never happens: handled by showdir()
      case BROWSE_FILE:
          fsize = 65536;            // XXX: there must be a better way
          break;
      case BROWSE_MULTI_FILE:
          _ofn.Flags |= OFN_ALLOWMULTISELECT;
          fsize = 65536;            // XXX: there must be a better way
          break;
      case BROWSE_SAVE_FILE:
          if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
            _ofn.Flags |= OFN_OVERWRITEPROMPT;
          }
          break;
    }
    // SPACE FOR RETURNED FILENAME
    _ofn.lpstrFile    = new char[fsize];
    _ofn.nMaxFile     = fsize-1;
    _ofn.lpstrFile[0] = '\0';
    if (_preset_file) {
        sprintf(_ofn.lpstrFile, "%.*s", _ofn.nMaxFile, _preset_file);
    }
    // PARENT WINDOW
    _ofn.hwndOwner = GetForegroundWindow();
    // DIALOG TITLE
    _ofn.lpstrTitle = _title ? _title : NULL;
    // FILTER
    _ofn.lpstrFilter = _parsedfilt ? _parsedfilt : NULL;
    // PRESET FILE
    //     If set, supercedes _directory. See KB Q86920 for details
    //
    if ( _preset_file ) {
        int len = strlen(_preset_file);
        char *strfile = new char[MAX_PATH];     // as per KB 222003 >8(
      strcpy(strfile, _preset_file);
      strfile[len+0] = '\0';              // (multiselect needs dnull)
      strfile[len+1] = '\0';
      Unix2Win(strfile);
      _ofn.lpstrFile = strfile;
      _ofn.nMaxFile = MAX_PATH;           // as per KB 222003 >8(
    }
    if ( _directory ) {
      // PRESET DIR
      //     XXX: See KB Q86920 for doc bug:
      //     http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
      //
      if ( _directory ) {
          _ofn.lpstrInitialDir = strnew(_directory);
          Unix2Win((char*)_ofn.lpstrInitialDir);
      }
    }
    // OPEN THE DIALOG WINDOW
    int err;
    if ( _btype == BROWSE_SAVE_FILE ) {
      err = GetSaveFileName(&_ofn);
    } else {
      err = GetOpenFileName(&_ofn);
    }
    if ( err == 0 ) {
      // EXTENDED ERROR CHECK
      int err = CommDlgExtendedError();
      // CANCEL?
      if ( err == 0 ) 
          return(1);    // user hit 'cancel'
      // AN ERROR OCCURRED
      char msg[80];
      sprintf(msg, "CommDlgExtendedError() code=%d", err);
      errmsg(msg);
      return(-1);
    }
    // PREPARE PATHNAMES FOR RETURN
    switch ( _btype ) {
      case BROWSE_FILE: 
      case BROWSE_SAVE_FILE:
          set_single_pathname(_ofn.lpstrFile);
          Win2Unix(_pathnames[_tpathnames-1]);
          break;
      case BROWSE_MULTI_FILE: {
          // EXTRACT MULTIPLE FILENAMES
          const char *dirname = _ofn.lpstrFile;
          int dirlen = strlen(dirname);
          if ( dirlen > 0 ) {
            char pathname[2048];

            // WALK STRING SEARCHING FOR 'DOUBLE-NULL'
            //     eg. "/dir/name\0foo1\0foo2\0foo3\0\0"
            //
            for ( const char *s = _ofn.lpstrFile + dirlen + 1; 
                                          *s; s+= (strlen(s)+1)) {
                strcpy(pathname, dirname);
                strcat(pathname, "\\");
                strcat(pathname, s);
                add_pathname(pathname);
                Win2Unix(_pathnames[_tpathnames-1]);
            }
          }
          // XXX
          //    Work around problem where pasted forward-slash pathname
          //    into the file browser causes new "Explorer" interface
          //    not to grok forward slashes, passing back as a 'filename'..!
          //
          if ( _tpathnames == 0 ) {
            add_pathname(dirname); 
            Win2Unix(_pathnames[_tpathnames-1]);
          }
          break;
      }
      case BROWSE_DIRECTORY:
      case BROWSE_MULTI_DIRECTORY:
      case BROWSE_SAVE_DIRECTORY:
          abort();                  // not here
    }
    return(0);
}

// Used by SHBrowseForFolder(), sets initial selected dir.
// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes
//              Subject: How to specify to select an initial folder .."
//
int CALLBACK Fl_Native_File_Chooser::Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) {
    switch (msg) {
      case BFFM_INITIALIZED:
          if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data);
          break;
      case BFFM_SELCHANGED:
          TCHAR path[MAX_PATH];
          if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) {
              ::SendMessage(win, BFFM_ENABLEOK, 0, 1);
          } else {
            //disable ok button if not a path
              ::SendMessage(win, BFFM_ENABLEOK, 0, 0);
          }
          break;
      case BFFM_VALIDATEFAILED:
          // we could pop up an annoying message here. 
          // also needs set ulFlags |=  BIF_VALIDATE
          break;
      default:
          break;
    }
    return(0);
}

// SHOW DIRECTORY BROWSER
int Fl_Native_File_Chooser::showdir() {
    OleInitialize(NULL);      // init needed by BIF_USENEWUI
    ClearBINF();
    clear_pathnames();
    // PARENT WINDOW
    _binf.hwndOwner = GetForegroundWindow();
    // DIALOG TITLE
    _binf.lpszTitle = _title ? _title : NULL;
    // FLAGS
    _binf.ulFlags =0;         // initialize

    // TBD: make sure matches to runtime system, if need be.
    //( what if _WIN32_IE doesn't match system? does the program not run? )
    // TBD: match all 3 types of directories

#if defined(BIF_NONEWFOLDERBUTTON)                    // Version 6.0
    if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_NONEWFOLDERBUTTON;
    _binf.ulFlags |= BIF_USENEWUI | BIF_SHAREABLE | BIF_RETURNONLYFSDIRS;
#elif defined(BIF_USENEWUI)                           // Version 5.0
    if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX;
    else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI;
    _binf.ulFlags |= BIF_SHAREABLE | BIF_RETURNONLYFSDIRS;
#elif defined(BIF_EDITBOX)                            // Version 4.71
    _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
#else                                           // Version Old
    _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
#endif

    // BUFFER
    char displayname[MAX_PATH];
    _binf.pszDisplayName = displayname;
    // PRESET DIR
    char presetname[MAX_PATH];
    if ( _directory ) {
      strcpy(presetname, _directory);
      Unix2Win(presetname);
      _binf.lParam = (LPARAM)presetname;
    }
    else _binf.lParam = 0;
    _binf.lpfn = Dir_CB;
    // OPEN BROWSER
    ITEMIDLIST *pidl = SHBrowseForFolder(&_binf);
    // CANCEL?
    if ( pidl == NULL ) return(1);

    // GET THE PATHNAME(S) THE USER SELECTED
    // TBD: expand NetHood shortcuts from this PIDL??
    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp

    TCHAR path[MAX_PATH];
    if ( SHGetPathFromIDList(pidl, path) )
      { Win2Unix(path); add_pathname(path); }
    FreePIDL(pidl);
    if ( !strlen(path) ) return(1);             // don't return empty pathnames
    return(0);
}

// RETURNS:
//    0 - user picked a file
//    1 - user cancelled
//   -1 - failed; errmsg() has reason
//
int Fl_Native_File_Chooser::show() {
    if ( _btype == BROWSE_DIRECTORY || 
         _btype == BROWSE_MULTI_DIRECTORY || 
       _btype == BROWSE_SAVE_DIRECTORY )
      return(showdir());
    else
      return(showfile());
}

// RETURN ERROR MESSAGE
const char *Fl_Native_File_Chooser::errmsg() const {
    return(_errmsg ? _errmsg : "No error");
}

// GET FILENAME
const char* Fl_Native_File_Chooser::filename() const {
    if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
    return("");
}

// GET FILENAME FROM LIST OF FILENAMES
const char* Fl_Native_File_Chooser::filename(int i) const {
    if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
    return("");
}

// GET TOTAL FILENAMES CHOSEN
int Fl_Native_File_Chooser::count() const {
    return(_tpathnames);
}

// PRESET PATHNAME
//     Can be NULL if no preset is desired.
//
void Fl_Native_File_Chooser::directory(const char *val) {
    _directory = strfree(_directory);
    _directory = strnew(val);
}

// GET PRESET PATHNAME
//    Can return NULL if none set.
//
const char *Fl_Native_File_Chooser::directory() const {
    return(_directory);
}

// SET TITLE
//     Can be NULL if no title desired.
//
void Fl_Native_File_Chooser::title(const char *val) {
    _title = strfree(_title);
    _title = strnew(val);
}

// GET TITLE
//    Can return NULL if none set.
//
const char *Fl_Native_File_Chooser::title() const {
    return(_title);
}

// SET FILTER
//     Can be NULL if no filter needed
//
void Fl_Native_File_Chooser::filter(const char *val) {
    _filter = strfree(_filter);
    clear_filters();
    if ( val ) {
      _filter = strnew(val);
      parse_filter(_filter);
    }
    add_filter("All Files", "*.*"); // always include 'all files' option

#ifdef DEBUG
    nullprint(_parsedfilt);
#endif /*DEBUG*/
}

// GET FILTER
//    Can return NULL if none set.
//
const char *Fl_Native_File_Chooser::filter() const {
    return(_filter);
}

// CLEAR FILTERS
void Fl_Native_File_Chooser::clear_filters() {
    _nfilters = 0;
    _parsedfilt = strfree(_parsedfilt);
}

// ADD A FILTER
void Fl_Native_File_Chooser::add_filter(
         const char *name_in,     // name of filter (optional: can be null)
         const char *winfilter    // windows style filter (eg. "*.cxx;*.h")
        ) {
    // No name? Make one..
    char name[1024];
    if ( !name_in || name_in[0] == '\0' ) {
      sprintf(name, "%.*s Files", sizeof(name)-10, winfilter);
    } else {
        sprintf(name, "%.*s", sizeof(name)-10, name_in);
    }
    dnullcat(_parsedfilt, name);
    dnullcat(_parsedfilt, winfilter);
    //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter);
}

// CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN
//    Handles:
//        IN              OUT
//        -----------     -----------------------------
//        *.{ma,mb}       "*.{ma,mb} Files\0*.ma;*.mb\0\0"
//        *.[abc]         "*.[abc] Files\0*.a;*.b;*.c\0\0"
//        *.txt           "*.txt Files\0*.txt\0\0"
//        C Files\t*.[ch] "C Files\0*.c;*.h\0\0"
//
//    Example:
//         IN: "*.{ma,mb}"
//        OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0"
//              ---------------  ---------  ---------  ---
//                     |             |          |       |
//                   Title       Wildcards    Title    Wildcards
//
// Parsing Mode:
//         IN:"C Files\t*.{cxx,h}"
//             |||||||  |||||||||
//       mode: nnnnnnn  ww{{{{{{{
//             \_____/  \_______/
//              Name     Wildcard
//
void Fl_Native_File_Chooser::parse_filter(const char *in) {
    clear_filters();
    if ( ! in ) return;

    int has_name = strchr(in, '\t') ? 1 : 0;
    const char *savein = in;

    char mode = has_name ? 'n' : 'w';     // parse mode: n=name, w=wildcard
    int nwildcards = 0;
    char wildcards[MAXFILTERS][1024];     // parsed wildcards (can be several)
    char wildprefix[512] = "";
    char name[512] = "";

    // Init
    int t;
    for ( t=0; t<MAXFILTERS; t++ ) {
        wildcards[t][0] = '\0';
    }

    // Parse
    for ( ; 1; in++ ) {

        //// DEBUG
        //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n",
      ////        *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]);

        switch (*in) {
          case ',':
          case '|':
              if ( mode == LCURLY_CHR ) {
                // create new wildcard, copy in prefix
                strcat(wildcards[nwildcards++], wildprefix);
                continue;
            } else {
                goto regchar;
            }
            continue;

          // FINISHED PARSING A NAME?
          case '\t':
              if ( mode != 'n' ) goto regchar;
            // finish parsing name? switch to wildcard mode
            mode = 'w';
            break;

          // ESCAPE NEXT CHAR
          case '\\':
              ++in;
            goto regchar;

          // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
          case '\r':
          case '\n':
          case '\0':
          {
              if ( mode == 'w' ) {        // finished parsing wildcard?
                if ( nwildcards == 0 ) {
                    strcpy(wildcards[nwildcards++], wildprefix);
                }
                // Append wildcards in Microsoft's "*.one;*.two" format
                char comp[4096] = "";
                for ( t=0; t<nwildcards; t++ ) {
                  if ( t != 0 ) strcat(comp, ";");
                  strcat(comp, wildcards[t]);
                }
                // Add if not empty
                if ( comp[0] ) {
                  add_filter(name, comp);
                }
            }
            // RESET
            for ( t=0; t<MAXFILTERS; t++ ) {
                wildcards[t][0] = '\0';
            }
            nwildcards = 0;
            wildprefix[0] = name[0] = '\0';
            mode = strchr(in,'\t') ? 'n' : 'w';
            // DONE?
            if ( *in == '\0' ) return;    // done
            continue;               // not done yet, more filters
          }

          // STARTING A WILDCARD?
          case LBRACKET_CHR:
          case LCURLY_CHR:
              mode = *in;
            if ( *in == LCURLY_CHR ) {
                // create new wildcard
                strcat(wildcards[nwildcards++], wildprefix);
            }
            continue;

          // ENDING A WILDCARD?
          case RBRACKET_CHR:
          case RCURLY_CHR:
            mode = 'w'; // back to wildcard mode
            continue;

          // ALL OTHER NON-SPECIAL CHARACTERS
          default:
          regchar:            // handle regular char
                switch ( mode ) {
                  case LBRACKET_CHR: 
                  // create new wildcard
                    ++nwildcards;
                  // copy in prefix
                  strcpy(wildcards[nwildcards-1], wildprefix);
                  // append search char
                  chrcat(wildcards[nwildcards-1], *in);
                  continue;

                  case LCURLY_CHR:
                    if ( nwildcards > 0 ) {
                      chrcat(wildcards[nwildcards-1], *in);
                  }
                  continue;

                  case 'n':
                    chrcat(name, *in);
                  continue;

                  case 'w':
                  chrcat(wildprefix, *in);
                    for ( t=0; t<nwildcards; t++ ) {
                      chrcat(wildcards[t], *in);
                  }
                  continue;
              }
            break;
      }
    }
}

// SET 'CURRENTLY SELECTED FILTER'
void Fl_Native_File_Chooser::filter_value(int i) {
    _ofn.nFilterIndex = i + 1;
}

// RETURN VALUE OF 'CURRENTLY SELECTED FILTER'
int Fl_Native_File_Chooser::filter_value() const {
    return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1);
}

// PRESET FILENAME FOR 'SAVE AS' CHOOSER
void Fl_Native_File_Chooser::preset_file(const char* val) {
    _preset_file = strfree(_preset_file);
    _preset_file = strnew(val);
}

// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER
const char* Fl_Native_File_Chooser::preset_file() const {
    return(_preset_file);
}

Generated by  Doxygen 1.6.0   Back to index