PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/fltk/src/Fl_File_Chooser2.cxx

http://luafltk.googlecode.com/
C++ | 1652 lines | 862 code | 296 blank | 494 comment | 398 complexity | b22d6de7a1c71abb36741b765e0f1c4a MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-3.0, 0BSD
  1. //
  2. // "$Id: Fl_File_Chooser2.cxx 7219 2010-03-05 18:53:00Z AlbrechtS $"
  3. //
  4. // More Fl_File_Chooser routines.
  5. //
  6. // Copyright 1999-2009 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.
  12. //
  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.
  17. //
  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.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. // fabien: ATTENTION: Only Out Of Source Gen. because cxx/H files are autogenerated by fluid.
  28. /** \defgroup group_comdlg Common Dialogs classes and functions
  29. @{
  30. */
  31. /** \class Fl_File_Chooser
  32. The Fl_File_Chooser widget displays a standard file selection
  33. dialog that supports various selection modes.
  34. \image html Fl_File_Chooser.jpg
  35. \image latex Fl_File_Chooser.eps "Fl_File_Chooser" width=12cm
  36. The Fl_File_Chooser class also exports several static values
  37. that may be used to localize or customize the appearance of all file chooser
  38. dialogs:
  39. <CENTER><TABLE BORDER="1">
  40. <TR>
  41. <TH>Member</TH>
  42. <TH>Default value</TH>
  43. </TR>
  44. <TR>
  45. <TD>add_favorites_label</TD>
  46. <TD>"Add to Favorites"</TD>
  47. </TR>
  48. <TR>
  49. <TD>all_files_label</TD>
  50. <TD>"All Files (*)"</TD>
  51. </TR>
  52. <TR>
  53. <TD>custom_filter_label</TD>
  54. <TD>"Custom Filter"</TD>
  55. </TR>
  56. <TR>
  57. <TD>existing_file_label</TD>
  58. <TD>"Please choose an existing file!"</TD>
  59. </TR>
  60. <TR>
  61. <TD>favorites_label</TD>
  62. <TD>"Favorites"</TD>
  63. </TR>
  64. <TR>
  65. <TD>filename_label</TD>
  66. <TD>"Filename:"</TD>
  67. </TR>
  68. <TR>
  69. <TD>filesystems_label</TD>
  70. <TD>"My Computer" (WIN32)<BR>
  71. "File Systems" (all others)</TD>
  72. </TR>
  73. <TR>
  74. <TD>manage_favorites_label</TD>
  75. <TD>"Manage Favorites"</TD>
  76. </TR>
  77. <TR>
  78. <TD>new_directory_label</TD>
  79. <TD>"New Directory?"</TD>
  80. </TR>
  81. <TR>
  82. <TD>new_directory_tooltip</TD>
  83. <TD>"Create a new directory."</TD>
  84. </TR>
  85. <TR>
  86. <TD>preview_label</TD>
  87. <TD>"Preview"</TD>
  88. </TR>
  89. <TR>
  90. <TD>save_label</TD>
  91. <TD>"Save"</TD>
  92. </TR>
  93. <TR>
  94. <TD>show_label</TD>
  95. <TD>"Show:"</TD>
  96. </TR>
  97. <TR>
  98. <TD>sort</TD>
  99. <TD>fl_numericsort</TD>
  100. </TR>
  101. </TABLE></CENTER>
  102. The Fl_File_Chooser::sort member specifies the sort function that is
  103. used when loading the contents of a directory and can be customized
  104. at run-time.
  105. The Fl_File_Chooser class also exports the Fl_File_Chooser::newButton
  106. and Fl_File_Chooser::previewButton widgets so that application developers
  107. can control their appearance and use. For more complex customization,
  108. consider copying the FLTK file chooser code and changing it accordingly.
  109. */
  110. /** @} */
  111. /** \fn Fl_File_Chooser::Fl_File_Chooser(const char *pathname, const char *pattern, int type, const char *title)
  112. The constructor creates the Fl_File_Chooser dialog shown.
  113. The pathname argument can be a directory name or a
  114. complete file name (in which case the corresponding file is highlighted
  115. in the list and in the filename input field.)
  116. The pattern argument can be a NULL
  117. string or "*" to list all files, or it can be a
  118. series of descriptions and filter strings separated by tab
  119. characters (\\t). The format of filters is either
  120. "Description text (patterns)" or just "patterns". A file chooser
  121. that provides filters for HTML and image files might look like:
  122. \code
  123. "HTML Files (*.html)\tImage Files (*.{bmp,gif,jpg,png})"
  124. \endcode
  125. The file chooser will automatically add the "All Files (*)"
  126. pattern to the end of the string you pass if you do not provide
  127. one. The first filter in the string is the default filter.
  128. See the FLTK documentation on fl_filename_match()
  129. for the kinds of pattern strings that are supported.
  130. The type argument can be one of the following:
  131. \li \c SINGLE - allows the user to select a single, existing file.
  132. \li \c MULTI - allows the user to select one or more existing files.
  133. \li \c CREATE - allows the user to select a single, existing file or
  134. specify a new filename.
  135. \li \c DIRECTORY - allows the user to select a single, existing directory.
  136. The title argument is used to set the title bar text for the
  137. Fl_File_Chooser window.
  138. */
  139. /** \var Fl_File_Chooser::newButton
  140. The "new directory" button is exported so that application developers
  141. can control the appearance and use.
  142. */
  143. /** \var Fl_File_Chooser::previewButton
  144. The "preview" button is exported so that application developers can
  145. control the appearance and use.
  146. */
  147. /** \fn Fl_File_Chooser::~Fl_File_Chooser()
  148. Destroys the widget and frees all memory used by it.*/
  149. /** \fn void Fl_File_Chooser::color(Fl_Color c)
  150. Sets or gets the background color of the Fl_File_Browser list.*/
  151. /** \fn Fl_Color Fl_File_Chooser::color()
  152. Sets or gets the background color of the Fl_File_Browser list.*/
  153. /** \fn int Fl_File_Chooser::count()
  154. Returns the number of selected files.*/
  155. /** \fn void Fl_File_Chooser::directory(const char *pathname)
  156. Sets or gets the current directory.*/
  157. /** \fn const char *Fl_File_Chooser::directory()
  158. Sets or gets the current directory.*/
  159. /** \fn void Fl_File_Chooser::filter(const char *pattern)
  160. Sets or gets the current filename filter patterns. The filter
  161. patterns use fl_filename_match().
  162. Multiple patterns can be used by separating them with tabs, like
  163. <tt>"*.jpg\t*.png\t*.gif\t*"</tt>. In addition, you can provide
  164. human-readable labels with the patterns inside parenthesis, like
  165. <tt>"JPEG Files (*.jpg)\tPNG Files (*.png)\tGIF Files (*.gif)\tAll Files (*)"
  166. </tt>.
  167. Use filter(NULL) to show all files.
  168. */
  169. /** \fn const char *Fl_File_Chooser::filter()
  170. See void filter(const char *pattern)*/
  171. /** \fn void Fl_File_Chooser::filter_value(int f)
  172. Sets or gets the current filename filter selection.*/
  173. /** \fn int Fl_File_Chooser::filter_value()
  174. Sets or gets the current filename filter selection.*/
  175. /** \fn void Fl_File_Chooser::hide()
  176. Hides the Fl_File_Chooser window.*/
  177. /** \fn void Fl_File_Chooser::iconsize(uchar s)
  178. Sets or gets the size of the icons in the Fl_File_Browser. By
  179. default the icon size is set to 1.5 times the textsize().
  180. */
  181. /** \fn uchar Fl_File_Chooser::iconsize()
  182. Sets or gets the size of the icons in the Fl_File_Browser. By
  183. default the icon size is set to 1.5 times the textsize().
  184. */
  185. /** \fn void Fl_File_Chooser::label(const char *l)
  186. Sets or gets the title bar text for the Fl_File_Chooser.*/
  187. /** \fn const char *Fl_File_Chooser::label()
  188. Sets or gets the title bar text for the Fl_File_Chooser.*/
  189. /** \fn void Fl_File_Chooser::ok_label(const char *l)
  190. Sets or gets the label for the "ok" button in the Fl_File_Chooser.
  191. */
  192. /** \fn const char *Fl_File_Chooser::ok_label()
  193. Sets or gets the label for the "ok" button in the Fl_File_Chooser.
  194. */
  195. /** \fn int Fl_File_Chooser::preview() const
  196. Returns the current state of the preview box. */
  197. /** \fn void Fl_File_Chooser::rescan()
  198. Reloads the current directory in the Fl_File_Browser.*/
  199. /** \fn void Fl_File_Chooser::show()
  200. Shows the Fl_File_Chooser window.*/
  201. /** \fn void Fl_File_Chooser::textcolor(Fl_Color c)
  202. Sets or gets the current Fl_File_Browser text color.*/
  203. /** \fn Fl_Color Fl_File_Chooser::textcolor()
  204. Sets or gets the current Fl_File_Browser text color.*/
  205. /** \fn void Fl_File_Chooser::textfont(Fl_Font f)
  206. Sets or gets the current Fl_File_Browser text font.*/
  207. /** \fn Fl_Font Fl_File_Chooser::textfont()
  208. Sets or gets the current Fl_File_Browser text font.*/
  209. /** \fn void Fl_File_Chooser::textsize(Fl_Fontsize s)
  210. Sets or gets the current Fl_File_Browser text size.*/
  211. /** \fn Fl_Fontsize Fl_File_Chooser::textsize()
  212. Sets or gets the current Fl_File_Browser text size.*/
  213. /** \fn void Fl_File_Chooser::type(int t)
  214. Sets or gets the current type of Fl_File_Chooser.*/
  215. /** \fn int Fl_File_Chooser::type()
  216. Sets or gets the current type of Fl_File_Chooser.*/
  217. /** \fn const char *Fl_File_Chooser::value(const char *pathname)
  218. Sets or gets the current value of the selected file.
  219. In the second form, \p file is a \c 1-based index into a list of
  220. file names. The number of selected files is returned by
  221. Fl_File_Chooser::count().
  222. This sample code loops through all selected files:
  223. \code
  224. // Get list of filenames user selected from a MULTI chooser
  225. for ( int t=1; t<=chooser->count(); t++ ) {
  226. const char *filename = chooser->value(t);
  227. ...
  228. }
  229. \endcode
  230. */
  231. /** \fn const char *Fl_File_Chooser::value(int file)
  232. See const char *value(const char *pathname)*/
  233. /** \fn int Fl_File_Chooser::visible()
  234. Returns 1 if the Fl_File_Chooser window is visible.*/
  235. /** \fn Fl_Widget* Fl_File_Chooser::add_extra(Fl_Widget*)
  236. Adds extra widget at the bottom of Fl_File_Chooser window.
  237. Returns pointer for previous extra widget or NULL if not set previously.
  238. If argument is NULL only remove previous extra widget.
  239. \note Fl_File_Chooser does \b not delete extra widget in destructor!
  240. To prevent memory leakage, don't forget to delete unused extra widgets
  241. */
  242. /** \fn int Fl_File_Chooser::shown()
  243. Returns non-zero if the file chooser main window show() has been called (but not hide()
  244. see Fl_Window::shown()
  245. */
  246. /** \fn void Fl_File_Chooser::callback(void (*cb)(Fl_File_Chooser *, void *), void *d = 0)
  247. Sets the file chooser callback cb and associated data d */
  248. /** \fn void Fl_File_Chooser::user_data(void *d)
  249. Sets the file chooser user data d */
  250. /** \fn void * Fl_File_Chooser::user_data() const
  251. Gets the file chooser user data d */
  252. /** \fn Fl_File_Browser* Fl_File_Chooser::browser()
  253. returns a pointer to the underlying Fl_File_Browser object */
  254. // *** END OF OUT OF SOURCE DOC ***
  255. // Contents:
  256. //
  257. // Fl_File_Chooser::count() - Return the number of selected files.
  258. // Fl_File_Chooser::directory() - Set the directory in the file chooser.
  259. // Fl_File_Chooser::filter() - Set the filter(s) for the chooser.
  260. // Fl_File_Chooser::newdir() - Make a new directory.
  261. // Fl_File_Chooser::value() - Return a selected filename.
  262. // Fl_File_Chooser::rescan() - Rescan the current directory.
  263. // Fl_File_Chooser::favoritesButtonCB() - Handle favorites selections.
  264. // Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks)
  265. // in the Fl_File_Browser.
  266. // Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser.
  267. // Fl_File_Chooser::showChoiceCB() - Handle show selections.
  268. // compare_dirnames() - Compare two directory names.
  269. // quote_pathname() - Quote a pathname for a menu.
  270. // unquote_pathname() - Unquote a pathname from a menu.
  271. //
  272. // Fl_File_Chooser::add_extra() - add extra widget at the bottom, return pointer
  273. // to previous extra widget or NULL if none,
  274. // If argument is NULL extra widget removed.
  275. // NOTE! file chooser does't delete extra widget in
  276. // destructor! To prevent memory leakage don't forget
  277. // delete unused extra widgets by yourself.
  278. //
  279. //
  280. // Include necessary headers.
  281. //
  282. #include <FL/Fl_File_Chooser.H>
  283. #include <FL/filename.H>
  284. #include <FL/fl_ask.H>
  285. #include <FL/x.H>
  286. #include <FL/Fl_Shared_Image.H>
  287. #include <stdio.h>
  288. #include <stdlib.h>
  289. #include "flstring.h"
  290. #include <errno.h>
  291. #include <sys/types.h>
  292. #include <sys/stat.h>
  293. #if defined(WIN32) && ! defined (__CYGWIN__)
  294. # include <direct.h>
  295. # include <io.h>
  296. // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
  297. // on Windows, which is supposed to be POSIX compliant...
  298. # define access _access
  299. # define mkdir _mkdir
  300. // Apparently Borland C++ defines DIRECTORY in <direct.h>, which
  301. // interfers with the Fl_File_Icon enumeration of the same name.
  302. # ifdef DIRECTORY
  303. # undef DIRECTORY
  304. # endif // DIRECTORY
  305. #else
  306. # include <unistd.h>
  307. # include <pwd.h>
  308. #endif /* WIN32 */
  309. //
  310. // File chooser label strings and sort function...
  311. //
  312. Fl_Preferences Fl_File_Chooser::prefs_(Fl_Preferences::USER, "fltk.org", "filechooser");
  313. const char *Fl_File_Chooser::add_favorites_label = "Add to Favorites";
  314. const char *Fl_File_Chooser::all_files_label = "All Files (*)";
  315. const char *Fl_File_Chooser::custom_filter_label = "Custom Filter";
  316. const char *Fl_File_Chooser::existing_file_label = "Please choose an existing file!";
  317. const char *Fl_File_Chooser::favorites_label = "Favorites";
  318. const char *Fl_File_Chooser::filename_label = "Filename:";
  319. #ifdef WIN32
  320. const char *Fl_File_Chooser::filesystems_label = "My Computer";
  321. #else
  322. const char *Fl_File_Chooser::filesystems_label = "File Systems";
  323. #endif // WIN32
  324. const char *Fl_File_Chooser::manage_favorites_label = "Manage Favorites";
  325. const char *Fl_File_Chooser::new_directory_label = "New Directory?";
  326. const char *Fl_File_Chooser::new_directory_tooltip = "Create a new directory.";
  327. const char *Fl_File_Chooser::preview_label = "Preview";
  328. const char *Fl_File_Chooser::save_label = "Save";
  329. const char *Fl_File_Chooser::show_label = "Show:";
  330. Fl_File_Sort_F *Fl_File_Chooser::sort = fl_numericsort;
  331. //
  332. // Local functions...
  333. //
  334. static int compare_dirnames(const char *a, const char *b);
  335. static void quote_pathname(char *, const char *, int);
  336. static void unquote_pathname(char *, const char *, int);
  337. //
  338. // 'Fl_File_Chooser::count()' - Return the number of selected files.
  339. //
  340. int // O - Number of selected files
  341. Fl_File_Chooser::count() {
  342. int i; // Looping var
  343. int fcount; // Number of selected files
  344. const char *filename; // Filename in input field or list
  345. filename = fileName->value();
  346. if (!(type_ & MULTI)) {
  347. // Check to see if the file name input field is blank...
  348. if (!filename || !filename[0]) return 0;
  349. else return 1;
  350. }
  351. for (i = 1, fcount = 0; i <= fileList->size(); i ++)
  352. if (fileList->selected(i)) {
  353. // See if this file is a directory...
  354. // matt: why would we do that? It is perfectly legal to select multiple
  355. // directories in a DIR chooser. They are visually selected and value(i)
  356. // returns all of them as expected
  357. //filename = (char *)fileList->text(i);
  358. //if (filename[strlen(filename) - 1] != '/')
  359. fcount ++;
  360. }
  361. if (fcount) return fcount;
  362. else if (!filename || !filename[0]) return 0;
  363. else return 1;
  364. }
  365. //
  366. // 'Fl_File_Chooser::directory()' - Set the directory in the file chooser.
  367. //
  368. void
  369. Fl_File_Chooser::directory(const char *d)// I - Directory to change to
  370. {
  371. char *dirptr; // Pointer into directory
  372. // printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d);
  373. // NULL == current directory
  374. if (d == NULL)
  375. d = ".";
  376. #ifdef WIN32
  377. // See if the filename contains backslashes...
  378. char *slash; // Pointer to slashes
  379. char fixpath[1024]; // Path with slashes converted
  380. if (strchr(d, '\\')) {
  381. // Convert backslashes to slashes...
  382. strlcpy(fixpath, d, sizeof(fixpath));
  383. for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
  384. *slash = '/';
  385. d = fixpath;
  386. }
  387. #endif // WIN32
  388. if (d[0] != '\0')
  389. {
  390. // Make the directory absolute...
  391. #if (defined(WIN32) && ! defined(__CYGWIN__))|| defined(__EMX__)
  392. if (d[0] != '/' && d[0] != '\\' && d[1] != ':')
  393. #else
  394. if (d[0] != '/' && d[0] != '\\')
  395. #endif /* WIN32 || __EMX__ */
  396. fl_filename_absolute(directory_, d);
  397. else
  398. strlcpy(directory_, d, sizeof(directory_));
  399. // Strip any trailing slash...
  400. dirptr = directory_ + strlen(directory_) - 1;
  401. if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_)
  402. *dirptr = '\0';
  403. // See if we have a trailing .. or . in the filename...
  404. dirptr = directory_ + strlen(directory_) - 3;
  405. if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) {
  406. // Yes, we have "..", so strip the trailing path...
  407. *dirptr = '\0';
  408. while (dirptr > directory_) {
  409. if (*dirptr == '/') break;
  410. dirptr --;
  411. }
  412. if (dirptr >= directory_ && *dirptr == '/')
  413. *dirptr = '\0';
  414. } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) {
  415. // Strip trailing "."...
  416. dirptr[1] = '\0';
  417. }
  418. }
  419. else
  420. directory_[0] = '\0';
  421. if (shown()) {
  422. // Rescan the directory...
  423. rescan();
  424. }
  425. }
  426. //
  427. // 'Fl_File_Chooser::favoritesButtonCB()' - Handle favorites selections.
  428. //
  429. void
  430. Fl_File_Chooser::favoritesButtonCB()
  431. {
  432. int v; // Current selection
  433. char pathname[1024], // Pathname
  434. menuname[2048]; // Menu name
  435. v = favoritesButton->value();
  436. if (!v) {
  437. // Add current directory to favorites...
  438. if (getenv("HOME")) v = favoritesButton->size() - 5;
  439. else v = favoritesButton->size() - 4;
  440. sprintf(menuname, "favorite%02d", v);
  441. prefs_.set(menuname, directory_);
  442. prefs_.flush();
  443. quote_pathname(menuname, directory_, sizeof(menuname));
  444. favoritesButton->add(menuname);
  445. if (favoritesButton->size() > 104) {
  446. ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
  447. }
  448. } else if (v == 1) {
  449. // Manage favorites...
  450. favoritesCB(0);
  451. } else if (v == 2) {
  452. // Filesystems/My Computer
  453. directory("");
  454. } else {
  455. unquote_pathname(pathname, favoritesButton->text(v), sizeof(pathname));
  456. directory(pathname);
  457. }
  458. }
  459. //
  460. // 'Fl_File_Chooser::favoritesCB()' - Handle favorites dialog.
  461. //
  462. void
  463. Fl_File_Chooser::favoritesCB(Fl_Widget *w)
  464. // I - Widget
  465. {
  466. int i; // Looping var
  467. char name[32], // Preference name
  468. pathname[1024]; // Directory in list
  469. if (!w) {
  470. // Load the favorites list...
  471. favList->clear();
  472. favList->deselect();
  473. for (i = 0; i < 100; i ++) {
  474. // Get favorite directory 0 to 99...
  475. sprintf(name, "favorite%02d", i);
  476. prefs_.get(name, pathname, "", sizeof(pathname));
  477. // Stop on the first empty favorite...
  478. if (!pathname[0]) break;
  479. // Add the favorite to the list...
  480. favList->add(pathname,
  481. Fl_File_Icon::find(pathname, Fl_File_Icon::DIRECTORY));
  482. }
  483. favUpButton->deactivate();
  484. favDeleteButton->deactivate();
  485. favDownButton->deactivate();
  486. favOkButton->deactivate();
  487. favWindow->hotspot(favList);
  488. favWindow->show();
  489. } else if (w == favList) {
  490. i = favList->value();
  491. if (i) {
  492. if (i > 1) favUpButton->activate();
  493. else favUpButton->deactivate();
  494. favDeleteButton->activate();
  495. if (i < favList->size()) favDownButton->activate();
  496. else favDownButton->deactivate();
  497. } else {
  498. favUpButton->deactivate();
  499. favDeleteButton->deactivate();
  500. favDownButton->deactivate();
  501. }
  502. } else if (w == favUpButton) {
  503. i = favList->value();
  504. favList->insert(i - 1, favList->text(i), favList->data(i));
  505. favList->remove(i + 1);
  506. favList->select(i - 1);
  507. if (i == 2) favUpButton->deactivate();
  508. favDownButton->activate();
  509. favOkButton->activate();
  510. } else if (w == favDeleteButton) {
  511. i = favList->value();
  512. favList->remove(i);
  513. if (i > favList->size()) i --;
  514. favList->select(i);
  515. if (i < favList->size()) favDownButton->activate();
  516. else favDownButton->deactivate();
  517. if (i > 1) favUpButton->activate();
  518. else favUpButton->deactivate();
  519. if (!i) favDeleteButton->deactivate();
  520. favOkButton->activate();
  521. } else if (w == favDownButton) {
  522. i = favList->value();
  523. favList->insert(i + 2, favList->text(i), favList->data(i));
  524. favList->remove(i);
  525. favList->select(i + 1);
  526. if ((i + 1) == favList->size()) favDownButton->deactivate();
  527. favUpButton->activate();
  528. favOkButton->activate();
  529. } else if (w == favOkButton) {
  530. // Copy the new list over...
  531. for (i = 0; i < favList->size(); i ++) {
  532. // Set favorite directory 0 to 99...
  533. sprintf(name, "favorite%02d", i);
  534. prefs_.set(name, favList->text(i + 1));
  535. }
  536. // Clear old entries as necessary...
  537. for (; i < 100; i ++) {
  538. // Clear favorite directory 0 to 99...
  539. sprintf(name, "favorite%02d", i);
  540. prefs_.get(name, pathname, "", sizeof(pathname));
  541. if (pathname[0]) prefs_.set(name, "");
  542. else break;
  543. }
  544. update_favorites();
  545. prefs_.flush();
  546. favWindow->hide();
  547. }
  548. }
  549. //
  550. // 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the
  551. // Fl_File_Browser.
  552. //
  553. void
  554. Fl_File_Chooser::fileListCB()
  555. {
  556. char *filename, // New filename
  557. pathname[1024]; // Full pathname to file
  558. filename = (char *)fileList->text(fileList->value());
  559. if (!filename)
  560. return;
  561. if (!directory_[0]) {
  562. strlcpy(pathname, filename, sizeof(pathname));
  563. } else if (strcmp(directory_, "/") == 0) {
  564. snprintf(pathname, sizeof(pathname), "/%s", filename);
  565. } else {
  566. snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
  567. }
  568. if (Fl::event_clicks()) {
  569. #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
  570. if ((strlen(pathname) == 2 && pathname[1] == ':') ||
  571. _fl_filename_isdir_quick(pathname))
  572. #else
  573. if (_fl_filename_isdir_quick(pathname))
  574. #endif /* WIN32 || __EMX__ */
  575. {
  576. // Change directories...
  577. directory(pathname);
  578. // Reset the click count so that a click in the same spot won't
  579. // be treated as a triple-click. We use a value of -1 because
  580. // the next click will increment click count to 0, which is what
  581. // we really want...
  582. Fl::event_clicks(-1);
  583. }
  584. else
  585. {
  586. // Hide the window - picked the file...
  587. window->hide();
  588. }
  589. }
  590. else
  591. {
  592. // Check if the user clicks on a directory when picking files;
  593. // if so, make sure only that item is selected...
  594. filename = pathname + strlen(pathname) - 1;
  595. if ((type_ & MULTI) && !(type_ & DIRECTORY)) {
  596. if (*filename == '/') {
  597. // Clicked on a directory, deselect everything else...
  598. int i = fileList->value();
  599. fileList->deselect();
  600. fileList->select(i);
  601. } else {
  602. // Clicked on a file - see if there are other directories selected...
  603. int i;
  604. const char *temp;
  605. for (i = 1; i <= fileList->size(); i ++) {
  606. if (i != fileList->value() && fileList->selected(i)) {
  607. temp = fileList->text(i);
  608. temp += strlen(temp) - 1;
  609. if (*temp == '/') break; // Yes, selected directory
  610. }
  611. }
  612. if (i <= fileList->size()) {
  613. i = fileList->value();
  614. fileList->deselect();
  615. fileList->select(i);
  616. }
  617. }
  618. }
  619. // Strip any trailing slash from the directory name...
  620. if (*filename == '/') *filename = '\0';
  621. // puts("Setting fileName from fileListCB...");
  622. fileName->value(pathname);
  623. // Update the preview box...
  624. Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this);
  625. Fl::add_timeout(1.0, (Fl_Timeout_Handler)previewCB, this);
  626. // Do any callback that is registered...
  627. if (callback_) (*callback_)(this, data_);
  628. // Activate the OK button as needed...
  629. if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY))
  630. okButton->activate();
  631. else
  632. okButton->deactivate();
  633. }
  634. }
  635. //
  636. // 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser.
  637. //
  638. void
  639. Fl_File_Chooser::fileNameCB()
  640. {
  641. char *filename, // New filename
  642. *slash, // Pointer to trailing slash
  643. pathname[1024], // Full pathname to file
  644. matchname[256]; // Matching filename
  645. int i, // Looping var
  646. min_match, // Minimum number of matching chars
  647. max_match, // Maximum number of matching chars
  648. num_files, // Number of files in directory
  649. first_line; // First matching line
  650. const char *file; // File from directory
  651. // puts("fileNameCB()");
  652. // printf("Event: %s\n", fl_eventnames[Fl::event()]);
  653. // Get the filename from the text field...
  654. filename = (char *)fileName->value();
  655. if (!filename || !filename[0]) {
  656. okButton->deactivate();
  657. return;
  658. }
  659. // Expand ~ and $ variables as needed...
  660. if (strchr(filename, '~') || strchr(filename, '$')) {
  661. fl_filename_expand(pathname, sizeof(pathname), filename);
  662. filename = pathname;
  663. value(pathname);
  664. }
  665. // Make sure we have an absolute path...
  666. #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__)
  667. if (directory_[0] != '\0' && filename[0] != '/' &&
  668. filename[0] != '\\' &&
  669. !(isalpha(filename[0] & 255) && (!filename[1] || filename[1] == ':'))) {
  670. #else
  671. if (directory_[0] != '\0' && filename[0] != '/') {
  672. #endif /* WIN32 || __EMX__ */
  673. fl_filename_absolute(pathname, sizeof(pathname), filename);
  674. value(pathname);
  675. fileName->mark(fileName->position()); // no selection after expansion
  676. } else if (filename != pathname) {
  677. // Finally, make sure that we have a writable copy...
  678. strlcpy(pathname, filename, sizeof(pathname));
  679. }
  680. filename = pathname;
  681. // Now process things according to the key pressed...
  682. if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter) {
  683. // Enter pressed - select or change directory...
  684. #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
  685. if ((isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2]) ||
  686. _fl_filename_isdir_quick(pathname) &&
  687. compare_dirnames(pathname, directory_)) {
  688. #else
  689. if (_fl_filename_isdir_quick(pathname) &&
  690. compare_dirnames(pathname, directory_)) {
  691. #endif /* WIN32 || __EMX__ */
  692. directory(pathname);
  693. } else if ((type_ & CREATE) || access(pathname, 0) == 0) {
  694. if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) {
  695. // Update the preview box...
  696. update_preview();
  697. // Do any callback that is registered...
  698. if (callback_) (*callback_)(this, data_);
  699. // Hide the window to signal things are done...
  700. window->hide();
  701. }
  702. } else {
  703. // File doesn't exist, so beep at and alert the user...
  704. fl_alert("%s",existing_file_label);
  705. }
  706. }
  707. else if (Fl::event_key() != FL_Delete &&
  708. Fl::event_key() != FL_BackSpace) {
  709. // Check to see if the user has entered a directory...
  710. if ((slash = strrchr(pathname, '/')) == NULL)
  711. slash = strrchr(pathname, '\\');
  712. if (!slash) return;
  713. // Yes, change directories if necessary...
  714. *slash++ = '\0';
  715. filename = slash;
  716. #if defined(WIN32) || defined(__EMX__)
  717. if (strcasecmp(pathname, directory_) &&
  718. (pathname[0] || strcasecmp("/", directory_))) {
  719. #else
  720. if (strcmp(pathname, directory_) &&
  721. (pathname[0] || strcasecmp("/", directory_))) {
  722. #endif // WIN32 || __EMX__
  723. int p = fileName->position();
  724. int m = fileName->mark();
  725. directory(pathname);
  726. if (filename[0]) {
  727. char tempname[1024];
  728. snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename);
  729. fileName->value(tempname);
  730. strlcpy(pathname, tempname, sizeof(pathname));
  731. }
  732. fileName->position(p, m);
  733. }
  734. // Other key pressed - do filename completion as possible...
  735. num_files = fileList->size();
  736. min_match = strlen(filename);
  737. max_match = min_match + 1;
  738. first_line = 0;
  739. for (i = 1; i <= num_files && max_match > min_match; i ++) {
  740. file = fileList->text(i);
  741. #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
  742. if (strncasecmp(filename, file, min_match) == 0) {
  743. #else
  744. if (strncmp(filename, file, min_match) == 0) {
  745. #endif // WIN32 || __EMX__
  746. // OK, this one matches; check against the previous match
  747. if (!first_line) {
  748. // First match; copy stuff over...
  749. strlcpy(matchname, file, sizeof(matchname));
  750. max_match = strlen(matchname);
  751. // Strip trailing /, if any...
  752. if (matchname[max_match - 1] == '/') {
  753. max_match --;
  754. matchname[max_match] = '\0';
  755. }
  756. // And then make sure that the item is visible
  757. fileList->topline(i);
  758. first_line = i;
  759. } else {
  760. // Succeeding match; compare to find maximum string match...
  761. while (max_match > min_match)
  762. #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__)
  763. if (strncasecmp(file, matchname, max_match) == 0)
  764. #else
  765. if (strncmp(file, matchname, max_match) == 0)
  766. #endif // WIN32 || __EMX__
  767. break;
  768. else
  769. max_match --;
  770. // Truncate the string as needed...
  771. matchname[max_match] = '\0';
  772. }
  773. }
  774. }
  775. // If we have any matches, add them to the input field...
  776. if (first_line > 0 && min_match == max_match &&
  777. max_match == (int)strlen(fileList->text(first_line))) {
  778. // This is the only possible match...
  779. fileList->deselect(0);
  780. fileList->select(first_line);
  781. fileList->redraw();
  782. } else if (max_match > min_match && first_line) {
  783. // Add the matching portion...
  784. fileName->replace(filename - pathname, filename - pathname + min_match,
  785. matchname);
  786. // Highlight it with the cursor at the end of the selection so
  787. // s/he can press the right arrow to accept the selection
  788. // (Tab and End also do this for both cases.)
  789. fileName->position(filename - pathname + max_match,
  790. filename - pathname + min_match);
  791. } else if (max_match == 0) {
  792. fileList->deselect(0);
  793. fileList->redraw();
  794. }
  795. // See if we need to enable the OK button...
  796. if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
  797. (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
  798. okButton->activate();
  799. } else {
  800. okButton->deactivate();
  801. }
  802. } else {
  803. // FL_Delete or FL_BackSpace
  804. fileList->deselect(0);
  805. fileList->redraw();
  806. if (((type_ & CREATE) || !access(fileName->value(), 0)) &&
  807. (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
  808. okButton->activate();
  809. } else {
  810. okButton->deactivate();
  811. }
  812. }
  813. }
  814. //
  815. // 'Fl_File_Chooser::filter()' - Set the filter(s) for the chooser.
  816. //
  817. void
  818. Fl_File_Chooser::filter(const char *p) // I - Pattern(s)
  819. {
  820. char *copyp, // Copy of pattern
  821. *start, // Start of pattern
  822. *end; // End of pattern
  823. int allfiles; // Do we have a "*" pattern?
  824. char temp[1024]; // Temporary pattern string
  825. // Make sure we have a pattern...
  826. if (!p || !*p) p = "*";
  827. // Copy the pattern string...
  828. copyp = strdup(p);
  829. // Separate the pattern string as necessary...
  830. showChoice->clear();
  831. for (start = copyp, allfiles = 0; start && *start; start = end) {
  832. end = strchr(start, '\t');
  833. if (end) *end++ = '\0';
  834. if (strcmp(start, "*") == 0) {
  835. showChoice->add(all_files_label);
  836. allfiles = 1;
  837. } else {
  838. quote_pathname(temp, start, sizeof(temp));
  839. showChoice->add(temp);
  840. if (strstr(start, "(*)") != NULL) allfiles = 1;
  841. }
  842. }
  843. free(copyp);
  844. if (!allfiles) showChoice->add(all_files_label);
  845. showChoice->add(custom_filter_label);
  846. showChoice->value(0);
  847. showChoiceCB();
  848. }
  849. //
  850. // 'Fl_File_Chooser::newdir()' - Make a new directory.
  851. //
  852. void
  853. Fl_File_Chooser::newdir()
  854. {
  855. const char *dir; // New directory name
  856. char pathname[1024]; // Full path of directory
  857. // Get a directory name from the user
  858. if ((dir = fl_input("%s", NULL, new_directory_label)) == NULL)
  859. return;
  860. // Make it relative to the current directory as needed...
  861. #if (defined(WIN32) && ! defined (__CYGWIN__)) || defined(__EMX__)
  862. if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':')
  863. #else
  864. if (dir[0] != '/' && dir[0] != '\\')
  865. #endif /* WIN32 || __EMX__ */
  866. snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir);
  867. else
  868. strlcpy(pathname, dir, sizeof(pathname));
  869. // Create the directory; ignore EEXIST errors...
  870. #if defined(WIN32) && ! defined (__CYGWIN__)
  871. if (mkdir(pathname))
  872. #else
  873. if (mkdir(pathname, 0777))
  874. #endif /* WIN32 */
  875. if (errno != EEXIST)
  876. {
  877. fl_alert("%s", strerror(errno));
  878. return;
  879. }
  880. // Show the new directory...
  881. directory(pathname);
  882. }
  883. /** Enable or disable the preview tile. 1 = enable preview, 0 = disable preview. */
  884. void Fl_File_Chooser::preview(int e)
  885. {
  886. previewButton->value(e);
  887. prefs_.set("preview", e);
  888. prefs_.flush();
  889. Fl_Group *p = previewBox->parent();
  890. if (e) {
  891. int w = p->w() * 2 / 3;
  892. fileList->resize(fileList->x(), fileList->y(),
  893. w, fileList->h());
  894. previewBox->resize(fileList->x()+w, previewBox->y(),
  895. p->w()-w, previewBox->h());
  896. previewBox->show();
  897. update_preview();
  898. } else {
  899. fileList->resize(fileList->x(), fileList->y(),
  900. p->w(), fileList->h());
  901. previewBox->resize(p->x()+p->w(), previewBox->y(),
  902. 0, previewBox->h());
  903. previewBox->hide();
  904. }
  905. p->init_sizes();
  906. fileList->parent()->redraw();
  907. }
  908. //
  909. // 'Fl_File_Chooser::previewCB()' - Timeout handler for the preview box.
  910. //
  911. void
  912. Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) { // I - File chooser
  913. fc->update_preview();
  914. }
  915. //
  916. // 'Fl_File_Chooser::rescan()' - Rescan the current directory.
  917. //
  918. void
  919. Fl_File_Chooser::rescan()
  920. {
  921. char pathname[1024]; // New pathname for filename field
  922. // Clear the current filename
  923. strlcpy(pathname, directory_, sizeof(pathname));
  924. if (pathname[0] && pathname[strlen(pathname) - 1] != '/') {
  925. strlcat(pathname, "/", sizeof(pathname));
  926. }
  927. // puts("Setting fileName in rescan()");
  928. fileName->value(pathname);
  929. if (type_ & DIRECTORY)
  930. okButton->activate();
  931. else
  932. okButton->deactivate();
  933. // Build the file list...
  934. fileList->load(directory_, sort);
  935. // Update the preview box...
  936. update_preview();
  937. }
  938. //
  939. /**
  940. Rescan the current directory without clearing the filename,
  941. then select the file if it is in the list
  942. */
  943. void Fl_File_Chooser::rescan_keep_filename()
  944. {
  945. // if no filename was set, this is likely a diretory browser
  946. const char *fn = fileName->value();
  947. if (!fn || !*fn || fn[strlen(fn) - 1]=='/') {
  948. rescan();
  949. return;
  950. }
  951. int i;
  952. char pathname[1024]; // New pathname for filename field
  953. strlcpy(pathname, fn, sizeof(pathname));
  954. // Build the file list...
  955. fileList->load(directory_, sort);
  956. // Update the preview box...
  957. update_preview();
  958. // and select the chosen file
  959. char found = 0;
  960. char *slash = strrchr(pathname, '/');
  961. if (slash)
  962. slash++;
  963. else
  964. slash = pathname;
  965. for (i = 1; i <= fileList->size(); i ++)
  966. #if defined(WIN32) || defined(__EMX__)
  967. if (strcasecmp(fileList->text(i), slash) == 0) {
  968. #else
  969. if (strcmp(fileList->text(i), slash) == 0) {
  970. #endif // WIN32 || __EMX__
  971. fileList->topline(i);
  972. fileList->select(i);
  973. found = 1;
  974. break;
  975. }
  976. // update OK button activity
  977. if (found || type_ & CREATE)
  978. okButton->activate();
  979. else
  980. okButton->deactivate();
  981. }
  982. //
  983. // 'Fl_File_Chooser::showChoiceCB()' - Handle show selections.
  984. //
  985. void
  986. Fl_File_Chooser::showChoiceCB()
  987. {
  988. const char *item, // Selected item
  989. *patstart; // Start of pattern
  990. char *patend; // End of pattern
  991. char temp[1024]; // Temporary string for pattern
  992. item = showChoice->text(showChoice->value());
  993. if (strcmp(item, custom_filter_label) == 0) {
  994. if ((item = fl_input("%s", pattern_, custom_filter_label)) != NULL) {
  995. strlcpy(pattern_, item, sizeof(pattern_));
  996. quote_pathname(temp, item, sizeof(temp));
  997. showChoice->add(temp);
  998. showChoice->value(showChoice->size() - 2);
  999. }
  1000. } else if ((patstart = strchr(item, '(')) == NULL) {
  1001. strlcpy(pattern_, item, sizeof(pattern_));
  1002. } else {
  1003. strlcpy(pattern_, patstart + 1, sizeof(pattern_));
  1004. if ((patend = strrchr(pattern_, ')')) != NULL) *patend = '\0';
  1005. }
  1006. fileList->filter(pattern_);
  1007. if (shown()) {
  1008. // Rescan the directory...
  1009. rescan_keep_filename();
  1010. }
  1011. }
  1012. //
  1013. // 'Fl_File_Chooser::update_favorites()' - Update the favorites menu.
  1014. //
  1015. void
  1016. Fl_File_Chooser::update_favorites()
  1017. {
  1018. int i; // Looping var
  1019. char pathname[1024], // Pathname
  1020. menuname[2048]; // Menu name
  1021. const char *home; // Home directory
  1022. favoritesButton->clear();
  1023. favoritesButton->add("bla");
  1024. favoritesButton->clear();
  1025. favoritesButton->add(add_favorites_label, FL_ALT + 'a', 0);
  1026. favoritesButton->add(manage_favorites_label, FL_ALT + 'm', 0, 0, FL_MENU_DIVIDER);
  1027. favoritesButton->add(filesystems_label, FL_ALT + 'f', 0);
  1028. if ((home = getenv("HOME")) != NULL) {
  1029. quote_pathname(menuname, home, sizeof(menuname));
  1030. favoritesButton->add(menuname, FL_ALT + 'h', 0);
  1031. }
  1032. for (i = 0; i < 100; i ++) {
  1033. sprintf(menuname, "favorite%02d", i);
  1034. prefs_.get(menuname, pathname, "", sizeof(pathname));
  1035. if (!pathname[0]) break;
  1036. quote_pathname(menuname, pathname, sizeof(menuname));
  1037. if (i < 10) favoritesButton->add(menuname, FL_ALT + '0' + i, 0);
  1038. else favoritesButton->add(menuname);
  1039. }
  1040. if (i == 100) ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate();
  1041. }
  1042. //
  1043. // 'Fl_File_Chooser::update_preview()' - Update the preview box...
  1044. //
  1045. void
  1046. Fl_File_Chooser::update_preview()
  1047. {
  1048. const char *filename; // Current filename
  1049. const char *newlabel = 0; // New label text
  1050. Fl_Shared_Image *image = 0, // New image
  1051. *oldimage; // Old image
  1052. int pbw, pbh; // Width and height of preview box
  1053. int w, h; // Width and height of preview image
  1054. int set = 0; // Set this flag as soon as a decent preview is found
  1055. if (!previewButton->value()) return;
  1056. filename = value();
  1057. if (filename == NULL) {
  1058. // no file name at all, so we have an empty preview
  1059. set = 1;
  1060. } else if (fl_filename_isdir(filename)) {
  1061. // filename is a directory, show a folder icon
  1062. newlabel = "@fileopen";
  1063. set = 1;
  1064. } else {
  1065. struct stat s;
  1066. if (fl_stat(filename, &s)==0) {
  1067. if ((s.st_mode&S_IFMT)!=S_IFREG) {
  1068. // this is no regular file, probably some kind of device
  1069. newlabel = "@-3refresh"; // a cross
  1070. set = 1;
  1071. } else if (s.st_size==0) {
  1072. // this file is emty
  1073. newlabel = "<empty file>";
  1074. set = 1;
  1075. } else {
  1076. // if this file is an image, try to load it
  1077. window->cursor(FL_CURSOR_WAIT);
  1078. Fl::check();
  1079. image = Fl_Shared_Image::get(filename);
  1080. if (image) {
  1081. window->cursor(FL_CURSOR_DEFAULT);
  1082. Fl::check();
  1083. set = 1;
  1084. }
  1085. }
  1086. }
  1087. }
  1088. oldimage = (Fl_Shared_Image *)previewBox->image();
  1089. if (oldimage) oldimage->release();
  1090. previewBox->image(0);
  1091. if (!set) {
  1092. FILE *fp;
  1093. int bytes;
  1094. char *ptr;
  1095. if (filename) fp = fopen(filename, "rb");
  1096. else fp = NULL;
  1097. if (fp != NULL) {
  1098. // Try reading the first 1k of data for a label...
  1099. bytes = fread(preview_text_, 1, sizeof(preview_text_) - 1, fp);
  1100. preview_text_[bytes] = '\0';
  1101. fclose(fp);
  1102. } else {
  1103. // Assume we can't read any data...
  1104. preview_text_[0] = '\0';
  1105. }
  1106. window->cursor(FL_CURSOR_DEFAULT);
  1107. Fl::check();
  1108. // Scan the buffer for printable UTF8 chars...
  1109. for (ptr = preview_text_; *ptr; ptr++) {
  1110. uchar c = uchar(*ptr);
  1111. if ( (c&0x80)==0 ) {
  1112. if (!isprint(c&255) && !isspace(c&255)) break;
  1113. } else if ( (c&0xe0)==0xc0 ) {
  1114. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1115. ptr++;
  1116. } else if ( (c&0xf0)==0xe0 ) {
  1117. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1118. ptr++;
  1119. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1120. ptr++;
  1121. } else if ( (c&0xf8)==0xf0 ) {
  1122. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1123. ptr++;
  1124. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1125. ptr++;
  1126. if (ptr[1] && (ptr[1]&0xc0)!=0x80) break;
  1127. ptr++;
  1128. }
  1129. }
  1130. // *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
  1131. // ptr ++);
  1132. // Scan the buffer for printable characters in 8 bit
  1133. if (*ptr || ptr == preview_text_) {
  1134. for (ptr = preview_text_;
  1135. *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255));
  1136. ptr ++);
  1137. }
  1138. if (*ptr || ptr == preview_text_) {
  1139. // Non-printable file, just show a big ?...
  1140. previewBox->label(filename ? "?" : 0);
  1141. previewBox->align(FL_ALIGN_CLIP);
  1142. previewBox->labelsize(75);
  1143. previewBox->labelfont(FL_HELVETICA);
  1144. } else {
  1145. // Show the first 1k of text...
  1146. int size = previewBox->h() / 20;
  1147. if (size < 6) size = 6;
  1148. else if (size > 14) size = 14;
  1149. previewBox->label(preview_text_);
  1150. previewBox->align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE |
  1151. FL_ALIGN_LEFT | FL_ALIGN_TOP));
  1152. previewBox->labelsize(size);
  1153. previewBox->labelfont(FL_COURIER);
  1154. }
  1155. } else if (image) {
  1156. pbw = previewBox->w() - 20;
  1157. pbh = previewBox->h() - 20;
  1158. if (image->w() > pbw || image->h() > pbh) {
  1159. w = pbw;
  1160. h = w * image->h() / image->w();
  1161. if (h > pbh) {
  1162. h = pbh;
  1163. w = h * image->w() / image->h();
  1164. }
  1165. oldimage = (Fl_Shared_Image *)image->copy(w, h);
  1166. previewBox->image((Fl_Image *)oldimage);
  1167. image->release();
  1168. } else {
  1169. previewBox->image((Fl_Image *)image);
  1170. }
  1171. previewBox->align(FL_ALIGN_CLIP);
  1172. previewBox->label(0);
  1173. } else if (newlabel) {
  1174. previewBox->label(newlabel);
  1175. previewBox->align(FL_ALIGN_CLIP);
  1176. previewBox->labelsize(newlabel[0]=='@'?75:12);
  1177. previewBox->labelfont(FL_HELVETICA);
  1178. }
  1179. previewBox->redraw();
  1180. }
  1181. //
  1182. // 'Fl_File_Chooser::value()' - Return a selected filename.
  1183. //
  1184. const char * // O - Filename or NULL
  1185. Fl_File_Chooser::value(int f) // I - File number
  1186. {
  1187. int i; // Looping var
  1188. int fcount; // Number of selected files
  1189. const char *name; // Current filename
  1190. static char pathname[1024]; // Filename + directory
  1191. name = fileName->value();
  1192. if (!(type_ & MULTI)) {
  1193. // Return the filename in the filename field...
  1194. if (!name || !name[0]) return NULL;
  1195. else return name;
  1196. }
  1197. // Return a filename from the list...
  1198. for (i = 1, fcount = 0; i <= fileList->size(); i ++)
  1199. if (fileList->selected(i)) {
  1200. // See if this file is a selected file/directory...
  1201. name = fileList->text(i);
  1202. fcount ++;
  1203. if (fcount == f) {
  1204. if (directory_[0]) {
  1205. snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name);
  1206. } else {
  1207. strlcpy(pathname, name, sizeof(pathname));
  1208. }
  1209. return pathname;
  1210. }
  1211. }
  1212. // If nothing is selected, use the filename field...
  1213. if (!name || !name[0]) return NULL;
  1214. else return name;
  1215. }
  1216. //
  1217. // 'Fl_File_Chooser::value()' - Set the current filename.
  1218. //
  1219. void
  1220. Fl_File_Chooser::value(const char *filename)
  1221. // I - Filename + directory
  1222. {
  1223. int i, // Looping var
  1224. fcount; // Number of items in list
  1225. char *slash; // Directory separator
  1226. char pathname[1024]; // Local copy of filename
  1227. // printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename);
  1228. // See if the filename is the "My System" directory...
  1229. if (filename == NULL || !filename[0]) {
  1230. // Yes, just change the current directory...
  1231. directory(filename);
  1232. fileName->value("");
  1233. okButton->deactivate();
  1234. return;
  1235. }
  1236. #ifdef WIN32
  1237. // See if the filename contains backslashes...
  1238. char fixpath[1024]; // Path with slashes converted
  1239. if (strchr(filename, '\\')) {
  1240. // Convert backslashes to slashes...
  1241. strlcpy(fixpath, filename, sizeof(fixpath));
  1242. for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\'))
  1243. *slash = '/';
  1244. filename = fixpath;
  1245. }
  1246. #endif // WIN32
  1247. // See if there is a directory in there...
  1248. fl_filename_absolute(pathname, sizeof(pathname), filename);
  1249. if ((slash = strrchr(pathname, '/')) != NULL) {
  1250. // Yes, change the display to the directory...
  1251. if (!fl_filename_isdir(pathname)) *slash++ = '\0';
  1252. directory(pathname);
  1253. if (*slash == '/') slash = pathname;
  1254. } else {
  1255. directory(".");
  1256. slash = pathname;
  1257. }
  1258. // Set the input field to the absolute path...
  1259. if (slash > pathname) slash[-1] = '/';
  1260. fileName->value(pathname);
  1261. fileName->position(0, strlen(pathname));
  1262. okButton->activate();
  1263. // Then find the file in the file list and select it...
  1264. fcount = fileList->size();
  1265. fileList->deselect(0);
  1266. fileList->redraw();
  1267. for (i = 1; i <= fcount; i ++)
  1268. #if defined(WIN32) || defined(__EMX__)
  1269. if (strcasecmp(fileList->text(i), slash) == 0) {
  1270. #else
  1271. if (strcmp(fileList->text(i), slash) == 0) {
  1272. #endif // WIN32 || __EMX__
  1273. // printf("Selecting line %d...\n", i);
  1274. fileList->topline(i);
  1275. fileList->select(i);
  1276. break;
  1277. }
  1278. }
  1279. //
  1280. // 'compare_dirnames()' - Compare two directory names.
  1281. //
  1282. static int
  1283. compare_dirnames(const char *a, const char *b) {
  1284. int alen, blen;
  1285. // Get length of each string...
  1286. alen = strlen(a) - 1;
  1287. blen = strlen(b) - 1;
  1288. if (alen < 0 || blen < 0) return alen - blen;
  1289. // Check for trailing slashes...
  1290. if (a[alen] != '/') alen ++;
  1291. if (b[blen] != '/') blen ++;
  1292. // If the lengths aren't the same, then return the difference...
  1293. if (alen != blen) return alen - blen;
  1294. // Do a comparison of the first N chars (alen == blen at this point)...
  1295. #ifdef WIN32
  1296. return strncasecmp(a, b, alen);
  1297. #else
  1298. return strncmp(a, b, alen);
  1299. #endif // WIN32
  1300. }
  1301. //
  1302. // 'quote_pathname()' - Quote a pathname for a menu.
  1303. //
  1304. static void
  1305. quote_pathname(char *dst, // O - Destination string
  1306. const char *src, // I - Source string
  1307. int dstsize) // I - Size of destination string
  1308. {
  1309. dstsize --;
  1310. while (*src && dstsize > 1) {
  1311. if (*src == '\\') {
  1312. // Convert backslash to forward slash...
  1313. *dst++ = '\\';
  1314. *dst++ = '/';
  1315. src ++;
  1316. } else {
  1317. if (*src == '/') *dst++ = '\\';
  1318. *dst++ = *src++;
  1319. }
  1320. }
  1321. *dst = '\0';
  1322. }
  1323. //
  1324. // 'unquote_pathname()' - Unquote a pathname from a menu.
  1325. //
  1326. static void
  1327. unquote_pathname(char *dst, // O - Destination string
  1328. const char *src, // I - Source string
  1329. int dstsize) // I - Size of destination string
  1330. {
  1331. dstsize --;
  1332. while (*src && dstsize > 1) {
  1333. if (*src == '\\') src ++;
  1334. *dst++ = *src++;
  1335. }
  1336. *dst = '\0';
  1337. }
  1338. //
  1339. // End of "$Id: Fl_File_Chooser2.cxx 7219 2010-03-05 18:53:00Z AlbrechtS $".
  1340. //