Tweak themes for more color consistency.
[ntk.git] / src / Fl_File_Chooser2.cxx
blob861f7399776385cd97d57aba5e6e50c025c9a0ab
1 //
2 // "$Id: Fl_File_Chooser2.cxx 8785 2011-06-06 16:11:22Z manolo $"
3 //
4 // More Fl_File_Chooser routines.
5 //
6 // Copyright 1999-2011 by Michael Sweet.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 // fabien: ATTENTION: Only Out Of Source Gen. because cxx/H files are autogenerated by fluid.
29 /** \defgroup group_comdlg Common Dialogs classes and functions
32 /** \class Fl_File_Chooser
33 The Fl_File_Chooser widget displays a standard file selection
34 dialog that supports various selection modes.
36 \image html Fl_File_Chooser.jpg
37 \image latex Fl_File_Chooser.jpg "Fl_File_Chooser" width=12cm
39 The Fl_File_Chooser class also exports several static values
40 that may be used to localize or customize the appearance of all file chooser
41 dialogs:
43 <CENTER><TABLE BORDER="1">
44 <TR>
45 <TH>Member</TH>
46 <TH>Default value</TH>
47 </TR>
48 <TR>
49 <TD>add_favorites_label</TD>
50 <TD>"Add to Favorites"</TD>
51 </TR>
52 <TR>
53 <TD>all_files_label</TD>
54 <TD>"All Files (*)"</TD>
55 </TR>
56 <TR>
57 <TD>custom_filter_label</TD>
58 <TD>"Custom Filter"</TD>
59 </TR>
60 <TR>
61 <TD>existing_file_label</TD>
62 <TD>"Please choose an existing file!"</TD>
63 </TR>
64 <TR>
65 <TD>favorites_label</TD>
66 <TD>"Favorites"</TD>
67 </TR>
68 <TR>
69 <TD>filename_label</TD>
70 <TD>"Filename:"</TD>
71 </TR>
72 <TR>
73 <TD>filesystems_label</TD>
74 <TD>"My Computer" (WIN32)<BR>
75 "File Systems" (all others)</TD>
76 </TR>
77 <TR>
78 <TD>hidden_label</TD>
79 <TD>"Show hidden files:"</TD>
80 </TR>
81 <TR>
82 <TD>manage_favorites_label</TD>
83 <TD>"Manage Favorites"</TD>
84 </TR>
85 <TR>
86 <TD>new_directory_label</TD>
87 <TD>"New Directory?"</TD>
88 </TR>
89 <TR>
90 <TD>new_directory_tooltip</TD>
91 <TD>"Create a new directory."</TD>
92 </TR>
93 <TR>
94 <TD>preview_label</TD>
95 <TD>"Preview"</TD>
96 </TR>
97 <TR>
98 <TD>save_label</TD>
99 <TD>"Save"</TD>
100 </TR>
101 <TR>
102 <TD>show_label</TD>
103 <TD>"Show:"</TD>
104 </TR>
105 <TR>
106 <TD>sort</TD>
107 <TD>fl_numericsort</TD>
108 </TR>
109 </TABLE></CENTER>
111 The Fl_File_Chooser::sort member specifies the sort function that is
112 used when loading the contents of a directory and can be customized
113 at run-time.
115 The Fl_File_Chooser class also exports the Fl_File_Chooser::newButton
116 and Fl_File_Chooser::previewButton widgets so that application developers
117 can control their appearance and use. For more complex customization,
118 consider copying the FLTK file chooser code and changing it accordingly.
120 /** @} */
122 /** \fn Fl_File_Chooser::Fl_File_Chooser(const char *pathname, const char *pattern, int type, const char *title)
123 The constructor creates the Fl_File_Chooser dialog shown.
124 The pathname argument can be a directory name or a
125 complete file name (in which case the corresponding file is highlighted
126 in the list and in the filename input field.)
128 The pattern argument can be a NULL
129 string or "*" to list all files, or it can be a
130 series of descriptions and filter strings separated by tab
131 characters (\\t). The format of filters is either
132 "Description text (patterns)" or just "patterns". A file chooser
133 that provides filters for HTML and image files might look like:
135 \code
136 "HTML Files (*.html)\tImage Files (*.{bmp,gif,jpg,png})"
137 \endcode
139 The file chooser will automatically add the "All Files (*)"
140 pattern to the end of the string you pass if you do not provide
141 one. The first filter in the string is the default filter.
143 See the FLTK documentation on fl_filename_match()
144 for the kinds of pattern strings that are supported.
146 The type argument can be one of the following:
148 \li \c SINGLE - allows the user to select a single, existing file.
149 \li \c MULTI - allows the user to select one or more existing files.
150 \li \c CREATE - allows the user to select a single, existing file or
151 specify a new filename.
152 \li \c DIRECTORY - allows the user to select a single, existing directory.
154 The title argument is used to set the title bar text for the
155 Fl_File_Chooser window.
158 /** \var Fl_File_Chooser::newButton
159 The "new directory" button is exported so that application developers
160 can control the appearance and use.
163 /** \var Fl_File_Chooser::previewButton
164 The "preview" button is exported so that application developers can
165 control the appearance and use.
168 /** \fn Fl_File_Chooser::~Fl_File_Chooser()
169 Destroys the widget and frees all memory used by it.*/
171 /** \fn void Fl_File_Chooser::color(Fl_Color c)
172 Sets the background color of the Fl_File_Browser list.*/
174 /** \fn Fl_Color Fl_File_Chooser::color()
175 Gets the background color of the Fl_File_Browser list.*/
177 /** \fn int Fl_File_Chooser::count()
178 Returns the number of selected files.*/
180 /** \fn void Fl_File_Chooser::directory(const char *pathname)
181 Sets the current directory.*/
183 /** \fn const char *Fl_File_Chooser::directory()
184 Gets the current directory.*/
186 /** \fn void Fl_File_Chooser::filter(const char *pattern)
187 Sets or gets the current filename filter patterns. The filter
188 patterns use fl_filename_match().
189 Multiple patterns can be used by separating them with tabs, like
190 <tt>"*.jpg\t*.png\t*.gif\t*"</tt>. In addition, you can provide
191 human-readable labels with the patterns inside parenthesis, like
192 <tt>"JPEG Files (*.jpg)\tPNG Files (*.png)\tGIF Files (*.gif)\tAll Files (*)"
193 </tt>.
195 Use filter(NULL) to show all files.
198 /** \fn const char *Fl_File_Chooser::filter()
199 See void filter(const char *pattern)*/
201 /** \fn void Fl_File_Chooser::filter_value(int f)
202 Sets the current filename filter selection.*/
204 /** \fn int Fl_File_Chooser::filter_value()
205 Gets the current filename filter selection.*/
207 /** \fn void Fl_File_Chooser::hide()
208 Hides the Fl_File_Chooser window.*/
210 /** \fn void Fl_File_Chooser::iconsize(uchar s)
211 Sets the size of the icons in the Fl_File_Browser. By
212 default the icon size is set to 1.5 times the textsize().
215 /** \fn uchar Fl_File_Chooser::iconsize()
216 Gets the size of the icons in the Fl_File_Browser. By
217 default the icon size is set to 1.5 times the textsize().
220 /** \fn void Fl_File_Chooser::label(const char *l)
221 Sets the title bar text for the Fl_File_Chooser.*/
223 /** \fn const char *Fl_File_Chooser::label()
224 Gets the title bar text for the Fl_File_Chooser.*/
226 /** \fn void Fl_File_Chooser::ok_label(const char *l)
227 Sets the label for the "ok" button in the Fl_File_Chooser.
230 /** \fn const char *Fl_File_Chooser::ok_label()
231 Gets the label for the "ok" button in the Fl_File_Chooser.
234 /** \fn int Fl_File_Chooser::preview() const
235 Returns the current state of the preview box. */
237 /** \fn void Fl_File_Chooser::rescan()
238 Reloads the current directory in the Fl_File_Browser.*/
240 /** \fn void Fl_File_Chooser::show()
241 Shows the Fl_File_Chooser window.*/
243 /** \fn void Fl_File_Chooser::textcolor(Fl_Color c)
244 Sets the current Fl_File_Browser text color.*/
246 /** \fn Fl_Color Fl_File_Chooser::textcolor()
247 Gets the current Fl_File_Browser text color.*/
249 /** \fn void Fl_File_Chooser::textfont(Fl_Font f)
250 Sets the current Fl_File_Browser text font.*/
252 /** \fn Fl_Font Fl_File_Chooser::textfont()
253 Gets the current Fl_File_Browser text font.*/
255 /** \fn void Fl_File_Chooser::textsize(Fl_Fontsize s)
256 Sets the current Fl_File_Browser text size.*/
258 /** \fn Fl_Fontsize Fl_File_Chooser::textsize()
259 Gets the current Fl_File_Browser text size.*/
261 /** \fn void Fl_File_Chooser::type(int t)
262 Sets the current type of Fl_File_Chooser.*/
264 /** \fn int Fl_File_Chooser::type()
265 Gets the current type of Fl_File_Chooser.*/
267 /** \fn void Fl_File_Chooser::value(const char *pathname)
268 Sets the current value of the selected file.
271 /** \fn const char *Fl_File_Chooser::value(int f)
272 Gets the current value of the selected file(s).
273 \p f is a \c 1-based index into a list of
274 file names. The number of selected files is returned by
275 Fl_File_Chooser::count().
277 This sample code loops through all selected files:
278 \code
279 // Get list of filenames user selected from a MULTI chooser
280 for ( int t=1; t<=chooser->count(); t++ ) {
281 const char *filename = chooser->value(t);
284 \endcode
287 /** \fn int Fl_File_Chooser::visible()
288 Returns 1 if the Fl_File_Chooser window is visible.*/
290 /** \fn Fl_Widget* Fl_File_Chooser::add_extra(Fl_Widget*)
291 Adds extra widget at the bottom of Fl_File_Chooser window.
292 Returns pointer for previous extra widget or NULL if not set previously.
293 If argument is NULL only remove previous extra widget.
295 \note Fl_File_Chooser does \b not delete extra widget in destructor!
296 To prevent memory leakage, don't forget to delete unused extra widgets
298 /** \fn int Fl_File_Chooser::shown()
299 Returns non-zero if the file chooser main window show() has been called (but not hide()
300 see Fl_Window::shown()
303 /** \fn void Fl_File_Chooser::callback(void (*cb)(Fl_File_Chooser *, void *), void *d = 0)
304 Sets the file chooser callback cb and associated data d */
306 /** \fn void Fl_File_Chooser::user_data(void *d)
307 Sets the file chooser user data d */
309 /** \fn void * Fl_File_Chooser::user_data() const
310 Gets the file chooser user data d */
312 /** \fn Fl_File_Browser* Fl_File_Chooser::browser()
313 returns a pointer to the underlying Fl_File_Browser object */
314 // *** END OF OUT OF SOURCE DOC ***
316 // Contents:
318 // Fl_File_Chooser::count() - Return the number of selected files.
319 // Fl_File_Chooser::directory() - Set the directory in the file chooser.
320 // Fl_File_Chooser::filter() - Set the filter(s) for the chooser.
321 // Fl_File_Chooser::newdir() - Make a new directory.
322 // Fl_File_Chooser::value() - Return a selected filename.
323 // Fl_File_Chooser::rescan() - Rescan the current directory.
324 // Fl_File_Chooser::favoritesButtonCB() - Handle favorites selections.
325 // Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks)
326 // in the Fl_File_Browser.
327 // Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser.
328 // Fl_File_Chooser::showChoiceCB() - Handle show selections.
329 // compare_dirnames() - Compare two directory names.
330 // quote_pathname() - Quote a pathname for a menu.
331 // unquote_pathname() - Unquote a pathname from a menu.
333 // Fl_File_Chooser::add_extra() - add extra widget at the bottom, return pointer
334 // to previous extra widget or NULL if none,
335 // If argument is NULL extra widget removed.
336 // NOTE! file chooser does't delete extra widget in
337 // destructor! To prevent memory leakage don't forget
338 // delete unused extra widgets by yourself.
342 // Include necessary headers.
345 #include <FL/Fl_File_Chooser.H>
346 #include <FL/filename.H>
347 #include <FL/fl_ask.H>
348 #include <FL/x.H>
349 #include <FL/Fl_Shared_Image.H>
350 #include <FL/fl_draw.H>
352 #include <stdio.h>
353 #include <stdlib.h>
354 #include "flstring.h"
355 #include <errno.h>
356 #include <sys/types.h>
357 #include <sys/stat.h>
359 #if defined(WIN32) && ! defined (__CYGWIN__)
360 # include <direct.h>
361 # include <io.h>
362 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
363 // on Windows, which is supposed to be POSIX compliant...
364 # define access _access
365 # define mkdir _mkdir
366 // Apparently Borland C++ defines DIRECTORY in <direct.h>, which
367 // interfers with the Fl_File_Icon enumeration of the same name.
368 # ifdef DIRECTORY
369 # undef DIRECTORY
370 # endif // DIRECTORY
371 #else
372 # include <unistd.h>
373 # include <pwd.h>
374 #endif /* WIN32 */
378 // File chooser label strings and sort function...
381 Fl_Preferences Fl_File_Chooser::prefs_(Fl_Preferences::USER, "fltk.org", "filechooser");
383 const char *Fl_File_Chooser::add_favorites_label = "Add to Favorites";
384 const char *Fl_File_Chooser::all_files_label = "All Files (*)";
385 const char *Fl_File_Chooser::custom_filter_label = "Custom Filter";
386 const char *Fl_File_Chooser::existing_file_label = "Please choose an existing file!";
387 const char *Fl_File_Chooser::favorites_label = "Favorites";
388 const char *Fl_File_Chooser::filename_label = "Filename:";
389 #ifdef WIN32
390 const char *Fl_File_Chooser::filesystems_label = "My Computer";
391 #else
392 const char *Fl_File_Chooser::filesystems_label = "File Systems";
393 #endif // WIN32
394 const char *Fl_File_Chooser::manage_favorites_label = "Manage Favorites";
395 const char *Fl_File_Chooser::new_directory_label = "New Directory?";
396 const char *Fl_File_Chooser::new_directory_tooltip = "Create a new directory.";
397 const char *Fl_File_Chooser::preview_label = "Preview";
398 const char *Fl_File_Chooser::save_label = "Save";
399 const char *Fl_File_Chooser::show_label = "Show:";
400 const char *Fl_File_Chooser::hidden_label = "Show hidden files";
401 Fl_File_Sort_F *Fl_File_Chooser::sort = fl_numericsort;
405 // Local functions...
408 static int compare_dirnames(const char *a, const char *b);
409 static void quote_pathname(char *, const char *, int);
410 static void unquote_pathname(char *, const char *, int);
414 // 'Fl_File_Chooser::count()' - Return the number of selected files.
417 int // O - Number of selected files
418 Fl_File_Chooser::count() {
419 int i; // Looping var
420 int fcount; // Number of selected files
421 const char *filename; // Filename in input field or list
424 filename = fileName->value();
426 if (!(type_ & MULTI)) {
427 // Check to see if the file name input field is blank...
428 if (!filename || !filename[0]) return 0;
429 else return 1;
432 for (i = 1, fcount = 0; i <= fileList->size(); i ++)
433 if (fileList->selected(i)) {
434 // See if this file is a directory...
435 // matt: why would we do that? It is perfectly legal to select multiple
436 // directories in a DIR chooser. They are visually selected and value(i)
437 // returns all of them as expected
438 //filename = (char *)fileList->text(i);
440 //if (filename[strlen(filename) - 1] != '/')
441 fcount ++;
444 if (fcount) return fcount;
445 else if (!filename || !filename[0]) return 0;
446 else return 1;
451 // 'Fl_File_Chooser::directory()' - Set the directory in the file chooser.
454 void
455 Fl_File_Chooser::directory(const char *d)// I - Directory to change to
457 char *dirptr; // Pointer into directory
460 // printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d);
462 // NULL == current directory
463 if (d == NULL)
464 d = ".";
466 #ifdef WIN32
467 // See if the filename contains backslashes...
468 char *slash; // Pointer to slashes
469 char fixpath[FL_PATH_MAX]; // Path with slashes converted
470 if (strchr(d, '\\')) {
471 // Convert backslashes to slashes...
472 strlcpy(fixpath, d, sizeof(fixpath));
474 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
475 *slash = '/';
477 d = fixpath;
479 #endif // WIN32
481 if (d[0] != '\0')
483 // Make the directory absolute...
484 #if (defined(WIN32) && ! defined(__CYGWIN__))|| defined(__EMX__)
485 if (d[0] != '/' && d[0] != '\\' && d[1] != ':')
486 #else
487 if (d[0] != '/' && d[0] != '\\')
488 #endif /* WIN32 || __EMX__ */
489 fl_filename_absolute(directory_, d);
490 else
491 strlcpy(directory_, d, sizeof(directory_));
493 // Strip any trailing slash...
494 dirptr = directory_ + strlen(directory_) - 1;
495 if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_)
496 *dirptr = '\0';
498 // See if we have a trailing .. or . in the filename...
499 dirptr = directory_ + strlen(directory_) - 3;
500 if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) {
501 // Yes, we have "..", so strip the trailing path...
502 *dirptr = '\0';
503 while (dirptr > directory_) {
504 if (*dirptr == '/') break;
505 dirptr --;
508 if (dirptr >= directory_ && *dirptr == '/')
509 *dirptr = '\0';
510 } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) {
511 // Strip trailing "."...
512 dirptr[1] = '\0';
515 else
516 directory_[0] = '\0';
518 if (shown()) {
519 // Rescan the directory...
520 rescan();
526 // 'Fl_File_Chooser::favoritesButtonCB()' - Handle favorites selections.
529 void
530 Fl_File_Chooser::favoritesButtonCB()
532 int v; // Current selection
533 char pathname[FL_PATH_MAX], // Pathname
534 menuname[FL_PATH_MAX]; // Menu name
537 v = favoritesButton->value();
539 if (!v) {
540 // Add current directory to favorites...
541 if (getenv("HOME")) v = favoritesButton->size() - 5;
542 else v = favoritesButton->size() - 4;
544 sprintf(menuname, "favorite%02d", v);
546 prefs_.set(menuname, directory_);
547 prefs_.flush();
549 quote_pathname(menuname, directory_, sizeof(menuname));
550 favoritesButton->add(menuname);
552 if (favoritesButton->size() > 104) {
553 ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
555 } else if (v == 1) {
556 // Manage favorites...
557 favoritesCB(0);
558 } else if (v == 2) {
559 // Filesystems/My Computer
560 directory("");
561 } else {
562 unquote_pathname(pathname, favoritesButton->text(v), sizeof(pathname));
563 directory(pathname);
569 // 'Fl_File_Chooser::favoritesCB()' - Handle favorites dialog.
572 void
573 Fl_File_Chooser::favoritesCB(Fl_Widget *w)
574 // I - Widget
576 int i; // Looping var
577 char name[32], // Preference name
578 pathname[1024]; // Directory in list
581 if (!w) {
582 // Load the favorites list...
583 favList->clear();
584 favList->deselect();
586 for (i = 0; i < 100; i ++) {
587 // Get favorite directory 0 to 99...
588 sprintf(name, "favorite%02d", i);
590 prefs_.get(name, pathname, "", sizeof(pathname));
592 // Stop on the first empty favorite...
593 if (!pathname[0]) break;
595 // Add the favorite to the list...
596 favList->add(pathname,
597 Fl_File_Icon::find(pathname, Fl_File_Icon::DIRECTORY));
600 favUpButton->deactivate();
601 favDeleteButton->deactivate();
602 favDownButton->deactivate();
603 favOkButton->deactivate();
605 favWindow->hotspot(favList);
606 favWindow->show();
607 } else if (w == favList) {
608 i = favList->value();
609 if (i) {
610 if (i > 1) favUpButton->activate();
611 else favUpButton->deactivate();
613 favDeleteButton->activate();
615 if (i < favList->size()) favDownButton->activate();
616 else favDownButton->deactivate();
617 } else {
618 favUpButton->deactivate();
619 favDeleteButton->deactivate();
620 favDownButton->deactivate();
622 } else if (w == favUpButton) {
623 i = favList->value();
625 favList->insert(i - 1, favList->text(i), favList->data(i));
626 favList->remove(i + 1);
627 favList->select(i - 1);
629 if (i == 2) favUpButton->deactivate();
631 favDownButton->activate();
633 favOkButton->activate();
634 } else if (w == favDeleteButton) {
635 i = favList->value();
637 favList->remove(i);
639 if (i > favList->size()) i --;
640 favList->select(i);
642 if (i < favList->size()) favDownButton->activate();
643 else favDownButton->deactivate();
645 if (i > 1) favUpButton->activate();
646 else favUpButton->deactivate();
648 if (!i) favDeleteButton->deactivate();
650 favOkButton->activate();
651 } else if (w == favDownButton) {
652 i = favList->value();
654 favList->insert(i + 2, favList->text(i), favList->data(i));
655 favList->remove(i);
656 favList->select(i + 1);
658 if ((i + 1) == favList->size()) favDownButton->deactivate();
660 favUpButton->activate();
662 favOkButton->activate();
663 } else if (w == favOkButton) {
664 // Copy the new list over...
665 for (i = 0; i < favList->size(); i ++) {
666 // Set favorite directory 0 to 99...
667 sprintf(name, "favorite%02d", i);
669 prefs_.set(name, favList->text(i + 1));
672 // Clear old entries as necessary...
673 for (; i < 100; i ++) {
674 // Clear favorite directory 0 to 99...
675 sprintf(name, "favorite%02d", i);
677 prefs_.get(name, pathname, "", sizeof(pathname));
679 if (pathname[0]) prefs_.set(name, "");
680 else break;
683 update_favorites();
684 prefs_.flush();
686 favWindow->hide();
692 // 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the
693 // Fl_File_Browser.
696 void
697 Fl_File_Chooser::fileListCB()
699 char *filename, // New filename
700 pathname[FL_PATH_MAX]; // Full pathname to file
703 filename = (char *)fileList->text(fileList->value());
704 if (!filename)
705 return;
707 if (!directory_[0]) {
708 strlcpy(pathname, filename, sizeof(pathname));
709 } else if (strcmp(directory_, "/") == 0) {
710 snprintf(pathname, sizeof(pathname), "/%s", filename);
711 } else {
712 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
715 if (Fl::event_clicks()) {
716 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
717 if ((strlen(pathname) == 2 && pathname[1] == ':') ||
718 _fl_filename_isdir_quick(pathname))
719 #else
720 if (_fl_filename_isdir_quick(pathname))
721 #endif /* WIN32 || __EMX__ */
723 // Change directories...
724 directory(pathname);
726 // Reset the click count so that a click in the same spot won't
727 // be treated as a triple-click. We use a value of -1 because
728 // the next click will increment click count to 0, which is what
729 // we really want...
730 Fl::event_clicks(-1);
732 else
734 // Hide the window - picked the file...
735 window->hide();
736 if (callback_) (*callback_)(this, data_);
739 else
741 // Check if the user clicks on a directory when picking files;
742 // if so, make sure only that item is selected...
743 filename = pathname + strlen(pathname) - 1;
745 if ((type_ & MULTI) && !(type_ & DIRECTORY)) {
746 if (*filename == '/') {
747 // Clicked on a directory, deselect everything else...
748 int i = fileList->value();
749 fileList->deselect();
750 fileList->select(i);
751 } else {
752 // Clicked on a file - see if there are other directories selected...
753 int i;
754 const char *temp;
755 for (i = 1; i <= fileList->size(); i ++) {
756 if (i != fileList->value() && fileList->selected(i)) {
757 temp = fileList->text(i);
758 temp += strlen(temp) - 1;
759 if (*temp == '/') break; // Yes, selected directory
763 if (i <= fileList->size()) {
764 i = fileList->value();
765 fileList->deselect();
766 fileList->select(i);
770 // Strip any trailing slash from the directory name...
771 if (*filename == '/') *filename = '\0';
773 // puts("Setting fileName from fileListCB...");
774 fileName->value(pathname);
776 // Update the preview box...
777 Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this);
778 Fl::add_timeout(1.0, (Fl_Timeout_Handler)previewCB, this);
780 // Do any callback that is registered...
781 if (callback_) (*callback_)(this, data_);
783 // Activate the OK button as needed...
784 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY))
785 okButton->activate();
786 else
787 okButton->deactivate();
793 // 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser.
796 void
797 Fl_File_Chooser::fileNameCB()
799 char *filename, // New filename
800 *slash, // Pointer to trailing slash
801 pathname[FL_PATH_MAX], // Full pathname to file
802 matchname[FL_PATH_MAX]; // Matching filename
803 int i, // Looping var
804 min_match, // Minimum number of matching chars
805 max_match, // Maximum number of matching chars
806 num_files, // Number of files in directory
807 first_line; // First matching line
808 const char *file; // File from directory
810 // puts("fileNameCB()");
811 // printf("Event: %s\n", fl_eventnames[Fl::event()]);
813 // Get the filename from the text field...
814 filename = (char *)fileName->value();
816 if (!filename || !filename[0]) {
817 okButton->deactivate();
818 return;
821 // Expand ~ and $ variables as needed...
822 if (strchr(filename, '~') || strchr(filename, '$')) {
823 fl_filename_expand(pathname, sizeof(pathname), filename);
824 filename = pathname;
825 value(pathname);
828 // Make sure we have an absolute path...
829 #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__)
830 if (directory_[0] != '\0' && filename[0] != '/' &&
831 filename[0] != '\\' &&
832 !(isalpha(filename[0] & 255) && (!filename[1] || filename[1] == ':'))) {
833 #else
834 if (directory_[0] != '\0' && filename[0] != '/') {
835 #endif /* WIN32 || __EMX__ */
836 fl_filename_absolute(pathname, sizeof(pathname), filename);
837 value(pathname);
838 fileName->mark(fileName->position()); // no selection after expansion
839 } else if (filename != pathname) {
840 // Finally, make sure that we have a writable copy...
841 strlcpy(pathname, filename, sizeof(pathname));
844 filename = pathname;
846 // Now process things according to the key pressed...
847 if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter) {
848 // Enter pressed - select or change directory...
849 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
850 if ((isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2]) ||
851 (_fl_filename_isdir_quick(pathname) &&
852 compare_dirnames(pathname, directory_))) {
853 #else
854 if (_fl_filename_isdir_quick(pathname) &&
855 compare_dirnames(pathname, directory_)) {
856 #endif /* WIN32 || __EMX__ */
857 directory(pathname);
858 } else if ((type_ & CREATE) || access(pathname, 0) == 0) {
859 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) {
860 // Update the preview box...
861 update_preview();
863 // Do any callback that is registered...
864 if (callback_) (*callback_)(this, data_);
866 // Hide the window to signal things are done...
867 window->hide();
869 } else {
870 // File doesn't exist, so beep at and alert the user...
871 fl_alert("%s",existing_file_label);
874 else if (Fl::event_key() != FL_Delete &&
875 Fl::event_key() != FL_BackSpace) {
876 // Check to see if the user has entered a directory...
877 if ((slash = strrchr(pathname, '/')) == NULL)
878 slash = strrchr(pathname, '\\');
880 if (!slash) return;
882 // Yes, change directories if necessary...
883 *slash++ = '\0';
884 filename = slash;
886 #if defined(WIN32) || defined(__EMX__)
887 if (strcasecmp(pathname, directory_) &&
888 (pathname[0] || strcasecmp("/", directory_))) {
889 #else
890 if (strcmp(pathname, directory_) &&
891 (pathname[0] || strcasecmp("/", directory_))) {
892 #endif // WIN32 || __EMX__
893 int p = fileName->position();
894 int m = fileName->mark();
896 directory(pathname);
898 if (filename[0]) {
899 char tempname[FL_PATH_MAX];
901 snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename);
902 fileName->value(tempname);
903 strlcpy(pathname, tempname, sizeof(pathname));
906 fileName->position(p, m);
909 // Other key pressed - do filename completion as possible...
910 num_files = fileList->size();
911 min_match = strlen(filename);
912 max_match = min_match + 1;
913 first_line = 0;
915 for (i = 1; i <= num_files && max_match > min_match; i ++) {
916 file = fileList->text(i);
918 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
919 if (strncasecmp(filename, file, min_match) == 0) {
920 #else
921 if (strncmp(filename, file, min_match) == 0) {
922 #endif // WIN32 || __EMX__
923 // OK, this one matches; check against the previous match
924 if (!first_line) {
925 // First match; copy stuff over...
926 strlcpy(matchname, file, sizeof(matchname));
927 max_match = strlen(matchname);
929 // Strip trailing /, if any...
930 if (matchname[max_match - 1] == '/') {
931 max_match --;
932 matchname[max_match] = '\0';
935 // And then make sure that the item is visible
936 fileList->topline(i);
937 first_line = i;
938 } else {
939 // Succeeding match; compare to find maximum string match...
940 while (max_match > min_match)
941 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
942 if (strncasecmp(file, matchname, max_match) == 0)
943 #else
944 if (strncmp(file, matchname, max_match) == 0)
945 #endif // WIN32 || __EMX__
946 break;
947 else
948 max_match --;
950 // Truncate the string as needed...
951 matchname[max_match] = '\0';
956 // If we have any matches, add them to the input field...
957 if (first_line > 0 && min_match == max_match &&
958 max_match == (int)strlen(fileList->text(first_line))) {
959 // This is the only possible match...
960 fileList->deselect(0);
961 fileList->select(first_line);
962 fileList->redraw();
963 } else if (max_match > min_match && first_line) {
964 // Add the matching portion...
965 fileName->replace(filename - pathname, filename - pathname + min_match,
966 matchname);
968 // Highlight it with the cursor at the end of the selection so
969 // s/he can press the right arrow to accept the selection
970 // (Tab and End also do this for both cases.)
971 fileName->position(filename - pathname + max_match,
972 filename - pathname + min_match);
973 } else if (max_match == 0) {
974 fileList->deselect(0);
975 fileList->redraw();
978 // See if we need to enable the OK button...
979 if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
980 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
981 okButton->activate();
982 } else {
983 okButton->deactivate();
985 } else {
986 // FL_Delete or FL_BackSpace
987 fileList->deselect(0);
988 fileList->redraw();
989 if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
990 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
991 okButton->activate();
992 } else {
993 okButton->deactivate();
1000 // 'Fl_File_Chooser::filter()' - Set the filter(s) for the chooser.
1003 void
1004 Fl_File_Chooser::filter(const char *p) // I - Pattern(s)
1006 char *copyp, // Copy of pattern
1007 *start, // Start of pattern
1008 *end; // End of pattern
1009 int allfiles; // Do we have a "*" pattern?
1010 char temp[FL_PATH_MAX]; // Temporary pattern string
1013 // Make sure we have a pattern...
1014 if (!p || !*p) p = "*";
1016 // Copy the pattern string...
1017 copyp = strdup(p);
1019 // Separate the pattern string as necessary...
1020 showChoice->clear();
1022 for (start = copyp, allfiles = 0; start && *start; start = end) {
1023 end = strchr(start, '\t');
1024 if (end) *end++ = '\0';
1026 if (strcmp(start, "*") == 0) {
1027 showChoice->add(all_files_label);
1028 allfiles = 1;
1029 } else {
1030 quote_pathname(temp, start, sizeof(temp));
1031 showChoice->add(temp);
1032 if (strstr(start, "(*)") != NULL) allfiles = 1;
1036 free(copyp);
1038 if (!allfiles) showChoice->add(all_files_label);
1040 showChoice->add(custom_filter_label);
1042 showChoice->value(0);
1043 showChoiceCB();
1048 // 'Fl_File_Chooser::newdir()' - Make a new directory.
1051 void
1052 Fl_File_Chooser::newdir()
1054 const char *dir; // New directory name
1055 char pathname[FL_PATH_MAX]; // Full path of directory
1058 // Get a directory name from the user
1059 if ((dir = fl_input("%s", NULL, new_directory_label)) == NULL)
1060 return;
1062 // Make it relative to the current directory as needed...
1063 #if (defined(WIN32) && ! defined (__CYGWIN__)) || defined(__EMX__)
1064 if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':')
1065 #else
1066 if (dir[0] != '/' && dir[0] != '\\')
1067 #endif /* WIN32 || __EMX__ */
1068 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir);
1069 else
1070 strlcpy(pathname, dir, sizeof(pathname));
1072 // Create the directory; ignore EEXIST errors...
1073 #if defined(WIN32) && ! defined (__CYGWIN__)
1074 if (mkdir(pathname))
1075 #else
1076 if (mkdir(pathname, 0777))
1077 #endif /* WIN32 */
1078 if (errno != EEXIST)
1080 fl_alert("%s", strerror(errno));
1081 return;
1084 // Show the new directory...
1085 directory(pathname);
1090 /** Enable or disable the preview tile. 1 = enable preview, 0 = disable preview. */
1091 void Fl_File_Chooser::preview(int e)
1093 previewButton->value(e);
1094 prefs_.set("preview", e);
1095 prefs_.flush();
1097 Fl_Group *p = previewBox->parent();
1098 if (e) {
1099 int w = p->w() * 2 / 3;
1100 fileList->resize(fileList->x(), fileList->y(),
1101 w, fileList->h());
1102 previewBox->resize(fileList->x()+w, previewBox->y(),
1103 p->w()-w, previewBox->h());
1104 previewBox->show();
1105 update_preview();
1106 } else {
1107 fileList->resize(fileList->x(), fileList->y(),
1108 p->w(), fileList->h());
1109 previewBox->resize(p->x()+p->w(), previewBox->y(),
1110 0, previewBox->h());
1111 previewBox->hide();
1113 p->init_sizes();
1115 fileList->parent()->redraw();
1120 // 'Fl_File_Chooser::previewCB()' - Timeout handler for the preview box.
1123 void
1124 Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) { // I - File chooser
1125 fc->update_preview();
1130 // 'Fl_File_Chooser::rescan()' - Rescan the current directory.
1133 void
1134 Fl_File_Chooser::rescan()
1136 char pathname[FL_PATH_MAX]; // New pathname for filename field
1139 // Clear the current filename
1140 strlcpy(pathname, directory_, sizeof(pathname));
1141 if (pathname[0] && pathname[strlen(pathname) - 1] != '/') {
1142 strlcat(pathname, "/", sizeof(pathname));
1144 // puts("Setting fileName in rescan()");
1145 fileName->value(pathname);
1147 if (type_ & DIRECTORY)
1148 okButton->activate();
1149 else
1150 okButton->deactivate();
1152 // Build the file list...
1153 fileList->load(directory_, sort);
1154 #ifndef WIN32
1155 if (!showHiddenButton->value()) remove_hidden_files();
1156 #endif
1157 // Update the preview box...
1158 update_preview();
1162 /**
1163 Rescan the current directory without clearing the filename,
1164 then select the file if it is in the list
1166 void Fl_File_Chooser::rescan_keep_filename()
1168 // if no filename was set, this is likely a diretory browser
1169 const char *fn = fileName->value();
1170 if (!fn || !*fn || fn[strlen(fn) - 1]=='/') {
1171 rescan();
1172 return;
1175 int i;
1176 char pathname[FL_PATH_MAX]; // New pathname for filename field
1177 strlcpy(pathname, fn, sizeof(pathname));
1179 // Build the file list...
1180 fileList->load(directory_, sort);
1181 #ifndef WIN32
1182 if (!showHiddenButton->value()) remove_hidden_files();
1183 #endif
1184 // Update the preview box...
1185 update_preview();
1187 // and select the chosen file
1188 char found = 0;
1189 char *slash = strrchr(pathname, '/');
1190 if (slash)
1191 slash++;
1192 else
1193 slash = pathname;
1194 for (i = 1; i <= fileList->size(); i ++)
1195 #if defined(WIN32) || defined(__EMX__)
1196 if (strcasecmp(fileList->text(i), slash) == 0) {
1197 #else
1198 if (strcmp(fileList->text(i), slash) == 0) {
1199 #endif // WIN32 || __EMX__
1200 fileList->topline(i);
1201 fileList->select(i);
1202 found = 1;
1203 break;
1206 // update OK button activity
1207 if (found || type_ & CREATE)
1208 okButton->activate();
1209 else
1210 okButton->deactivate();
1215 // 'Fl_File_Chooser::showChoiceCB()' - Handle show selections.
1218 void
1219 Fl_File_Chooser::showChoiceCB()
1221 const char *item, // Selected item
1222 *patstart; // Start of pattern
1223 char *patend; // End of pattern
1224 char temp[FL_PATH_MAX]; // Temporary string for pattern
1227 item = showChoice->text(showChoice->value());
1229 if (strcmp(item, custom_filter_label) == 0) {
1230 if ((item = fl_input("%s", pattern_, custom_filter_label)) != NULL) {
1231 strlcpy(pattern_, item, sizeof(pattern_));
1233 quote_pathname(temp, item, sizeof(temp));
1234 showChoice->add(temp);
1235 showChoice->value(showChoice->size() - 2);
1237 } else if ((patstart = strchr(item, '(')) == NULL) {
1238 strlcpy(pattern_, item, sizeof(pattern_));
1239 } else {
1240 strlcpy(pattern_, patstart + 1, sizeof(pattern_));
1241 if ((patend = strrchr(pattern_, ')')) != NULL) *patend = '\0';
1244 fileList->filter(pattern_);
1246 if (shown()) {
1247 // Rescan the directory...
1248 rescan_keep_filename();
1254 // 'Fl_File_Chooser::update_favorites()' - Update the favorites menu.
1257 void
1258 Fl_File_Chooser::update_favorites()
1260 int i; // Looping var
1261 char pathname[FL_PATH_MAX], // Pathname
1262 menuname[2048]; // Menu name
1263 const char *home; // Home directory
1266 favoritesButton->clear();
1267 favoritesButton->add("bla");
1268 favoritesButton->clear();
1269 favoritesButton->add(add_favorites_label, FL_ALT + 'a', 0);
1270 favoritesButton->add(manage_favorites_label, FL_ALT + 'm', 0, 0, FL_MENU_DIVIDER);
1271 favoritesButton->add(filesystems_label, FL_ALT + 'f', 0);
1273 if ((home = getenv("HOME")) != NULL) {
1274 quote_pathname(menuname, home, sizeof(menuname));
1275 favoritesButton->add(menuname, FL_ALT + 'h', 0);
1278 for (i = 0; i < 100; i ++) {
1279 sprintf(menuname, "favorite%02d", i);
1280 prefs_.get(menuname, pathname, "", sizeof(pathname));
1281 if (!pathname[0]) break;
1283 quote_pathname(menuname, pathname, sizeof(menuname));
1285 if (i < 10) favoritesButton->add(menuname, FL_ALT + '0' + i, 0);
1286 else favoritesButton->add(menuname);
1289 if (i == 100) ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
1294 // 'Fl_File_Chooser::update_preview()' - Update the preview box...
1297 void
1298 Fl_File_Chooser::update_preview()
1300 const char *filename; // Current filename
1301 const char *newlabel = 0; // New label text
1302 Fl_Shared_Image *image = 0, // New image
1303 *oldimage; // Old image
1304 int pbw, pbh; // Width and height of preview box
1305 int w, h; // Width and height of preview image
1306 int set = 0; // Set this flag as soon as a decent preview is found
1308 if (!previewButton->value()) return;
1310 filename = value();
1311 if (filename == NULL) {
1312 // no file name at all, so we have an empty preview
1313 set = 1;
1314 } else if (fl_filename_isdir(filename)) {
1315 // filename is a directory, show a folder icon
1316 newlabel = "@fileopen";
1317 set = 1;
1318 } else {
1319 struct stat s;
1320 if (fl_stat(filename, &s)==0) {
1321 if ((s.st_mode&S_IFMT)!=S_IFREG) {
1322 // this is no regular file, probably some kind of device
1323 newlabel = "@-3refresh"; // a cross
1324 set = 1;
1325 } else if (s.st_size==0) {
1326 // this file is emty
1327 newlabel = "<empty file>";
1328 set = 1;
1329 } else {
1330 // if this file is an image, try to load it
1331 window->cursor(FL_CURSOR_WAIT);
1332 Fl::check();
1334 image = Fl_Shared_Image::get(filename);
1336 if (image) {
1337 window->cursor(FL_CURSOR_DEFAULT);
1338 Fl::check();
1339 set = 1;
1345 oldimage = (Fl_Shared_Image *)previewBox->image();
1347 if (oldimage) oldimage->release();
1349 previewBox->image(0);
1351 if (!set) {
1352 FILE *fp;
1353 int bytes;
1354 char *ptr;
1356 if (filename) fp = fl_fopen(filename, "rb");
1357 else fp = NULL;
1359 if (fp != NULL) {
1360 // Try reading the first 1k of data for a label...
1361 bytes = fread(preview_text_, 1, sizeof(preview_text_) - 1, fp);
1362 preview_text_[bytes] = '\0';
1363 fclose(fp);
1364 } else {
1365 // Assume we can't read any data...
1366 preview_text_[0] = '\0';
1369 window->cursor(FL_CURSOR_DEFAULT);
1370 Fl::check();
1372 // Scan the buffer for printable UTF8 chars...
1373 for (ptr = preview_text_; *ptr; ptr++) {
1374 uchar c = uchar(*ptr);
1375 if ( (c&0x80)==0 ) {
1376 if (!isprint(c&255) && !isspace(c&255)) break;
1377 } else if ( (c&0xe0)==0xc0 ) {
1378 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1379 ptr++;
1380 } else if ( (c&0xf0)==0xe0 ) {
1381 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1382 ptr++;
1383 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1384 ptr++;
1385 } else if ( (c&0xf8)==0xf0 ) {
1386 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1387 ptr++;
1388 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1389 ptr++;
1390 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
1391 ptr++;
1394 // *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
1395 // ptr ++);
1397 // Scan the buffer for printable characters in 8 bit
1398 if (*ptr || ptr == preview_text_) {
1399 for (ptr = preview_text_;
1400 *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
1401 ptr ++);
1404 if (*ptr || ptr == preview_text_) {
1405 // Non-printable file, just show a big ?...
1406 previewBox->label(filename ? "?" : 0);
1407 previewBox->align(FL_ALIGN_CLIP);
1408 previewBox->labelsize(75);
1409 previewBox->labelfont(FL_HELVETICA);
1410 } else {
1411 // Show the first 1k of text...
1412 int size = previewBox->h() / 20;
1413 if (size < 6) size = 6;
1414 else if (size > FL_NORMAL_SIZE) size = FL_NORMAL_SIZE;
1416 previewBox->label(preview_text_);
1417 previewBox->align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE |
1418 FL_ALIGN_LEFT | FL_ALIGN_TOP));
1419 previewBox->labelsize(size);
1420 previewBox->labelfont(FL_COURIER);
1422 } else if (image) {
1423 pbw = previewBox->w() - 20;
1424 pbh = previewBox->h() - 20;
1426 if (image->w() > pbw || image->h() > pbh) {
1427 w = pbw;
1428 h = w * image->h() / image->w();
1430 if (h > pbh) {
1431 h = pbh;
1432 w = h * image->w() / image->h();
1435 oldimage = (Fl_Shared_Image *)image->copy(w, h);
1436 previewBox->image((Fl_Image *)oldimage);
1438 image->release();
1439 } else {
1440 previewBox->image((Fl_Image *)image);
1443 previewBox->align(FL_ALIGN_CLIP);
1444 previewBox->label(0);
1445 } else if (newlabel) {
1446 previewBox->label(newlabel);
1447 previewBox->align(FL_ALIGN_CLIP);
1448 previewBox->labelsize(newlabel[0]=='@'?75:12);
1449 previewBox->labelfont(FL_HELVETICA);
1452 previewBox->redraw();
1457 // 'Fl_File_Chooser::value()' - Return a selected filename.
1460 const char * // O - Filename or NULL
1461 Fl_File_Chooser::value(int f) // I - File number
1463 int i; // Looping var
1464 int fcount; // Number of selected files
1465 const char *name; // Current filename
1466 static char pathname[FL_PATH_MAX]; // Filename + directory
1469 name = fileName->value();
1471 if (!(type_ & MULTI)) {
1472 // Return the filename in the filename field...
1473 if (!name || !name[0]) return NULL;
1474 else return name;
1477 // Return a filename from the list...
1478 for (i = 1, fcount = 0; i <= fileList->size(); i ++)
1479 if (fileList->selected(i)) {
1480 // See if this file is a selected file/directory...
1481 name = fileList->text(i);
1483 fcount ++;
1485 if (fcount == f) {
1486 if (directory_[0]) {
1487 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name);
1488 } else {
1489 strlcpy(pathname, name, sizeof(pathname));
1492 return pathname;
1496 // If nothing is selected, use the filename field...
1497 if (!name || !name[0]) return NULL;
1498 else return name;
1503 // 'Fl_File_Chooser::value()' - Set the current filename.
1506 void
1507 Fl_File_Chooser::value(const char *filename)
1508 // I - Filename + directory
1510 int i, // Looping var
1511 fcount; // Number of items in list
1512 char *slash; // Directory separator
1513 char pathname[FL_PATH_MAX]; // Local copy of filename
1516 // printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename);
1518 // See if the filename is the "My System" directory...
1519 if (filename == NULL || !filename[0]) {
1520 // Yes, just change the current directory...
1521 directory(filename);
1522 fileName->value("");
1523 okButton->deactivate();
1524 return;
1527 #ifdef WIN32
1528 // See if the filename contains backslashes...
1529 char fixpath[FL_PATH_MAX]; // Path with slashes converted
1530 if (strchr(filename, '\\')) {
1531 // Convert backslashes to slashes...
1532 strlcpy(fixpath, filename, sizeof(fixpath));
1534 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
1535 *slash = '/';
1537 filename = fixpath;
1539 #endif // WIN32
1541 // See if there is a directory in there...
1542 fl_filename_absolute(pathname, sizeof(pathname), filename);
1544 if ((slash = strrchr(pathname, '/')) != NULL) {
1545 // Yes, change the display to the directory...
1546 if (!fl_filename_isdir(pathname)) *slash++ = '\0';
1548 directory(pathname);
1549 if (*slash == '/') slash = pathname;
1550 } else {
1551 directory(".");
1552 slash = pathname;
1555 // Set the input field to the absolute path...
1556 if (slash > pathname) slash[-1] = '/';
1558 fileName->value(pathname);
1559 fileName->position(0, strlen(pathname));
1560 okButton->activate();
1562 // Then find the file in the file list and select it...
1563 fcount = fileList->size();
1565 fileList->deselect(0);
1566 fileList->redraw();
1568 for (i = 1; i <= fcount; i ++)
1569 #if defined(WIN32) || defined(__EMX__)
1570 if (strcasecmp(fileList->text(i), slash) == 0) {
1571 #else
1572 if (strcmp(fileList->text(i), slash) == 0) {
1573 #endif // WIN32 || __EMX__
1574 // printf("Selecting line %d...\n", i);
1575 fileList->topline(i);
1576 fileList->select(i);
1577 break;
1581 void Fl_File_Chooser::show()
1583 window->hotspot(fileList);
1584 window->show();
1585 Fl::flush();
1586 fl_cursor(FL_CURSOR_WAIT);
1587 rescan_keep_filename();
1588 fl_cursor(FL_CURSOR_DEFAULT);
1589 fileName->take_focus();
1590 #ifdef WIN32
1591 showHiddenButton->hide();
1592 #endif
1595 void Fl_File_Chooser::showHidden(int value)
1597 if (value) {
1598 fileList->load(directory());
1599 } else {
1600 remove_hidden_files();
1601 fileList->redraw();
1605 void Fl_File_Chooser::remove_hidden_files()
1607 int count = fileList->size();
1608 for(int num = count; num >= 1; num--) {
1609 const char *p = fileList->text(num);
1610 if (*p == '.' && strcmp(p, "../") != 0) fileList->remove(num);
1612 fileList->topline(1);
1617 // 'compare_dirnames()' - Compare two directory names.
1620 static int
1621 compare_dirnames(const char *a, const char *b) {
1622 int alen, blen;
1624 // Get length of each string...
1625 alen = strlen(a) - 1;
1626 blen = strlen(b) - 1;
1628 if (alen < 0 || blen < 0) return alen - blen;
1630 // Check for trailing slashes...
1631 if (a[alen] != '/') alen ++;
1632 if (b[blen] != '/') blen ++;
1634 // If the lengths aren't the same, then return the difference...
1635 if (alen != blen) return alen - blen;
1637 // Do a comparison of the first N chars (alen == blen at this point)...
1638 #ifdef WIN32
1639 return strncasecmp(a, b, alen);
1640 #else
1641 return strncmp(a, b, alen);
1642 #endif // WIN32
1647 // 'quote_pathname()' - Quote a pathname for a menu.
1650 static void
1651 quote_pathname(char *dst, // O - Destination string
1652 const char *src, // I - Source string
1653 int dstsize) // I - Size of destination string
1655 dstsize --;
1657 while (*src && dstsize > 1) {
1658 if (*src == '\\') {
1659 // Convert backslash to forward slash...
1660 *dst++ = '\\';
1661 *dst++ = '/';
1662 src ++;
1663 } else {
1664 if (*src == '/') *dst++ = '\\';
1666 *dst++ = *src++;
1670 *dst = '\0';
1675 // 'unquote_pathname()' - Unquote a pathname from a menu.
1678 static void
1679 unquote_pathname(char *dst, // O - Destination string
1680 const char *src, // I - Source string
1681 int dstsize) // I - Size of destination string
1683 dstsize --;
1685 while (*src && dstsize > 1) {
1686 if (*src == '\\') src ++;
1687 *dst++ = *src++;
1690 *dst = '\0';
1695 // End of "$Id: Fl_File_Chooser2.cxx 8785 2011-06-06 16:11:22Z manolo $".