1 // "$Id: Fl_Native_File_Chooser_WIN32.cxx 8454 2011-02-20 21:46:11Z manolo $"
3 // FLTK native OS file chooser widget
5 // Copyright 1998-2010 by Bill Spitzak and others.
6 // Copyright 2004 Greg Ercolano.
7 // API changes + filter improvements by Nathan Vander Wilt 2005
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Library General Public License for more details.
19 // You should have received a copy of the GNU Library General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 // Please report all bugs and problems to:
26 // http://www.fltk.org/str.php
29 // Any application to multi-folder implementation:
30 // http://www.codeproject.com/dialog/selectfolder.asp
33 #ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE
35 #include <stdio.h> // debugging
36 #include <wchar.h> //MG
37 #include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat
38 typedef const wchar_t *LPCWSTR
; //MG
39 LPCWSTR
utf8towchar(const char *in
); //MG
40 char *wchartoutf8(LPCWSTR in
); //MG
42 #include <FL/Fl_Native_File_Chooser.H>
44 #define LCURLY_CHR '{'
45 #define RCURLY_CHR '}'
46 #define LBRACKET_CHR '['
47 #define RBRACKET_CHR ']'
50 void fl_OleInitialize(); // in Fl.cxx (Windows only)
52 // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG)
54 static void dnullprint(char *wp
) {
56 for ( int t
=0; true; t
++ ) {
57 if ( wp
[t
] == '\0' && wp
[t
+1] == '\0' ) {
61 } else if ( wp
[t
] == '\0' ) {
70 // RETURN LENGTH OF DOUBLENULL STRING
71 // Includes single nulls in count, excludes trailing doublenull.
78 static int dnulllen(const char *wp
) {
80 while ( ! ( *(wp
+0) == 0 && *(wp
+1) == 0 ) ) {
87 // STATIC: Append a string to another, leaving terminated with DOUBLE NULL.
88 // Automatically handles extending length of string.
89 // wp can be NULL (a new wp will be allocated and initialized).
90 // string must be NULL terminated.
91 // The pointer wp may be modified on return.
93 static void dnullcat(char*&wp
, const char *string
, int n
= -1 ) {
94 //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n");
95 int inlen
= ( n
< 0 ) ? strlen(string
) : n
;
97 wp
= new char[inlen
+ 4];
101 int wplen
= dnulllen(wp
);
102 // Make copy of wp into larger buffer
103 char *tmp
= new char[wplen
+ inlen
+ 4];
104 memcpy(tmp
, wp
, wplen
+2); // copy of wp plus doublenull
105 delete [] wp
; // delete old wp
106 wp
= tmp
; // use new copy
107 //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen);
110 // Find end of double null string
111 // *wp2 is left pointing at second null.
114 if ( *(wp2
+0) != '\0' && *(wp2
+1) != '\0' ) {
116 if ( *(wp2
+0) == '\0' && *(wp2
+1) == '\0' ) {
123 if ( n
== -1 ) n
= strlen(string
);
124 strncpy(wp2
, string
, n
);
126 // Leave string double-null terminated
129 //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n");
133 Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val
) {
135 _options
= NO_OPTIONS
;
136 memset((void*)&_ofn
, 0, sizeof(OPENFILENAMEW
));
137 _ofn
.lStructSize
= sizeof(OPENFILENAMEW
);
138 _ofn
.hwndOwner
= NULL
;
139 memset((void*)&_binf
, 0, sizeof(BROWSEINFO
));
152 Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
153 //_pathnames // managed by clear_pathnames()
154 //_tpathnames // managed by clear_pathnames()
155 _directory
= strfree(_directory
);
156 _title
= strfree(_title
);
157 _filter
= strfree(_filter
);
158 //_parsedfilt // managed by clear_filters()
159 //_nfilters // managed by clear_filters()
160 _preset_file
= strfree(_preset_file
);
161 _errmsg
= strfree(_errmsg
);
168 // SET TYPE OF BROWSER
169 void Fl_Native_File_Chooser::type(int val
) {
173 // GET TYPE OF BROWSER
174 int Fl_Native_File_Chooser::type() const {
179 void Fl_Native_File_Chooser::options(int val
) {
184 int Fl_Native_File_Chooser::options() const {
188 // PRIVATE: SET ERROR MESSAGE
189 void Fl_Native_File_Chooser::errmsg(const char *val
) {
190 _errmsg
= strfree(_errmsg
);
191 _errmsg
= strnew(val
);
194 // FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
195 void Fl_Native_File_Chooser::clear_pathnames() {
197 while ( --_tpathnames
>= 0 ) {
198 _pathnames
[_tpathnames
] = strfree(_pathnames
[_tpathnames
]);
200 delete [] _pathnames
;
206 // SET A SINGLE PATHNAME
207 void Fl_Native_File_Chooser::set_single_pathname(const char *s
) {
209 _pathnames
= new char*[1];
210 _pathnames
[0] = strnew(s
);
214 // ADD PATHNAME TO EXISTING ARRAY
215 void Fl_Native_File_Chooser::add_pathname(const char *s
) {
216 if ( ! _pathnames
) {
217 // Create first element in array
219 _pathnames
= new char*[_tpathnames
];
222 char **tmp
= new char*[_tpathnames
+1]; // create new buffer
223 memcpy((void*)tmp
, (void*)_pathnames
,
224 sizeof(char*)*_tpathnames
); // copy old
225 delete [] _pathnames
; // delete old
226 _pathnames
= tmp
; // use new
229 _pathnames
[_tpathnames
-1] = strnew(s
);
232 // FREE A PIDL (Pointer to IDentity List)
233 void Fl_Native_File_Chooser::FreePIDL(ITEMIDLIST
*pidl
) {
234 IMalloc
*imalloc
= NULL
;
235 if ( SUCCEEDED(SHGetMalloc(&imalloc
)) ) {
242 // CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS
243 void Fl_Native_File_Chooser::ClearOFN() {
244 // Free any previously allocated lpstrFile before zeroing out _ofn
245 if ( _ofn
.lpstrFile
) {
246 delete [] _ofn
.lpstrFile
;
247 _ofn
.lpstrFile
= NULL
;
249 if ( _ofn
.lpstrInitialDir
) {
250 delete [] (TCHAR
*) _ofn
.lpstrInitialDir
; //msvc6 compilation fix
251 _ofn
.lpstrInitialDir
= NULL
;
253 _ofn
.lpstrFilter
= NULL
; // (deleted elsewhere)
254 int temp
= _ofn
.nFilterIndex
; // keep the filter_value
255 memset((void*)&_ofn
, 0, sizeof(_ofn
));
256 _ofn
.lStructSize
= sizeof(OPENFILENAMEW
);
257 _ofn
.nFilterIndex
= temp
;
260 // CLEAR MICROSOFT BINF (BROWSER INFO) CLASS
261 void Fl_Native_File_Chooser::ClearBINF() {
262 if ( _binf
.pidlRoot
) {
263 FreePIDL((ITEMIDLIST
*)_binf
.pidlRoot
);
264 _binf
.pidlRoot
= NULL
;
266 memset((void*)&_binf
, 0, sizeof(_binf
));
269 // CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
270 void Fl_Native_File_Chooser::Win2Unix(char *s
) {
272 if ( *s
== '\\' ) *s
= '/';
275 // CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
276 void Fl_Native_File_Chooser::Unix2Win(char *s
) {
278 if ( *s
== '/' ) *s
= '\\';
282 int Fl_Native_File_Chooser::showfile() {
285 size_t fsize
= MAX_PATH
;
286 _ofn
.Flags
|= OFN_NOVALIDATE
; // prevent disabling of front slashes
287 _ofn
.Flags
|= OFN_HIDEREADONLY
; // hide goofy readonly flag
289 _ofn
.Flags
|= OFN_EXPLORER
; // use newer explorer windows
290 _ofn
.Flags
|= OFN_ENABLESIZING
; // allow window to be resized (hey, why not?)
292 // XXX: The docs for OFN_NOCHANGEDIR says the flag is 'ineffective' on XP/2K/NT!
293 // But let's set it anyway..
295 _ofn
.Flags
|= OFN_NOCHANGEDIR
; // prevent dialog for messing up the cwd
298 case BROWSE_DIRECTORY
:
299 case BROWSE_MULTI_DIRECTORY
:
300 case BROWSE_SAVE_DIRECTORY
:
301 abort(); // never happens: handled by showdir()
303 fsize
= 65536; // XXX: there must be a better way
305 case BROWSE_MULTI_FILE
:
306 _ofn
.Flags
|= OFN_ALLOWMULTISELECT
;
307 fsize
= 65536; // XXX: there must be a better way
309 case BROWSE_SAVE_FILE
:
310 if ( options() & SAVEAS_CONFIRM
&& type() == BROWSE_SAVE_FILE
) {
311 _ofn
.Flags
|= OFN_OVERWRITEPROMPT
;
315 // SPACE FOR RETURNED FILENAME
316 _ofn
.lpstrFile
= new WCHAR
[fsize
];
317 _ofn
.nMaxFile
= fsize
-1;
318 _ofn
.lpstrFile
[0] = 0;
319 _ofn
.lpstrFile
[1] = 0; // dnull
321 _ofn
.hwndOwner
= GetForegroundWindow();
324 static WCHAR wtitle
[200];
325 wcscpy(wtitle
, utf8towchar(_title
));
326 _ofn
.lpstrTitle
= wtitle
;
328 _ofn
.lpstrTitle
= NULL
;
331 if (_parsedfilt
!= NULL
) { // to convert a null-containing char string into a widechar string
332 static WCHAR wpattern
[MAX_PATH
];
333 const char *p
= _parsedfilt
;
334 while(*(p
+ strlen(p
) + 1) != 0) p
+= strlen(p
) + 1;
336 MultiByteToWideChar(CP_UTF8
, 0, _parsedfilt
, p
- _parsedfilt
, wpattern
, MAX_PATH
);
337 _ofn
.lpstrFilter
= wpattern
;
339 _ofn
.lpstrFilter
= NULL
;
342 // If set, supercedes _directory. See KB Q86920 for details
344 if ( _preset_file
) {
345 size_t len
= strlen(_preset_file
);
346 if ( len
>= _ofn
.nMaxFile
) {
348 sprintf(msg
, "preset_file() filename is too long: %ld is >=%ld", (long)len
, (long)fsize
);
351 wcscpy(_ofn
.lpstrFile
, utf8towchar(_preset_file
));
352 // Unix2Win(_ofn.lpstrFile);
353 len
= wcslen(_ofn
.lpstrFile
);
354 _ofn
.lpstrFile
[len
+0] = 0; // multiselect needs dnull
355 _ofn
.lpstrFile
[len
+1] = 0;
359 // XXX: See KB Q86920 for doc bug:
360 // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
362 _ofn
.lpstrInitialDir
= new WCHAR
[MAX_PATH
];
363 wcscpy((WCHAR
*)_ofn
.lpstrInitialDir
, utf8towchar(_directory
));
364 // Unix2Win((char*)_ofn.lpstrInitialDir);
366 // SAVE THE CURRENT DIRECTORY
367 // XXX: Save the cwd because GetOpenFileName() is probably going to
368 // change it, in spite of the OFN_NOCHANGEDIR flag, due to its docs
369 // saying the flag is 'ineffective'. %^(
371 char oldcwd
[MAX_PATH
];
372 GetCurrentDirectory(MAX_PATH
, oldcwd
);
373 oldcwd
[MAX_PATH
-1] = '\0';
374 // OPEN THE DIALOG WINDOW
376 if ( _btype
== BROWSE_SAVE_FILE
) {
377 err
= GetSaveFileNameW(&_ofn
);
379 err
= GetOpenFileNameW(&_ofn
);
382 // EXTENDED ERROR CHECK
383 int err
= CommDlgExtendedError();
385 if ( err
== 0 ) return(1); // user hit 'cancel'
388 sprintf(msg
, "CommDlgExtendedError() code=%d", err
);
391 if ( oldcwd
[0] ) SetCurrentDirectory(oldcwd
);
396 SetCurrentDirectory(oldcwd
);
398 // PREPARE PATHNAMES FOR RETURN
401 case BROWSE_SAVE_FILE
:
402 set_single_pathname(wchartoutf8(_ofn
.lpstrFile
));
403 // Win2Unix(_pathnames[_tpathnames-1]);
405 case BROWSE_MULTI_FILE
: {
406 // EXTRACT MULTIPLE FILENAMES
407 const WCHAR
*dirname
= _ofn
.lpstrFile
;
408 int dirlen
= wcslen(dirname
);
410 // WALK STRING SEARCHING FOR 'DOUBLE-NULL'
411 // eg. "/dir/name\0foo1\0foo2\0foo3\0\0"
413 char pathname
[MAX_PATH
];
414 for ( const WCHAR
*s
= dirname
+ dirlen
+ 1;
415 *s
; s
+= (wcslen(s
)+1)) {
416 strcpy(pathname
, wchartoutf8(dirname
));
417 strcat(pathname
, "\\");
418 strcat(pathname
, wchartoutf8(s
));
419 add_pathname(pathname
);
423 // Work around problem where pasted forward-slash pathname
424 // into the file browser causes new "Explorer" interface
425 // not to grok forward slashes, passing back as a 'filename'..!
427 if ( _tpathnames
== 0 ) {
428 add_pathname(wchartoutf8(dirname
));
429 // Win2Unix(_pathnames[_tpathnames-1]);
433 case BROWSE_DIRECTORY
:
434 case BROWSE_MULTI_DIRECTORY
:
435 case BROWSE_SAVE_DIRECTORY
:
436 abort(); // never happens: handled by showdir()
441 // Used by SHBrowseForFolder(), sets initial selected dir.
442 // Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes
443 // Subject: How to specify to select an initial folder .."
445 int CALLBACK
Fl_Native_File_Chooser::Dir_CB(HWND win
, UINT msg
, LPARAM param
, LPARAM data
) {
447 case BFFM_INITIALIZED
:
448 if (data
) ::SendMessage(win
, BFFM_SETSELECTION
, TRUE
, data
);
450 case BFFM_SELCHANGED
:
451 TCHAR path
[MAX_PATH
];
452 if ( SHGetPathFromIDList((ITEMIDLIST
*)param
, path
) ) {
453 ::SendMessage(win
, BFFM_ENABLEOK
, 0, 1);
455 // disable ok button if not a path
456 ::SendMessage(win
, BFFM_ENABLEOK
, 0, 0);
459 case BFFM_VALIDATEFAILED
:
460 // we could pop up an annoying message here.
461 // also needs set ulFlags |= BIF_VALIDATE
469 // SHOW DIRECTORY BROWSER
470 int Fl_Native_File_Chooser::showdir() {
471 // initialize OLE only once
472 fl_OleInitialize(); // init needed by BIF_USENEWUI
476 _binf
.hwndOwner
= GetForegroundWindow();
478 _binf
.lpszTitle
= _title
? _title
: NULL
;
480 _binf
.ulFlags
= 0; // initialize
482 // TBD: make sure matches to runtime system, if need be.
483 //(what if _WIN32_IE doesn't match system? does the program not run?)
485 // TBD: match all 3 types of directories
487 // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares
488 // from being visible in BROWSE_DIRECTORY mode.
489 // See Walter Garm's comments in ./TODO.
491 #if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0
492 if ( _btype
== BROWSE_DIRECTORY
) _binf
.ulFlags
|= BIF_NONEWFOLDERBUTTON
;
493 _binf
.ulFlags
|= BIF_USENEWUI
| BIF_RETURNONLYFSDIRS
;
494 #elif defined(BIF_USENEWUI) // Version 5.0
495 if ( _btype
== BROWSE_DIRECTORY
) _binf
.ulFlags
|= BIF_EDITBOX
;
496 else if ( _btype
== BROWSE_SAVE_DIRECTORY
) _binf
.ulFlags
|= BIF_USENEWUI
;
497 _binf
.ulFlags
|= BIF_RETURNONLYFSDIRS
;
498 #elif defined(BIF_EDITBOX) // Version 4.71
499 _binf
.ulFlags
|= BIF_RETURNONLYFSDIRS
| BIF_EDITBOX
;
501 _binf
.ulFlags
|= BIF_RETURNONLYFSDIRS
;
505 char displayname
[MAX_PATH
];
506 _binf
.pszDisplayName
= displayname
;
508 char presetname
[MAX_PATH
];
510 strcpy(presetname
, _directory
);
511 // Unix2Win(presetname);
512 _binf
.lParam
= (LPARAM
)presetname
;
514 else _binf
.lParam
= 0;
517 ITEMIDLIST
*pidl
= SHBrowseForFolder(&_binf
);
519 if ( pidl
== NULL
) return(1);
521 // GET THE PATHNAME(S) THE USER SELECTED
522 // TBD: expand NetHood shortcuts from this PIDL??
523 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp
525 TCHAR path
[MAX_PATH
];
526 if ( SHGetPathFromIDList(pidl
, path
) ) {
531 if ( !strlen(path
) ) return(1); // don't return empty pathnames
536 // 0 - user picked a file
537 // 1 - user cancelled
538 // -1 - failed; errmsg() has reason
540 int Fl_Native_File_Chooser::show() {
541 if ( _btype
== BROWSE_DIRECTORY
||
542 _btype
== BROWSE_MULTI_DIRECTORY
||
543 _btype
== BROWSE_SAVE_DIRECTORY
) {
550 // RETURN ERROR MESSAGE
551 const char *Fl_Native_File_Chooser::errmsg() const {
552 return(_errmsg
? _errmsg
: "No error");
556 const char* Fl_Native_File_Chooser::filename() const {
557 if ( _pathnames
&& _tpathnames
> 0 ) return(_pathnames
[0]);
561 // GET FILENAME FROM LIST OF FILENAMES
562 const char* Fl_Native_File_Chooser::filename(int i
) const {
563 if ( _pathnames
&& i
< _tpathnames
) return(_pathnames
[i
]);
567 // GET TOTAL FILENAMES CHOSEN
568 int Fl_Native_File_Chooser::count() const {
573 // Can be NULL if no preset is desired.
575 void Fl_Native_File_Chooser::directory(const char *val
) {
576 _directory
= strfree(_directory
);
577 _directory
= strnew(val
);
580 // GET PRESET PATHNAME
581 // Can return NULL if none set.
583 const char *Fl_Native_File_Chooser::directory() const {
588 // Can be NULL if no title desired.
590 void Fl_Native_File_Chooser::title(const char *val
) {
591 _title
= strfree(_title
);
592 _title
= strnew(val
);
596 // Can return NULL if none set.
598 const char *Fl_Native_File_Chooser::title() const {
603 // Can be NULL if no filter needed
605 void Fl_Native_File_Chooser::filter(const char *val
) {
606 _filter
= strfree(_filter
);
609 _filter
= strnew(val
);
610 parse_filter(_filter
);
612 add_filter("All Files", "*.*"); // always include 'all files' option
615 nullprint(_parsedfilt
);
620 // Can return NULL if none set.
622 const char *Fl_Native_File_Chooser::filter() const {
627 void Fl_Native_File_Chooser::clear_filters() {
629 _parsedfilt
= strfree(_parsedfilt
);
633 void Fl_Native_File_Chooser::add_filter(const char *name_in
, // name of filter (optional: can be null)
634 const char *winfilter
) { // windows style filter (eg. "*.cxx;*.h")
635 // No name? Make one..
637 if ( !name_in
|| name_in
[0] == '\0' ) {
638 sprintf(name
, "%.*s Files", int(sizeof(name
)-10), winfilter
);
640 sprintf(name
, "%.*s", int(sizeof(name
)-10), name_in
);
642 dnullcat(_parsedfilt
, name
);
643 dnullcat(_parsedfilt
, winfilter
);
645 //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter);
648 // CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN
651 // ----------- -----------------------------
652 // *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0"
653 // *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0"
654 // *.txt "*.txt Files\0*.txt\0\0"
655 // C Files\t*.[ch] "C Files\0*.c;*.h\0\0"
659 // OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0"
660 // --------------- --------- --------- ---
662 // Title Wildcards Title Wildcards
665 // IN:"C Files\t*.{cxx,h}"
667 // mode: nnnnnnn ww{{{{{{{
671 void Fl_Native_File_Chooser::parse_filter(const char *in
) {
675 int has_name
= strchr(in
, '\t') ? 1 : 0;
677 char mode
= has_name
? 'n' : 'w'; // parse mode: n=name, w=wildcard
679 char wildcards
[MAXFILTERS
][1024]; // parsed wildcards (can be several)
680 char wildprefix
[512] = "";
685 for ( t
=0; t
<MAXFILTERS
; t
++ ) {
686 wildcards
[t
][0] = '\0';
693 //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n",
694 //// *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]);
699 if ( mode
== LCURLY_CHR
) {
700 // create new wildcard, copy in prefix
701 strcat(wildcards
[nwildcards
++], wildprefix
);
708 // FINISHED PARSING A NAME?
710 if ( mode
!= 'n' ) goto regchar
;
711 // finish parsing name? switch to wildcard mode
720 // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
725 if ( mode
== 'w' ) { // finished parsing wildcard?
726 if ( nwildcards
== 0 ) {
727 strcpy(wildcards
[nwildcards
++], wildprefix
);
729 // Append wildcards in Microsoft's "*.one;*.two" format
730 char comp
[4096] = "";
731 for ( t
=0; t
<nwildcards
; t
++ ) {
732 if ( t
!= 0 ) strcat(comp
, ";");
733 strcat(comp
, wildcards
[t
]);
737 add_filter(name
, comp
);
741 for ( t
=0; t
<MAXFILTERS
; t
++ ) {
742 wildcards
[t
][0] = '\0';
745 wildprefix
[0] = name
[0] = '\0';
746 mode
= strchr(in
,'\t') ? 'n' : 'w';
748 if ( *in
== '\0' ) return; // done
749 continue; // not done yet, more filters
752 // STARTING A WILDCARD?
756 if ( *in
== LCURLY_CHR
) {
757 // create new wildcard
758 strcat(wildcards
[nwildcards
++], wildprefix
);
762 // ENDING A WILDCARD?
765 mode
= 'w'; // back to wildcard mode
768 // ALL OTHER NON-SPECIAL CHARACTERS
770 regchar
: // handle regular char
773 // create new wildcard
776 strcpy(wildcards
[nwildcards
-1], wildprefix
);
777 // append search char
778 chrcat(wildcards
[nwildcards
-1], *in
);
782 if ( nwildcards
> 0 ) {
783 chrcat(wildcards
[nwildcards
-1], *in
);
792 chrcat(wildprefix
, *in
);
793 for ( t
=0; t
<nwildcards
; t
++ ) {
794 chrcat(wildcards
[t
], *in
);
803 // SET 'CURRENTLY SELECTED FILTER'
804 void Fl_Native_File_Chooser::filter_value(int i
) {
805 _ofn
.nFilterIndex
= i
+ 1;
808 // RETURN VALUE OF 'CURRENTLY SELECTED FILTER'
809 int Fl_Native_File_Chooser::filter_value() const {
810 return(_ofn
.nFilterIndex
? _ofn
.nFilterIndex
-1 : _nfilters
+1);
813 // PRESET FILENAME FOR 'SAVE AS' CHOOSER
814 void Fl_Native_File_Chooser::preset_file(const char* val
) {
815 _preset_file
= strfree(_preset_file
);
816 _preset_file
= strnew(val
);
819 // GET PRESET FILENAME FOR 'SAVE AS' CHOOSER
820 const char* Fl_Native_File_Chooser::preset_file() const {
821 return(_preset_file
);
824 int Fl_Native_File_Chooser::filters() const {
828 char *wchartoutf8(LPCWSTR in
)
830 static char *out
= NULL
;
831 static int lchar
= 0;
832 if (in
== NULL
)return NULL
;
833 int utf8len
= WideCharToMultiByte(CP_UTF8
, 0, in
, -1, NULL
, 0, NULL
, NULL
);
834 if (utf8len
> lchar
) {
836 out
= (char *)realloc(out
, lchar
* sizeof(char));
838 WideCharToMultiByte(CP_UTF8
, 0, in
, -1, out
, utf8len
, NULL
, NULL
);
842 LPCWSTR
utf8towchar(const char *in
)
844 static WCHAR
*wout
= NULL
;
845 static int lwout
= 0;
846 if (in
== NULL
)return NULL
;
847 int wlen
= MultiByteToWideChar(CP_UTF8
, 0, in
, -1, NULL
, 0);
850 wout
= (WCHAR
*)realloc(wout
, lwout
* sizeof(WCHAR
));
852 MultiByteToWideChar(CP_UTF8
, 0, in
, -1, wout
, wlen
);
856 #endif /*!FL_DOXYGEN*/
859 // End of "$Id: Fl_Native_File_Chooser_WIN32.cxx 8454 2011-02-20 21:46:11Z manolo $".