2 // "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $"
4 // Fl_File_Browser routines.
6 // Copyright 1999-2010 by Michael Sweet.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 // Fl_File_Browser::full_height() - Return the height of the list.
30 // Fl_File_Browser::item_height() - Return the height of a list item.
31 // Fl_File_Browser::item_width() - Return the width of a list item.
32 // Fl_File_Browser::item_draw() - Draw a list item.
33 // Fl_File_Browser::Fl_File_Browser() - Create a Fl_File_Browser widget.
34 // Fl_File_Browser::load() - Load a directory into the browser.
35 // Fl_File_Browser::filter() - Set the filename filter.
39 // Include necessary header files...
42 #include <FL/Fl_File_Browser.H>
43 #include <FL/fl_draw.H>
44 #include <FL/filename.H>
45 #include <FL/Fl_Image.H> // icon
55 // Apparently Borland C++ defines DIRECTORY in <direct.h>, which
56 // interfers with the Fl_File_Icon enumeration of the same name.
68 #if defined(__APPLE__)
69 # include <sys/param.h>
70 # include <sys/ucred.h>
71 # include <sys/mount.h>
75 // FL_BLINE definition from "Fl_Browser.cxx"...
79 #define NOTDISPLAYED 2
81 // TODO -- Warning: The definition of FL_BLINE here is a hack.
82 // Fl_File_Browser should not do this. PLEASE FIX.
83 // FL_BLINE should be private to Fl_Browser, and not re-defined here.
84 // For now, make sure this struct is precisely consistent with Fl_Browser.cxx.
86 struct FL_BLINE
// data is in a linked list of these
88 FL_BLINE
*prev
; // Previous item in list
89 FL_BLINE
*next
; // Next item in list
90 void *data
; // Pointer to data (function)
91 Fl_Image
*icon
; // Pointer to optional icon
92 short length
; // sizeof(txt)-1, may be longer than string
93 char flags
; // selected, displayed
94 char txt
[1]; // start of allocated array
99 // 'Fl_File_Browser::full_height()' - Return the height of the list.
102 int // O - Height in pixels
103 Fl_File_Browser::full_height() const
105 int i
, // Looping var
106 th
; // Total height of list.
109 for (i
= 0, th
= 0; i
< size(); i
++)
110 th
+= item_height(find_line(i
));
117 // 'Fl_File_Browser::item_height()' - Return the height of a list item.
120 int // O - Height in pixels
121 Fl_File_Browser::item_height(void *p
) const // I - List item data
123 FL_BLINE
*line
; // Pointer to line
124 char *t
; // Pointer into text
125 int height
; // Width of line
126 int textheight
; // Height of text
129 // Figure out the standard text height...
130 fl_font(textfont(), textsize());
131 textheight
= fl_height();
133 // We always have at least 1 line...
136 // Scan for newlines...
137 line
= (FL_BLINE
*)p
;
140 for (t
= line
->txt
; *t
!= '\0'; t
++)
142 height
+= textheight
;
144 // If we have enabled icons then add space for them...
145 if (Fl_File_Icon::first() != NULL
&& height
< iconsize_
)
148 // Add space for the selection border..
157 // 'Fl_File_Browser::item_width()' - Return the width of a list item.
160 int // O - Width in pixels
161 Fl_File_Browser::item_width(void *p
) const // I - List item data
163 int i
; // Looping var
164 FL_BLINE
*line
; // Pointer to line
165 char *t
, // Pointer into text
166 *ptr
, // Pointer into fragment
167 fragment
[10240]; // Fragment of text
168 int width
, // Width of line
169 tempwidth
; // Width of fragment
170 int column
; // Current column
171 const int *columns
; // Columns
174 // Scan for newlines...
175 line
= (FL_BLINE
*)p
;
176 columns
= column_widths();
178 // Set the font and size...
179 if (line
->txt
[strlen(line
->txt
) - 1] == '/')
180 fl_font(textfont() | FL_BOLD
, textsize());
182 fl_font(textfont(), textsize());
184 if (strchr(line
->txt
, '\n') == NULL
&&
185 strchr(line
->txt
, column_char()) == NULL
)
187 // Do a fast width calculation...
188 width
= (int)fl_width(line
->txt
);
192 // More than 1 line or have columns; find the maximum width...
197 for (t
= line
->txt
, ptr
= fragment
; *t
!= '\0'; t
++)
200 // Newline - nul terminate this fragment and get the width...
203 tempwidth
+= (int)fl_width(fragment
);
205 // Update the max width as needed...
206 if (tempwidth
> width
)
209 // Point back to the start of the fragment...
214 else if (*t
== column_char())
216 // Advance to the next column...
220 for (i
= 0, tempwidth
= 0; i
< column
&& columns
[i
]; i
++)
221 tempwidth
+= columns
[i
];
224 tempwidth
= column
* (int)(fl_height() * 0.6 * 8.0);
226 if (tempwidth
> width
)
236 // Nul terminate this fragment and get the width...
239 tempwidth
+= (int)fl_width(fragment
);
241 // Update the max width as needed...
242 if (tempwidth
> width
)
247 // If we have enabled icons then add space for them...
248 if (Fl_File_Icon::first() != NULL
)
249 width
+= iconsize_
+ 8;
251 // Add space for the selection border..
260 // 'Fl_File_Browser::item_draw()' - Draw a list item.
264 Fl_File_Browser::item_draw(void *p
, // I - List item data
265 int X
, // I - Upper-lefthand X coordinate
266 int Y
, // I - Upper-lefthand Y coordinate
267 int W
, // I - Width of item
268 int) const // I - Height of item
270 int i
; // Looping var
271 FL_BLINE
*line
; // Pointer to line
272 Fl_Color c
; // Text color
273 char *t
, // Pointer into text
274 *ptr
, // Pointer into fragment
275 fragment
[10240]; // Fragment of text
276 int width
, // Width of line
277 height
; // Height of line
278 int column
; // Current column
279 const int *columns
; // Columns
282 // Draw the list item text...
283 line
= (FL_BLINE
*)p
;
285 if (line
->txt
[strlen(line
->txt
) - 1] == '/')
286 fl_font(textfont() | FL_BOLD
, textsize());
288 fl_font(textfont(), textsize());
290 if (line
->flags
& SELECTED
)
291 c
= fl_contrast(textcolor(), selection_color());
295 if (Fl_File_Icon::first() == NULL
)
297 // No icons, just draw the text...
303 // Draw the icon if it is set...
305 ((Fl_File_Icon
*)line
->data
)->draw(X
, Y
, iconsize_
, iconsize_
,
306 (line
->flags
& SELECTED
) ? FL_YELLOW
:
310 // Draw the text offset to the right...
314 // Center the text vertically...
315 height
= fl_height();
317 for (t
= line
->txt
; *t
!= '\0'; t
++)
319 height
+= fl_height();
321 if (height
< iconsize_
)
322 Y
+= (iconsize_
- height
) / 2;
326 line
= (FL_BLINE
*)p
;
327 columns
= column_widths();
334 fl_color(fl_inactive(c
));
336 for (t
= line
->txt
, ptr
= fragment
; *t
!= '\0'; t
++)
339 // Newline - nul terminate this fragment and draw it...
342 fl_draw(fragment
, X
+ width
, Y
, W
- width
, fl_height(),
343 (Fl_Align
)(FL_ALIGN_LEFT
| FL_ALIGN_CLIP
), 0, 0);
345 // Point back to the start of the fragment...
351 else if (*t
== column_char())
353 // Tab - nul terminate this fragment and draw it...
356 int cW
= W
- width
; // Clip width...
360 // Try clipping inside this column...
361 for (i
= 0; i
< column
&& columns
[i
]; i
++);
367 fl_draw(fragment
, X
+ width
, Y
, cW
, fl_height(),
368 (Fl_Align
)(FL_ALIGN_LEFT
| FL_ALIGN_CLIP
), 0, 0);
370 // Advance to the next column...
374 for (i
= 0, width
= 0; i
< column
&& columns
[i
]; i
++)
378 width
= column
* (int)(fl_height() * 0.6 * 8.0);
387 // Nul terminate this fragment and draw it...
390 fl_draw(fragment
, X
+ width
, Y
, W
- width
, fl_height(),
391 (Fl_Align
)(FL_ALIGN_LEFT
| FL_ALIGN_CLIP
), 0, 0);
397 // 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget.
400 Fl_File_Browser::Fl_File_Browser(int X
, // I - Upper-lefthand X coordinate
401 int Y
, // I - Upper-lefthand Y coordinate
402 int W
, // I - Width in pixels
403 int H
, // I - Height in pixels
404 const char *l
) // I - Label text
405 : Fl_Browser(X
, Y
, W
, H
, l
)
407 // Initialize the filter pattern, current directory, and icon size...
410 iconsize_
= (uchar
)(3 * textsize() / 2);
416 // 'Fl_File_Browser::load()' - Load a directory into the browser.
419 int // O - Number of files loaded
420 Fl_File_Browser::load(const char *directory
,// I - Directory to load
421 Fl_File_Sort_F
*sort
) // I - Sort function to use
423 int i
; // Looping var
424 int num_files
; // Number of files in directory
425 int num_dirs
; // Number of directories in list
426 char filename
[4096]; // Current file
427 Fl_File_Icon
*icon
; // Icon to use
430 // printf("Fl_File_Browser::load(\"%s\")\n", directory);
434 directory_
= directory
;
439 if (directory_
[0] == '\0')
442 // No directory specified; for UNIX list all mount points. For DOS
443 // list all valid drive letters...
447 if ((icon
= Fl_File_Icon::find("any", Fl_File_Icon::DEVICE
)) == NULL
)
448 icon
= Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY
);
453 // Cygwin provides an implementation of setmntent() to get the list
454 // of available drives...
456 FILE *m
= setmntent("/-not-used-", "r");
459 while ((p
= getmntent (m
)) != NULL
) {
460 add(p
->mnt_dir
, icon
);
467 // Normal WIN32 code uses drive bits...
469 DWORD drives
; // Drive available bits
471 drives
= GetLogicalDrives();
472 for (i
= 'A'; i
<= 'Z'; i
++, drives
>>= 1)
475 sprintf(filename
, "%c:/", i
);
477 if (i
< 'C') // see also: GetDriveType and GetVolumeInformation in WIN32
484 # endif // __CYGWIN__
485 #elif defined(__EMX__)
487 // OS/2 code uses drive bits...
489 ULONG curdrive
; // Current drive
490 ULONG drives
; // Drive available bits
491 int start
= 3; // 'C' (MRS - dunno if this is correct!)
494 DosQueryCurrentDisk(&curdrive
, &drives
);
495 drives
>>= start
- 1;
496 for (i
= 'A'; i
<= 'Z'; i
++, drives
>>= 1)
499 sprintf(filename
, "%c:/", i
);
504 #elif defined(__APPLE__)
505 // MacOS X and Darwin use getfsstat() system call...
506 int numfs
; // Number of file systems
507 struct statfs
*fs
; // Buffer for file system info
510 // We always have the root filesystem.
513 // Get the mounted filesystems...
514 numfs
= getfsstat(NULL
, 0, MNT_NOWAIT
);
516 // We have file systems, get them...
517 fs
= new struct statfs
[numfs
];
518 getfsstat(fs
, sizeof(struct statfs
) * numfs
, MNT_NOWAIT
);
520 // Add filesystems to the list...
521 for (i
= 0; i
< numfs
; i
++) {
522 // Ignore "/", "/dev", and "/.vol"...
523 if (fs
[i
].f_mntonname
[1] && strcmp(fs
[i
].f_mntonname
, "/dev") &&
524 strcmp(fs
[i
].f_mntonname
, "/.vol")) {
525 snprintf(filename
, sizeof(filename
), "%s/", fs
[i
].f_mntonname
);
531 // Free the memory used for the file system info array...
536 // UNIX code uses /etc/fstab or similar...
538 FILE *mtab
; // /etc/mtab or /etc/mnttab file
539 char line
[FL_PATH_MAX
]; // Input line
542 // Open the file that contains a list of mounted filesystems...
545 mtab
= fl_fopen("/etc/mnttab", "r"); // Fairly standard
547 mtab
= fl_fopen("/etc/mtab", "r"); // More standard
549 mtab
= fl_fopen("/etc/fstab", "r"); // Otherwise fallback to full list
551 mtab
= fl_fopen("/etc/vfstab", "r"); // Alternate full list file
555 while (fgets(line
, sizeof(line
), mtab
) != NULL
)
557 if (line
[0] == '#' || line
[0] == '\n')
559 if (sscanf(line
, "%*s%4095s", filename
) != 1)
562 strlcat(filename
, "/", sizeof(filename
));
564 // printf("Fl_File_Browser::load() - adding \"%s\" to list...\n", filename);
571 #endif // WIN32 || __EMX__
575 dirent
**files
; // Files in in directory
579 // Build the file list...
582 #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__)
583 strlcpy(filename
, directory_
, sizeof(filename
));
584 i
= strlen(filename
) - 1;
586 if (i
== 2 && filename
[1] == ':' &&
587 (filename
[2] == '/' || filename
[2] == '\\'))
589 else if (filename
[i
] != '/' && filename
[i
] != '\\')
590 strlcat(filename
, "/", sizeof(filename
));
592 num_files
= fl_filename_list(filename
, &files
, sort
);
594 num_files
= fl_filename_list(directory_
, &files
, sort
);
595 #endif /* WIN32 || __EMX__ */
600 for (i
= 0, num_dirs
= 0; i
< num_files
; i
++) {
601 if (strcmp(files
[i
]->d_name
, "./")) {
602 snprintf(filename
, sizeof(filename
), "%s/%s", directory_
,
605 icon
= Fl_File_Icon::find(filename
);
606 if ((icon
&& icon
->type() == Fl_File_Icon::DIRECTORY
) ||
607 _fl_filename_isdir_quick(filename
)) {
609 insert(num_dirs
, files
[i
]->d_name
, icon
);
610 } else if (filetype_
== FILES
&&
611 fl_filename_match(files
[i
]->d_name
, pattern_
)) {
612 add(files
[i
]->d_name
, icon
);
627 // 'Fl_File_Browser::filter()' - Set the filename filter.
631 Fl_File_Browser::filter(const char *pattern
) // I - Pattern string
633 // If pattern is NULL set the pattern to "*"...
642 // End of "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $".