1 // $Id: Flu_File_Chooser.h,v 1.63 2004/10/18 15:14:58 jbryan Exp $ 2 3 /*************************************************************** 4 * FLU - FLTK Utility Widgets 5 * Copyright (C) 2002 Ohio Supercomputer Center, Ohio State University 6 * 7 * This file and its content is protected by a software license. 8 * You should have received a copy of this license with this file. 9 * If not, please contact the Ohio Supercomputer Center immediately: 10 * Attn: Jason Bryan Re: FLU 1224 Kinnear Rd, Columbus, Ohio 43212 11 * 12 ***************************************************************/ 13 14 15 16 #ifndef _FLU_FILE_CHOOSER_H 17 #define _FLU_FILE_CHOOSER_H 18 19 #include <FL/Fl_Double_Window.H> 20 #include <FL/Fl_Input.H> 21 #include <FL/Fl_Menu_Button.H> 22 #include <FL/Fl_Tile.H> 23 #include <FL/Fl_Pack.H> 24 #include <FL/Fl_Scroll.H> 25 #include <FL/Fl_Check_Button.H> 26 27 #include "Flu_Button.h" 28 #include "Flu_Return_Button.h" 29 #include "Flu_Wrap_Group.h" 30 #include "Flu_Combo_Tree.h" 31 #include "Flu_Combo_List.h" 32 #include "flu_export.h" 33 #include "FluSimpleString.h" 34 #include "FluVectorClass.h" 35 36 FluMakeVectorClass( FluSimpleString, FluStringVector ); 37 38 FLU_EXPORT const char* flu_file_chooser( const char *message, const char *pattern, const char *filename ); 39 FLU_EXPORT int flu_multi_file_chooser( const char *message, const char *pattern, const char *filename, FluStringVector *filelist ); 40 FLU_EXPORT const char* flu_save_chooser( const char *message, const char *pattern, const char *filename ); 41 FLU_EXPORT const char* flu_dir_chooser( const char *message, const char *filename ); 42 FLU_EXPORT const char* flu_dir_chooser( const char *message, const char *filename, bool showFiles ); 43 FLU_EXPORT const char* flu_file_and_dir_chooser( const char *message, const char *filename ); 44 45 //! A file and directory choosing widget that looks and acts similar to the stock Windows file chooser 46 class FLU_EXPORT Flu_File_Chooser : public Fl_Double_Window 47 { 48 49 friend class FileInput; 50 class FileInput : public Fl_Input 51 { 52 public: 53 FileInput( int x, int y, int w, int h, const char *l, Flu_File_Chooser *c ); 54 ~FileInput(); 55 56 int handle( int event ); 57 protected: 58 Flu_File_Chooser *chooser; 59 }; 60 61 public: 62 63 //! strings to be set by a programmer to the correct phrase or name for their language 64 /*! (they are in english by default) */ 65 static FluSimpleString favoritesTxt; 66 static FluSimpleString desktopTxt; 67 static FluSimpleString myComputerTxt; 68 static FluSimpleString myDocumentsTxt; 69 70 static FluSimpleString filenameTxt; 71 static FluSimpleString okTxt; 72 static FluSimpleString cancelTxt; 73 static FluSimpleString locationTxt; 74 static FluSimpleString showHiddenTxt; 75 static FluSimpleString fileTypesTxt; 76 static FluSimpleString directoryTxt; 77 static FluSimpleString allFilesTxt; 78 static FluSimpleString defaultFolderNameTxt; 79 80 static FluSimpleString backTTxt; 81 static FluSimpleString forwardTTxt; 82 static FluSimpleString upTTxt; 83 static FluSimpleString reloadTTxt; 84 static FluSimpleString trashTTxt; 85 static FluSimpleString newDirTTxt; 86 static FluSimpleString addFavoriteTTxt; 87 static FluSimpleString previewTTxt; 88 static FluSimpleString listTTxt; 89 static FluSimpleString wideListTTxt; 90 static FluSimpleString detailTTxt; 91 92 static FluSimpleString detailTxt[4]; 93 static FluSimpleString contextMenuTxt[3]; 94 static FluSimpleString diskTypesTxt[6]; 95 96 static FluSimpleString createFolderErrTxt; 97 static FluSimpleString deleteFileErrTxt; 98 static FluSimpleString fileExistsErrTxt; 99 static FluSimpleString renameErrTxt; 100 101 //! This class must be derived from to create a "preview" widget. 102 /*! Simply derive from this class and overload Fl_Group's methods to create a widget 103 able to preview whatever file type you want. Register it with Flu_File_Chooser::add_preview_handler() 104 When a file is previewed, all registered handlers are visited until the preview() virtual function 105 for one of them returns nonzero. When preview() is called, the absolute path of the file is passed in, 106 and the widget should determine whether it can preview the file and update itself accordingly. If 107 it can preview the file, it should return nonzero, else it should return zero. 108 */ 109 class FLU_EXPORT PreviewWidgetBase : public Fl_Group 110 { 111 public: 112 PreviewWidgetBase(); 113 virtual ~PreviewWidgetBase(); 114 virtual int preview( const char *filename ) = 0; 115 }; 116 117 //! File entry type 118 enum { 119 ENTRY_NONE = 1, /*!< An empty (or non-existant) entry */ 120 ENTRY_DIR = 2, /*!< A directory entry */ 121 ENTRY_FILE = 4, /*!< A file entry */ 122 ENTRY_FAVORITE = 8, /*!< A favorite entry */ 123 ENTRY_DRIVE = 16, /*!< An entry that refers to a disk drive */ 124 ENTRY_MYDOCUMENTS = 32, /*!< The entry referring to the current user's documents */ 125 ENTRY_MYCOMPUTER = 64 /*!< The entry referring to "My Computer" in Windows */ 126 }; 127 128 //! Chooser type 129 enum { 130 SINGLE = 0, /*!< Choose a single file or directory */ 131 MULTI = 1, /*!< Choose multiple files or directories */ 132 DIRECTORY = 4, /*!< Choose directories (choosing files is implicit if this bit is clear) */ 133 DEACTIVATE_FILES = 8, /*!< When choosing directories, also show the files in a deactivated state */ 134 SAVING = 16, /*!< When choosing files, whether to keep the current filename always in the input area */ 135 STDFILE = 32 /*!< Choose both files and directories at the same time */ 136 }; 137 138 //! Structure holding the info needed for custom file types 139 struct FileTypeInfo 140 { 141 Fl_Image *icon; 142 FluSimpleString extensions; 143 FluSimpleString type, shortType; 144 }; 145 146 //! Constructor opening a file chooser with title \b title visiting directory \b path with files filtered according to \b pattern. \b type is a logical OR of Flu_File_Chooser::SINGLE, Flu_File_Chooser::MULTI, and Flu_File_Chooser::DIRECTORY 147 Flu_File_Chooser( const char *path, const char *pattern, int type, const char *title ); 148 149 //! Destructor 150 ~Flu_File_Chooser(); 151 152 //! Add a custom callback that is called when the user right-clicks on an entry 153 /*! \param type is the type of entry to handle (i.e. a logical OR of \c ENTRY_NONE, \c ENTRY_DIR, \c ENTRY_FILE, \c ENTRY_FAVORITE, \c ENTRY_DRIVE, \c ENTRY_MYDOCUMENTS, \c ENTRY_MYCOMPUTER). To add a "nothing" handler (when the user right-clicks on nothing), use ENTRY_NONE 154 \param ext is the extension of the file that will cause this handler to be added to the popup menu 155 \param name is the name that will appear in the popup menu for this handler 156 */ 157 static void add_context_handler( int type, const char *ext, const char *name, 158 void (*cb)(const char*,int,void*), void *cbd ); 159 160 //! Add a "preview" widget (derived from class Flu_File_Chooser::PreviewWidgetBase) that will handle custom previewing of files 161 static void add_preview_handler( PreviewWidgetBase *w ); 162 163 //! Add descriptive information and an icon for a file type 164 /*! \param extensions is a space- or comma-delimited list of file extensions, or \c NULL for directories. e.g. "zip,tgz,rar" 165 \param short_description is a short description (!) of the file type. e.g. "Compressed Archive" 166 \param icon is an optional custom icon to use for this file type 167 */ 168 static void add_type( const char *extensions, const char *short_description, Fl_Image *icon = NULL ); 169 170 //! deprecated - do not use - right click to change filenames allow_file_editing(bool b)171 inline void allow_file_editing( bool b ) 172 { fileEditing = b; } 173 174 //! deprecated - do not use - right click to change filenames allow_file_editing()175 inline bool allow_file_editing() const 176 { return fileEditing; } 177 178 //! Set whether file sorting is case insensitive. Default value is case-insensitive for windows, case-sensitive for everything else case_insensitive_sort(bool b)179 inline void case_insensitive_sort( bool b ) 180 { caseSort = !b; } 181 182 //! Get whether file sorting is case insensitive case_insensitive_sort()183 inline bool case_insensitive_sort() const 184 { return !caseSort; } 185 186 //! Change the current directory the chooser is browsing to \b path 187 void cd( const char *path ); 188 189 //! Clear the history of which directories have been visited 190 void clear_history(); 191 192 //! \return how many files are selected 193 int count(); 194 195 //! Set the default icon to use for all files for which no other icon has been specified default_file_icon(Fl_Image * i)196 inline void default_file_icon( Fl_Image* i ) 197 { defaultFileIcon = i; } 198 199 //! Alias for cd() directory(const char * d)200 inline void directory( const char *d ) 201 { cd( d ); } 202 203 //! Alias for pattern() filter(const char * p)204 inline void filter( const char *p ) 205 { pattern( p ); } 206 207 //! Alias for pattern() filter()208 inline const char* filter() const 209 { return pattern(); } 210 211 //! \return a pointer to a FileTypeInfo structure for files with type \b extension 212 static FileTypeInfo *find_type( const char *extension ); 213 214 //! \return the current directory that the browser is visiting get_current_directory()215 inline const char* get_current_directory() const 216 { return currentDir.c_str(); } 217 218 //! Override of Fl_Double_Window::handle() 219 int handle( int event ); 220 221 //! Change the file filter pattern to \b p 222 void pattern( const char *p ); 223 224 //! Get the current file filter pattern pattern()225 inline const char* pattern() const 226 { return rawPattern.c_str(); } 227 228 //! Set the state of the preview button preview(bool b)229 inline void preview( bool b ) 230 { previewBtn->value(b); previewBtn->do_callback(); } 231 232 //! Get the state of the preview button preview()233 inline int preview() const 234 { return previewBtn->value(); } 235 236 //! Refresh the current directory rescan()237 inline void rescan() { reloadCB(); } 238 239 //! Override of Fl_Double_Window::resize() 240 void resize( int x, int y, int w, int h ); 241 242 //! Select all entries (only valid for multiple-selections) 243 void select_all(); 244 245 //! Set a custom sorting function for sorting entries based on filename set_sort_function(int (* cb)(const char *,const char *))246 inline void set_sort_function( int (*cb)(const char*,const char*) ) 247 { customSort = cb; rescan(); } 248 249 //! Set the type of the chooser (see constructor) type(int t)250 inline void type( int t ) 251 { selectionType = t; rescan(); } 252 253 //! Get the type of the chooser type(int)254 inline int type( int /*t*/ ) const 255 { return selectionType; } 256 257 //! Unselect all entries 258 void unselect_all(); 259 260 //! Set the current file the chooser is selecting 261 void value( const char *v ); 262 263 //! Get the current file the chooser is selecting 264 const char *value(); 265 266 //! For MULTI file queries, get selected file \b n (base 1 - i.e. 1 returns the first file, 2 the second, etc) 267 const char *value( int n ); 268 269 FileInput filename; 270 // the <Enter> key behavior is not correct for versions before 1.1.4rc2 271 #if FL_MAJOR_VERSION >= 1 && FL_MINOR_VERSION >= 1 && FL_PATCH_VERSION >= 4 272 Flu_Return_Button ok; 273 #else 274 Flu_Button ok; 275 #endif 276 Flu_Button cancel; 277 278 // apparently there is a bug in VC6 that prevents friend classes from accessing 279 // non-public members. stupid windows 280 // several other compilers were reported to have a problem with this too, so 281 // i'm just making the whole class public to eliminate potential problems. 282 // bad c++ - i know... 283 //#ifndef WIN32 284 //protected: 285 //#endif 286 287 class ContextHandler 288 { 289 public: 290 FluSimpleString ext, name; 291 int type; 292 void (*callback)(const char*,int,void*); 293 void *callbackData; 294 inline ContextHandler& operator =( const ContextHandler &c ) 295 { ext = c.ext; name = c.name; type = c.type; callback = c.callback; callbackData = c.callbackData; return *this; } 296 }; 297 FluMakeVectorClass( ContextHandler, ContextHandlerVector ); 298 static ContextHandlerVector contextHandlers; 299 300 typedef PreviewWidgetBase* pPreviewWidgetBase; 301 FluMakeVectorClass( pPreviewWidgetBase, PreviewHandlerVector ); 302 static PreviewHandlerVector previewHandlers; 303 304 Fl_Check_Button *hiddenFiles; 305 Flu_Combo_Tree *location; 306 _backCB(Fl_Widget *,void * arg)307 inline static void _backCB( Fl_Widget * /*w*/, void *arg ) 308 { ((Flu_File_Chooser*)arg)->backCB(); } 309 void backCB(); 310 _forwardCB(Fl_Widget *,void * arg)311 inline static void _forwardCB( Fl_Widget * /*w*/, void *arg ) 312 { ((Flu_File_Chooser*)arg)->forwardCB(); } 313 void forwardCB(); 314 _sortCB(Fl_Widget * w,void * arg)315 inline static void _sortCB( Fl_Widget *w, void *arg ) 316 { ((Flu_File_Chooser*)arg)->sortCB( w ); } 317 void sortCB( Fl_Widget *w ); 318 _previewCB(Fl_Widget *,void * arg)319 inline static void _previewCB( Fl_Widget*, void *arg ) 320 { ((Flu_File_Chooser*)arg)->previewCB(); } 321 void previewCB(); 322 _listModeCB(Fl_Widget *,void * arg)323 inline static void _listModeCB( Fl_Widget * /*w*/, void *arg ) 324 { ((Flu_File_Chooser*)arg)->listModeCB(); } 325 void listModeCB(); 326 _filenameCB(Fl_Widget *,void * arg)327 inline static void _filenameCB( Fl_Widget * /*w*/, void *arg ) 328 { ((Flu_File_Chooser*)arg)->filenameCB(); } 329 void filenameCB(); 330 _locationCB(Fl_Widget * w,void * arg)331 inline static void _locationCB( Fl_Widget *w, void *arg ) 332 { ((Flu_File_Chooser*)arg)->locationCB( ((Flu_Combo_Tree*)w)->value() ); } 333 void locationCB( const char *path ); 334 _locationQJCB(Fl_Widget * w,void * arg)335 inline static void _locationQJCB( Fl_Widget *w, void *arg ) 336 { ((Flu_File_Chooser*)arg)->cd( ((Fl_Button*)w)->label() ); } 337 delayedCdCB(void * arg)338 inline static void delayedCdCB( void *arg ) 339 { ((Flu_File_Chooser*)arg)->cd( ((Flu_File_Chooser*)arg)->delayedCd.c_str() ); } 340 selectCB(void * arg)341 inline static void selectCB( void *arg ) 342 { ((Flu_File_Chooser*)arg)->okCB(); } 343 _cancelCB(Fl_Widget *,void * arg)344 inline static void _cancelCB( Fl_Widget*, void *arg ) 345 { ((Flu_File_Chooser*)arg)->cancelCB(); } 346 void cancelCB(); 347 _okCB(Fl_Widget *,void * arg)348 inline static void _okCB( Fl_Widget*, void *arg ) 349 { ((Flu_File_Chooser*)arg)->okCB(); } 350 void okCB(); 351 _trashCB(Fl_Widget *,void * arg)352 inline static void _trashCB( Fl_Widget*, void *arg ) 353 { ((Flu_File_Chooser*)arg)->trashCB(); } 354 void trashCB( bool recycle = true ); 355 _newFolderCB(Fl_Widget *,void * arg)356 inline static void _newFolderCB( Fl_Widget*, void *arg ) 357 { ((Flu_File_Chooser*)arg)->newFolderCB(); } 358 void newFolderCB(); 359 upDirCB(Fl_Widget *,void * arg)360 inline static void upDirCB( Fl_Widget*, void *arg ) 361 { ((Flu_File_Chooser*)arg)->cd( "../" ); } 362 reloadCB(Fl_Widget *,void * arg)363 inline static void reloadCB( Fl_Widget*, void *arg ) 364 { ((Flu_File_Chooser*)arg)->reloadCB(); } 365 void reloadCB(); 366 _homeCB(Fl_Widget *,void * arg)367 inline static void _homeCB( Fl_Widget*, void *arg ) 368 { ((Flu_File_Chooser*)arg)->homeCB(); } 369 void homeCB(); 370 _desktopCB(Fl_Widget *,void * arg)371 inline static void _desktopCB( Fl_Widget*, void *arg ) 372 { ((Flu_File_Chooser*)arg)->desktopCB(); } 373 void desktopCB(); 374 _favoritesCB(Fl_Widget *,void * arg)375 inline static void _favoritesCB( Fl_Widget*, void *arg ) 376 { ((Flu_File_Chooser*)arg)->favoritesCB(); } 377 void favoritesCB(); 378 _myComputerCB(Fl_Widget *,void * arg)379 inline static void _myComputerCB( Fl_Widget*, void *arg ) 380 { ((Flu_File_Chooser*)arg)->myComputerCB(); } 381 void myComputerCB(); 382 _addToFavoritesCB(Fl_Widget *,void * arg)383 inline static void _addToFavoritesCB( Fl_Widget*, void *arg ) 384 { ((Flu_File_Chooser*)arg)->addToFavoritesCB(); } 385 void addToFavoritesCB(); 386 _documentsCB(Fl_Widget *,void * arg)387 inline static void _documentsCB( Fl_Widget*, void *arg ) 388 { ((Flu_File_Chooser*)arg)->documentsCB(); } 389 void documentsCB(); 390 _hideCB(Fl_Widget *,void * arg)391 inline static void _hideCB( Fl_Widget*, void *arg ) 392 { ((Flu_File_Chooser*)arg)->hideCB(); } 393 void hideCB(); 394 void do_callback(); 395 396 enum { 397 SORT_NAME = 1, 398 SORT_SIZE = 2, 399 SORT_TYPE = 4, 400 SORT_DATE = 8, 401 SORT_REVERSE = 16 402 }; 403 static void _qSort( int how, bool caseSort, Fl_Widget **array, int low, int high ); 404 405 friend class Entry; 406 class Entry : public Fl_Input 407 { 408 public: 409 Entry( const char* name, int t, bool d, Flu_File_Chooser *c ); 410 ~Entry(); 411 412 int handle( int event ); 413 void draw(); 414 415 void updateSize(); 416 void updateIcon(); 417 418 FluSimpleString filename, date, filesize, shortname, 419 description, shortDescription, toolTip, altname; 420 //FluSimpleString permissions; 421 //unsigned char pU, pG, pO; // 3-bit unix style permissions 422 unsigned int type, idate; 423 unsigned long isize; 424 bool selected; 425 int editMode; 426 Flu_File_Chooser *chooser; 427 Fl_Image *icon; 428 429 int nameW, typeW, sizeW, dateW; 430 bool details; 431 _inputCB(Fl_Widget *,void * arg)432 inline static void _inputCB( Fl_Widget * /*w*/, void *arg ) 433 { ((Entry*)arg)->inputCB(); } 434 void inputCB(); 435 _editCB(void * arg)436 inline static void _editCB( void *arg ) 437 { ((Entry*)arg)->editCB(); } 438 void editCB(); 439 }; 440 441 friend class FileList; 442 class FileList : public Flu_Wrap_Group 443 { 444 public: 445 FileList( int x, int y, int w, int h, Flu_File_Chooser *c ); 446 ~FileList(); 447 448 int handle( int event ); 449 void sort( int numDirs = -1 ); 450 child(int n)451 inline Fl_Widget *child(int n) const 452 { return Flu_Wrap_Group::child(n); } 453 children()454 inline int children() const 455 { return Flu_Wrap_Group::children(); } 456 457 int numDirs; 458 Flu_File_Chooser *chooser; 459 }; 460 461 friend class FileDetails; 462 class FileDetails : public Fl_Pack 463 { 464 public: 465 FileDetails( int x, int y, int w, int h, Flu_File_Chooser *c ); 466 ~FileDetails(); 467 468 int handle( int event ); 469 void sort( int numDirs = -1 ); 470 471 void scroll_to( Fl_Widget *w ); 472 Fl_Widget* next( Fl_Widget* w ); 473 Fl_Widget* previous( Fl_Widget* w ); 474 475 int numDirs; 476 Flu_File_Chooser *chooser; 477 }; 478 479 friend class CBTile; 480 class CBTile : public Fl_Tile 481 { 482 public: 483 CBTile( int x, int y, int w, int h, Flu_File_Chooser *c ); 484 int handle( int event ); 485 Flu_File_Chooser *chooser; 486 }; 487 488 friend class FileColumns; 489 class FileColumns : public Fl_Tile 490 { 491 public: 492 FileColumns( int x, int y, int w, int h, Flu_File_Chooser *c ); 493 ~FileColumns(); 494 495 int handle( int event ); 496 void resize( int x, int y, int w, int h ); 497 Flu_File_Chooser *chooser; 498 int W1, W2, W3, W4; 499 }; 500 501 friend class PreviewTile; 502 class PreviewTile : public Fl_Tile 503 { 504 public: 505 PreviewTile( int x, int y, int w, int h, Flu_File_Chooser *c ); 506 int handle( int event ); 507 Flu_File_Chooser *chooser; 508 int last; 509 }; 510 511 class ImgTxtPreview : public PreviewWidgetBase 512 { 513 public: 514 int preview( const char *filename ); 515 unsigned char previewTxt[1024]; 516 }; 517 518 friend class PreviewGroup; 519 class PreviewGroup : public Fl_Group 520 { 521 public: 522 PreviewGroup( int x, int y, int w, int h, Flu_File_Chooser *c ); 523 void draw(); 524 Flu_File_Chooser *chooser; 525 FluSimpleString lastFile, file; 526 PreviewWidgetBase* handled; 527 }; 528 529 Fl_Group *getEntryGroup(); 530 Fl_Group *getEntryContainer(); 531 532 void win2unix( FluSimpleString &s ); 533 534 void cleanupPath( FluSimpleString &s ); 535 536 bool correctPath( FluSimpleString &path ); 537 538 void updateEntrySizes(); 539 540 void buildLocationCombo(); 541 542 void updateLocationQJ(); 543 544 void addToHistory(); 545 546 FluSimpleString formatDate( const char *d ); 547 548 void recursiveScan( const char *dir, FluStringVector *files ); 549 550 bool stripPatterns( FluSimpleString s, FluStringVector* patterns ); 551 552 int popupContextMenu( Entry *entry ); 553 554 FluSimpleString commonStr(); 555 556 static ImgTxtPreview *imgTxtPreview; 557 558 static int (*customSort)(const char*,const char*); 559 560 PreviewGroup *previewGroup; 561 PreviewTile *previewTile; 562 Fl_Group *fileGroup, *locationQuickJump; 563 Fl_Menu_Button entryPopup; 564 Fl_Image *defaultFileIcon; 565 Entry *lastSelected; 566 FileList *filelist; 567 FileColumns *filecolumns; 568 Fl_Group *fileDetailsGroup; 569 Fl_Scroll *filescroll; 570 FileDetails *filedetails; 571 Flu_Button *detailNameBtn, *detailTypeBtn, *detailSizeBtn, *detailDateBtn; 572 FluSimpleString currentDir, delayedCd, rawPattern; 573 FluSimpleString configFilename; 574 FluSimpleString userHome, userDesktop, userDocs; 575 FluSimpleString drives[26]; 576 Fl_Pixmap* driveIcons[26]; 577 Flu_Button *fileListBtn, *fileListWideBtn, *fileDetailsBtn, *backBtn, *forwardBtn, *upDirBtn, *trashBtn, 578 *newDirBtn, *addFavoriteBtn, *reloadBtn, *previewBtn; 579 Fl_Browser *favoritesList; 580 Flu_Combo_List *filePattern; 581 int selectionType; 582 bool filenameEnterCallback, filenameTabCallback, walkingHistory, caseSort, fileEditing; 583 int sortMethod; 584 585 FluStringVector patterns; 586 587 static FileTypeInfo *types; 588 static int numTypes; 589 static int typeArraySize; 590 591 static FluSimpleString dArrow[4]; 592 static FluSimpleString uArrow[4]; 593 594 #ifdef WIN32 595 unsigned int driveMask; 596 unsigned int driveTypes[26]; 597 FluSimpleString volumeNames[26]; 598 bool refreshDrives; 599 #endif 600 601 class History 602 { 603 public: History()604 History() { last = next = NULL; } 605 FluSimpleString path; 606 History *last, *next; 607 }; 608 609 History *history, *currentHist; 610 611 Fl_Callback *_callback; 612 void *_userdata; 613 614 }; 615 616 #endif 617