|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $" 00003 // 00004 // Fl_File_Browser routines. 00005 // 00006 // Copyright 1999-2010 by Michael Sweet. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 // Contents: 00028 // 00029 // Fl_File_Browser::full_height() - Return the height of the list. 00030 // Fl_File_Browser::item_height() - Return the height of a list item. 00031 // Fl_File_Browser::item_width() - Return the width of a list item. 00032 // Fl_File_Browser::item_draw() - Draw a list item. 00033 // Fl_File_Browser::Fl_File_Browser() - Create a Fl_File_Browser widget. 00034 // Fl_File_Browser::load() - Load a directory into the browser. 00035 // Fl_File_Browser::filter() - Set the filename filter. 00036 // 00037 00038 // 00039 // Include necessary header files... 00040 // 00041 00042 #include <FL/Fl_File_Browser.H> 00043 #include <FL/fl_draw.H> 00044 #include <FL/filename.H> 00045 #include <FL/Fl_Image.H> // icon 00046 #include <stdio.h> 00047 #include <stdlib.h> 00048 #include "flstring.h" 00049 00050 #ifdef __CYGWIN__ 00051 # include <mntent.h> 00052 #elif defined(WIN32) 00053 # include <windows.h> 00054 # include <direct.h> 00055 // Apparently Borland C++ defines DIRECTORY in <direct.h>, which 00056 // interfers with the Fl_File_Icon enumeration of the same name. 00057 # ifdef DIRECTORY 00058 # undef DIRECTORY 00059 # endif // DIRECTORY 00060 #endif // __CYGWIN__ 00061 00062 #ifdef __EMX__ 00063 # define INCL_DOS 00064 # define INCL_DOSMISC 00065 # include <os2.h> 00066 #endif // __EMX__ 00067 00068 #if defined(__APPLE__) 00069 # include <sys/param.h> 00070 # include <sys/ucred.h> 00071 # include <sys/mount.h> 00072 #endif // __APPLE__ 00073 00074 // 00075 // FL_BLINE definition from "Fl_Browser.cxx"... 00076 // 00077 00078 #define SELECTED 1 00079 #define NOTDISPLAYED 2 00080 00081 // TODO -- Warning: The definition of FL_BLINE here is a hack. 00082 // Fl_File_Browser should not do this. PLEASE FIX. 00083 // FL_BLINE should be private to Fl_Browser, and not re-defined here. 00084 // For now, make sure this struct is precisely consistent with Fl_Browser.cxx. 00085 // 00086 struct FL_BLINE // data is in a linked list of these 00087 { 00088 FL_BLINE *prev; // Previous item in list 00089 FL_BLINE *next; // Next item in list 00090 void *data; // Pointer to data (function) 00091 Fl_Image *icon; // Pointer to optional icon 00092 short length; // sizeof(txt)-1, may be longer than string 00093 char flags; // selected, displayed 00094 char txt[1]; // start of allocated array 00095 }; 00096 00097 00098 // 00099 // 'Fl_File_Browser::full_height()' - Return the height of the list. 00100 // 00101 00102 int // O - Height in pixels 00103 Fl_File_Browser::full_height() const 00104 { 00105 int i, // Looping var 00106 th; // Total height of list. 00107 00108 00109 for (i = 0, th = 0; i < size(); i ++) 00110 th += item_height(find_line(i)); 00111 00112 return (th); 00113 } 00114 00115 00116 // 00117 // 'Fl_File_Browser::item_height()' - Return the height of a list item. 00118 // 00119 00120 int // O - Height in pixels 00121 Fl_File_Browser::item_height(void *p) const // I - List item data 00122 { 00123 FL_BLINE *line; // Pointer to line 00124 char *t; // Pointer into text 00125 int height; // Width of line 00126 int textheight; // Height of text 00127 00128 00129 // Figure out the standard text height... 00130 fl_font(textfont(), textsize()); 00131 textheight = fl_height(); 00132 00133 // We always have at least 1 line... 00134 height = textheight; 00135 00136 // Scan for newlines... 00137 line = (FL_BLINE *)p; 00138 00139 if (line != NULL) 00140 for (t = line->txt; *t != '\0'; t ++) 00141 if (*t == '\n') 00142 height += textheight; 00143 00144 // If we have enabled icons then add space for them... 00145 if (Fl_File_Icon::first() != NULL && height < iconsize_) 00146 height = iconsize_; 00147 00148 // Add space for the selection border.. 00149 height += 2; 00150 00151 // Return the height 00152 return (height); 00153 } 00154 00155 00156 // 00157 // 'Fl_File_Browser::item_width()' - Return the width of a list item. 00158 // 00159 00160 int // O - Width in pixels 00161 Fl_File_Browser::item_width(void *p) const // I - List item data 00162 { 00163 int i; // Looping var 00164 FL_BLINE *line; // Pointer to line 00165 char *t, // Pointer into text 00166 *ptr, // Pointer into fragment 00167 fragment[10240]; // Fragment of text 00168 int width, // Width of line 00169 tempwidth; // Width of fragment 00170 int column; // Current column 00171 const int *columns; // Columns 00172 00173 00174 // Scan for newlines... 00175 line = (FL_BLINE *)p; 00176 columns = column_widths(); 00177 00178 // Set the font and size... 00179 if (line->txt[strlen(line->txt) - 1] == '/') 00180 fl_font(textfont() | FL_BOLD, textsize()); 00181 else 00182 fl_font(textfont(), textsize()); 00183 00184 if (strchr(line->txt, '\n') == NULL && 00185 strchr(line->txt, column_char()) == NULL) 00186 { 00187 // Do a fast width calculation... 00188 width = (int)fl_width(line->txt); 00189 } 00190 else 00191 { 00192 // More than 1 line or have columns; find the maximum width... 00193 width = 0; 00194 tempwidth = 0; 00195 column = 0; 00196 00197 for (t = line->txt, ptr = fragment; *t != '\0'; t ++) 00198 if (*t == '\n') 00199 { 00200 // Newline - nul terminate this fragment and get the width... 00201 *ptr = '\0'; 00202 00203 tempwidth += (int)fl_width(fragment); 00204 00205 // Update the max width as needed... 00206 if (tempwidth > width) 00207 width = tempwidth; 00208 00209 // Point back to the start of the fragment... 00210 ptr = fragment; 00211 tempwidth = 0; 00212 column = 0; 00213 } 00214 else if (*t == column_char()) 00215 { 00216 // Advance to the next column... 00217 column ++; 00218 if (columns) 00219 { 00220 for (i = 0, tempwidth = 0; i < column && columns[i]; i ++) 00221 tempwidth += columns[i]; 00222 } 00223 else 00224 tempwidth = column * (int)(fl_height() * 0.6 * 8.0); 00225 00226 if (tempwidth > width) 00227 width = tempwidth; 00228 00229 ptr = fragment; 00230 } 00231 else 00232 *ptr++ = *t; 00233 00234 if (ptr > fragment) 00235 { 00236 // Nul terminate this fragment and get the width... 00237 *ptr = '\0'; 00238 00239 tempwidth += (int)fl_width(fragment); 00240 00241 // Update the max width as needed... 00242 if (tempwidth > width) 00243 width = tempwidth; 00244 } 00245 } 00246 00247 // If we have enabled icons then add space for them... 00248 if (Fl_File_Icon::first() != NULL) 00249 width += iconsize_ + 8; 00250 00251 // Add space for the selection border.. 00252 width += 2; 00253 00254 // Return the width 00255 return (width); 00256 } 00257 00258 00259 // 00260 // 'Fl_File_Browser::item_draw()' - Draw a list item. 00261 // 00262 00263 void 00264 Fl_File_Browser::item_draw(void *p, // I - List item data 00265 int X, // I - Upper-lefthand X coordinate 00266 int Y, // I - Upper-lefthand Y coordinate 00267 int W, // I - Width of item 00268 int) const // I - Height of item 00269 { 00270 int i; // Looping var 00271 FL_BLINE *line; // Pointer to line 00272 Fl_Color c; // Text color 00273 char *t, // Pointer into text 00274 *ptr, // Pointer into fragment 00275 fragment[10240]; // Fragment of text 00276 int width, // Width of line 00277 height; // Height of line 00278 int column; // Current column 00279 const int *columns; // Columns 00280 00281 00282 // Draw the list item text... 00283 line = (FL_BLINE *)p; 00284 00285 if (line->txt[strlen(line->txt) - 1] == '/') 00286 fl_font(textfont() | FL_BOLD, textsize()); 00287 else 00288 fl_font(textfont(), textsize()); 00289 00290 if (line->flags & SELECTED) 00291 c = fl_contrast(textcolor(), selection_color()); 00292 else 00293 c = textcolor(); 00294 00295 if (Fl_File_Icon::first() == NULL) 00296 { 00297 // No icons, just draw the text... 00298 X ++; 00299 W -= 2; 00300 } 00301 else 00302 { 00303 // Draw the icon if it is set... 00304 if (line->data) 00305 ((Fl_File_Icon *)line->data)->draw(X, Y, iconsize_, iconsize_, 00306 (line->flags & SELECTED) ? FL_YELLOW : 00307 FL_LIGHT2, 00308 active_r()); 00309 00310 // Draw the text offset to the right... 00311 X += iconsize_ + 9; 00312 W -= iconsize_ - 10; 00313 00314 // Center the text vertically... 00315 height = fl_height(); 00316 00317 for (t = line->txt; *t != '\0'; t ++) 00318 if (*t == '\n') 00319 height += fl_height(); 00320 00321 if (height < iconsize_) 00322 Y += (iconsize_ - height) / 2; 00323 } 00324 00325 // Draw the text... 00326 line = (FL_BLINE *)p; 00327 columns = column_widths(); 00328 width = 0; 00329 column = 0; 00330 00331 if (active_r()) 00332 fl_color(c); 00333 else 00334 fl_color(fl_inactive(c)); 00335 00336 for (t = line->txt, ptr = fragment; *t != '\0'; t ++) 00337 if (*t == '\n') 00338 { 00339 // Newline - nul terminate this fragment and draw it... 00340 *ptr = '\0'; 00341 00342 fl_draw(fragment, X + width, Y, W - width, fl_height(), 00343 (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); 00344 00345 // Point back to the start of the fragment... 00346 ptr = fragment; 00347 width = 0; 00348 Y += fl_height(); 00349 column = 0; 00350 } 00351 else if (*t == column_char()) 00352 { 00353 // Tab - nul terminate this fragment and draw it... 00354 *ptr = '\0'; 00355 00356 int cW = W - width; // Clip width... 00357 00358 if (columns) 00359 { 00360 // Try clipping inside this column... 00361 for (i = 0; i < column && columns[i]; i ++); 00362 00363 if (columns[i]) 00364 cW = columns[i]; 00365 } 00366 00367 fl_draw(fragment, X + width, Y, cW, fl_height(), 00368 (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); 00369 00370 // Advance to the next column... 00371 column ++; 00372 if (columns) 00373 { 00374 for (i = 0, width = 0; i < column && columns[i]; i ++) 00375 width += columns[i]; 00376 } 00377 else 00378 width = column * (int)(fl_height() * 0.6 * 8.0); 00379 00380 ptr = fragment; 00381 } 00382 else 00383 *ptr++ = *t; 00384 00385 if (ptr > fragment) 00386 { 00387 // Nul terminate this fragment and draw it... 00388 *ptr = '\0'; 00389 00390 fl_draw(fragment, X + width, Y, W - width, fl_height(), 00391 (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); 00392 } 00393 } 00394 00395 00396 // 00397 // 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget. 00398 // 00399 00400 Fl_File_Browser::Fl_File_Browser(int X, // I - Upper-lefthand X coordinate 00401 int Y, // I - Upper-lefthand Y coordinate 00402 int W, // I - Width in pixels 00403 int H, // I - Height in pixels 00404 const char *l) // I - Label text 00405 : Fl_Browser(X, Y, W, H, l) 00406 { 00407 // Initialize the filter pattern, current directory, and icon size... 00408 pattern_ = "*"; 00409 directory_ = ""; 00410 iconsize_ = (uchar)(3 * textsize() / 2); 00411 filetype_ = FILES; 00412 } 00413 00414 00415 // 00416 // 'Fl_File_Browser::load()' - Load a directory into the browser. 00417 // 00418 00419 int // O - Number of files loaded 00420 Fl_File_Browser::load(const char *directory,// I - Directory to load 00421 Fl_File_Sort_F *sort) // I - Sort function to use 00422 { 00423 int i; // Looping var 00424 int num_files; // Number of files in directory 00425 int num_dirs; // Number of directories in list 00426 char filename[4096]; // Current file 00427 Fl_File_Icon *icon; // Icon to use 00428 00429 00430 // printf("Fl_File_Browser::load(\"%s\")\n", directory); 00431 00432 clear(); 00433 00434 directory_ = directory; 00435 00436 if (!directory) 00437 return (0); 00438 00439 if (directory_[0] == '\0') 00440 { 00441 // 00442 // No directory specified; for UNIX list all mount points. For DOS 00443 // list all valid drive letters... 00444 // 00445 00446 num_files = 0; 00447 if ((icon = Fl_File_Icon::find("any", Fl_File_Icon::DEVICE)) == NULL) 00448 icon = Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY); 00449 00450 #ifdef WIN32 00451 # ifdef __CYGWIN__ 00452 // 00453 // Cygwin provides an implementation of setmntent() to get the list 00454 // of available drives... 00455 // 00456 FILE *m = setmntent("/-not-used-", "r"); 00457 struct mntent *p; 00458 00459 while ((p = getmntent (m)) != NULL) { 00460 add(p->mnt_dir, icon); 00461 num_files ++; 00462 } 00463 00464 endmntent(m); 00465 # else 00466 // 00467 // Normal WIN32 code uses drive bits... 00468 // 00469 DWORD drives; // Drive available bits 00470 00471 drives = GetLogicalDrives(); 00472 for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) 00473 if (drives & 1) 00474 { 00475 sprintf(filename, "%c:/", i); 00476 00477 if (i < 'C') // see also: GetDriveType and GetVolumeInformation in WIN32 00478 add(filename, icon); 00479 else 00480 add(filename, icon); 00481 00482 num_files ++; 00483 } 00484 # endif // __CYGWIN__ 00485 #elif defined(__EMX__) 00486 // 00487 // OS/2 code uses drive bits... 00488 // 00489 ULONG curdrive; // Current drive 00490 ULONG drives; // Drive available bits 00491 int start = 3; // 'C' (MRS - dunno if this is correct!) 00492 00493 00494 DosQueryCurrentDisk(&curdrive, &drives); 00495 drives >>= start - 1; 00496 for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) 00497 if (drives & 1) 00498 { 00499 sprintf(filename, "%c:/", i); 00500 add(filename, icon); 00501 00502 num_files ++; 00503 } 00504 #elif defined(__APPLE__) 00505 // MacOS X and Darwin use getfsstat() system call... 00506 int numfs; // Number of file systems 00507 struct statfs *fs; // Buffer for file system info 00508 00509 00510 // We always have the root filesystem. 00511 add("/", icon); 00512 00513 // Get the mounted filesystems... 00514 numfs = getfsstat(NULL, 0, MNT_NOWAIT); 00515 if (numfs > 0) { 00516 // We have file systems, get them... 00517 fs = new struct statfs[numfs]; 00518 getfsstat(fs, sizeof(struct statfs) * numfs, MNT_NOWAIT); 00519 00520 // Add filesystems to the list... 00521 for (i = 0; i < numfs; i ++) { 00522 // Ignore "/", "/dev", and "/.vol"... 00523 if (fs[i].f_mntonname[1] && strcmp(fs[i].f_mntonname, "/dev") && 00524 strcmp(fs[i].f_mntonname, "/.vol")) { 00525 snprintf(filename, sizeof(filename), "%s/", fs[i].f_mntonname); 00526 add(filename, icon); 00527 } 00528 num_files ++; 00529 } 00530 00531 // Free the memory used for the file system info array... 00532 delete[] fs; 00533 } 00534 #else 00535 // 00536 // UNIX code uses /etc/fstab or similar... 00537 // 00538 FILE *mtab; // /etc/mtab or /etc/mnttab file 00539 char line[FL_PATH_MAX]; // Input line 00540 00541 // 00542 // Open the file that contains a list of mounted filesystems... 00543 // 00544 00545 mtab = fl_fopen("/etc/mnttab", "r"); // Fairly standard 00546 if (mtab == NULL) 00547 mtab = fl_fopen("/etc/mtab", "r"); // More standard 00548 if (mtab == NULL) 00549 mtab = fl_fopen("/etc/fstab", "r"); // Otherwise fallback to full list 00550 if (mtab == NULL) 00551 mtab = fl_fopen("/etc/vfstab", "r"); // Alternate full list file 00552 00553 if (mtab != NULL) 00554 { 00555 while (fgets(line, sizeof(line), mtab) != NULL) 00556 { 00557 if (line[0] == '#' || line[0] == '\n') 00558 continue; 00559 if (sscanf(line, "%*s%4095s", filename) != 1) 00560 continue; 00561 00562 strlcat(filename, "/", sizeof(filename)); 00563 00564 // printf("Fl_File_Browser::load() - adding \"%s\" to list...\n", filename); 00565 add(filename, icon); 00566 num_files ++; 00567 } 00568 00569 fclose(mtab); 00570 } 00571 #endif // WIN32 || __EMX__ 00572 } 00573 else 00574 { 00575 dirent **files; // Files in in directory 00576 00577 00578 // 00579 // Build the file list... 00580 // 00581 00582 #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__) 00583 strlcpy(filename, directory_, sizeof(filename)); 00584 i = strlen(filename) - 1; 00585 00586 if (i == 2 && filename[1] == ':' && 00587 (filename[2] == '/' || filename[2] == '\\')) 00588 filename[2] = '/'; 00589 else if (filename[i] != '/' && filename[i] != '\\') 00590 strlcat(filename, "/", sizeof(filename)); 00591 00592 num_files = fl_filename_list(filename, &files, sort); 00593 #else 00594 num_files = fl_filename_list(directory_, &files, sort); 00595 #endif /* WIN32 || __EMX__ */ 00596 00597 if (num_files <= 0) 00598 return (0); 00599 00600 for (i = 0, num_dirs = 0; i < num_files; i ++) { 00601 if (strcmp(files[i]->d_name, "./")) { 00602 snprintf(filename, sizeof(filename), "%s/%s", directory_, 00603 files[i]->d_name); 00604 00605 icon = Fl_File_Icon::find(filename); 00606 if ((icon && icon->type() == Fl_File_Icon::DIRECTORY) || 00607 _fl_filename_isdir_quick(filename)) { 00608 num_dirs ++; 00609 insert(num_dirs, files[i]->d_name, icon); 00610 } else if (filetype_ == FILES && 00611 fl_filename_match(files[i]->d_name, pattern_)) { 00612 add(files[i]->d_name, icon); 00613 } 00614 } 00615 00616 free(files[i]); 00617 } 00618 00619 free(files); 00620 } 00621 00622 return (num_files); 00623 } 00624 00625 00626 // 00627 // 'Fl_File_Browser::filter()' - Set the filename filter. 00628 // 00629 00630 void 00631 Fl_File_Browser::filter(const char *pattern) // I - Pattern string 00632 { 00633 // If pattern is NULL set the pattern to "*"... 00634 if (pattern) 00635 pattern_ = pattern; 00636 else 00637 pattern_ = "*"; 00638 } 00639 00640 00641 // 00642 // End of "$Id: Fl_File_Browser.cxx 8063 2010-12-19 21:20:10Z matt $". 00643 //