From 6a4714ce12d546c8131389853fe5593555c73b77 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Sat, 29 Sep 2001 14:38:59 +0000 Subject: Fl_FileXYZ -> Fl_File_XYZ Fl_HelpXYZ -> Fl_Help_XYZ Fl_File_Chooser now supports directory choosing. Added fl_dir_chooser() function. Now set FLTK_DOCDIR env var in test/demo. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1612 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- src/Fl_FileBrowser.cxx | 570 -------- src/Fl_FileChooser.cxx | 255 ---- src/Fl_FileChooser.fl | 206 --- src/Fl_FileChooser2.cxx | 695 --------- src/Fl_FileIcon.cxx | 1225 ---------------- src/Fl_File_Browser.cxx | 570 ++++++++ src/Fl_File_Chooser.cxx | 259 ++++ src/Fl_File_Chooser.fl | 210 +++ src/Fl_File_Chooser2.cxx | 688 +++++++++ src/Fl_File_Icon.cxx | 1225 ++++++++++++++++ src/Fl_HelpDialog.cxx | 221 --- src/Fl_HelpDialog.fl | 191 --- src/Fl_HelpView.cxx | 3584 ---------------------------------------------- src/Fl_Help_Dialog.cxx | 221 +++ src/Fl_Help_Dialog.fl | 191 +++ src/Fl_Help_View.cxx | 3584 ++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile | 16 +- src/fl_file_chooser.cxx | 37 +- src/makedepend | 83 +- 19 files changed, 7030 insertions(+), 7001 deletions(-) delete mode 100644 src/Fl_FileBrowser.cxx delete mode 100644 src/Fl_FileChooser.cxx delete mode 100644 src/Fl_FileChooser.fl delete mode 100644 src/Fl_FileChooser2.cxx delete mode 100644 src/Fl_FileIcon.cxx create mode 100644 src/Fl_File_Browser.cxx create mode 100644 src/Fl_File_Chooser.cxx create mode 100644 src/Fl_File_Chooser.fl create mode 100644 src/Fl_File_Chooser2.cxx create mode 100644 src/Fl_File_Icon.cxx delete mode 100644 src/Fl_HelpDialog.cxx delete mode 100644 src/Fl_HelpDialog.fl delete mode 100644 src/Fl_HelpView.cxx create mode 100644 src/Fl_Help_Dialog.cxx create mode 100644 src/Fl_Help_Dialog.fl create mode 100644 src/Fl_Help_View.cxx (limited to 'src') diff --git a/src/Fl_FileBrowser.cxx b/src/Fl_FileBrowser.cxx deleted file mode 100644 index 63587bcf4..000000000 --- a/src/Fl_FileBrowser.cxx +++ /dev/null @@ -1,570 +0,0 @@ -// -// "$Id: Fl_FileBrowser.cxx,v 1.13.2.5 2001/09/04 13:13:29 easysw Exp $" -// -// Fl_FileBrowser routines. -// -// Copyright 1999-2001 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems to "fltk-bugs@fltk.org". -// -// Contents: -// -// Fl_FileBrowser::full_height() - Return the height of the list. -// Fl_FileBrowser::item_height() - Return the height of a list item. -// Fl_FileBrowser::item_width() - Return the width of a list item. -// Fl_FileBrowser::item_draw() - Draw a list item. -// Fl_FileBrowser::Fl_FileBrowser() - Create a Fl_FileBrowser widget. -// Fl_FileBrowser::load() - Load a directory into the browser. -// Fl_FileBrowser::filter() - Set the filename filter. -// - -// -// Include necessary header files... -// - -#include -#include -#include -#include -#include -#include -#include - -#if defined(WIN32) -# include -# include -#endif /* WIN32 */ - -#if defined(__EMX__) -#define INCL_DOS -#define INCL_DOSMISC -#include -#endif /* __EMX__ */ - -#if !HAVE_SNPRINTF -extern "C" { -extern int snprintf(char* str, size_t size, const char* fmt, ...); -} -#endif // !HAVE_SNPRINTF - - -// -// FL_BLINE definition from "Fl_Browser.cxx"... -// - -#define SELECTED 1 -#define NOTDISPLAYED 2 - -struct FL_BLINE // data is in a linked list of these -{ - FL_BLINE *prev; // Previous item in list - FL_BLINE *next; // Next item in list - void *data; // Pointer to data (function) - short length; // sizeof(txt)-1, may be longer than string - char flags; // selected, displayed - char txt[1]; // start of allocated array -}; - - -// -// 'Fl_FileBrowser::full_height()' - Return the height of the list. -// - -int // O - Height in pixels -Fl_FileBrowser::full_height() const -{ - int i, // Looping var - th; // Total height of list. - - - for (i = 0, th = 0; i < size(); i ++) - th += item_height(find_line(i)); - - return (th); -} - - -// -// 'Fl_FileBrowser::item_height()' - Return the height of a list item. -// - -int // O - Height in pixels -Fl_FileBrowser::item_height(void *p) const // I - List item data -{ - FL_BLINE *line; // Pointer to line - char *text; // Pointer into text - int height; // Width of line - int textheight; // Height of text - - - // Figure out the standard text height... - fl_font(textfont(), textsize()); - textheight = fl_height(); - - // We always have at least 1 line... - height = textheight; - - // Scan for newlines... - line = (FL_BLINE *)p; - - if (line != NULL) - for (text = line->txt; *text != '\0'; text ++) - if (*text == '\n') - height += textheight; - - // If we have enabled icons then add space for them... - if (Fl_FileIcon::first() != NULL && height < iconsize_) - height = iconsize_; - - // Add space for the selection border.. - height += 2; - - // Return the height - return (height); -} - - -// -// 'Fl_FileBrowser::item_width()' - Return the width of a list item. -// - -int // O - Width in pixels -Fl_FileBrowser::item_width(void *p) const // I - List item data -{ - int i; // Looping var - FL_BLINE *line; // Pointer to line - char *text, // Pointer into text - *ptr, // Pointer into fragment - fragment[10240]; // Fragment of text - int width, // Width of line - tempwidth; // Width of fragment - int column; // Current column - const int *columns; // Columns - - - // Set the font and size... - fl_font(textfont(), textsize()); - - // Scan for newlines... - line = (FL_BLINE *)p; - columns = column_widths(); - - if (strchr(line->txt, '\n') == NULL && - strchr(line->txt, column_char()) == NULL) - { - // Do a fast width calculation... - width = (int)fl_width(line->txt); - } - else - { - // More than 1 line or have columns; find the maximum width... - width = 0; - tempwidth = 0; - column = 0; - - for (text = line->txt, ptr = fragment; *text != '\0'; text ++) - if (*text == '\n') - { - // Newline - nul terminate this fragment and get the width... - *ptr = '\0'; - - tempwidth += (int)fl_width(fragment); - - // Update the max width as needed... - if (tempwidth > width) - width = tempwidth; - - // Point back to the start of the fragment... - ptr = fragment; - tempwidth = 0; - column = 0; - } - else if (*text == column_char()) - { - // Advance to the next column... - column ++; - if (columns) - { - for (i = 0, tempwidth = 0; i < column && columns[i]; i ++) - tempwidth += columns[i]; - } - else - tempwidth = column * (int)(fl_height() * 0.6 * 8.0); - - if (tempwidth > width) - width = tempwidth; - - ptr = fragment; - } - else - *ptr++ = *text; - - if (ptr > fragment) - { - // Nul terminate this fragment and get the width... - *ptr = '\0'; - - tempwidth += (int)fl_width(fragment); - - // Update the max width as needed... - if (tempwidth > width) - width = tempwidth; - } - } - - // If we have enabled icons then add space for them... - if (Fl_FileIcon::first() != NULL) - width += iconsize_ + 8; - - // Add space for the selection border.. - width += 2; - - // Return the width - return (width); -} - - -// -// 'Fl_FileBrowser::item_draw()' - Draw a list item. -// - -void -Fl_FileBrowser::item_draw(void *p, // I - List item data - int x, // I - Upper-lefthand X coordinate - int y, // I - Upper-lefthand Y coordinate - int w, // I - Width of item - int h) const // I - Height of item -{ - int i; // Looping var - FL_BLINE *line; // Pointer to line - Fl_Color c; // Text color - char *text, // Pointer into text - *ptr, // Pointer into fragment - fragment[10240]; // Fragment of text - int width, // Width of line - height; // Height of line - int column; // Current column - const int *columns; // Columns - - - (void)h; - - // Draw the list item text... - line = (FL_BLINE *)p; - - if (line->txt[strlen(line->txt) - 1] == '/') - fl_font(textfont() | FL_BOLD, textsize()); - else - fl_font(textfont(), textsize()); - - if (line->flags & SELECTED) - c = contrast(textcolor(), selection_color()); - else - c = textcolor(); - - if (Fl_FileIcon::first() == NULL) - { - // No icons, just draw the text... - x ++; - w -= 2; - } - else - { - // Draw the icon if it is set... - if (line->data) - ((Fl_FileIcon *)line->data)->draw(x, y, iconsize_, iconsize_, - (line->flags & SELECTED) ? FL_YELLOW : - FL_LIGHT2, - active_r()); - - // Draw the text offset to the right... - x += iconsize_ + 9; - w -= iconsize_ - 10; - - // Center the text vertically... - height = fl_height(); - - for (text = line->txt; *text != '\0'; text ++) - if (*text == '\n') - height += fl_height(); - - if (height < iconsize_) - y += (iconsize_ - height) / 2; - } - - // Draw the text... - line = (FL_BLINE *)p; - columns = column_widths(); - width = 0; - column = 0; - - if (active_r()) - fl_color(c); - else - fl_color(inactive(c)); - - for (text = line->txt, ptr = fragment; *text != '\0'; text ++) - if (*text == '\n') - { - // Newline - nul terminate this fragment and draw it... - *ptr = '\0'; - - fl_draw(fragment, x + width, y, w - width, fl_height(), - (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); - - // Point back to the start of the fragment... - ptr = fragment; - width = 0; - y += fl_height(); - column = 0; - } - else if (*text == column_char()) - { - // Tab - nul terminate this fragment and draw it... - *ptr = '\0'; - - fl_draw(fragment, x + width, y, w - width, fl_height(), - (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); - - // Advance to the next column... - column ++; - if (columns) - { - for (i = 0, width = 0; i < column && columns[i]; i ++) - width += columns[i]; - } - else - width = column * (int)(fl_height() * 0.6 * 8.0); - - ptr = fragment; - } - else - *ptr++ = *text; - - if (ptr > fragment) - { - // Nul terminate this fragment and draw it... - *ptr = '\0'; - - fl_draw(fragment, x + width, y, w - width, fl_height(), - (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); - } -} - - -// -// 'Fl_FileBrowser::Fl_FileBrowser()' - Create a Fl_FileBrowser widget. -// - -Fl_FileBrowser::Fl_FileBrowser(int x, // I - Upper-lefthand X coordinate - int y, // I - Upper-lefthand Y coordinate - int w, // I - Width in pixels - int h, // I - Height in pixels - const char *l) // I - Label text - : Fl_Browser(x, y, w, h, l) -{ - // Initialize the filter pattern, current directory, and icon size... - pattern_ = "*"; - directory_ = ""; - iconsize_ = 3 * textsize() / 2; - filetype_ = FILES; -} - - -// -// 'Fl_FileBrowser::load()' - Load a directory into the browser. -// - -int // O - Number of files loaded -Fl_FileBrowser::load(const char *directory)// I - Directory to load -{ - int i; // Looping var - int num_files; // Number of files in directory - int num_dirs; // Number of directories in list - char filename[4096]; // Current file - Fl_FileIcon *icon; // Icon to use - - -// printf("Fl_FileBrowser::load(\"%s\")\n", directory); - - clear(); - directory_ = directory; - - if (directory_[0] == '\0') - { - // - // No directory specified; for UNIX list all mount points. For DOS - // list all valid drive letters... - // - - num_files = 0; - if ((icon = Fl_FileIcon::find("any", Fl_FileIcon::DEVICE)) == NULL) - icon = Fl_FileIcon::find("any", Fl_FileIcon::DIRECTORY); - -#if defined(WIN32) - DWORD drives; // Drive available bits - - - drives = GetLogicalDrives(); - for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) - if (drives & 1) - { - sprintf(filename, "%c:/", i); - - if (i < 'C') - add(filename, icon); - else - add(filename, icon); - - num_files ++; - } -#elif defined(__EMX__) - ULONG curdrive; // Current drive - ULONG drives; // Drive available bits - int start = 3; // 'C' (MRS - dunno if this is correct!) - - - DosQueryCurrentDisk(&curdrive, &drives); - drives >>= start - 1; - for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) - if (drives & 1) - { - sprintf(filename, "%c:/", i); - add(filename, icon); - - num_files ++; - } -#else - FILE *mtab; // /etc/mtab or /etc/mnttab file - char line[1024]; // Input line - - - // - // Open the file that contains a list of mounted filesystems... - // -# if defined(hpux) || defined(__sun) - mtab = fopen("/etc/mnttab", "r"); // Fairly standard -# elif defined(__sgi) || defined(linux) - mtab = fopen("/etc/mtab", "r"); // More standard -# else - mtab = fopen("/etc/fstab", "r"); // Otherwise fallback to full list - if (mtab == NULL) - mtab = fopen("/etc/vfstab", "r"); -# endif - - if (mtab != NULL) - { - while (fgets(line, sizeof(line), mtab) != NULL) - { - if (line[0] == '#' || line[0] == '\n') - continue; - if (sscanf(line, "%*s%4095s", filename) != 1) - continue; - - strncat(filename, "/", sizeof(filename) - 1); - -// printf("Fl_FileBrowser::load() - adding \"%s\" to list...\n", filename); - add(filename, icon); - num_files ++; - } - - fclose(mtab); - } -#endif // WIN32 || __EMX__ - } - else - { - dirent **files; // Files in in directory - - - // - // Build the file list... - // - -#if defined(WIN32) || defined(__EMX__) - strncpy(filename, directory_, sizeof(filename) - 1); - filename[sizeof(filename) - 1] = '\0'; - i = strlen(filename) - 1; - - if (i == 2 && filename[1] == ':' && - (filename[2] == '/' || filename[2] == '\\')) - filename[2] = '/'; - else if (filename[i] != '/' && filename[i] != '\\') - strcat(filename, "/"); - - num_files = filename_list(filename, &files); -#else - num_files = filename_list(directory_, &files); -#endif /* WIN32 || __EMX__ */ - - if (num_files <= 0) - return (0); - - for (i = 0, num_dirs = 0; i < num_files; i ++) - { - if (strcmp(files[i]->d_name, ".") != 0 && - strcmp(files[i]->d_name, "..") != 0) - { - snprintf(filename, sizeof(filename), "%s/%s", directory_, - files[i]->d_name); - - if (filename_isdir(filename)) - { - char name[1024]; // Temporary directory name - - snprintf(name, sizeof(name), "%s/", files[i]->d_name); - - num_dirs ++; - insert(num_dirs, name, Fl_FileIcon::find(filename)); - } - else if (filetype_ == FILES && - filename_match(files[i]->d_name, pattern_)) - add(files[i]->d_name, Fl_FileIcon::find(filename)); - } - - free(files[i]); - } - - free(files); - } - - return (num_files); -} - - -// -// 'Fl_FileBrowser::filter()' - Set the filename filter. -// - -void -Fl_FileBrowser::filter(const char *pattern) // I - Pattern string -{ - // If pattern is NULL set the pattern to "*"... - if (pattern) - pattern_ = pattern; - else - pattern_ = "*"; - - // Reload the current directory... - load(directory_); -} - - -// -// End of "$Id: Fl_FileBrowser.cxx,v 1.13.2.5 2001/09/04 13:13:29 easysw Exp $". -// diff --git a/src/Fl_FileChooser.cxx b/src/Fl_FileChooser.cxx deleted file mode 100644 index 724324f8c..000000000 --- a/src/Fl_FileChooser.cxx +++ /dev/null @@ -1,255 +0,0 @@ -// generated by Fast Light User Interface Designer (fluid) version 1.0100 - -#include "../FL/Fl_FileChooser.H" - -inline void Fl_FileChooser::cb_window_i(Fl_Window*, void*) { - fileList->deselect(); -fileName->value(""); -window->hide(); -} -void Fl_FileChooser::cb_window(Fl_Window* o, void* v) { - ((Fl_FileChooser*)(o->user_data()))->cb_window_i(o,v); -} - -inline void Fl_FileChooser::cb_fileList_i(Fl_FileBrowser*, void*) { - fileListCB(); -} -void Fl_FileChooser::cb_fileList(Fl_FileBrowser* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_fileList_i(o,v); -} - -inline void Fl_FileChooser::cb_Cancel_i(Fl_Button*, void*) { - fileList->deselect(); -fileName->value(""); -window->hide(); -} -void Fl_FileChooser::cb_Cancel(Fl_Button* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_Cancel_i(o,v); -} - -inline void Fl_FileChooser::cb_okButton_i(Fl_Return_Button*, void*) { - // Do any callback that is registered... -if (callback_) - (*callback_)(this, data_); - -window->hide(); -} -void Fl_FileChooser::cb_okButton(Fl_Return_Button* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_okButton_i(o,v); -} - -inline void Fl_FileChooser::cb_fileName_i(Fl_Input*, void*) { - fileNameCB(); -} -void Fl_FileChooser::cb_fileName(Fl_Input* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_fileName_i(o,v); -} - -inline void Fl_FileChooser::cb_upButton_i(Fl_Button*, void*) { - up(); -} -void Fl_FileChooser::cb_upButton(Fl_Button* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_upButton_i(o,v); -} - -#include -static unsigned char bits_up[] = -"\0\0x\0\204\0\2\1""1\376y\200\375\200""1\200""1\200""1\200""1\200""1\200\1\ -\200\1\200\377\377\0\0"; -static Fl_Bitmap bitmap_up(bits_up, 16, 16); - -inline void Fl_FileChooser::cb_newButton_i(Fl_Button*, void*) { - newdir(); -} -void Fl_FileChooser::cb_newButton(Fl_Button* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_newButton_i(o,v); -} - -static unsigned char bits_new[] = -"\0\0x\0\204\0\2\1\1\376\1\200""1\200""1\200\375\200\375\200""1\200""1\200\1\ -\200\1\200\377\377\0\0"; -static Fl_Bitmap bitmap_new(bits_new, 16, 16); - -inline void Fl_FileChooser::cb_dirMenu_i(Fl_Choice*, void*) { - char pathname[1024]; -int i; - -pathname[0] = '\0'; -for (i = 1; i <= dirMenu->value(); i ++) - strcat(pathname, dirMenu->text(i)); -directory(pathname); -} -void Fl_FileChooser::cb_dirMenu(Fl_Choice* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb_dirMenu_i(o,v); -} - -inline void Fl_FileChooser::cb__i(Fl_Button*, void*) { - const char *f; -if ((f = fl_input("New Filter?", - fileList->filter())) != NULL) -{ - fileList->filter(f); - rescan(); -}; -} -void Fl_FileChooser::cb_(Fl_Button* o, void* v) { - ((Fl_FileChooser*)(o->parent()->user_data()))->cb__i(o,v); -} - -static unsigned char bits_allfiles[] = -"\374?\4 \4 \4 \204!\244%\304#\364/\364/\304#\244%\204!\4 \4 \4 \374?"; -static Fl_Bitmap bitmap_allfiles(bits_allfiles, 16, 16); - -Fl_FileChooser::Fl_FileChooser(const char *d, const char *p, int t, const char *title) { - Fl_Window* w; - { Fl_Window* o = window = new Fl_Window(375, 315, "Pick a File"); - w = o; - o->callback((Fl_Callback*)cb_window, (void*)(this)); - w->hotspot(o); - { Fl_FileBrowser* o = fileList = new Fl_FileBrowser(10, 45, 355, 180); - o->type(2); - o->callback((Fl_Callback*)cb_fileList); - Fl_Group::current()->resizable(o); - w->hotspot(o); - } - { Fl_Button* o = new Fl_Button(285, 280, 80, 25, "Cancel"); - o->callback((Fl_Callback*)cb_Cancel); - o->label(fl_cancel); - } - { Fl_Return_Button* o = okButton = new Fl_Return_Button(200, 280, 75, 25, "OK"); - o->callback((Fl_Callback*)cb_okButton); - okButton->label(fl_ok); - } - { Fl_Input* o = fileName = new Fl_Input(10, 245, 355, 25, "Filename:"); - o->callback((Fl_Callback*)cb_fileName); - o->align(FL_ALIGN_TOP_LEFT); - o->when(FL_WHEN_ENTER_KEY); - fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS); - } - { Fl_Button* o = upButton = new Fl_Button(280, 10, 25, 25); - o->image(bitmap_up); - o->labelsize(8); - o->callback((Fl_Callback*)cb_upButton); - } - { Fl_Button* o = newButton = new Fl_Button(310, 10, 25, 25); - o->image(bitmap_new); - o->labelsize(8); - o->callback((Fl_Callback*)cb_newButton); - } - { Fl_Choice* o = dirMenu = new Fl_Choice(95, 10, 180, 25, "Directory:"); - o->down_box(FL_BORDER_BOX); - o->callback((Fl_Callback*)cb_dirMenu); - } - { Fl_Button* o = new Fl_Button(340, 10, 25, 25); - o->image(bitmap_allfiles); - o->labelsize(28); - o->labelcolor(4); - o->callback((Fl_Callback*)cb_); - o->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); - } - if (title) window->label(title); - o->set_modal(); - o->end(); - } - window->size_range(345, 270, 345); -fileList->filter(p); -type(t); -value(d); -callback_ = 0; -data_ = 0; -} - -void Fl_FileChooser::callback(void (*cb)(Fl_FileChooser *, void *), void *d) { - callback_ = cb; -data_ = d; -} - -void Fl_FileChooser::color(Fl_Color c) { - fileList->color(c); -} - -Fl_Color Fl_FileChooser::color() { - return (fileList->color()); -} - -char * Fl_FileChooser::directory() { - return directory_; -} - -void Fl_FileChooser::filter(const char *p) { - fileList->filter(p); -rescan(); -} - -const char * Fl_FileChooser::filter() { - return (fileList->filter()); -} - -void Fl_FileChooser::hide() { - window->hide(); -} - -void Fl_FileChooser::iconsize(uchar s) { - fileList->iconsize(s); -} - -uchar Fl_FileChooser::iconsize() { - return (fileList->iconsize()); -} - -void Fl_FileChooser::label(const char *l) { - window->label(l); -} - -const char * Fl_FileChooser::label() { - return (window->label()); -} - -void Fl_FileChooser::show() { - window->show(); -fileList->deselect(); -} - -void Fl_FileChooser::textcolor(Fl_Color c) { - fileList->textcolor(c); -} - -Fl_Color Fl_FileChooser::textcolor() { - return (fileList->textcolor()); -} - -void Fl_FileChooser::textfont(uchar f) { - fileList->textfont(f); -} - -uchar Fl_FileChooser::textfont() { - return (fileList->textfont()); -} - -void Fl_FileChooser::textsize(uchar s) { - fileList->textsize(s); -} - -uchar Fl_FileChooser::textsize() { - return (fileList->textsize()); -} - -void Fl_FileChooser::type(int t) { - type_ = t; -if (t == MULTI) - fileList->type(FL_MULTI_BROWSER); -else - fileList->type(FL_HOLD_BROWSER); -if (t != CREATE) - newButton->deactivate(); -else - newButton->activate(); -} - -int Fl_FileChooser::type() { - return (type_); -} - -int Fl_FileChooser::visible() { - return window->visible(); -} diff --git a/src/Fl_FileChooser.fl b/src/Fl_FileChooser.fl deleted file mode 100644 index ac11c961b..000000000 --- a/src/Fl_FileChooser.fl +++ /dev/null @@ -1,206 +0,0 @@ -# data file for the Fltk User Interface Designer (fluid) -version 1.0100 -header_name {../FL/Fl_FileChooser.H} -code_name {.cxx} -gridx 5 -gridy 5 -snap 3 -class Fl_FileChooser {open -} { - decl {enum { SINGLE, MULTI, CREATE };} {public - } - Function {Fl_FileChooser(const char *d, const char *p, int t, const char *title)} {open - } { - Fl_Window window { - label {Pick a File} - callback {fileList->deselect(); -fileName->value(""); -window->hide();} open - private xywh {99 225 375 315} resizable hotspot - code0 {if (title) window->label(title);} - code1 {\#include } - code2 {\#include } - code3 {\#include } modal visible - } { - Fl_Browser fileList { - callback {fileListCB();} - private xywh {10 45 355 180} type Hold resizable hotspot - code0 {\#include } - class Fl_FileBrowser - } - Fl_Button {} { - label Cancel - callback {fileList->deselect(); -fileName->value(""); -window->hide();} - private xywh {285 280 80 25} - code0 {o->label(fl_cancel);} - } - Fl_Return_Button okButton { - label OK - callback {// Do any callback that is registered... -if (callback_) - (*callback_)(this, data_); - -window->hide();} - private xywh {200 280 75 25} - code0 {\#include } - code1 {okButton->label(fl_ok);} - } - Fl_Input fileName { - label {Filename:} - callback {fileNameCB();} - private xywh {10 245 355 25} align 5 when 8 - code0 {fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS);} - } - Fl_Button upButton { - callback {up();} selected - private image {up.xbm} xywh {280 10 25 25} labelsize 8 - } - Fl_Button newButton { - callback {newdir();} - private image {new.xbm} xywh {310 10 25 25} labelsize 8 - } - Fl_Choice dirMenu { - label {Directory:} - callback {char pathname[1024]; -int i; - -pathname[0] = '\\0'; -for (i = 1; i <= dirMenu->value(); i ++) - strcat(pathname, dirMenu->text(i)); -directory(pathname);} open - private xywh {95 10 180 25} down_box BORDER_BOX - } {} - Fl_Button {} { - callback {const char *f; -if ((f = fl_input("New Filter?", - fileList->filter())) != NULL) -{ - fileList->filter(f); - rescan(); -}} - private image {allfiles.xbm} xywh {340 10 25 25} labelsize 28 labelcolor 4 align 16 - code0 {\#include } - } - } - code {window->size_range(345, 270, 345); -fileList->filter(p); -type(t); -value(d); -callback_ = 0; -data_ = 0;} {} - } - decl {void (*callback_)(Fl_FileChooser*, void *);} {} - decl {void *data_;} {} - decl {char directory_[1024];} {} - decl {int type_;} {} - decl {void fileListCB();} {} - decl {void fileNameCB();} {} - decl {void newdir();} {} - decl {void up();} {} - Function {callback(void (*cb)(Fl_FileChooser *, void *), void *d)} {return_type void - } { - code {callback_ = cb; -data_ = d;} {} - } - Function {color(Fl_Color c)} {} { - code {fileList->color(c);} {} - } - Function {color()} {return_type Fl_Color - } { - code {return (fileList->color());} {} - } - decl {int count();} {public - } - decl {void directory(const char *d);} {public - } - Function {directory()} {return_type {char *} - } { - code {return directory_;} {} - } - Function {filter(const char *p)} {return_type void - } { - code {fileList->filter(p); -rescan();} {} - } - Function {filter()} {return_type {const char *} - } { - code {return (fileList->filter());} {} - } - Function {hide()} {return_type void - } { - code {window->hide();} {} - } - Function {iconsize(uchar s)} {return_type void - } { - code {fileList->iconsize(s);} {} - } - Function {iconsize()} {return_type uchar - } { - code {return (fileList->iconsize());} {} - } - Function {label(const char *l)} {return_type void - } { - code {window->label(l);} {} - } - Function {label()} {return_type {const char *} - } { - code {return (window->label());} {} - } - decl {void rescan();} {public - } - Function {show()} {return_type void - } { - code {window->show(); -fileList->deselect();} {} - } - Function {textcolor(Fl_Color c)} {return_type void - } { - code {fileList->textcolor(c);} {} - } - Function {textcolor()} {return_type Fl_Color - } { - code {return (fileList->textcolor());} {} - } - Function {textfont(uchar f)} {return_type void - } { - code {fileList->textfont(f);} {} - } - Function {textfont()} {return_type uchar - } { - code {return (fileList->textfont());} {} - } - Function {textsize(uchar s)} {return_type void - } { - code {fileList->textsize(s);} {} - } - Function {textsize()} {return_type uchar - } { - code {return (fileList->textsize());} {} - } - Function {type(int t)} {return_type void - } { - code {type_ = t; -if (t == MULTI) - fileList->type(FL_MULTI_BROWSER); -else - fileList->type(FL_HOLD_BROWSER); -if (t != CREATE) - newButton->deactivate(); -else - newButton->activate();} {} - } - Function {type()} {return_type int - } { - code {return (type_);} {} - } - decl {const char *value(int f = 1);} {public - } - decl {void value(const char *filename);} {public - } - Function {visible()} {return_type int - } { - code {return window->visible();} {} - } -} diff --git a/src/Fl_FileChooser2.cxx b/src/Fl_FileChooser2.cxx deleted file mode 100644 index e353f56f2..000000000 --- a/src/Fl_FileChooser2.cxx +++ /dev/null @@ -1,695 +0,0 @@ -// -// "$Id: Fl_FileChooser2.cxx,v 1.15.2.2 2001/08/04 12:21:33 easysw Exp $" -// -// More Fl_FileChooser routines. -// -// Copyright 1999-2001 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems to "fltk-bugs@fltk.org". -// -// Contents: -// -// Fl_FileChooser::directory() - Set the directory in the file chooser. -// Fl_FileChooser::count() - Return the number of selected files. -// Fl_FileChooser::value() - Return a selected filename. -// Fl_FileChooser::up() - Go up one directory. -// Fl_FileChooser::newdir() - Make a new directory. -// Fl_FileChooser::rescan() - Rescan the current directory. -// Fl_FileChooser::fileListCB() - Handle clicks (and double-clicks) in the -// FileBrowser. -// Fl_FileChooser::fileNameCB() - Handle text entry in the FileBrowser. -// - -// -// Include necessary headers. -// - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(WIN32) -# include -# include -#else -# include -# include -#endif /* WIN32 */ - - -// -// 'Fl_FileChooser::directory()' - Set the directory in the file chooser. -// - -void -Fl_FileChooser::directory(const char *d) // I - Directory to change to -{ - char pathname[1024], // Full path of directory - *pathptr, // Pointer into full path - *dirptr; // Pointer into directory - int levels; // Number of levels in directory - - -// printf("Fl_FileChooser::directory(\"%s\")\n", d == NULL ? "(null)" : d); - - // NULL == current directory - if (d == NULL) - d = "."; - - if (d[0] != '\0') - { - // Make the directory absolute... -#if defined(WIN32) || defined(__EMX__) - if (d[0] != '/' && d[0] != '\\' && d[1] != ':') -#else - if (d[0] != '/' && d[0] != '\\') -#endif /* WIN32 || __EMX__ */ - filename_absolute(directory_, d); - else - { - strncpy(directory_, d, sizeof(directory_) - 1); - directory_[sizeof(directory_) - 1] = '\0'; - } - - // Strip any trailing slash and/or period... - dirptr = directory_ + strlen(directory_) - 1; - if (*dirptr == '.') - *dirptr-- = '\0'; - if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_) - *dirptr = '\0'; - } - else - directory_[0] = '\0'; - - // Clear the directory menu and fill it as needed... - dirMenu->clear(); -#if defined(WIN32) || defined(__EMX__) - dirMenu->add("My Computer"); -#else - dirMenu->add("File Systems"); -#endif /* WIN32 || __EMX__ */ - - levels = 0; - for (dirptr = directory_, pathptr = pathname; *dirptr != '\0';) - { - if (*dirptr == '/' || *dirptr == '\\') - { - // Need to quote the slash first, and then add it to the menu... - *pathptr++ = '\\'; - *pathptr++ = '/'; - *pathptr++ = '\0'; - dirptr ++; - - dirMenu->add(pathname); - levels ++; - pathptr = pathname; - } - else - *pathptr++ = *dirptr++; - } - - if (pathptr > pathname) - { - *pathptr = '\0'; - dirMenu->add(pathname); - levels ++; - } - - dirMenu->value(levels); - - // Rescan the directory... - rescan(); -} - - -// -// 'Fl_FileChooser::count()' - Return the number of selected files. -// - -int // O - Number of selected files -Fl_FileChooser::count() -{ - int i; // Looping var - int count; // Number of selected files - const char *filename; // Filename in input field or list - char pathname[1024]; // Full path to file - - - if (type_ != MULTI) - { - // Check to see if the file name input field is blank... - filename = fileName->value(); - if (filename == NULL || filename[0] == '\0') - return (0); - - // Is the file name a directory? - if (directory_[0] != '\0') - sprintf(pathname, "%s/%s", directory_, filename); - else - { - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } - - if (filename_isdir(pathname)) - return (0); - else - return (1); - } - - for (i = 1, count = 0; i <= fileList->size(); i ++) - if (fileList->selected(i)) - { - // See if this file is a directory... - filename = (char *)fileList->text(i); - if (directory_[0] != '\0') - sprintf(pathname, "%s/%s", directory_, filename); - else - { - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } - - if (!filename_isdir(pathname)) - count ++; - } - - return (count); -} - - -// -// 'Fl_FileChooser::value()' - Return a selected filename. -// - -const char * // O - Filename or NULL -Fl_FileChooser::value(int f) // I - File number -{ - int i; // Looping var - int count; // Number of selected files - const char *name; // Current filename - static char pathname[1024]; // Filename + directory - - - if (type_ != MULTI) - { - name = fileName->value(); - if (name[0] == '\0') - return (NULL); - - sprintf(pathname, "%s/%s", directory_, name); - return ((const char *)pathname); - } - - for (i = 1, count = 0; i <= fileList->size(); i ++) - if (fileList->selected(i)) - { - // See if this file is a directory... - name = fileList->text(i); - sprintf(pathname, "%s/%s", directory_, name); - - if (!filename_isdir(pathname)) - { - // Nope, see if this this is "the one"... - count ++; - if (count == f) - return ((const char *)pathname); - } - } - - return (NULL); -} - - -// -// 'Fl_FileChooser::value()' - Set the current filename. -// - -void -Fl_FileChooser::value(const char *filename) // I - Filename + directory -{ - int i, // Looping var - count; // Number of items in list - char *slash; // Directory separator - char pathname[1024]; // Local copy of filename - - -// printf("Fl_FileChooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename); - - // See if the filename is actually a directory... - if (filename == NULL || !filename[0] || filename_isdir(filename)) - { - // Yes, just change the current directory... - directory(filename); - return; - } - - // Switch to single-selection mode as needed - if (type_ == MULTI) - type(SINGLE); - - // See if there is a directory in there... - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - - if ((slash = strrchr(pathname, '/')) == NULL) - slash = strrchr(pathname, '\\'); - - if (slash != NULL) - { - // Yes, change the display to the directory... - *slash++ = '\0'; - directory(pathname); - } - else - slash = pathname; - - // Set the input field to the remaining portion - fileName->value(slash); - fileName->position(0, strlen(slash)); - okButton->activate(); - - // Then find the file in the file list and select it... - count = fileList->size(); - - for (i = 1; i <= count; i ++) - if (strcmp(fileList->text(i), slash) == 0) - { - fileList->select(i); - break; - } -} - - -// -// 'Fl_FileChooser::up()' - Go up one directory. -// - -void -Fl_FileChooser::up() -{ - char *slash; // Trailing slash - - - if ((slash = strrchr(directory_, '/')) == NULL) - slash = strrchr(directory_, '\\'); - - if (directory_[0] != '\0') - dirMenu->value(dirMenu->value() - 1); - - if (slash != NULL) - *slash = '\0'; - else - { - upButton->deactivate(); - directory_[0] = '\0'; - } - - rescan(); -} - - -// -// 'Fl_FileChooser::newdir()' - Make a new directory. -// - -void -Fl_FileChooser::newdir() -{ - const char *dir; // New directory name - char pathname[1024]; // Full path of directory - - - // Get a directory name from the user - if ((dir = fl_input("New Directory?", NULL)) == NULL) - return; - - // Make it relative to the current directory as needed... -#if defined(WIN32) || defined(__EMX__) - if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':') -#else - if (dir[0] != '/' && dir[0] != '\\') -#endif /* WIN32 || __EMX__ */ - sprintf(pathname, "%s/%s", directory_, dir); - else - { - strncpy(pathname, dir, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } - - // Create the directory; ignore EEXIST errors... -#if defined(WIN32) - if (mkdir(pathname)) -#else - if (mkdir(pathname, 0777)) -#endif /* WIN32 */ - if (errno != EEXIST) - { - fl_alert("Unable to create directory!"); - return; - } - - // Show the new directory... - directory(pathname); -} - - -// -// 'Fl_FileChooser::rescan()' - Rescan the current directory. -// - -void -Fl_FileChooser::rescan() -{ -// printf("Fl_FileChooser::rescan(); directory = \"%s\"\n", directory_); - - // Clear the current filename - fileName->value(""); - okButton->deactivate(); - - // Build the file list... - fileList->load(directory_); -} - - -// -// 'Fl_FileChooser::fileListCB()' - Handle clicks (and double-clicks) in the -// FileBrowser. -// - -void -Fl_FileChooser::fileListCB() -{ - char *filename, // New filename - pathname[1024]; // Full pathname to file - - - filename = (char *)fileList->text(fileList->value()); - if (directory_[0] != '\0') - sprintf(pathname, "%s/%s", directory_, filename); - else - { - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } - - if (Fl::event_clicks()) - { -#if defined(WIN32) || defined(__EMX__) - if ((strlen(pathname) == 2 && pathname[1] == ':') || - filename_isdir(pathname)) -#else - if (filename_isdir(pathname)) -#endif /* WIN32 || __EMX__ */ - { - directory(pathname); - upButton->activate(); - } - else - { - // Do any callback that is registered... - if (callback_) - (*callback_)(this, data_); - - // Hide the window... - window->hide(); - } - } - else - { - fileName->value(filename); - - if (!filename_isdir(pathname)) - okButton->activate(); - } -} - - -// -// 'Fl_FileChooser::fileNameCB()' - Handle text entry in the FileBrowser. -// - -void -Fl_FileChooser::fileNameCB() -{ - char *filename, // New filename - *slash, // Pointer to trailing slash - pathname[1024]; // Full pathname to file - int i, // Looping var - min_match, // Minimum number of matching chars - max_match, // Maximum number of matching chars - num_files, // Number of files in directory - first_line; // First matching line - const char *file; // File from directory - - - // Get the filename from the text field... - filename = (char *)fileName->value(); - - if (filename == NULL || filename[0] == '\0') - { - okButton->deactivate(); - return; - } - -#if defined(WIN32) || defined(__EMX__) - if (directory_[0] != '\0' && - filename[0] != '/' && - filename[0] != '\\' && - !(isalpha(filename[0]) && filename[1] == ':')) - sprintf(pathname, "%s/%s", directory_, filename); - else - { - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } -#else - if (filename[0] == '~') - { - // Lookup user... - struct passwd *pwd; - - if (!filename[1] || filename[1] == '/') - pwd = getpwuid(getuid()); - else - { - strncpy(pathname, filename + 1, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - - i = strlen(pathname) - 1; - if (pathname[i] == '/') - pathname[i] = '\0'; - - pwd = getpwnam(pathname); - } - - if (pwd) - { - strncpy(pathname, pwd->pw_dir, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - - if (filename[strlen(filename) - 1] == '/') - strncat(pathname, "/", sizeof(pathname) - 1); - } - else - sprintf(pathname, "%s/%s", directory_, filename); - - endpwent(); - } - else if (directory_[0] != '\0' && - filename[0] != '/') - sprintf(pathname, "%s/%s", directory_, filename); - else - { - strncpy(pathname, filename, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - } -#endif /* WIN32 || __EMX__ */ - - if (Fl::event_key() == FL_Enter) - { - // Enter pressed - select or change directory... - -#if defined(WIN32) || defined(__EMX__) - if ((strlen(pathname) == 2 && pathname[1] == ':') || - filename_isdir(pathname)) -#else - if (filename_isdir(pathname)) -#endif /* WIN32 || __EMX__ */ - directory(pathname); - else if (type_ == CREATE || access(pathname, 0) == 0) - { - // New file or file exists... If we are in multiple selection mode, - // switch to single selection mode... - if (type_ == MULTI) - type(SINGLE); - - // Do any callback that is registered... - if (callback_) - (*callback_)(this, data_); - - // Hide the window to signal things are done... - window->hide(); - } - else - { - // File doesn't exist, so beep at and alert the user... - // TODO: NEED TO ADD fl_beep() FUNCTION TO 2.0! -#ifdef WIN32 - MessageBeep(MB_ICONEXCLAMATION); -#else - XBell(fl_display, 100); -#endif // WIN32 - - fl_alert("Please choose an existing file!"); - } - } - else if (Fl::event_key() != FL_Delete) - { - // Check to see if the user has entered a directory... - if ((slash = strrchr(filename, '/')) == NULL) - slash = strrchr(filename, '\\'); - - if (slash != NULL) - { - // Yes, change directories and update the file name field... - if ((slash = strrchr(pathname, '/')) == NULL) - slash = strrchr(pathname, '\\'); - - if (slash > pathname) // Special case for "/" - *slash++ = '\0'; - else - slash++; - - if (strcmp(filename, "../") == 0) // Special case for "../" - up(); - else - directory(pathname); - - // If the string ended after the slash, we're done for now... - if (*slash == '\0') - return; - - // Otherwise copy the remainder and proceed... - fileName->value(slash); - fileName->position(strlen(slash)); - filename = slash; - } - - // Other key pressed - do filename completion as possible... - num_files = fileList->size(); - min_match = strlen(filename); - max_match = 100000; - first_line = 0; - - for (i = 1; i <= num_files && max_match > min_match; i ++) - { - file = fileList->text(i); - -#if defined(WIN32) || defined(__EMX__) - if (strnicmp(filename, file, min_match) == 0) -#else - if (strncmp(filename, file, min_match) == 0) -#endif // WIN32 || __EMX__ - { - // OK, this one matches; check against the previous match - if (max_match == 100000) - { - // First match; copy stuff over... - strncpy(pathname, file, sizeof(pathname) - 1); - pathname[sizeof(pathname) - 1] = '\0'; - max_match = strlen(pathname); - - // Strip trailing /, if any... - if (pathname[max_match - 1] == '/') - { - max_match --; - pathname[max_match] = '\0'; - } - - // And then make sure that the item is visible - fileList->topline(i); - first_line = i; - } - else - { - // Succeeding match; compare to find maximum string match... - while (max_match > min_match) -#if defined(WIN32) || defined(__EMX__) - if (strnicmp(file, pathname, max_match) == 0) -#else - if (strncmp(file, pathname, max_match) == 0) -#endif // WIN32 || __EMX__ - break; - else - max_match --; - - // Truncate the string as needed... - pathname[max_match] = '\0'; - } - } - } - - fileList->deselect(0); - fileList->redraw(); - - // If we have any matches, add them to the input field... - if (first_line > 0 && min_match == max_match && - max_match == (int)strlen(fileList->text(first_line))) - fileList->select(first_line); - else if (max_match > min_match && max_match != 100000) - { - // Add the matching portion... - fileName->replace(0, min_match, pathname); - - // Highlight it; if the user just pressed the backspace - // key, position the cursor at the start of the selection. - // Otherwise, put the cursor at the end of the selection so - // s/he can press the right arrow to accept the selection - // (Tab and End also do this for both cases.) - if (Fl::event_key() == FL_BackSpace) - fileName->position(min_match - 1, max_match); - else - fileName->position(max_match, min_match); - } - - // See if we need to enable the OK button... - sprintf(pathname, "%s/%s", directory_, fileName->value()); - - if ((type_ == CREATE || access(pathname, 0) == 0) && - !filename_isdir(pathname)) - okButton->activate(); - else - okButton->deactivate(); - } -} - - -// -// End of "$Id: Fl_FileChooser2.cxx,v 1.15.2.2 2001/08/04 12:21:33 easysw Exp $". -// diff --git a/src/Fl_FileIcon.cxx b/src/Fl_FileIcon.cxx deleted file mode 100644 index dc0273d95..000000000 --- a/src/Fl_FileIcon.cxx +++ /dev/null @@ -1,1225 +0,0 @@ -// -// "$Id: Fl_FileIcon.cxx,v 1.10.2.1 2001/08/02 16:17:04 easysw Exp $" -// -// Fl_FileIcon routines. -// -// KDE icon code donated by Maarten De Boer. -// -// Copyright 1999-2001 by Michael Sweet. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems to "fltk-bugs@fltk.org". -// -// Contents: -// -// Fl_FileIcon::Fl_FileIcon() - Create a new file icon. -// Fl_FileIcon::~Fl_FileIcon() - Remove a file icon. -// Fl_FileIcon::add() - Add data to an icon. -// Fl_FileIcon::find() - Find an icon based upon a given file. -// Fl_FileIcon::draw() - Draw an icon. -// Fl_FileIcon::label() - Set the widgets label to an icon. -// Fl_FileIcon::labeltype() - Draw the icon label. -// Fl_FileIcon::load() - Load an icon file... -// Fl_FileIcon::load_fti() - Load an SGI-format FTI file... -// Fl_FileIcon::load_xpm() - Load an XPM icon file... -// Fl_FileIcon::load_system_icons() - Load the standard system icons/filetypes. -// - -// -// Include necessary header files... -// - -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -# include -#endif /* HAVE_STRINGS_H */ -#include -#include -#include -#include -#if defined(WIN32) || defined(__EMX__) -# include -# define F_OK 0 -# define strcasecmp stricmp -# define strncasecmp strnicmp -#else -# include -#endif /* WIN32 || __EMX__ */ - -#include -#include -#include -#include - - -// -// Define missing POSIX/XPG4 macros as needed... -// - -#ifndef S_ISDIR -# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif /* !S_ISDIR */ - - -// -// Icon cache... -// - -Fl_FileIcon *Fl_FileIcon::first_ = (Fl_FileIcon *)0; - - -// -// Local functions... -// - -static void load_kde_icons(const char *directory); -static void load_kde_mimelnk(const char *filename); -static char *kde_to_fltk_pattern(const char *kdepattern); -static char *get_kde_val(char *str, const char *key); - - -// -// 'Fl_FileIcon::Fl_FileIcon()' - Create a new file icon. -// - -Fl_FileIcon::Fl_FileIcon(const char *p, /* I - Filename pattern */ - int t, /* I - File type */ - int nd, /* I - Number of data values */ - short *d) /* I - Data values */ -{ - // Initialize the pattern and type... - pattern_ = p; - type_ = t; - - // Copy icon data as needed... - if (nd) - { - num_data_ = nd; - alloc_data_ = nd + 1; - data_ = (short *)calloc(sizeof(short), nd + 1); - memcpy(data_, d, nd * sizeof(short)); - } - else - { - num_data_ = 0; - alloc_data_ = 0; - } - - // And add the icon to the list of icons... - next_ = first_; - first_ = this; -} - - -// -// 'Fl_FileIcon::~Fl_FileIcon()' - Remove a file icon. -// - -Fl_FileIcon::~Fl_FileIcon() -{ - Fl_FileIcon *current, // Current icon in list - *prev; // Previous icon in list - - - // Find the icon in the list... - for (current = first_, prev = (Fl_FileIcon *)0; - current != this && current != (Fl_FileIcon *)0; - prev = current, current = current->next_); - - // Remove the icon from the list as needed... - if (current) - { - if (prev) - prev->next_ = current->next_; - else - first_ = current->next_; - } - - // Free any memory used... - if (alloc_data_) - free(data_); -} - - -// -// 'Fl_FileIcon::add()' - Add data to an icon. -// - -short * // O - Pointer to new data value -Fl_FileIcon::add(short d) // I - Data to add -{ - short *dptr; // Pointer to new data value - - - // Allocate/reallocate memory as needed - if ((num_data_ + 1) >= alloc_data_) - { - alloc_data_ += 128; - - if (alloc_data_ == 128) - dptr = (short *)malloc(sizeof(short) * alloc_data_); - else - dptr = (short *)realloc(data_, sizeof(short) * alloc_data_); - - if (dptr == NULL) - return (NULL); - - data_ = dptr; - } - - // Store the new data value and return - data_[num_data_++] = d; - data_[num_data_] = END; - - return (data_ + num_data_ - 1); -} - - -// -// 'Fl_FileIcon::find()' - Find an icon based upon a given file. -// - -Fl_FileIcon * // O - Matching file icon or NULL -Fl_FileIcon::find(const char *filename, // I - Name of file */ - int filetype) // I - Enumerated file type -{ - Fl_FileIcon *current; // Current file in list - struct stat fileinfo; // Information on file - - - // Get file information if needed... - if (filetype == ANY) - if (!stat(filename, &fileinfo)) - { - if (S_ISDIR(fileinfo.st_mode)) - filetype = DIRECTORY; -#ifdef S_IFIFO - else if (S_ISFIFO(fileinfo.st_mode)) - filetype = FIFO; -#endif // S_IFIFO -#if defined(S_ICHR) && defined(S_IBLK) - else if (S_ISCHR(fileinfo.st_mode) || S_ISBLK(fileinfo.st_mode)) - filetype = DEVICE; -#endif // S_ICHR && S_IBLK -#ifdef S_ILNK - else if (S_ISLNK(fileinfo.st_mode)) - filetype = LINK; -#endif // S_ILNK - else - filetype = PLAIN; - } - - // Loop through the available file types and return any match that - // is found... - for (current = first_; current != (Fl_FileIcon *)0; current = current->next_) - if ((current->type_ == filetype || current->type_ == ANY) && - filename_match(filename, current->pattern_)) - break; - - // Return the match (if any)... - return (current); -} - - -// -// 'Fl_FileIcon::draw()' - Draw an icon. -// - -void -Fl_FileIcon::draw(int x, // I - Upper-lefthand X - int y, // I - Upper-lefthand Y - int w, // I - Width of bounding box - int h, // I - Height of bounding box - Fl_Color ic, // I - Icon color... - int active) // I - Active or inactive? -{ - Fl_Color c; // Current color - short *d; // Pointer to data - short *prim; // Pointer to start of primitive... - double scale; // Scale of icon - - - // Don't try to draw a NULL array! - if (num_data_ == 0) - return; - - // Setup the transform matrix as needed... - scale = w < h ? w : h; - - fl_push_matrix(); - fl_translate((float)x + 0.5 * ((float)w - scale), - (float)y + 0.5 * ((float)h + scale)); - fl_scale(scale, -scale); - - // Loop through the array until we see an unmatched END... - d = data_; - prim = NULL; - c = ic; - - if (active) - fl_color(c); - else - fl_color(inactive(c)); - - while (*d != END || prim) - switch (*d) - { - case END : - switch (*prim) - { - case LINE : - fl_end_line(); - break; - - case CLOSEDLINE : - fl_end_loop(); - break; - - case POLYGON : - fl_end_polygon(); - break; - - case OUTLINEPOLYGON : - fl_end_polygon(); - - if (active) - { - if (prim[1] == 256) - fl_color(ic); - else - fl_color((Fl_Color)prim[1]); - } - else - { - if (prim[1] == 256) - fl_color(inactive(ic)); - else - fl_color(inactive((Fl_Color)prim[1])); - } - - fl_begin_loop(); - - prim += 2; - while (*prim == VERTEX) - { - fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); - prim += 3; - } - - fl_end_loop(); - fl_color(c); - break; - } - - prim = NULL; - d ++; - break; - - case COLOR : - if (d[1] == 256) - c = ic; - else - c = (Fl_Color)d[1]; - - if (!active) - c = inactive(c); - - fl_color(c); - d += 2; - break; - - case LINE : - prim = d; - d ++; - fl_begin_line(); - break; - - case CLOSEDLINE : - prim = d; - d ++; - fl_begin_loop(); - break; - - case POLYGON : - prim = d; - d ++; - fl_begin_polygon(); - break; - - case OUTLINEPOLYGON : - prim = d; - d += 2; - fl_begin_polygon(); - break; - - case VERTEX : - if (prim) - fl_vertex(d[1] * 0.0001, d[2] * 0.0001); - d += 3; - break; - } - - // If we still have an open primitive, close it... - if (prim) - switch (*prim) - { - case LINE : - fl_end_line(); - break; - - case CLOSEDLINE : - fl_end_loop(); - break; - - case POLYGON : - fl_end_polygon(); - break; - - case OUTLINEPOLYGON : - fl_end_polygon(); - - if (active) - { - if (prim[1] == 256) - fl_color(ic); - else - fl_color((Fl_Color)prim[1]); - } - else - { - if (prim[1] == 256) - fl_color(inactive(ic)); - else - fl_color(inactive((Fl_Color)prim[1])); - } - - fl_begin_loop(); - - prim += 2; - while (*prim == VERTEX) - { - fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); - prim += 3; - } - - fl_end_loop(); - fl_color(c); - break; - } - - // Restore the transform matrix - fl_pop_matrix(); -} - - -// -// 'Fl_FileIcon::label()' - Set the widget's label to an icon. -// - -void -Fl_FileIcon::label(Fl_Widget *w) // I - Widget to label -{ - Fl::set_labeltype(_FL_ICON_LABEL, labeltype, 0); - w->label(_FL_ICON_LABEL, (const char*)this); -} - - -// -// 'Fl_FileIcon::labeltype()' - Draw the icon label. -// - -void -Fl_FileIcon::labeltype(const Fl_Label *o, // I - Label data - int x, // I - X position of label - int y, // I - Y position of label - int w, // I - Width of label - int h, // I - Height of label - Fl_Align a) // I - Label alignment (not used) -{ - Fl_FileIcon *icon; // Pointer to icon data - - - (void)a; - - icon = (Fl_FileIcon *)(o->value); - - icon->draw(x, y, w, h, (Fl_Color)(o->color)); -} - - -// -// 'Fl_FileIcon::load()' - Load an icon file... -// - -void -Fl_FileIcon::load(const char *f) // I - File to read from -{ - const char *ext; // File extension - - - if ((ext = filename_ext(f)) == NULL) - { - fprintf(stderr, "Fl_FileIcon::load(): Unknown file type for \"%s\".\n", f); - return; - } - - if (strcmp(ext, ".fti") == 0) - load_fti(f); - else if (strcmp(ext, ".xpm") == 0) - load_xpm(f); -#if 0 - else if (strcmp(ext, ".png") == 0) - load_png(f); -#endif /* 0 */ - else - { - fprintf(stderr, "Fl_FileIcon::load(): Unknown file type for \"%s\".\n", f); - return; - } -} - - -// -// 'Fl_FileIcon::load_fti()' - Load an SGI-format FTI file... -// - -void -Fl_FileIcon::load_fti(const char *fti) // I - File to read from -{ - FILE *fp; // File pointer - int ch; // Current character - char command[255], // Command string ("vertex", etc.) - params[255], // Parameter string ("10.0,20.0", etc.) - *ptr; // Pointer into strings - int outline; // Outline polygon - - - // Try to open the file... - if ((fp = fopen(fti, "rb")) == NULL) - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Unable to open \"%s\" - %s\n", - fti, strerror(errno)); - return; - } - - // Read the entire file, adding data as needed... - outline = 0; - - while ((ch = getc(fp)) != EOF) - { - // Skip whitespace - if (isspace(ch)) - continue; - - // Skip comments starting with "#"... - if (ch == '#') - { - while ((ch = getc(fp)) != EOF) - if (ch == '\n') - break; - - if (ch == EOF) - break; - else - continue; - } - - // OK, this character better be a letter... - if (!isalpha(ch)) - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Expected a letter at file position %ld (saw '%c')\n", - ftell(fp) - 1, ch); - break; - } - - // Scan the command name... - ptr = command; - *ptr++ = ch; - - while ((ch = getc(fp)) != EOF) - { - if (ch == '(') - break; - else if (ptr < (command + sizeof(command) - 1)) - *ptr++ = ch; - } - - *ptr++ = '\0'; - - // Make sure we stopped on a parenthesis... - if (ch != '(') - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Expected a ( at file position %ld (saw '%c')\n", - ftell(fp) - 1, ch); - break; - } - - // Scan the parameters... - ptr = params; - - while ((ch = getc(fp)) != EOF) - { - if (ch == ')') - break; - else if (ptr < (params + sizeof(params) - 1)) - *ptr++ = ch; - } - - *ptr++ = '\0'; - - // Make sure we stopped on a parenthesis... - if (ch != ')') - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Expected a ) at file position %ld (saw '%c')\n", - ftell(fp) - 1, ch); - break; - } - - // Make sure the next character is a semicolon... - if ((ch = getc(fp)) != ';') - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Expected a ; at file position %ld (saw '%c')\n", - ftell(fp) - 1, ch); - break; - } - - // Now process the command... - if (strcmp(command, "color") == 0) - { - // Set the color; for negative colors blend the two primaries to - // produce a composite color. Also, the following symbolic color - // names are understood: - // - // name FLTK color - // ------------- ---------- - // iconcolor 256; mapped to the icon color in Fl_FileIcon::draw() - // shadowcolor FL_DARK3 - // outlinecolor FL_BLACK - if (strcmp(params, "iconcolor") == 0) - add_color(256); - else if (strcmp(params, "shadowcolor") == 0) - add_color(FL_DARK3); - else if (strcmp(params, "outlinecolor") == 0) - add_color(FL_BLACK); - else - { - short c = atoi(params); // Color value - - - if (c < 0) - { - // Composite color; compute average... - c = -c; - add_color(fl_color_average((Fl_Color)(c >> 4), - (Fl_Color)(c & 15), 0.5)); - } - else - add_color(c); - } - } - else if (strcmp(command, "bgnline") == 0) - add(LINE); - else if (strcmp(command, "bgnclosedline") == 0) - add(CLOSEDLINE); - else if (strcmp(command, "bgnpolygon") == 0) - add(POLYGON); - else if (strcmp(command, "bgnoutlinepolygon") == 0) - { - add(OUTLINEPOLYGON); - outline = add(0) - data_; - } - else if (strcmp(command, "endoutlinepolygon") == 0 && outline) - { - // Set the outline color; see above for valid values... - if (strcmp(params, "iconcolor") == 0) - data_[outline] = 256; - else if (strcmp(params, "shadowcolor") == 0) - data_[outline] = FL_DARK3; - else if (strcmp(params, "outlinecolor") == 0) - data_[outline] = FL_BLACK; - else - { - short c = atoi(params); // Color value - - - if (c < 0) - { - // Composite color; compute average... - c = -c; - data_[outline] = fl_color_average((Fl_Color)(c >> 4), (Fl_Color)(c & 15), 0.5); - } - else - data_[outline] = c; - } - - outline = 0; - add(END); - } - else if (strncmp(command, "end", 3) == 0) - add(END); - else if (strcmp(command, "vertex") == 0) - { - float x, y; // Coordinates of vertex - - - if (sscanf(params, "%f,%f", &x, &y) != 2) - break; - - add_vertex((short)(x * 100.0 + 0.5), (short)(y * 100.0 + 0.5)); - } - else - { - fprintf(stderr, "Fl_FileIcon::load_fti(): Unknown command \"%s\" at file position %ld.\n", - command, ftell(fp) - 1); - break; - } - } - - // Close the file and return... - fclose(fp); - -#ifdef DEBUG - printf("Icon File \"%s\":\n", fti); - for (int i = 0; i < num_data_; i ++) - printf(" %d,\n", data_[i]); -#endif /* DEBUG */ -} - - -// -// 'Fl_FileIcon::load_xpm()' - Load an XPM icon file... -// - -void -Fl_FileIcon::load_xpm(const char *xpm) // I - File to read from -{ - FILE *fp; // File pointer - int i, j; // Looping vars - int ch; // Current character - int bg; // Background color - char line[1024], // Line from file - val[16], // Color value - *ptr; // Pointer into line - int x, y; // X & Y in image - int startx; // Starting X coord - int width, height; // Width and height of image - int ncolors; // Number of colors - short colors[256]; // Colors - int red, green, blue; // Red, green, and blue values - - - // Try to open the file... - if ((fp = fopen(xpm, "rb")) == NULL) - return; - - // Read the file header until we find the first string... - ptr = NULL; - while (fgets(line, sizeof(line), fp) != NULL) - if ((ptr = strchr(line, '\"')) != NULL) - break; - - if (ptr == NULL) - { - // Nothing to load... - fclose(fp); - return; - } - - // Get the size of the image... - sscanf(ptr + 1, "%d%d%d", &width, &height, &ncolors); - - // Now read the colormap... - memset(colors, 0, sizeof(colors)); - bg = ' '; - - for (i = 0; i < ncolors; i ++) - { - while (fgets(line, sizeof(line), fp) != NULL) - if ((ptr = strchr(line, '\"')) != NULL) - break; - - if (ptr == NULL) - { - // Nothing to load... - fclose(fp); - return; - } - - // Get the color's character - ptr ++; - ch = *ptr++; - - // Get the color value... - if ((ptr = strstr(ptr, "c ")) == NULL) - { - // No color; make this black... - colors[ch] = FL_BLACK; - } - else if (ptr[2] == '#') - { - // Read the RGB triplet... - ptr += 3; - for (j = 0; j < 12; j ++) - if (!isxdigit(ptr[j])) - break; - - switch (j) - { - case 0 : - bg = ch; - default : - red = green = blue = 0; - break; - - case 3 : - val[0] = ptr[0]; - val[1] = '\0'; - red = 255 * strtol(val, NULL, 16) / 15; - - val[0] = ptr[1]; - val[1] = '\0'; - green = 255 * strtol(val, NULL, 16) / 15; - - val[0] = ptr[2]; - val[1] = '\0'; - blue = 255 * strtol(val, NULL, 16) / 15; - break; - - case 6 : - case 9 : - case 12 : - j /= 3; - - val[0] = ptr[0]; - val[1] = ptr[1]; - val[2] = '\0'; - red = strtol(val, NULL, 16); - - val[0] = ptr[j + 0]; - val[1] = ptr[j + 1]; - val[2] = '\0'; - green = strtol(val, NULL, 16); - - val[0] = ptr[2 * j + 0]; - val[1] = ptr[2 * j + 1]; - val[2] = '\0'; - blue = strtol(val, NULL, 16); - break; - } - - if (red == green && green == blue) - colors[ch] = FL_GRAY_RAMP + (FL_NUM_GRAY - 1) * red / 255; - else - colors[ch] = fl_color_cube((FL_NUM_RED - 1) * red / 255, - (FL_NUM_GREEN - 1) * green / 255, - (FL_NUM_BLUE - 1) * blue / 255); - } - else - { - // Read a color name... - if (strncasecmp(ptr + 2, "white", 5) == 0) - colors[ch] = FL_WHITE; - else if (strncasecmp(ptr + 2, "black", 5) == 0) - colors[ch] = FL_BLACK; - else if (strncasecmp(ptr + 2, "none", 4) == 0) - { - colors[ch] = FL_BLACK; - bg = ch; - } - else - colors[ch] = FL_GRAY; - } - } - - // Read the image data... - for (y = height - 1; y >= 0; y --) - { - while (fgets(line, sizeof(line), fp) != NULL) - if ((ptr = strchr(line, '\"')) != NULL) - break; - - if (ptr == NULL) - { - // Nothing to load... - fclose(fp); - return; - } - - startx = 0; - ch = bg; - ptr ++; - - for (x = 0; x < width; x ++, ptr ++) - if (*ptr != ch) - { - if (ch != bg) - { - add_color(colors[ch]); - add(POLYGON); - add_vertex(startx * 9000 / width + 1000, y * 9000 / height + 500); - add_vertex(x * 9000 / width + 1000, y * 9000 / height + 500); - add_vertex(x * 9000 / width + 1000, (y + 1) * 9000 / height + 500); - add_vertex(startx * 9000 / width + 1000, (y + 1) * 9000 / height + 500); - add(END); - } - - ch = *ptr; - startx = x; - } - - if (ch != bg) - { - add_color(colors[ch]); - add(POLYGON); - add_vertex(startx * 9000 / width + 1000, y * 9000 / height + 500); - add_vertex(x * 9000 / width + 1000, y * 9000 / height + 500); - add_vertex(x * 9000 / width + 1000, (y + 1) * 9000 / height + 500); - add_vertex(startx * 9000 / width + 1000, (y + 1) * 9000 / height + 500); - add(END); - } - } - - // Close the file and return... - fclose(fp); - -#ifdef DEBUG - printf("Icon File \"%s\":\n", xpm); - for (i = 0; i < num_data_; i ++) - printf(" %d,\n", data_[i]); -#endif /* DEBUG */ -} - - -// -// 'Fl_FileIcon::load_system_icons()' - Load the standard system icons/filetypes. - -void -Fl_FileIcon::load_system_icons(void) -{ - Fl_FileIcon *icon; // New icons - static int init = 0; // Have the icons been initialized? - static short plain[] = // Plain file icon - { - COLOR, 256, OUTLINEPOLYGON, FL_GRAY, - VERTEX, 2000, 1000, VERTEX, 2000, 9000, - VERTEX, 6000, 9000, VERTEX, 8000, 7000, - VERTEX, 8000, 1000, END, OUTLINEPOLYGON, FL_GRAY, - VERTEX, 6000, 9000, VERTEX, 6000, 7000, - VERTEX, 8000, 7000, END, - COLOR, FL_BLACK, LINE, VERTEX, 6000, 7000, - VERTEX, 8000, 7000, VERTEX, 8000, 1000, - VERTEX, 2000, 1000, END, LINE, VERTEX, 3000, 7000, - VERTEX, 5000, 7000, END, LINE, VERTEX, 3000, 6000, - VERTEX, 5000, 6000, END, LINE, VERTEX, 3000, 5000, - VERTEX, 7000, 5000, END, LINE, VERTEX, 3000, 4000, - VERTEX, 7000, 4000, END, LINE, VERTEX, 3000, 3000, - VERTEX, 7000, 3000, END, LINE, VERTEX, 3000, 2000, - VERTEX, 7000, 2000, END, - END - }; - static short image[] = // Image file icon - { - COLOR, 256, OUTLINEPOLYGON, FL_GRAY, - VERTEX, 2000, 1000, VERTEX, 2000, 9000, - VERTEX, 6000, 9000, VERTEX, 8000, 7000, - VERTEX, 8000, 1000, END, OUTLINEPOLYGON, FL_GRAY, - VERTEX, 6000, 9000, VERTEX, 6000, 7000, - VERTEX, 8000, 7000, END, - COLOR, FL_BLACK, LINE, VERTEX, 6000, 7000, - VERTEX, 8000, 7000, VERTEX, 8000, 1000, - VERTEX, 2000, 1000, END, - COLOR, FL_RED, POLYGON, VERTEX, 3500, 2500, - VERTEX, 3000, 3000, VERTEX, 3000, 4000, - VERTEX, 3500, 4500, VERTEX, 4500, 4500, - VERTEX, 5000, 4000, VERTEX, 5000, 3000, - VERTEX, 4500, 2500, END, - COLOR, FL_GREEN, POLYGON, VERTEX, 5500, 2500, - VERTEX, 5000, 3000, VERTEX, 5000, 4000, - VERTEX, 5500, 4500, VERTEX, 6500, 4500, - VERTEX, 7000, 4000, VERTEX, 7000, 3000, - VERTEX, 6500, 2500, END, - COLOR, FL_BLUE, POLYGON, VERTEX, 4500, 3500, - VERTEX, 4000, 4000, VERTEX, 4000, 5000, - VERTEX, 4500, 5500, VERTEX, 5500, 5500, - VERTEX, 6000, 5000, VERTEX, 6000, 4000, - VERTEX, 5500, 3500, END, - END - }; - static short dir[] = // Directory icon - { - COLOR, 256, POLYGON, VERTEX, 1000, 1000, - VERTEX, 1000, 7500, VERTEX, 9000, 7500, - VERTEX, 9000, 1000, END, - POLYGON, VERTEX, 1000, 7500, VERTEX, 2500, 9000, - VERTEX, 5000, 9000, VERTEX, 6500, 7500, END, - COLOR, FL_WHITE, LINE, VERTEX, 1500, 1500, - VERTEX, 1500, 7000, VERTEX, 9000, 7000, END, - COLOR, FL_BLACK, LINE, VERTEX, 9000, 7500, - VERTEX, 9000, 1000, VERTEX, 1000, 1000, END, - COLOR, FL_GRAY, LINE, VERTEX, 1000, 1000, - VERTEX, 1000, 7500, VERTEX, 2500, 9000, - VERTEX, 5000, 9000, VERTEX, 6500, 7500, - VERTEX, 9000, 7500, END, - END - }; - - - // Add symbols if they haven't been added already... - if (!init) - { - if (!access("/usr/share/mimelnk", F_OK)) - { - // Load KDE icons... - icon = new Fl_FileIcon("*", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/share/icons/unknown.xpm"); - - load_kde_icons("/usr/share/mimelnk"); - } - else if (!access("/usr/share/icons/folder.xpm", F_OK)) - { - // Load GNOME icons... - icon = new Fl_FileIcon("*", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/share/icons/page.xpm"); - - icon = new Fl_FileIcon("*", Fl_FileIcon::DIRECTORY); - icon->load_xpm("/usr/share/icons/folder.xpm"); - } - else if (!access("/usr/dt/appconfig/icons", F_OK)) - { - // Load CDE icons... - icon = new Fl_FileIcon("*", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/dt/appconfig/icons/C/Dtdata.m.pm"); - - icon = new Fl_FileIcon("*", Fl_FileIcon::DIRECTORY); - icon->load_xpm("/usr/dt/appconfig/icons/C/DtdirB.m.pm"); - - icon = new Fl_FileIcon("core", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/dt/appconfig/icons/C/Dtcore.m.pm"); - - icon = new Fl_FileIcon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/dt/appconfig/icons/C/Dtimage.m.pm"); - - icon = new Fl_FileIcon("*.{eps|pdf|ps}", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/dt/appconfig/icons/C/Dtps.m.pm"); - - icon = new Fl_FileIcon("*.ppd", Fl_FileIcon::PLAIN); - icon->load_xpm("/usr/dt/appconfig/icons/C/DtPrtpr.m.pm"); - } - else if (!access("/usr/lib/filetype", F_OK)) - { - // Load SGI icons... - icon = new Fl_FileIcon("*", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); - - icon = new Fl_FileIcon("*", Fl_FileIcon::DIRECTORY); - icon->load_fti("/usr/lib/filetype/iconlib/generic.folder.closed.fti"); - - icon = new Fl_FileIcon("core", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/default/iconlib/CoreFile.fti"); - - icon = new Fl_FileIcon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/system/iconlib/ImageFile.fti"); - - if (!access("/usr/lib/filetype/install/iconlib/acroread.doc.fti", F_OK)) - { - icon = new Fl_FileIcon("*.{eps|ps}", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); - - icon = new Fl_FileIcon("*.pdf", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/install/iconlib/acroread.doc.fti"); - } - else - { - icon = new Fl_FileIcon("*.{eps|pdf|ps}", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); - } - - if (!access("/usr/lib/filetype/install/iconlib/html.fti", F_OK)) - { - icon = new Fl_FileIcon("*.{htm|html|shtml}", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); - icon->load_fti("/usr/lib/filetype/install/iconlib/html.fti"); - } - - if (!access("/usr/lib/filetype/install/iconlib/color.ps.idle.fti", F_OK)) - { - icon = new Fl_FileIcon("*.ppd", Fl_FileIcon::PLAIN); - icon->load_fti("/usr/lib/filetype/install/iconlib/color.ps.idle.fti"); - } - } - else - { - // Create the default icons... - new Fl_FileIcon("*", Fl_FileIcon::PLAIN, sizeof(plain) / sizeof(plain[0]), plain); - new Fl_FileIcon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_FileIcon::PLAIN, - sizeof(image) / sizeof(image[0]), image); - new Fl_FileIcon("*", Fl_FileIcon::DIRECTORY, sizeof(dir) / sizeof(dir[0]), dir); - } - - // Mark things as initialized... - init = 1; - } -} - - -// -// 'load_kde_icons()' - Load KDE icon files. -// - -static void -load_kde_icons(const char *directory) // I - Directory to load -{ - int i; // Looping var - int n; // Number of entries in directory - dirent **entries; // Entries in directory - char full[1024]; // Full name of file - - - entries = (dirent **)0; - n = filename_list(directory, &entries); - - for (i = 0; i < n; i ++) - { - if (entries[i]->d_name[0] != '.') - { - strcpy(full, directory); - strcat(full,"/"); - strcat(full, entries[i]->d_name); - - if (filename_isdir(full)) - load_kde_icons(full); - else - load_kde_mimelnk(full); - } - - free((void *)entries[i]); - } - - free((void*)entries); -} - - -// -// 'load_kde_mimelnk()' - Load a KDE "mimelnk" file. -// - -static void -load_kde_mimelnk(const char *filename) -{ - FILE *fp; - char tmp[256]; - char iconfilename[1024]; - char pattern[1024]; - char mimetype[1024]; - char *val; - char full_iconfilename[1024]; - Fl_FileIcon *icon; - - - if ((fp = fopen(filename, "rb")) != NULL) - { - while (fgets(tmp, sizeof(tmp), fp)) - { - if ((val = get_kde_val(tmp, "Icon")) != NULL) - strcpy(iconfilename, val); - else if ((val = get_kde_val(tmp, "MimeType")) != NULL) - strcpy(mimetype, val); - else if ((val = get_kde_val(tmp, "Patterns")) != NULL) - strcpy(pattern, val); - } - - if (iconfilename && pattern) - { - sprintf(full_iconfilename, "/usr/share/icons/%s", iconfilename); - - if (strcmp(mimetype, "inode/directory") == 0) - icon = new Fl_FileIcon("*", Fl_FileIcon::DIRECTORY); - else - icon = new Fl_FileIcon(kde_to_fltk_pattern(pattern), Fl_FileIcon::PLAIN); - - icon->load_xpm(full_iconfilename); - } - - fclose(fp); - } -} - - -// -// 'kde_to_fltk_pattern()' - Convert a KDE pattern to a FLTK pattern. -// - -static char * -kde_to_fltk_pattern(const char *kdepattern) -{ - char *pattern, - *patptr; - - - pattern = (char *)malloc(strlen(kdepattern) + 3); - strcpy(pattern, "{"); - strcat(pattern, kdepattern); - - if (pattern[strlen(pattern) - 1] == ';') - pattern[strlen(pattern) - 1] = '\0'; - - strcat(pattern, "}"); - - for (patptr = pattern; *patptr; patptr ++) - if (*patptr == ';') - *patptr = '|'; - - return (pattern); -} - - -// -// 'get_kde_val()' - Get a KDE value. -// - -static char * -get_kde_val(char *str, - const char *key) -{ - while (*str == *key) - { - str ++; - key ++; - } - - if (*key == '\0' && *str == '=') - { - if (str[strlen(str) - 1] == '\n') - str[strlen(str) - 1] = '\0'; - - return (str + 1); - } - - return ((char *)0); -} - - -// -// End of "$Id: Fl_FileIcon.cxx,v 1.10.2.1 2001/08/02 16:17:04 easysw Exp $". -// diff --git a/src/Fl_File_Browser.cxx b/src/Fl_File_Browser.cxx new file mode 100644 index 000000000..d1a5af82f --- /dev/null +++ b/src/Fl_File_Browser.cxx @@ -0,0 +1,570 @@ +// +// "$Id: Fl_File_Browser.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $" +// +// Fl_File_Browser routines. +// +// Copyright 1999-2001 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// +// Contents: +// +// Fl_File_Browser::full_height() - Return the height of the list. +// Fl_File_Browser::item_height() - Return the height of a list item. +// Fl_File_Browser::item_width() - Return the width of a list item. +// Fl_File_Browser::item_draw() - Draw a list item. +// Fl_File_Browser::Fl_File_Browser() - Create a Fl_File_Browser widget. +// Fl_File_Browser::load() - Load a directory into the browser. +// Fl_File_Browser::filter() - Set the filename filter. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) +# include +# include +#endif /* WIN32 */ + +#if defined(__EMX__) +#define INCL_DOS +#define INCL_DOSMISC +#include +#endif /* __EMX__ */ + +#if !HAVE_SNPRINTF +extern "C" { +extern int snprintf(char* str, size_t size, const char* fmt, ...); +} +#endif // !HAVE_SNPRINTF + + +// +// FL_BLINE definition from "Fl_Browser.cxx"... +// + +#define SELECTED 1 +#define NOTDISPLAYED 2 + +struct FL_BLINE // data is in a linked list of these +{ + FL_BLINE *prev; // Previous item in list + FL_BLINE *next; // Next item in list + void *data; // Pointer to data (function) + short length; // sizeof(txt)-1, may be longer than string + char flags; // selected, displayed + char txt[1]; // start of allocated array +}; + + +// +// 'Fl_File_Browser::full_height()' - Return the height of the list. +// + +int // O - Height in pixels +Fl_File_Browser::full_height() const +{ + int i, // Looping var + th; // Total height of list. + + + for (i = 0, th = 0; i < size(); i ++) + th += item_height(find_line(i)); + + return (th); +} + + +// +// 'Fl_File_Browser::item_height()' - Return the height of a list item. +// + +int // O - Height in pixels +Fl_File_Browser::item_height(void *p) const // I - List item data +{ + FL_BLINE *line; // Pointer to line + char *text; // Pointer into text + int height; // Width of line + int textheight; // Height of text + + + // Figure out the standard text height... + fl_font(textfont(), textsize()); + textheight = fl_height(); + + // We always have at least 1 line... + height = textheight; + + // Scan for newlines... + line = (FL_BLINE *)p; + + if (line != NULL) + for (text = line->txt; *text != '\0'; text ++) + if (*text == '\n') + height += textheight; + + // If we have enabled icons then add space for them... + if (Fl_File_Icon::first() != NULL && height < iconsize_) + height = iconsize_; + + // Add space for the selection border.. + height += 2; + + // Return the height + return (height); +} + + +// +// 'Fl_File_Browser::item_width()' - Return the width of a list item. +// + +int // O - Width in pixels +Fl_File_Browser::item_width(void *p) const // I - List item data +{ + int i; // Looping var + FL_BLINE *line; // Pointer to line + char *text, // Pointer into text + *ptr, // Pointer into fragment + fragment[10240]; // Fragment of text + int width, // Width of line + tempwidth; // Width of fragment + int column; // Current column + const int *columns; // Columns + + + // Set the font and size... + fl_font(textfont(), textsize()); + + // Scan for newlines... + line = (FL_BLINE *)p; + columns = column_widths(); + + if (strchr(line->txt, '\n') == NULL && + strchr(line->txt, column_char()) == NULL) + { + // Do a fast width calculation... + width = (int)fl_width(line->txt); + } + else + { + // More than 1 line or have columns; find the maximum width... + width = 0; + tempwidth = 0; + column = 0; + + for (text = line->txt, ptr = fragment; *text != '\0'; text ++) + if (*text == '\n') + { + // Newline - nul terminate this fragment and get the width... + *ptr = '\0'; + + tempwidth += (int)fl_width(fragment); + + // Update the max width as needed... + if (tempwidth > width) + width = tempwidth; + + // Point back to the start of the fragment... + ptr = fragment; + tempwidth = 0; + column = 0; + } + else if (*text == column_char()) + { + // Advance to the next column... + column ++; + if (columns) + { + for (i = 0, tempwidth = 0; i < column && columns[i]; i ++) + tempwidth += columns[i]; + } + else + tempwidth = column * (int)(fl_height() * 0.6 * 8.0); + + if (tempwidth > width) + width = tempwidth; + + ptr = fragment; + } + else + *ptr++ = *text; + + if (ptr > fragment) + { + // Nul terminate this fragment and get the width... + *ptr = '\0'; + + tempwidth += (int)fl_width(fragment); + + // Update the max width as needed... + if (tempwidth > width) + width = tempwidth; + } + } + + // If we have enabled icons then add space for them... + if (Fl_File_Icon::first() != NULL) + width += iconsize_ + 8; + + // Add space for the selection border.. + width += 2; + + // Return the width + return (width); +} + + +// +// 'Fl_File_Browser::item_draw()' - Draw a list item. +// + +void +Fl_File_Browser::item_draw(void *p, // I - List item data + int x, // I - Upper-lefthand X coordinate + int y, // I - Upper-lefthand Y coordinate + int w, // I - Width of item + int h) const // I - Height of item +{ + int i; // Looping var + FL_BLINE *line; // Pointer to line + Fl_Color c; // Text color + char *text, // Pointer into text + *ptr, // Pointer into fragment + fragment[10240]; // Fragment of text + int width, // Width of line + height; // Height of line + int column; // Current column + const int *columns; // Columns + + + (void)h; + + // Draw the list item text... + line = (FL_BLINE *)p; + + if (line->txt[strlen(line->txt) - 1] == '/') + fl_font(textfont() | FL_BOLD, textsize()); + else + fl_font(textfont(), textsize()); + + if (line->flags & SELECTED) + c = contrast(textcolor(), selection_color()); + else + c = textcolor(); + + if (Fl_File_Icon::first() == NULL) + { + // No icons, just draw the text... + x ++; + w -= 2; + } + else + { + // Draw the icon if it is set... + if (line->data) + ((Fl_File_Icon *)line->data)->draw(x, y, iconsize_, iconsize_, + (line->flags & SELECTED) ? FL_YELLOW : + FL_LIGHT2, + active_r()); + + // Draw the text offset to the right... + x += iconsize_ + 9; + w -= iconsize_ - 10; + + // Center the text vertically... + height = fl_height(); + + for (text = line->txt; *text != '\0'; text ++) + if (*text == '\n') + height += fl_height(); + + if (height < iconsize_) + y += (iconsize_ - height) / 2; + } + + // Draw the text... + line = (FL_BLINE *)p; + columns = column_widths(); + width = 0; + column = 0; + + if (active_r()) + fl_color(c); + else + fl_color(inactive(c)); + + for (text = line->txt, ptr = fragment; *text != '\0'; text ++) + if (*text == '\n') + { + // Newline - nul terminate this fragment and draw it... + *ptr = '\0'; + + fl_draw(fragment, x + width, y, w - width, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); + + // Point back to the start of the fragment... + ptr = fragment; + width = 0; + y += fl_height(); + column = 0; + } + else if (*text == column_char()) + { + // Tab - nul terminate this fragment and draw it... + *ptr = '\0'; + + fl_draw(fragment, x + width, y, w - width, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); + + // Advance to the next column... + column ++; + if (columns) + { + for (i = 0, width = 0; i < column && columns[i]; i ++) + width += columns[i]; + } + else + width = column * (int)(fl_height() * 0.6 * 8.0); + + ptr = fragment; + } + else + *ptr++ = *text; + + if (ptr > fragment) + { + // Nul terminate this fragment and draw it... + *ptr = '\0'; + + fl_draw(fragment, x + width, y, w - width, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); + } +} + + +// +// 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget. +// + +Fl_File_Browser::Fl_File_Browser(int x, // I - Upper-lefthand X coordinate + int y, // I - Upper-lefthand Y coordinate + int w, // I - Width in pixels + int h, // I - Height in pixels + const char *l) // I - Label text + : Fl_Browser(x, y, w, h, l) +{ + // Initialize the filter pattern, current directory, and icon size... + pattern_ = "*"; + directory_ = ""; + iconsize_ = 3 * textsize() / 2; + filetype_ = FILES; +} + + +// +// 'Fl_File_Browser::load()' - Load a directory into the browser. +// + +int // O - Number of files loaded +Fl_File_Browser::load(const char *directory)// I - Directory to load +{ + int i; // Looping var + int num_files; // Number of files in directory + int num_dirs; // Number of directories in list + char filename[4096]; // Current file + Fl_File_Icon *icon; // Icon to use + + +// printf("Fl_File_Browser::load(\"%s\")\n", directory); + + clear(); + directory_ = directory; + + if (directory_[0] == '\0') + { + // + // No directory specified; for UNIX list all mount points. For DOS + // list all valid drive letters... + // + + num_files = 0; + if ((icon = Fl_File_Icon::find("any", Fl_File_Icon::DEVICE)) == NULL) + icon = Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY); + +#if defined(WIN32) + DWORD drives; // Drive available bits + + + drives = GetLogicalDrives(); + for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) + if (drives & 1) + { + sprintf(filename, "%c:/", i); + + if (i < 'C') + add(filename, icon); + else + add(filename, icon); + + num_files ++; + } +#elif defined(__EMX__) + ULONG curdrive; // Current drive + ULONG drives; // Drive available bits + int start = 3; // 'C' (MRS - dunno if this is correct!) + + + DosQueryCurrentDisk(&curdrive, &drives); + drives >>= start - 1; + for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) + if (drives & 1) + { + sprintf(filename, "%c:/", i); + add(filename, icon); + + num_files ++; + } +#else + FILE *mtab; // /etc/mtab or /etc/mnttab file + char line[1024]; // Input line + + + // + // Open the file that contains a list of mounted filesystems... + // +# if defined(hpux) || defined(__sun) + mtab = fopen("/etc/mnttab", "r"); // Fairly standard +# elif defined(__sgi) || defined(linux) + mtab = fopen("/etc/mtab", "r"); // More standard +# else + mtab = fopen("/etc/fstab", "r"); // Otherwise fallback to full list + if (mtab == NULL) + mtab = fopen("/etc/vfstab", "r"); +# endif + + if (mtab != NULL) + { + while (fgets(line, sizeof(line), mtab) != NULL) + { + if (line[0] == '#' || line[0] == '\n') + continue; + if (sscanf(line, "%*s%4095s", filename) != 1) + continue; + + strncat(filename, "/", sizeof(filename) - 1); + +// printf("Fl_File_Browser::load() - adding \"%s\" to list...\n", filename); + add(filename, icon); + num_files ++; + } + + fclose(mtab); + } +#endif // WIN32 || __EMX__ + } + else + { + dirent **files; // Files in in directory + + + // + // Build the file list... + // + +#if defined(WIN32) || defined(__EMX__) + strncpy(filename, directory_, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + i = strlen(filename) - 1; + + if (i == 2 && filename[1] == ':' && + (filename[2] == '/' || filename[2] == '\\')) + filename[2] = '/'; + else if (filename[i] != '/' && filename[i] != '\\') + strcat(filename, "/"); + + num_files = filename_list(filename, &files); +#else + num_files = filename_list(directory_, &files); +#endif /* WIN32 || __EMX__ */ + + if (num_files <= 0) + return (0); + + for (i = 0, num_dirs = 0; i < num_files; i ++) + { + if (strcmp(files[i]->d_name, ".") != 0 && + strcmp(files[i]->d_name, "..") != 0) + { + snprintf(filename, sizeof(filename), "%s/%s", directory_, + files[i]->d_name); + + if (filename_isdir(filename)) + { + char name[1024]; // Temporary directory name + + snprintf(name, sizeof(name), "%s/", files[i]->d_name); + + num_dirs ++; + insert(num_dirs, name, Fl_File_Icon::find(filename)); + } + else if (filetype_ == FILES && + filename_match(files[i]->d_name, pattern_)) + add(files[i]->d_name, Fl_File_Icon::find(filename)); + } + + free(files[i]); + } + + free(files); + } + + return (num_files); +} + + +// +// 'Fl_File_Browser::filter()' - Set the filename filter. +// + +void +Fl_File_Browser::filter(const char *pattern) // I - Pattern string +{ + // If pattern is NULL set the pattern to "*"... + if (pattern) + pattern_ = pattern; + else + pattern_ = "*"; + + // Reload the current directory... + load(directory_); +} + + +// +// End of "$Id: Fl_File_Browser.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $". +// diff --git a/src/Fl_File_Chooser.cxx b/src/Fl_File_Chooser.cxx new file mode 100644 index 000000000..42e4747a0 --- /dev/null +++ b/src/Fl_File_Chooser.cxx @@ -0,0 +1,259 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0100 + +#include "../FL/Fl_File_Chooser.H" + +inline void Fl_File_Chooser::cb_window_i(Fl_Window*, void*) { + fileList->deselect(); +fileName->value(""); +window->hide(); +} +void Fl_File_Chooser::cb_window(Fl_Window* o, void* v) { + ((Fl_File_Chooser*)(o->user_data()))->cb_window_i(o,v); +} + +inline void Fl_File_Chooser::cb_fileList_i(Fl_File_Browser*, void*) { + fileListCB(); +} +void Fl_File_Chooser::cb_fileList(Fl_File_Browser* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_fileList_i(o,v); +} + +inline void Fl_File_Chooser::cb_Cancel_i(Fl_Button*, void*) { + fileList->deselect(); +fileName->value(""); +window->hide(); +} +void Fl_File_Chooser::cb_Cancel(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_Cancel_i(o,v); +} + +inline void Fl_File_Chooser::cb_okButton_i(Fl_Return_Button*, void*) { + // Do any callback that is registered... +if (callback_) + (*callback_)(this, data_); + +window->hide(); +} +void Fl_File_Chooser::cb_okButton(Fl_Return_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_okButton_i(o,v); +} + +inline void Fl_File_Chooser::cb_fileName_i(Fl_Input*, void*) { + fileNameCB(); +} +void Fl_File_Chooser::cb_fileName(Fl_Input* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_fileName_i(o,v); +} + +inline void Fl_File_Chooser::cb_upButton_i(Fl_Button*, void*) { + up(); +} +void Fl_File_Chooser::cb_upButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_upButton_i(o,v); +} + +#include +static unsigned char bits_up[] = +"\0\0x\0\204\0\2\1""1\376y\200\375\200""1\200""1\200""1\200""1\200""1\200\1\ +\200\1\200\377\377\0\0"; +static Fl_Bitmap bitmap_up(bits_up, 16, 16); + +inline void Fl_File_Chooser::cb_newButton_i(Fl_Button*, void*) { + newdir(); +} +void Fl_File_Chooser::cb_newButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_newButton_i(o,v); +} + +static unsigned char bits_new[] = +"\0\0x\0\204\0\2\1\1\376\1\200""1\200""1\200\375\200\375\200""1\200""1\200\1\ +\200\1\200\377\377\0\0"; +static Fl_Bitmap bitmap_new(bits_new, 16, 16); + +inline void Fl_File_Chooser::cb_dirMenu_i(Fl_Choice*, void*) { + char pathname[1024]; +int i; + +pathname[0] = '\0'; +for (i = 1; i <= dirMenu->value(); i ++) + strcat(pathname, dirMenu->text(i)); +directory(pathname); +} +void Fl_File_Chooser::cb_dirMenu(Fl_Choice* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_dirMenu_i(o,v); +} + +inline void Fl_File_Chooser::cb__i(Fl_Button*, void*) { + const char *f; +if ((f = fl_input("New Filter?", + fileList->filter())) != NULL) +{ + fileList->filter(f); + rescan(); +}; +} +void Fl_File_Chooser::cb_(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb__i(o,v); +} + +static unsigned char bits_allfiles[] = +"\374?\4 \4 \4 \204!\244%\304#\364/\364/\304#\244%\204!\4 \4 \4 \374?"; +static Fl_Bitmap bitmap_allfiles(bits_allfiles, 16, 16); + +Fl_File_Chooser::Fl_File_Chooser(const char *d, const char *p, int t, const char *title) { + Fl_Window* w; + { Fl_Window* o = window = new Fl_Window(375, 315, "Pick a File"); + w = o; + o->callback((Fl_Callback*)cb_window, (void*)(this)); + w->hotspot(o); + { Fl_File_Browser* o = fileList = new Fl_File_Browser(10, 45, 355, 180); + o->type(2); + o->callback((Fl_Callback*)cb_fileList); + Fl_Group::current()->resizable(o); + w->hotspot(o); + } + { Fl_Button* o = new Fl_Button(285, 280, 80, 25, "Cancel"); + o->callback((Fl_Callback*)cb_Cancel); + o->label(fl_cancel); + } + { Fl_Return_Button* o = okButton = new Fl_Return_Button(200, 280, 75, 25, "OK"); + o->callback((Fl_Callback*)cb_okButton); + okButton->label(fl_ok); + } + { Fl_Input* o = fileName = new Fl_Input(10, 245, 355, 25, "Filename:"); + o->callback((Fl_Callback*)cb_fileName); + o->align(FL_ALIGN_TOP_LEFT); + o->when(FL_WHEN_ENTER_KEY); + fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS); + } + { Fl_Button* o = upButton = new Fl_Button(280, 10, 25, 25); + o->image(bitmap_up); + o->labelsize(8); + o->callback((Fl_Callback*)cb_upButton); + } + { Fl_Button* o = newButton = new Fl_Button(310, 10, 25, 25); + o->image(bitmap_new); + o->labelsize(8); + o->callback((Fl_Callback*)cb_newButton); + } + { Fl_Choice* o = dirMenu = new Fl_Choice(95, 10, 180, 25, "Directory:"); + o->down_box(FL_BORDER_BOX); + o->callback((Fl_Callback*)cb_dirMenu); + } + { Fl_Button* o = new Fl_Button(340, 10, 25, 25); + o->image(bitmap_allfiles); + o->labelsize(28); + o->labelcolor(4); + o->callback((Fl_Callback*)cb_); + o->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); + } + if (title) window->label(title); + o->set_modal(); + o->end(); + } + window->size_range(345, 270, 345); +fileList->filter(p); +type(t); +value(d); +callback_ = 0; +data_ = 0; +} + +void Fl_File_Chooser::callback(void (*cb)(Fl_File_Chooser *, void *), void *d) { + callback_ = cb; +data_ = d; +} + +void Fl_File_Chooser::color(Fl_Color c) { + fileList->color(c); +} + +Fl_Color Fl_File_Chooser::color() { + return (fileList->color()); +} + +char * Fl_File_Chooser::directory() { + return directory_; +} + +void Fl_File_Chooser::filter(const char *p) { + fileList->filter(p); +rescan(); +} + +const char * Fl_File_Chooser::filter() { + return (fileList->filter()); +} + +void Fl_File_Chooser::hide() { + window->hide(); +} + +void Fl_File_Chooser::iconsize(uchar s) { + fileList->iconsize(s); +} + +uchar Fl_File_Chooser::iconsize() { + return (fileList->iconsize()); +} + +void Fl_File_Chooser::label(const char *l) { + window->label(l); +} + +const char * Fl_File_Chooser::label() { + return (window->label()); +} + +void Fl_File_Chooser::show() { + window->show(); +fileList->deselect(); +} + +void Fl_File_Chooser::textcolor(Fl_Color c) { + fileList->textcolor(c); +} + +Fl_Color Fl_File_Chooser::textcolor() { + return (fileList->textcolor()); +} + +void Fl_File_Chooser::textfont(uchar f) { + fileList->textfont(f); +} + +uchar Fl_File_Chooser::textfont() { + return (fileList->textfont()); +} + +void Fl_File_Chooser::textsize(uchar s) { + fileList->textsize(s); +} + +uchar Fl_File_Chooser::textsize() { + return (fileList->textsize()); +} + +void Fl_File_Chooser::type(int t) { + type_ = t; +if (t & MULTI) + fileList->type(FL_MULTI_BROWSER); +else + fileList->type(FL_HOLD_BROWSER); +if (t & CREATE) + newButton->deactivate(); +else + newButton->activate(); +if (t & DIRECTORY) + fileList->filetype(Fl_File_Browser::DIRECTORIES); +else + fileList->filetype(Fl_File_Browser::FILES); +} + +int Fl_File_Chooser::type() { + return (type_); +} + +int Fl_File_Chooser::visible() { + return window->visible(); +} diff --git a/src/Fl_File_Chooser.fl b/src/Fl_File_Chooser.fl new file mode 100644 index 000000000..1302d773f --- /dev/null +++ b/src/Fl_File_Chooser.fl @@ -0,0 +1,210 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0100 +header_name {../FL/Fl_File_Chooser.H} +code_name {.cxx} +gridx 5 +gridy 5 +snap 3 +class Fl_File_Chooser {open +} { + decl {enum { SINGLE = 0, MULTI = 1, CREATE = 2, DIRECTORY = 4 };} {selected public + } + Function {Fl_File_Chooser(const char *d, const char *p, int t, const char *title)} {open + } { + Fl_Window window { + label {Pick a File} + callback {fileList->deselect(); +fileName->value(""); +window->hide();} open + private xywh {99 225 375 315} resizable hotspot + code0 {if (title) window->label(title);} + code1 {\#include } + code2 {\#include } + code3 {\#include } modal visible + } { + Fl_Browser fileList { + callback {fileListCB();} + private xywh {10 45 355 180} type Hold resizable hotspot + code0 {\#include } + class Fl_File_Browser + } + Fl_Button {} { + label Cancel + callback {fileList->deselect(); +fileName->value(""); +window->hide();} + private xywh {285 280 80 25} + code0 {o->label(fl_cancel);} + } + Fl_Return_Button okButton { + label OK + callback {// Do any callback that is registered... +if (callback_) + (*callback_)(this, data_); + +window->hide();} + private xywh {200 280 75 25} + code0 {\#include } + code1 {okButton->label(fl_ok);} + } + Fl_Input fileName { + label {Filename:} + callback {fileNameCB();} + private xywh {10 245 355 25} align 5 when 8 + code0 {fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS);} + } + Fl_Button upButton { + callback {up();} + private image {up.xbm} xywh {280 10 25 25} labelsize 8 + } + Fl_Button newButton { + callback {newdir();} + private image {new.xbm} xywh {310 10 25 25} labelsize 8 + } + Fl_Choice dirMenu { + label {Directory:} + callback {char pathname[1024]; +int i; + +pathname[0] = '\\0'; +for (i = 1; i <= dirMenu->value(); i ++) + strcat(pathname, dirMenu->text(i)); +directory(pathname);} open + private xywh {95 10 180 25} down_box BORDER_BOX + } {} + Fl_Button {} { + callback {const char *f; +if ((f = fl_input("New Filter?", + fileList->filter())) != NULL) +{ + fileList->filter(f); + rescan(); +}} + private image {allfiles.xbm} xywh {340 10 25 25} labelsize 28 labelcolor 4 align 16 + code0 {\#include } + } + } + code {window->size_range(345, 270, 345); +fileList->filter(p); +type(t); +value(d); +callback_ = 0; +data_ = 0;} {} + } + decl {void (*callback_)(Fl_File_Chooser*, void *);} {} + decl {void *data_;} {} + decl {char directory_[1024];} {} + decl {int type_;} {} + decl {void fileListCB();} {} + decl {void fileNameCB();} {} + decl {void newdir();} {} + decl {void up();} {} + Function {callback(void (*cb)(Fl_File_Chooser *, void *), void *d)} {return_type void + } { + code {callback_ = cb; +data_ = d;} {} + } + Function {color(Fl_Color c)} {} { + code {fileList->color(c);} {} + } + Function {color()} {return_type Fl_Color + } { + code {return (fileList->color());} {} + } + decl {int count();} {public + } + decl {void directory(const char *d);} {public + } + Function {directory()} {return_type {char *} + } { + code {return directory_;} {} + } + Function {filter(const char *p)} {return_type void + } { + code {fileList->filter(p); +rescan();} {} + } + Function {filter()} {return_type {const char *} + } { + code {return (fileList->filter());} {} + } + Function {hide()} {return_type void + } { + code {window->hide();} {} + } + Function {iconsize(uchar s)} {return_type void + } { + code {fileList->iconsize(s);} {} + } + Function {iconsize()} {return_type uchar + } { + code {return (fileList->iconsize());} {} + } + Function {label(const char *l)} {return_type void + } { + code {window->label(l);} {} + } + Function {label()} {return_type {const char *} + } { + code {return (window->label());} {} + } + decl {void rescan();} {public + } + Function {show()} {return_type void + } { + code {window->show(); +fileList->deselect();} {} + } + Function {textcolor(Fl_Color c)} {return_type void + } { + code {fileList->textcolor(c);} {} + } + Function {textcolor()} {return_type Fl_Color + } { + code {return (fileList->textcolor());} {} + } + Function {textfont(uchar f)} {return_type void + } { + code {fileList->textfont(f);} {} + } + Function {textfont()} {return_type uchar + } { + code {return (fileList->textfont());} {} + } + Function {textsize(uchar s)} {return_type void + } { + code {fileList->textsize(s);} {} + } + Function {textsize()} {return_type uchar + } { + code {return (fileList->textsize());} {} + } + Function {type(int t)} {return_type void + } { + code {type_ = t; +if (t & MULTI) + fileList->type(FL_MULTI_BROWSER); +else + fileList->type(FL_HOLD_BROWSER); +if (t & CREATE) + newButton->deactivate(); +else + newButton->activate(); +if (t & DIRECTORY) + fileList->filetype(Fl_File_Browser::DIRECTORIES); +else + fileList->filetype(Fl_File_Browser::FILES);} {} + } + Function {type()} {return_type int + } { + code {return (type_);} {} + } + decl {const char *value(int f = 1);} {public + } + decl {void value(const char *filename);} {public + } + Function {visible()} {return_type int + } { + code {return window->visible();} {} + } +} diff --git a/src/Fl_File_Chooser2.cxx b/src/Fl_File_Chooser2.cxx new file mode 100644 index 000000000..801c6050d --- /dev/null +++ b/src/Fl_File_Chooser2.cxx @@ -0,0 +1,688 @@ +// +// "$Id: Fl_File_Chooser2.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $" +// +// More Fl_File_Chooser routines. +// +// Copyright 1999-2001 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// +// Contents: +// +// Fl_File_Chooser::directory() - Set the directory in the file chooser. +// Fl_File_Chooser::count() - Return the number of selected files. +// Fl_File_Chooser::value() - Return a selected filename. +// Fl_File_Chooser::up() - Go up one directory. +// Fl_File_Chooser::newdir() - Make a new directory. +// Fl_File_Chooser::rescan() - Rescan the current directory. +// Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks) in the +// FileBrowser. +// Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser. +// + +// +// Include necessary headers. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) +# include +# include +#else +# include +# include +#endif /* WIN32 */ + + +// +// 'Fl_File_Chooser::directory()' - Set the directory in the file chooser. +// + +void +Fl_File_Chooser::directory(const char *d) // I - Directory to change to +{ + char pathname[1024], // Full path of directory + *pathptr, // Pointer into full path + *dirptr; // Pointer into directory + int levels; // Number of levels in directory + + +// printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d); + + // NULL == current directory + if (d == NULL) + d = "."; + + if (d[0] != '\0') + { + // Make the directory absolute... +#if defined(WIN32) || defined(__EMX__) + if (d[0] != '/' && d[0] != '\\' && d[1] != ':') +#else + if (d[0] != '/' && d[0] != '\\') +#endif /* WIN32 || __EMX__ */ + filename_absolute(directory_, d); + else + { + strncpy(directory_, d, sizeof(directory_) - 1); + directory_[sizeof(directory_) - 1] = '\0'; + } + + // Strip any trailing slash and/or period... + dirptr = directory_ + strlen(directory_) - 1; + if (*dirptr == '.') + *dirptr-- = '\0'; + if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_) + *dirptr = '\0'; + } + else + directory_[0] = '\0'; + + // Clear the directory menu and fill it as needed... + dirMenu->clear(); +#if defined(WIN32) || defined(__EMX__) + dirMenu->add("My Computer"); +#else + dirMenu->add("File Systems"); +#endif /* WIN32 || __EMX__ */ + + levels = 0; + for (dirptr = directory_, pathptr = pathname; *dirptr != '\0';) + { + if (*dirptr == '/' || *dirptr == '\\') + { + // Need to quote the slash first, and then add it to the menu... + *pathptr++ = '\\'; + *pathptr++ = '/'; + *pathptr++ = '\0'; + dirptr ++; + + dirMenu->add(pathname); + levels ++; + pathptr = pathname; + } + else + *pathptr++ = *dirptr++; + } + + if (pathptr > pathname) + { + *pathptr = '\0'; + dirMenu->add(pathname); + levels ++; + } + + dirMenu->value(levels); + + // Rescan the directory... + rescan(); +} + + +// +// 'Fl_File_Chooser::count()' - Return the number of selected files. +// + +int // O - Number of selected files +Fl_File_Chooser::count() +{ + int i; // Looping var + int count; // Number of selected files + const char *filename; // Filename in input field or list + char pathname[1024]; // Full path to file + + + if (!(type_ & MULTI)) + { + // Check to see if the file name input field is blank... + filename = fileName->value(); + if (filename == NULL || filename[0] == '\0') + return (0); + + // Is the file name a directory? + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (filename_isdir(pathname)) + return (0); + else + return (1); + } + + for (i = 1, count = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) + { + // See if this file is a directory... + filename = (char *)fileList->text(i); + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (!filename_isdir(pathname)) + count ++; + } + + return (count); +} + + +// +// 'Fl_File_Chooser::value()' - Return a selected filename. +// + +const char * // O - Filename or NULL +Fl_File_Chooser::value(int f) // I - File number +{ + int i; // Looping var + int count; // Number of selected files + const char *name; // Current filename + static char pathname[1024]; // Filename + directory + + + if (!(type_ & MULTI)) + { + name = fileName->value(); + if (name[0] == '\0') + return (NULL); + + sprintf(pathname, "%s/%s", directory_, name); + return ((const char *)pathname); + } + + for (i = 1, count = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) + { + // See if this file is a directory... + name = fileList->text(i); + sprintf(pathname, "%s/%s", directory_, name); + + if (!filename_isdir(pathname)) + { + // Nope, see if this this is "the one"... + count ++; + if (count == f) + return ((const char *)pathname); + } + } + + return (NULL); +} + + +// +// 'Fl_File_Chooser::value()' - Set the current filename. +// + +void +Fl_File_Chooser::value(const char *filename) // I - Filename + directory +{ + int i, // Looping var + count; // Number of items in list + char *slash; // Directory separator + char pathname[1024]; // Local copy of filename + + +// printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename); + + // See if the filename is actually a directory... + if (filename == NULL || !filename[0] || filename_isdir(filename)) + { + // Yes, just change the current directory... + directory(filename); + return; + } + + // Switch to single-selection mode as needed + if (type_ & MULTI) + type(SINGLE); + + // See if there is a directory in there... + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + if ((slash = strrchr(pathname, '/')) == NULL) + slash = strrchr(pathname, '\\'); + + if (slash != NULL) + { + // Yes, change the display to the directory... + *slash++ = '\0'; + directory(pathname); + } + else + slash = pathname; + + // Set the input field to the remaining portion + fileName->value(slash); + fileName->position(0, strlen(slash)); + okButton->activate(); + + // Then find the file in the file list and select it... + count = fileList->size(); + + for (i = 1; i <= count; i ++) + if (strcmp(fileList->text(i), slash) == 0) + { + fileList->select(i); + break; + } +} + + +// +// 'Fl_File_Chooser::up()' - Go up one directory. +// + +void +Fl_File_Chooser::up() +{ + char *slash; // Trailing slash + + + if ((slash = strrchr(directory_, '/')) == NULL) + slash = strrchr(directory_, '\\'); + + if (directory_[0] != '\0') + dirMenu->value(dirMenu->value() - 1); + + if (slash != NULL) + *slash = '\0'; + else + { + upButton->deactivate(); + directory_[0] = '\0'; + } + + rescan(); +} + + +// +// 'Fl_File_Chooser::newdir()' - Make a new directory. +// + +void +Fl_File_Chooser::newdir() +{ + const char *dir; // New directory name + char pathname[1024]; // Full path of directory + + + // Get a directory name from the user + if ((dir = fl_input("New Directory?", NULL)) == NULL) + return; + + // Make it relative to the current directory as needed... +#if defined(WIN32) || defined(__EMX__) + if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':') +#else + if (dir[0] != '/' && dir[0] != '\\') +#endif /* WIN32 || __EMX__ */ + sprintf(pathname, "%s/%s", directory_, dir); + else + { + strncpy(pathname, dir, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + // Create the directory; ignore EEXIST errors... +#if defined(WIN32) + if (mkdir(pathname)) +#else + if (mkdir(pathname, 0777)) +#endif /* WIN32 */ + if (errno != EEXIST) + { + fl_alert("Unable to create directory!"); + return; + } + + // Show the new directory... + directory(pathname); +} + + +// +// 'Fl_File_Chooser::rescan()' - Rescan the current directory. +// + +void +Fl_File_Chooser::rescan() +{ +// printf("Fl_File_Chooser::rescan(); directory = \"%s\"\n", directory_); + + // Clear the current filename + fileName->value(""); + okButton->deactivate(); + + // Build the file list... + fileList->load(directory_); +} + + +// +// 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the +// FileBrowser. +// + +void +Fl_File_Chooser::fileListCB() +{ + char *filename, // New filename + pathname[1024]; // Full pathname to file + + + filename = (char *)fileList->text(fileList->value()); + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (Fl::event_clicks()) + { +#if defined(WIN32) || defined(__EMX__) + if ((strlen(pathname) == 2 && pathname[1] == ':') || + filename_isdir(pathname)) +#else + if (filename_isdir(pathname)) +#endif /* WIN32 || __EMX__ */ + { + directory(pathname); + upButton->activate(); + } + else + { + // Do any callback that is registered... + if (callback_) + (*callback_)(this, data_); + + // Hide the window... + window->hide(); + } + } + else + { + fileName->value(filename); + + if (!filename_isdir(pathname) || (type_ & DIRECTORY)) + okButton->activate(); + } +} + + +// +// 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser. +// + +void +Fl_File_Chooser::fileNameCB() +{ + char *filename, // New filename + *slash, // Pointer to trailing slash + pathname[1024]; // Full pathname to file + int i, // Looping var + min_match, // Minimum number of matching chars + max_match, // Maximum number of matching chars + num_files, // Number of files in directory + first_line; // First matching line + const char *file; // File from directory + + + // Get the filename from the text field... + filename = (char *)fileName->value(); + + if (filename == NULL || filename[0] == '\0') + { + okButton->deactivate(); + return; + } + +#if defined(WIN32) || defined(__EMX__) + if (directory_[0] != '\0' && + filename[0] != '/' && + filename[0] != '\\' && + !(isalpha(filename[0]) && filename[1] == ':')) + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } +#else + if (filename[0] == '~') + { + // Lookup user... + struct passwd *pwd; + + if (!filename[1] || filename[1] == '/') + pwd = getpwuid(getuid()); + else + { + strncpy(pathname, filename + 1, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + i = strlen(pathname) - 1; + if (pathname[i] == '/') + pathname[i] = '\0'; + + pwd = getpwnam(pathname); + } + + if (pwd) + { + strncpy(pathname, pwd->pw_dir, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + if (filename[strlen(filename) - 1] == '/') + strncat(pathname, "/", sizeof(pathname) - 1); + } + else + sprintf(pathname, "%s/%s", directory_, filename); + + endpwent(); + } + else if (directory_[0] != '\0' && + filename[0] != '/') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } +#endif /* WIN32 || __EMX__ */ + + if (Fl::event_key() == FL_Enter) + { + // Enter pressed - select or change directory... + +#if defined(WIN32) || defined(__EMX__) + if ((strlen(pathname) == 2 && pathname[1] == ':') || + filename_isdir(pathname)) +#else + if (filename_isdir(pathname)) +#endif /* WIN32 || __EMX__ */ + directory(pathname); + else if ((type_ & CREATE) || access(pathname, 0) == 0) + { + // New file or file exists... If we are in multiple selection mode, + // switch to single selection mode... + if (type_ & MULTI) + type(SINGLE); + + // Do any callback that is registered... + if (callback_) + (*callback_)(this, data_); + + // Hide the window to signal things are done... + window->hide(); + } + else + { + // File doesn't exist, so beep at and alert the user... + fl_alert("Please choose an existing file!"); + } + } + else if (Fl::event_key() != FL_Delete) + { + // Check to see if the user has entered a directory... + if ((slash = strrchr(filename, '/')) == NULL) + slash = strrchr(filename, '\\'); + + if (slash != NULL) + { + // Yes, change directories and update the file name field... + if ((slash = strrchr(pathname, '/')) == NULL) + slash = strrchr(pathname, '\\'); + + if (slash > pathname) // Special case for "/" + *slash++ = '\0'; + else + slash++; + + if (strcmp(filename, "../") == 0) // Special case for "../" + up(); + else + directory(pathname); + + // If the string ended after the slash, we're done for now... + if (*slash == '\0') + return; + + // Otherwise copy the remainder and proceed... + fileName->value(slash); + fileName->position(strlen(slash)); + filename = slash; + } + + // Other key pressed - do filename completion as possible... + num_files = fileList->size(); + min_match = strlen(filename); + max_match = 100000; + first_line = 0; + + for (i = 1; i <= num_files && max_match > min_match; i ++) + { + file = fileList->text(i); + +#if defined(WIN32) || defined(__EMX__) + if (strnicmp(filename, file, min_match) == 0) +#else + if (strncmp(filename, file, min_match) == 0) +#endif // WIN32 || __EMX__ + { + // OK, this one matches; check against the previous match + if (max_match == 100000) + { + // First match; copy stuff over... + strncpy(pathname, file, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + max_match = strlen(pathname); + + // Strip trailing /, if any... + if (pathname[max_match - 1] == '/') + { + max_match --; + pathname[max_match] = '\0'; + } + + // And then make sure that the item is visible + fileList->topline(i); + first_line = i; + } + else + { + // Succeeding match; compare to find maximum string match... + while (max_match > min_match) +#if defined(WIN32) || defined(__EMX__) + if (strnicmp(file, pathname, max_match) == 0) +#else + if (strncmp(file, pathname, max_match) == 0) +#endif // WIN32 || __EMX__ + break; + else + max_match --; + + // Truncate the string as needed... + pathname[max_match] = '\0'; + } + } + } + + fileList->deselect(0); + fileList->redraw(); + + // If we have any matches, add them to the input field... + if (first_line > 0 && min_match == max_match && + max_match == (int)strlen(fileList->text(first_line))) + fileList->select(first_line); + else if (max_match > min_match && max_match != 100000) + { + // Add the matching portion... + fileName->replace(0, min_match, pathname); + + // Highlight it; if the user just pressed the backspace + // key, position the cursor at the start of the selection. + // Otherwise, put the cursor at the end of the selection so + // s/he can press the right arrow to accept the selection + // (Tab and End also do this for both cases.) + if (Fl::event_key() == FL_BackSpace) + fileName->position(min_match - 1, max_match); + else + fileName->position(max_match, min_match); + } + + // See if we need to enable the OK button... + sprintf(pathname, "%s/%s", directory_, fileName->value()); + + if ((type_ & CREATE || access(pathname, 0) == 0) && + (!filename_isdir(pathname) || type_ & DIRECTORY)) + okButton->activate(); + else + okButton->deactivate(); + } +} + + +// +// End of "$Id: Fl_File_Chooser2.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $". +// diff --git a/src/Fl_File_Icon.cxx b/src/Fl_File_Icon.cxx new file mode 100644 index 000000000..5c711235a --- /dev/null +++ b/src/Fl_File_Icon.cxx @@ -0,0 +1,1225 @@ +// +// "$Id: Fl_File_Icon.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $" +// +// Fl_File_Icon routines. +// +// KDE icon code donated by Maarten De Boer. +// +// Copyright 1999-2001 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// +// Contents: +// +// Fl_File_Icon::Fl_File_Icon() - Create a new file icon. +// Fl_File_Icon::~Fl_File_Icon() - Remove a file icon. +// Fl_File_Icon::add() - Add data to an icon. +// Fl_File_Icon::find() - Find an icon based upon a given file. +// Fl_File_Icon::draw() - Draw an icon. +// Fl_File_Icon::label() - Set the widgets label to an icon. +// Fl_File_Icon::labeltype() - Draw the icon label. +// Fl_File_Icon::load() - Load an icon file... +// Fl_File_Icon::load_fti() - Load an SGI-format FTI file... +// Fl_File_Icon::load_xpm() - Load an XPM icon file... +// Fl_File_Icon::load_system_icons() - Load the standard system icons/filetypes. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +# define F_OK 0 +# define strcasecmp stricmp +# define strncasecmp strnicmp +#else +# include +#endif /* WIN32 || __EMX__ */ + +#include +#include +#include +#include + + +// +// Define missing POSIX/XPG4 macros as needed... +// + +#ifndef S_ISDIR +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif /* !S_ISDIR */ + + +// +// Icon cache... +// + +Fl_File_Icon *Fl_File_Icon::first_ = (Fl_File_Icon *)0; + + +// +// Local functions... +// + +static void load_kde_icons(const char *directory); +static void load_kde_mimelnk(const char *filename); +static char *kde_to_fltk_pattern(const char *kdepattern); +static char *get_kde_val(char *str, const char *key); + + +// +// 'Fl_File_Icon::Fl_File_Icon()' - Create a new file icon. +// + +Fl_File_Icon::Fl_File_Icon(const char *p, /* I - Filename pattern */ + int t, /* I - File type */ + int nd, /* I - Number of data values */ + short *d) /* I - Data values */ +{ + // Initialize the pattern and type... + pattern_ = p; + type_ = t; + + // Copy icon data as needed... + if (nd) + { + num_data_ = nd; + alloc_data_ = nd + 1; + data_ = (short *)calloc(sizeof(short), nd + 1); + memcpy(data_, d, nd * sizeof(short)); + } + else + { + num_data_ = 0; + alloc_data_ = 0; + } + + // And add the icon to the list of icons... + next_ = first_; + first_ = this; +} + + +// +// 'Fl_File_Icon::~Fl_File_Icon()' - Remove a file icon. +// + +Fl_File_Icon::~Fl_File_Icon() +{ + Fl_File_Icon *current, // Current icon in list + *prev; // Previous icon in list + + + // Find the icon in the list... + for (current = first_, prev = (Fl_File_Icon *)0; + current != this && current != (Fl_File_Icon *)0; + prev = current, current = current->next_); + + // Remove the icon from the list as needed... + if (current) + { + if (prev) + prev->next_ = current->next_; + else + first_ = current->next_; + } + + // Free any memory used... + if (alloc_data_) + free(data_); +} + + +// +// 'Fl_File_Icon::add()' - Add data to an icon. +// + +short * // O - Pointer to new data value +Fl_File_Icon::add(short d) // I - Data to add +{ + short *dptr; // Pointer to new data value + + + // Allocate/reallocate memory as needed + if ((num_data_ + 1) >= alloc_data_) + { + alloc_data_ += 128; + + if (alloc_data_ == 128) + dptr = (short *)malloc(sizeof(short) * alloc_data_); + else + dptr = (short *)realloc(data_, sizeof(short) * alloc_data_); + + if (dptr == NULL) + return (NULL); + + data_ = dptr; + } + + // Store the new data value and return + data_[num_data_++] = d; + data_[num_data_] = END; + + return (data_ + num_data_ - 1); +} + + +// +// 'Fl_File_Icon::find()' - Find an icon based upon a given file. +// + +Fl_File_Icon * // O - Matching file icon or NULL +Fl_File_Icon::find(const char *filename, // I - Name of file */ + int filetype) // I - Enumerated file type +{ + Fl_File_Icon *current; // Current file in list + struct stat fileinfo; // Information on file + + + // Get file information if needed... + if (filetype == ANY) + if (!stat(filename, &fileinfo)) + { + if (S_ISDIR(fileinfo.st_mode)) + filetype = DIRECTORY; +#ifdef S_IFIFO + else if (S_ISFIFO(fileinfo.st_mode)) + filetype = FIFO; +#endif // S_IFIFO +#if defined(S_ICHR) && defined(S_IBLK) + else if (S_ISCHR(fileinfo.st_mode) || S_ISBLK(fileinfo.st_mode)) + filetype = DEVICE; +#endif // S_ICHR && S_IBLK +#ifdef S_ILNK + else if (S_ISLNK(fileinfo.st_mode)) + filetype = LINK; +#endif // S_ILNK + else + filetype = PLAIN; + } + + // Loop through the available file types and return any match that + // is found... + for (current = first_; current != (Fl_File_Icon *)0; current = current->next_) + if ((current->type_ == filetype || current->type_ == ANY) && + filename_match(filename, current->pattern_)) + break; + + // Return the match (if any)... + return (current); +} + + +// +// 'Fl_File_Icon::draw()' - Draw an icon. +// + +void +Fl_File_Icon::draw(int x, // I - Upper-lefthand X + int y, // I - Upper-lefthand Y + int w, // I - Width of bounding box + int h, // I - Height of bounding box + Fl_Color ic, // I - Icon color... + int active) // I - Active or inactive? +{ + Fl_Color c; // Current color + short *d; // Pointer to data + short *prim; // Pointer to start of primitive... + double scale; // Scale of icon + + + // Don't try to draw a NULL array! + if (num_data_ == 0) + return; + + // Setup the transform matrix as needed... + scale = w < h ? w : h; + + fl_push_matrix(); + fl_translate((float)x + 0.5 * ((float)w - scale), + (float)y + 0.5 * ((float)h + scale)); + fl_scale(scale, -scale); + + // Loop through the array until we see an unmatched END... + d = data_; + prim = NULL; + c = ic; + + if (active) + fl_color(c); + else + fl_color(inactive(c)); + + while (*d != END || prim) + switch (*d) + { + case END : + switch (*prim) + { + case LINE : + fl_end_line(); + break; + + case CLOSEDLINE : + fl_end_loop(); + break; + + case POLYGON : + fl_end_polygon(); + break; + + case OUTLINEPOLYGON : + fl_end_polygon(); + + if (active) + { + if (prim[1] == 256) + fl_color(ic); + else + fl_color((Fl_Color)prim[1]); + } + else + { + if (prim[1] == 256) + fl_color(inactive(ic)); + else + fl_color(inactive((Fl_Color)prim[1])); + } + + fl_begin_loop(); + + prim += 2; + while (*prim == VERTEX) + { + fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); + prim += 3; + } + + fl_end_loop(); + fl_color(c); + break; + } + + prim = NULL; + d ++; + break; + + case COLOR : + if (d[1] == 256) + c = ic; + else + c = (Fl_Color)d[1]; + + if (!active) + c = inactive(c); + + fl_color(c); + d += 2; + break; + + case LINE : + prim = d; + d ++; + fl_begin_line(); + break; + + case CLOSEDLINE : + prim = d; + d ++; + fl_begin_loop(); + break; + + case POLYGON : + prim = d; + d ++; + fl_begin_polygon(); + break; + + case OUTLINEPOLYGON : + prim = d; + d += 2; + fl_begin_polygon(); + break; + + case VERTEX : + if (prim) + fl_vertex(d[1] * 0.0001, d[2] * 0.0001); + d += 3; + break; + } + + // If we still have an open primitive, close it... + if (prim) + switch (*prim) + { + case LINE : + fl_end_line(); + break; + + case CLOSEDLINE : + fl_end_loop(); + break; + + case POLYGON : + fl_end_polygon(); + break; + + case OUTLINEPOLYGON : + fl_end_polygon(); + + if (active) + { + if (prim[1] == 256) + fl_color(ic); + else + fl_color((Fl_Color)prim[1]); + } + else + { + if (prim[1] == 256) + fl_color(inactive(ic)); + else + fl_color(inactive((Fl_Color)prim[1])); + } + + fl_begin_loop(); + + prim += 2; + while (*prim == VERTEX) + { + fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); + prim += 3; + } + + fl_end_loop(); + fl_color(c); + break; + } + + // Restore the transform matrix + fl_pop_matrix(); +} + + +// +// 'Fl_File_Icon::label()' - Set the widget's label to an icon. +// + +void +Fl_File_Icon::label(Fl_Widget *w) // I - Widget to label +{ + Fl::set_labeltype(_FL_ICON_LABEL, labeltype, 0); + w->label(_FL_ICON_LABEL, (const char*)this); +} + + +// +// 'Fl_File_Icon::labeltype()' - Draw the icon label. +// + +void +Fl_File_Icon::labeltype(const Fl_Label *o, // I - Label data + int x, // I - X position of label + int y, // I - Y position of label + int w, // I - Width of label + int h, // I - Height of label + Fl_Align a) // I - Label alignment (not used) +{ + Fl_File_Icon *icon; // Pointer to icon data + + + (void)a; + + icon = (Fl_File_Icon *)(o->value); + + icon->draw(x, y, w, h, (Fl_Color)(o->color)); +} + + +// +// 'Fl_File_Icon::load()' - Load an icon file... +// + +void +Fl_File_Icon::load(const char *f) // I - File to read from +{ + const char *ext; // File extension + + + if ((ext = filename_ext(f)) == NULL) + { + fprintf(stderr, "Fl_File_Icon::load(): Unknown file type for \"%s\".\n", f); + return; + } + + if (strcmp(ext, ".fti") == 0) + load_fti(f); + else if (strcmp(ext, ".xpm") == 0) + load_xpm(f); +#if 0 + else if (strcmp(ext, ".png") == 0) + load_png(f); +#endif /* 0 */ + else + { + fprintf(stderr, "Fl_File_Icon::load(): Unknown file type for \"%s\".\n", f); + return; + } +} + + +// +// 'Fl_File_Icon::load_fti()' - Load an SGI-format FTI file... +// + +void +Fl_File_Icon::load_fti(const char *fti) // I - File to read from +{ + FILE *fp; // File pointer + int ch; // Current character + char command[255], // Command string ("vertex", etc.) + params[255], // Parameter string ("10.0,20.0", etc.) + *ptr; // Pointer into strings + int outline; // Outline polygon + + + // Try to open the file... + if ((fp = fopen(fti, "rb")) == NULL) + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Unable to open \"%s\" - %s\n", + fti, strerror(errno)); + return; + } + + // Read the entire file, adding data as needed... + outline = 0; + + while ((ch = getc(fp)) != EOF) + { + // Skip whitespace + if (isspace(ch)) + continue; + + // Skip comments starting with "#"... + if (ch == '#') + { + while ((ch = getc(fp)) != EOF) + if (ch == '\n') + break; + + if (ch == EOF) + break; + else + continue; + } + + // OK, this character better be a letter... + if (!isalpha(ch)) + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Expected a letter at file position %ld (saw '%c')\n", + ftell(fp) - 1, ch); + break; + } + + // Scan the command name... + ptr = command; + *ptr++ = ch; + + while ((ch = getc(fp)) != EOF) + { + if (ch == '(') + break; + else if (ptr < (command + sizeof(command) - 1)) + *ptr++ = ch; + } + + *ptr++ = '\0'; + + // Make sure we stopped on a parenthesis... + if (ch != '(') + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Expected a ( at file position %ld (saw '%c')\n", + ftell(fp) - 1, ch); + break; + } + + // Scan the parameters... + ptr = params; + + while ((ch = getc(fp)) != EOF) + { + if (ch == ')') + break; + else if (ptr < (params + sizeof(params) - 1)) + *ptr++ = ch; + } + + *ptr++ = '\0'; + + // Make sure we stopped on a parenthesis... + if (ch != ')') + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Expected a ) at file position %ld (saw '%c')\n", + ftell(fp) - 1, ch); + break; + } + + // Make sure the next character is a semicolon... + if ((ch = getc(fp)) != ';') + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Expected a ; at file position %ld (saw '%c')\n", + ftell(fp) - 1, ch); + break; + } + + // Now process the command... + if (strcmp(command, "color") == 0) + { + // Set the color; for negative colors blend the two primaries to + // produce a composite color. Also, the following symbolic color + // names are understood: + // + // name FLTK color + // ------------- ---------- + // iconcolor 256; mapped to the icon color in Fl_File_Icon::draw() + // shadowcolor FL_DARK3 + // outlinecolor FL_BLACK + if (strcmp(params, "iconcolor") == 0) + add_color(256); + else if (strcmp(params, "shadowcolor") == 0) + add_color(FL_DARK3); + else if (strcmp(params, "outlinecolor") == 0) + add_color(FL_BLACK); + else + { + short c = atoi(params); // Color value + + + if (c < 0) + { + // Composite color; compute average... + c = -c; + add_color(fl_color_average((Fl_Color)(c >> 4), + (Fl_Color)(c & 15), 0.5)); + } + else + add_color(c); + } + } + else if (strcmp(command, "bgnline") == 0) + add(LINE); + else if (strcmp(command, "bgnclosedline") == 0) + add(CLOSEDLINE); + else if (strcmp(command, "bgnpolygon") == 0) + add(POLYGON); + else if (strcmp(command, "bgnoutlinepolygon") == 0) + { + add(OUTLINEPOLYGON); + outline = add(0) - data_; + } + else if (strcmp(command, "endoutlinepolygon") == 0 && outline) + { + // Set the outline color; see above for valid values... + if (strcmp(params, "iconcolor") == 0) + data_[outline] = 256; + else if (strcmp(params, "shadowcolor") == 0) + data_[outline] = FL_DARK3; + else if (strcmp(params, "outlinecolor") == 0) + data_[outline] = FL_BLACK; + else + { + short c = atoi(params); // Color value + + + if (c < 0) + { + // Composite color; compute average... + c = -c; + data_[outline] = fl_color_average((Fl_Color)(c >> 4), (Fl_Color)(c & 15), 0.5); + } + else + data_[outline] = c; + } + + outline = 0; + add(END); + } + else if (strncmp(command, "end", 3) == 0) + add(END); + else if (strcmp(command, "vertex") == 0) + { + float x, y; // Coordinates of vertex + + + if (sscanf(params, "%f,%f", &x, &y) != 2) + break; + + add_vertex((short)(x * 100.0 + 0.5), (short)(y * 100.0 + 0.5)); + } + else + { + fprintf(stderr, "Fl_File_Icon::load_fti(): Unknown command \"%s\" at file position %ld.\n", + command, ftell(fp) - 1); + break; + } + } + + // Close the file and return... + fclose(fp); + +#ifdef DEBUG + printf("Icon File \"%s\":\n", fti); + for (int i = 0; i < num_data_; i ++) + printf(" %d,\n", data_[i]); +#endif /* DEBUG */ +} + + +// +// 'Fl_File_Icon::load_xpm()' - Load an XPM icon file... +// + +void +Fl_File_Icon::load_xpm(const char *xpm) // I - File to read from +{ + FILE *fp; // File pointer + int i, j; // Looping vars + int ch; // Current character + int bg; // Background color + char line[1024], // Line from file + val[16], // Color value + *ptr; // Pointer into line + int x, y; // X & Y in image + int startx; // Starting X coord + int width, height; // Width and height of image + int ncolors; // Number of colors + short colors[256]; // Colors + int red, green, blue; // Red, green, and blue values + + + // Try to open the file... + if ((fp = fopen(xpm, "rb")) == NULL) + return; + + // Read the file header until we find the first string... + ptr = NULL; + while (fgets(line, sizeof(line), fp) != NULL) + if ((ptr = strchr(line, '\"')) != NULL) + break; + + if (ptr == NULL) + { + // Nothing to load... + fclose(fp); + return; + } + + // Get the size of the image... + sscanf(ptr + 1, "%d%d%d", &width, &height, &ncolors); + + // Now read the colormap... + memset(colors, 0, sizeof(colors)); + bg = ' '; + + for (i = 0; i < ncolors; i ++) + { + while (fgets(line, sizeof(line), fp) != NULL) + if ((ptr = strchr(line, '\"')) != NULL) + break; + + if (ptr == NULL) + { + // Nothing to load... + fclose(fp); + return; + } + + // Get the color's character + ptr ++; + ch = *ptr++; + + // Get the color value... + if ((ptr = strstr(ptr, "c ")) == NULL) + { + // No color; make this black... + colors[ch] = FL_BLACK; + } + else if (ptr[2] == '#') + { + // Read the RGB triplet... + ptr += 3; + for (j = 0; j < 12; j ++) + if (!isxdigit(ptr[j])) + break; + + switch (j) + { + case 0 : + bg = ch; + default : + red = green = blue = 0; + break; + + case 3 : + val[0] = ptr[0]; + val[1] = '\0'; + red = 255 * strtol(val, NULL, 16) / 15; + + val[0] = ptr[1]; + val[1] = '\0'; + green = 255 * strtol(val, NULL, 16) / 15; + + val[0] = ptr[2]; + val[1] = '\0'; + blue = 255 * strtol(val, NULL, 16) / 15; + break; + + case 6 : + case 9 : + case 12 : + j /= 3; + + val[0] = ptr[0]; + val[1] = ptr[1]; + val[2] = '\0'; + red = strtol(val, NULL, 16); + + val[0] = ptr[j + 0]; + val[1] = ptr[j + 1]; + val[2] = '\0'; + green = strtol(val, NULL, 16); + + val[0] = ptr[2 * j + 0]; + val[1] = ptr[2 * j + 1]; + val[2] = '\0'; + blue = strtol(val, NULL, 16); + break; + } + + if (red == green && green == blue) + colors[ch] = FL_GRAY_RAMP + (FL_NUM_GRAY - 1) * red / 255; + else + colors[ch] = fl_color_cube((FL_NUM_RED - 1) * red / 255, + (FL_NUM_GREEN - 1) * green / 255, + (FL_NUM_BLUE - 1) * blue / 255); + } + else + { + // Read a color name... + if (strncasecmp(ptr + 2, "white", 5) == 0) + colors[ch] = FL_WHITE; + else if (strncasecmp(ptr + 2, "black", 5) == 0) + colors[ch] = FL_BLACK; + else if (strncasecmp(ptr + 2, "none", 4) == 0) + { + colors[ch] = FL_BLACK; + bg = ch; + } + else + colors[ch] = FL_GRAY; + } + } + + // Read the image data... + for (y = height - 1; y >= 0; y --) + { + while (fgets(line, sizeof(line), fp) != NULL) + if ((ptr = strchr(line, '\"')) != NULL) + break; + + if (ptr == NULL) + { + // Nothing to load... + fclose(fp); + return; + } + + startx = 0; + ch = bg; + ptr ++; + + for (x = 0; x < width; x ++, ptr ++) + if (*ptr != ch) + { + if (ch != bg) + { + add_color(colors[ch]); + add(POLYGON); + add_vertex(startx * 9000 / width + 1000, y * 9000 / height + 500); + add_vertex(x * 9000 / width + 1000, y * 9000 / height + 500); + add_vertex(x * 9000 / width + 1000, (y + 1) * 9000 / height + 500); + add_vertex(startx * 9000 / width + 1000, (y + 1) * 9000 / height + 500); + add(END); + } + + ch = *ptr; + startx = x; + } + + if (ch != bg) + { + add_color(colors[ch]); + add(POLYGON); + add_vertex(startx * 9000 / width + 1000, y * 9000 / height + 500); + add_vertex(x * 9000 / width + 1000, y * 9000 / height + 500); + add_vertex(x * 9000 / width + 1000, (y + 1) * 9000 / height + 500); + add_vertex(startx * 9000 / width + 1000, (y + 1) * 9000 / height + 500); + add(END); + } + } + + // Close the file and return... + fclose(fp); + +#ifdef DEBUG + printf("Icon File \"%s\":\n", xpm); + for (i = 0; i < num_data_; i ++) + printf(" %d,\n", data_[i]); +#endif /* DEBUG */ +} + + +// +// 'Fl_File_Icon::load_system_icons()' - Load the standard system icons/filetypes. + +void +Fl_File_Icon::load_system_icons(void) +{ + Fl_File_Icon *icon; // New icons + static int init = 0; // Have the icons been initialized? + static short plain[] = // Plain file icon + { + COLOR, 256, OUTLINEPOLYGON, FL_GRAY, + VERTEX, 2000, 1000, VERTEX, 2000, 9000, + VERTEX, 6000, 9000, VERTEX, 8000, 7000, + VERTEX, 8000, 1000, END, OUTLINEPOLYGON, FL_GRAY, + VERTEX, 6000, 9000, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, END, + COLOR, FL_BLACK, LINE, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, VERTEX, 8000, 1000, + VERTEX, 2000, 1000, END, LINE, VERTEX, 3000, 7000, + VERTEX, 5000, 7000, END, LINE, VERTEX, 3000, 6000, + VERTEX, 5000, 6000, END, LINE, VERTEX, 3000, 5000, + VERTEX, 7000, 5000, END, LINE, VERTEX, 3000, 4000, + VERTEX, 7000, 4000, END, LINE, VERTEX, 3000, 3000, + VERTEX, 7000, 3000, END, LINE, VERTEX, 3000, 2000, + VERTEX, 7000, 2000, END, + END + }; + static short image[] = // Image file icon + { + COLOR, 256, OUTLINEPOLYGON, FL_GRAY, + VERTEX, 2000, 1000, VERTEX, 2000, 9000, + VERTEX, 6000, 9000, VERTEX, 8000, 7000, + VERTEX, 8000, 1000, END, OUTLINEPOLYGON, FL_GRAY, + VERTEX, 6000, 9000, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, END, + COLOR, FL_BLACK, LINE, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, VERTEX, 8000, 1000, + VERTEX, 2000, 1000, END, + COLOR, FL_RED, POLYGON, VERTEX, 3500, 2500, + VERTEX, 3000, 3000, VERTEX, 3000, 4000, + VERTEX, 3500, 4500, VERTEX, 4500, 4500, + VERTEX, 5000, 4000, VERTEX, 5000, 3000, + VERTEX, 4500, 2500, END, + COLOR, FL_GREEN, POLYGON, VERTEX, 5500, 2500, + VERTEX, 5000, 3000, VERTEX, 5000, 4000, + VERTEX, 5500, 4500, VERTEX, 6500, 4500, + VERTEX, 7000, 4000, VERTEX, 7000, 3000, + VERTEX, 6500, 2500, END, + COLOR, FL_BLUE, POLYGON, VERTEX, 4500, 3500, + VERTEX, 4000, 4000, VERTEX, 4000, 5000, + VERTEX, 4500, 5500, VERTEX, 5500, 5500, + VERTEX, 6000, 5000, VERTEX, 6000, 4000, + VERTEX, 5500, 3500, END, + END + }; + static short dir[] = // Directory icon + { + COLOR, 256, POLYGON, VERTEX, 1000, 1000, + VERTEX, 1000, 7500, VERTEX, 9000, 7500, + VERTEX, 9000, 1000, END, + POLYGON, VERTEX, 1000, 7500, VERTEX, 2500, 9000, + VERTEX, 5000, 9000, VERTEX, 6500, 7500, END, + COLOR, FL_WHITE, LINE, VERTEX, 1500, 1500, + VERTEX, 1500, 7000, VERTEX, 9000, 7000, END, + COLOR, FL_BLACK, LINE, VERTEX, 9000, 7500, + VERTEX, 9000, 1000, VERTEX, 1000, 1000, END, + COLOR, FL_GRAY, LINE, VERTEX, 1000, 1000, + VERTEX, 1000, 7500, VERTEX, 2500, 9000, + VERTEX, 5000, 9000, VERTEX, 6500, 7500, + VERTEX, 9000, 7500, END, + END + }; + + + // Add symbols if they haven't been added already... + if (!init) + { + if (!access("/usr/share/mimelnk", F_OK)) + { + // Load KDE icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/share/icons/unknown.xpm"); + + load_kde_icons("/usr/share/mimelnk"); + } + else if (!access("/usr/share/icons/folder.xpm", F_OK)) + { + // Load GNOME icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/share/icons/page.xpm"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_xpm("/usr/share/icons/folder.xpm"); + } + else if (!access("/usr/dt/appconfig/icons", F_OK)) + { + // Load CDE icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/dt/appconfig/icons/C/Dtdata.m.pm"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_xpm("/usr/dt/appconfig/icons/C/DtdirB.m.pm"); + + icon = new Fl_File_Icon("core", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/dt/appconfig/icons/C/Dtcore.m.pm"); + + icon = new Fl_File_Icon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/dt/appconfig/icons/C/Dtimage.m.pm"); + + icon = new Fl_File_Icon("*.{eps|pdf|ps}", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/dt/appconfig/icons/C/Dtps.m.pm"); + + icon = new Fl_File_Icon("*.ppd", Fl_File_Icon::PLAIN); + icon->load_xpm("/usr/dt/appconfig/icons/C/DtPrtpr.m.pm"); + } + else if (!access("/usr/lib/filetype", F_OK)) + { + // Load SGI icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_fti("/usr/lib/filetype/iconlib/generic.folder.closed.fti"); + + icon = new Fl_File_Icon("core", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/default/iconlib/CoreFile.fti"); + + icon = new Fl_File_Icon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/ImageFile.fti"); + + if (!access("/usr/lib/filetype/install/iconlib/acroread.doc.fti", F_OK)) + { + icon = new Fl_File_Icon("*.{eps|ps}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); + + icon = new Fl_File_Icon("*.pdf", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/install/iconlib/acroread.doc.fti"); + } + else + { + icon = new Fl_File_Icon("*.{eps|pdf|ps}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); + } + + if (!access("/usr/lib/filetype/install/iconlib/html.fti", F_OK)) + { + icon = new Fl_File_Icon("*.{htm|html|shtml}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); + icon->load_fti("/usr/lib/filetype/install/iconlib/html.fti"); + } + + if (!access("/usr/lib/filetype/install/iconlib/color.ps.idle.fti", F_OK)) + { + icon = new Fl_File_Icon("*.ppd", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/install/iconlib/color.ps.idle.fti"); + } + } + else + { + // Create the default icons... + new Fl_File_Icon("*", Fl_File_Icon::PLAIN, sizeof(plain) / sizeof(plain[0]), plain); + new Fl_File_Icon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN, + sizeof(image) / sizeof(image[0]), image); + new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY, sizeof(dir) / sizeof(dir[0]), dir); + } + + // Mark things as initialized... + init = 1; + } +} + + +// +// 'load_kde_icons()' - Load KDE icon files. +// + +static void +load_kde_icons(const char *directory) // I - Directory to load +{ + int i; // Looping var + int n; // Number of entries in directory + dirent **entries; // Entries in directory + char full[1024]; // Full name of file + + + entries = (dirent **)0; + n = filename_list(directory, &entries); + + for (i = 0; i < n; i ++) + { + if (entries[i]->d_name[0] != '.') + { + strcpy(full, directory); + strcat(full,"/"); + strcat(full, entries[i]->d_name); + + if (filename_isdir(full)) + load_kde_icons(full); + else + load_kde_mimelnk(full); + } + + free((void *)entries[i]); + } + + free((void*)entries); +} + + +// +// 'load_kde_mimelnk()' - Load a KDE "mimelnk" file. +// + +static void +load_kde_mimelnk(const char *filename) +{ + FILE *fp; + char tmp[256]; + char iconfilename[1024]; + char pattern[1024]; + char mimetype[1024]; + char *val; + char full_iconfilename[1024]; + Fl_File_Icon *icon; + + + if ((fp = fopen(filename, "rb")) != NULL) + { + while (fgets(tmp, sizeof(tmp), fp)) + { + if ((val = get_kde_val(tmp, "Icon")) != NULL) + strcpy(iconfilename, val); + else if ((val = get_kde_val(tmp, "MimeType")) != NULL) + strcpy(mimetype, val); + else if ((val = get_kde_val(tmp, "Patterns")) != NULL) + strcpy(pattern, val); + } + + if (iconfilename && pattern) + { + sprintf(full_iconfilename, "/usr/share/icons/%s", iconfilename); + + if (strcmp(mimetype, "inode/directory") == 0) + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + else + icon = new Fl_File_Icon(kde_to_fltk_pattern(pattern), Fl_File_Icon::PLAIN); + + icon->load_xpm(full_iconfilename); + } + + fclose(fp); + } +} + + +// +// 'kde_to_fltk_pattern()' - Convert a KDE pattern to a FLTK pattern. +// + +static char * +kde_to_fltk_pattern(const char *kdepattern) +{ + char *pattern, + *patptr; + + + pattern = (char *)malloc(strlen(kdepattern) + 3); + strcpy(pattern, "{"); + strcat(pattern, kdepattern); + + if (pattern[strlen(pattern) - 1] == ';') + pattern[strlen(pattern) - 1] = '\0'; + + strcat(pattern, "}"); + + for (patptr = pattern; *patptr; patptr ++) + if (*patptr == ';') + *patptr = '|'; + + return (pattern); +} + + +// +// 'get_kde_val()' - Get a KDE value. +// + +static char * +get_kde_val(char *str, + const char *key) +{ + while (*str == *key) + { + str ++; + key ++; + } + + if (*key == '\0' && *str == '=') + { + if (str[strlen(str) - 1] == '\n') + str[strlen(str) - 1] = '\0'; + + return (str + 1); + } + + return ((char *)0); +} + + +// +// End of "$Id: Fl_File_Icon.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $". +// diff --git a/src/Fl_HelpDialog.cxx b/src/Fl_HelpDialog.cxx deleted file mode 100644 index 71e04e8a8..000000000 --- a/src/Fl_HelpDialog.cxx +++ /dev/null @@ -1,221 +0,0 @@ -// generated by Fast Light User Interface Designer (fluid) version 1.0100 - -#include "../FL/Fl_HelpDialog.H" - -inline void Fl_HelpDialog::cb_view__i(Fl_HelpView*, void*) { - if (view_->changed()) -{ - index_ ++; - - if (index_ >= 100) - { - memcpy(line_, line_ + 10, sizeof(line_[0]) * 90); - memcpy(file_, file_ + 10, sizeof(file_[0]) * 90); - index_ -= 10; - } - - max_ = index_; - - strcpy(file_[index_], view_->filename()); - line_[index_] = view_->topline(); - - if (index_ > 0) - back_->activate(); - else - back_->deactivate(); - - forward_->deactivate(); - window_->label(view_->title()); -} -else if (view_->filename()) -{ - strncpy(file_[index_], view_->filename(), 255); - file_[index_][255] = '\0'; - line_[index_] = view_->topline(); -}; -} -void Fl_HelpDialog::cb_view_(Fl_HelpView* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_view__i(o,v); -} - -inline void Fl_HelpDialog::cb_Close_i(Fl_Button*, void*) { - window_->hide(); -} -void Fl_HelpDialog::cb_Close(Fl_Button* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_Close_i(o,v); -} - -inline void Fl_HelpDialog::cb_back__i(Fl_Button*, void*) { - if (index_ > 0) - index_ --; - -if (index_ == 0) - back_->deactivate(); - -forward_->activate(); - -if (strcmp(view_->filename(), file_[index_]) != 0) - view_->load(file_[index_]); - -view_->topline(line_[index_]); -} -void Fl_HelpDialog::cb_back_(Fl_Button* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_back__i(o,v); -} - -inline void Fl_HelpDialog::cb_forward__i(Fl_Button*, void*) { - if (index_ < max_) - index_ ++; - -if (index_ >= max_) - forward_->deactivate(); - -back_->activate(); - -if (strcmp(view_->filename(), file_[index_]) != 0) - view_->load(file_[index_]); - -view_->topline(line_[index_]); -} -void Fl_HelpDialog::cb_forward_(Fl_Button* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_forward__i(o,v); -} - -inline void Fl_HelpDialog::cb_smaller__i(Fl_Button*, void*) { - if (view_->textsize() > 8) - view_->textsize(view_->textsize() - 2); - -if (view_->textsize() <= 8) - smaller_->deactivate(); -larger_->activate(); -} -void Fl_HelpDialog::cb_smaller_(Fl_Button* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_smaller__i(o,v); -} - -inline void Fl_HelpDialog::cb_larger__i(Fl_Button*, void*) { - if (view_->textsize() < 18) - view_->textsize(view_->textsize() + 2); - -if (view_->textsize() >= 18) - larger_->deactivate(); -smaller_->activate(); -} -void Fl_HelpDialog::cb_larger_(Fl_Button* o, void* v) { - ((Fl_HelpDialog*)(o->parent()->user_data()))->cb_larger__i(o,v); -} - -Fl_HelpDialog::Fl_HelpDialog() { - Fl_Double_Window* w; - { Fl_Double_Window* o = window_ = new Fl_Double_Window(530, 385, "Help Dialog"); - w = o; - o->user_data((void*)(this)); - { Fl_HelpView* o = view_ = new Fl_HelpView(10, 10, 510, 330); - o->box(FL_DOWN_BOX); - o->callback((Fl_Callback*)cb_view_); - o->end(); - Fl_Group::current()->resizable(o); - } - { Fl_Button* o = new Fl_Button(425, 350, 95, 25, "Close"); - o->callback((Fl_Callback*)cb_Close); - } - { Fl_Button* o = back_ = new Fl_Button(365, 350, 25, 25, "@<-"); - o->shortcut(0xff51); - o->labelcolor(2); - o->callback((Fl_Callback*)cb_back_); - } - { Fl_Button* o = forward_ = new Fl_Button(395, 350, 25, 25, "@->"); - o->shortcut(0xff53); - o->labelcolor(2); - o->callback((Fl_Callback*)cb_forward_); - } - { Fl_Button* o = smaller_ = new Fl_Button(305, 350, 25, 25, "F"); - o->labelfont(1); - o->labelsize(10); - o->callback((Fl_Callback*)cb_smaller_); - } - { Fl_Button* o = larger_ = new Fl_Button(335, 350, 25, 25, "F"); - o->labelfont(1); - o->labelsize(16); - o->callback((Fl_Callback*)cb_larger_); - } - o->end(); - } - back_->deactivate(); -forward_->deactivate(); - -index_ = -1; -max_ = 0; -} - -Fl_HelpDialog::~Fl_HelpDialog() { - delete window_; -} - -int Fl_HelpDialog::h() { - return (window_->h()); -} - -void Fl_HelpDialog::hide() { - window_->hide(); -} - -void Fl_HelpDialog::load(const char *f) { - view_->set_changed(); -view_->load(f); -window_->label(view_->title()); -} - -void Fl_HelpDialog::position(int xx, int yy) { - window_->position(xx, yy); -} - -void Fl_HelpDialog::resize(int xx, int yy, int ww, int hh) { - window_->resize(xx, yy, ww, hh); -} - -void Fl_HelpDialog::show() { - window_->show(); -} - -void Fl_HelpDialog::textsize(uchar s) { - view_->textsize(s); - -if (s <= 8) - smaller_->deactivate(); -else - smaller_->activate(); - -if (s >= 18) - larger_->deactivate(); -else - larger_->activate(); -} - -uchar Fl_HelpDialog::textsize() { - return (view_->textsize()); -} - -void Fl_HelpDialog::topline(const char *n) { - view_->topline(n); -} - -void Fl_HelpDialog::topline(int n) { - view_->topline(n); -} - -int Fl_HelpDialog::visible() { - return (window_->visible()); -} - -int Fl_HelpDialog::w() { - return (window_->w()); -} - -int Fl_HelpDialog::x() { - return (window_->x()); -} - -int Fl_HelpDialog::y() { - return (window_->y()); -} diff --git a/src/Fl_HelpDialog.fl b/src/Fl_HelpDialog.fl deleted file mode 100644 index 53f7fe698..000000000 --- a/src/Fl_HelpDialog.fl +++ /dev/null @@ -1,191 +0,0 @@ -# data file for the Fltk User Interface Designer (fluid) -version 1.0100 -header_name {../FL/Fl_HelpDialog.H} -code_name {.cxx} -gridx 5 -gridy 5 -snap 3 -class Fl_HelpDialog {open -} { - decl {int index_;} {} - decl {int max_;} {} - decl {int line_[100];} {} - decl {char file_[100][256];} {} - Function {Fl_HelpDialog()} {open - } { - Fl_Window window_ { - label {Help Dialog} open selected - private xywh {470 380 530 385} type Double resizable - code0 {\#include } visible - } { - Fl_Group view_ { - callback {if (view_->changed()) -{ - index_ ++; - - if (index_ >= 100) - { - memcpy(line_, line_ + 10, sizeof(line_[0]) * 90); - memcpy(file_, file_ + 10, sizeof(file_[0]) * 90); - index_ -= 10; - } - - max_ = index_; - - strcpy(file_[index_], view_->filename()); - line_[index_] = view_->topline(); - - if (index_ > 0) - back_->activate(); - else - back_->deactivate(); - - forward_->deactivate(); - window_->label(view_->title()); -} -else if (view_->filename()) -{ - strncpy(file_[index_], view_->filename(), 255); - file_[index_][255] = '\\0'; - line_[index_] = view_->topline(); -}} open - private xywh {10 10 510 330} box DOWN_BOX resizable - code0 {\#include } - class Fl_HelpView - } {} - Fl_Button {} { - label Close - callback {window_->hide();} - xywh {425 350 95 25} - } - Fl_Button back_ { - label {@<-} - callback {if (index_ > 0) - index_ --; - -if (index_ == 0) - back_->deactivate(); - -forward_->activate(); - -if (strcmp(view_->filename(), file_[index_]) != 0) - view_->load(file_[index_]); - -view_->topline(line_[index_]);} - private xywh {365 350 25 25} shortcut 0xff51 labelcolor 2 - } - Fl_Button forward_ { - label {@->} - callback {if (index_ < max_) - index_ ++; - -if (index_ >= max_) - forward_->deactivate(); - -back_->activate(); - -if (strcmp(view_->filename(), file_[index_]) != 0) - view_->load(file_[index_]); - -view_->topline(line_[index_]);} - private xywh {395 350 25 25} shortcut 0xff53 labelcolor 2 - } - Fl_Button smaller_ { - label F - callback {if (view_->textsize() > 8) - view_->textsize(view_->textsize() - 2); - -if (view_->textsize() <= 8) - smaller_->deactivate(); -larger_->activate();} - private xywh {305 350 25 25} labelfont 1 labelsize 10 - } - Fl_Button larger_ { - label F - callback {if (view_->textsize() < 18) - view_->textsize(view_->textsize() + 2); - -if (view_->textsize() >= 18) - larger_->deactivate(); -smaller_->activate();} - private xywh {335 350 25 25} labelfont 1 labelsize 16 - } - } - code {back_->deactivate(); -forward_->deactivate(); - -index_ = -1; -max_ = 0;} {} - } - Function {~Fl_HelpDialog()} {} { - code {delete window_;} {} - } - Function {h()} {return_type int - } { - code {return (window_->h());} {} - } - Function {hide()} {return_type void - } { - code {window_->hide();} {} - } - Function {load(const char *f)} {return_type void - } { - code {view_->set_changed(); -view_->load(f); -window_->label(view_->title());} {} - } - Function {position(int xx, int yy)} {return_type void - } { - code {window_->position(xx, yy);} {} - } - Function {resize(int xx, int yy, int ww, int hh)} {return_type void - } { - code {window_->resize(xx, yy, ww, hh);} {} - } - Function {show()} {return_type void - } { - code {window_->show();} {} - } - Function {textsize(uchar s)} {return_type void - } { - code {view_->textsize(s); - -if (s <= 8) - smaller_->deactivate(); -else - smaller_->activate(); - -if (s >= 18) - larger_->deactivate(); -else - larger_->activate();} {} - } - Function {textsize()} {return_type uchar - } { - code {return (view_->textsize());} {} - } - Function {topline(const char *n)} {return_type void - } { - code {view_->topline(n);} {} - } - Function {topline(int n)} {return_type void - } { - code {view_->topline(n);} {} - } - Function {visible()} {return_type int - } { - code {return (window_->visible());} {} - } - Function {w()} {return_type int - } { - code {return (window_->w());} {} - } - Function {x()} {return_type int - } { - code {return (window_->x());} {} - } - Function {y()} {return_type int - } { - code {return (window_->y());} {} - } -} diff --git a/src/Fl_HelpView.cxx b/src/Fl_HelpView.cxx deleted file mode 100644 index 479e8865d..000000000 --- a/src/Fl_HelpView.cxx +++ /dev/null @@ -1,3584 +0,0 @@ -// -// "$Id: Fl_HelpView.cxx,v 1.1.2.5 2001/09/10 03:09:43 easysw Exp $" -// -// Fl_HelpView widget routines. -// -// Copyright 1997-2001 by Easy Software Products. -// Image support donated by Matthias Melcher, Copyright 2000. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems to "fltk-bugs@fltk.org". -// -// Contents: -// -// Fl_HelpView::add_block() - Add a text block to the list. -// Fl_HelpView::add_image() - Add an image to the image cache. -// Fl_HelpView::add_link() - Add a new link to the list. -// Fl_HelpView::add_target() - Add a new target to the list. -// Fl_HelpView::compare_targets() - Compare two targets. -// Fl_HelpView::do_align() - Compute the alignment for a line in -// a block. -// Fl_HelpView::draw() - Draw the Fl_HelpView widget. -// Fl_HelpView::find_image() - Find an image by name -// Fl_HelpView::format() - Format the help text. -// Fl_HelpView::format_table() - Format a table... -// Fl_HelpView::get_align() - Get an alignment attribute. -// Fl_HelpView::get_attr() - Get an attribute value from the string. -// Fl_HelpView::get_color() - Get an alignment attribute. -// Fl_HelpView::handle() - Handle events in the widget. -// Fl_HelpView::Fl_HelpView() - Build a Fl_HelpView widget. -// Fl_HelpView::~Fl_HelpView() - Destroy a Fl_HelpView widget. -// Fl_HelpView::load() - Load the specified file. -// Fl_HelpView::load_gif() - Load a GIF image file... -// Fl_HelpView::load_jpeg() - Load a JPEG image file. -// Fl_HelpView::load_png() - Load a PNG image file. -// Fl_HelpView::resize() - Resize the help widget. -// Fl_HelpView::topline() - Set the top line to the named target. -// Fl_HelpView::topline() - Set the top line by number. -// Fl_HelpView::value() - Set the help text directly. -// Fl_HelpView::compare_blocks() - Compare two blocks. -// gif_read_cmap() - Read the colormap from a GIF file... -// gif_get_block() - Read a GIF data block... -// gif_get_code() - Get a LZW code from the file... -// gif_read_lzw() - Read a byte from the LZW stream... -// gif_read_image() - Read a GIF image stream... -// scrollbar_callback() - A callback for the scrollbar. -// - -// -// Include necessary header files... -// - -#include -#include "config.h" -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -# include -#endif /* HAVE_STRINGS_H */ -#include - -#include -#include - -#if defined(WIN32) -# include -# include -# define strcasecmp(s,t) stricmp((s), (t)) -# define strncasecmp(s,t,n) strnicmp((s), (t), (n)) -#elif defined(__EMX__) -# define strcasecmp(s,t) stricmp((s), (t)) -# define strncasecmp(s,t,n) strnicmp((s), (t), (n)) -#else -# include -#endif // WIN32 - -extern "C" -{ -#ifdef HAVE_LIBPNG -# include -# include -#endif // HAVE_LIBPNG - -#ifdef HAVE_LIBJPEG -# include -#endif // HAVE_LIBJPEG -} - -#define MAX_COLUMNS 200 - - -// -// Typedef the C API sort function type the only way I know how... -// - -extern "C" -{ - typedef int (*compare_func_t)(const void *, const void *); -} - -// -// GIF definitions... -// - -#define GIF_INTERLACE 0x40 -#define GIF_COLORMAP 0x80 - -typedef unsigned char gif_cmap_t[256][3]; - - -// -// Local globals... -// - -static const char *broken_xpm[] = - { - "16 24 4 1", - "@ c #000000", - " c #ffffff", - "+ c none", - "x c #ff0000", - // pixels - "@@@@@@@+++++++++", - "@ @++++++++++", - "@ @+++++++++++", - "@ @++@++++++++", - "@ @@+++++++++", - "@ @+++@+++++", - "@ @++@@++++@", - "@ xxx @@ @++@@", - "@ xxx xx@@ @", - "@ xxx xxx @", - "@ xxxxxx @", - "@ xxxx @", - "@ xxxxxx @", - "@ xxx xxx @", - "@ xxx xxx @", - "@ xxx xxx @", - "@ @", - "@ @", - "@ @", - "@ @", - "@ @", - "@ @", - "@ @", - "@@@@@@@@@@@@@@@@", - NULL - }; - -static Fl_Pixmap *broken_image = (Fl_Pixmap *)0; -static int gif_eof = 0; // Did we hit EOF? -static unsigned fltk_colors[] = - { - 0x00000000, - 0xff000000, - 0x00ff0000, - 0xffff0000, - 0x0000ff00, - 0xff00ff00, - 0x00ffff00, - 0xffffff00, - 0x55555500, - 0xc6717100, - 0x71c67100, - 0x8e8e3800, - 0x7171c600, - 0x8e388e00, - 0x388e8e00, - 0xaaaaaa00, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x55555500, - 0x00000000, - 0x0d0d0d00, - 0x1a1a1a00, - 0x26262600, - 0x31313100, - 0x3d3d3d00, - 0x48484800, - 0x55555500, - 0x5f5f5f00, - 0x6a6a6a00, - 0x75757500, - 0x80808000, - 0x8a8a8a00, - 0x95959500, - 0xa0a0a000, - 0xaaaaaa00, - 0xb5b5b500, - 0xc0c0c000, - 0xcbcbcb00, - 0xd5d5d500, - 0xe0e0e000, - 0xeaeaea00, - 0xf5f5f500, - 0xffffff00, - 0x00000000, - 0x00240000, - 0x00480000, - 0x006d0000, - 0x00910000, - 0x00b60000, - 0x00da0000, - 0x00ff0000, - 0x3f000000, - 0x3f240000, - 0x3f480000, - 0x3f6d0000, - 0x3f910000, - 0x3fb60000, - 0x3fda0000, - 0x3fff0000, - 0x7f000000, - 0x7f240000, - 0x7f480000, - 0x7f6d0000, - 0x7f910000, - 0x7fb60000, - 0x7fda0000, - 0x7fff0000, - 0xbf000000, - 0xbf240000, - 0xbf480000, - 0xbf6d0000, - 0xbf910000, - 0xbfb60000, - 0xbfda0000, - 0xbfff0000, - 0xff000000, - 0xff240000, - 0xff480000, - 0xff6d0000, - 0xff910000, - 0xffb60000, - 0xffda0000, - 0xffff0000, - 0x00003f00, - 0x00243f00, - 0x00483f00, - 0x006d3f00, - 0x00913f00, - 0x00b63f00, - 0x00da3f00, - 0x00ff3f00, - 0x3f003f00, - 0x3f243f00, - 0x3f483f00, - 0x3f6d3f00, - 0x3f913f00, - 0x3fb63f00, - 0x3fda3f00, - 0x3fff3f00, - 0x7f003f00, - 0x7f243f00, - 0x7f483f00, - 0x7f6d3f00, - 0x7f913f00, - 0x7fb63f00, - 0x7fda3f00, - 0x7fff3f00, - 0xbf003f00, - 0xbf243f00, - 0xbf483f00, - 0xbf6d3f00, - 0xbf913f00, - 0xbfb63f00, - 0xbfda3f00, - 0xbfff3f00, - 0xff003f00, - 0xff243f00, - 0xff483f00, - 0xff6d3f00, - 0xff913f00, - 0xffb63f00, - 0xffda3f00, - 0xffff3f00, - 0x00007f00, - 0x00247f00, - 0x00487f00, - 0x006d7f00, - 0x00917f00, - 0x00b67f00, - 0x00da7f00, - 0x00ff7f00, - 0x3f007f00, - 0x3f247f00, - 0x3f487f00, - 0x3f6d7f00, - 0x3f917f00, - 0x3fb67f00, - 0x3fda7f00, - 0x3fff7f00, - 0x7f007f00, - 0x7f247f00, - 0x7f487f00, - 0x7f6d7f00, - 0x7f917f00, - 0x7fb67f00, - 0x7fda7f00, - 0x7fff7f00, - 0xbf007f00, - 0xbf247f00, - 0xbf487f00, - 0xbf6d7f00, - 0xbf917f00, - 0xbfb67f00, - 0xbfda7f00, - 0xbfff7f00, - 0xff007f00, - 0xff247f00, - 0xff487f00, - 0xff6d7f00, - 0xff917f00, - 0xffb67f00, - 0xffda7f00, - 0xffff7f00, - 0x0000bf00, - 0x0024bf00, - 0x0048bf00, - 0x006dbf00, - 0x0091bf00, - 0x00b6bf00, - 0x00dabf00, - 0x00ffbf00, - 0x3f00bf00, - 0x3f24bf00, - 0x3f48bf00, - 0x3f6dbf00, - 0x3f91bf00, - 0x3fb6bf00, - 0x3fdabf00, - 0x3fffbf00, - 0x7f00bf00, - 0x7f24bf00, - 0x7f48bf00, - 0x7f6dbf00, - 0x7f91bf00, - 0x7fb6bf00, - 0x7fdabf00, - 0x7fffbf00, - 0xbf00bf00, - 0xbf24bf00, - 0xbf48bf00, - 0xbf6dbf00, - 0xbf91bf00, - 0xbfb6bf00, - 0xbfdabf00, - 0xbfffbf00, - 0xff00bf00, - 0xff24bf00, - 0xff48bf00, - 0xff6dbf00, - 0xff91bf00, - 0xffb6bf00, - 0xffdabf00, - 0xffffbf00, - 0x0000ff00, - 0x0024ff00, - 0x0048ff00, - 0x006dff00, - 0x0091ff00, - 0x00b6ff00, - 0x00daff00, - 0x00ffff00, - 0x3f00ff00, - 0x3f24ff00, - 0x3f48ff00, - 0x3f6dff00, - 0x3f91ff00, - 0x3fb6ff00, - 0x3fdaff00, - 0x3fffff00, - 0x7f00ff00, - 0x7f24ff00, - 0x7f48ff00, - 0x7f6dff00, - 0x7f91ff00, - 0x7fb6ff00, - 0x7fdaff00, - 0x7fffff00, - 0xbf00ff00, - 0xbf24ff00, - 0xbf48ff00, - 0xbf6dff00, - 0xbf91ff00, - 0xbfb6ff00, - 0xbfdaff00, - 0xbfffff00, - 0xff00ff00, - 0xff24ff00, - 0xff48ff00, - 0xff6dff00, - 0xff91ff00, - 0xffb6ff00, - 0xffdaff00, - 0xffffff00 - }; - - -// -// Local functions... -// - -static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap); -static int gif_get_block(FILE *fp, unsigned char *buffer); -static int gif_get_code (FILE *fp, int code_size, int first_time); -static int gif_read_lzw(FILE *fp, int first_time, int input_code_size); -static int gif_read_image(FILE *fp, Fl_HelpImage *img, gif_cmap_t cmap, - int interlace); -static void scrollbar_callback(Fl_Widget *s, void *); - - -// -// 'Fl_HelpView::add_block()' - Add a text block to the list. -// - -Fl_HelpBlock * // O - Pointer to new block -Fl_HelpView::add_block(const char *s, // I - Pointer to start of block text - int xx, // I - X position of block - int yy, // I - Y position of block - int ww, // I - Right margin of block - int hh, // I - Height of block - unsigned char border) // I - Draw border? -{ - Fl_HelpBlock *temp; // New block - - -// printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n", -// s, xx, yy, ww, hh, border); - - if (nblocks_ >= ablocks_) - { - ablocks_ += 16; - - if (ablocks_ == 16) - blocks_ = (Fl_HelpBlock *)malloc(sizeof(Fl_HelpBlock) * ablocks_); - else - blocks_ = (Fl_HelpBlock *)realloc(blocks_, sizeof(Fl_HelpBlock) * ablocks_); - } - - temp = blocks_ + nblocks_; - temp->start = s; - temp->x = xx; - temp->y = yy; - temp->w = ww; - temp->h = hh; - temp->border = border; - nblocks_ ++; - - return (temp); -} - - -// -// 'Fl_HelpView::add_image()' - Add an image to the image cache. -// - -Fl_HelpImage * // O - Image or NULL if not found -Fl_HelpView::add_image(const char *name, // I - Path of image - const char *wattr, // I - Width attribute - const char *hattr, // I - Height attribute - int make) // I - Make the image? -{ - Fl_HelpImage *img, // New image - *orig; // Original image - FILE *fp; // File pointer - unsigned char header[16]; // First 16 bytes of file - int status; // Status of load... - const char *localname; // Local filename - char dir[1024]; // Current directory - char temp[1024], // Temporary filename - *tempptr; // Pointer into temporary name - int width, // Desired width of image - height; // Desired height of image - - - // See if the image has already been loaded... - if ((img = find_image(name, wattr, hattr)) != (Fl_HelpImage *)0) - { - // Make the image if needed... - if (!img->image) - img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d); - - return (img); - } - - // See if the image exists with the default size info... - orig = find_image(name, "", ""); - - // Allocate memory as needed... - if (aimage_ == nimage_) - { - aimage_ += 16; - - if (aimage_ == 16) - image_ = (Fl_HelpImage *)malloc(sizeof(Fl_HelpImage) * aimage_); - else - image_ = (Fl_HelpImage *)realloc(image_, sizeof(Fl_HelpImage) * aimage_); - } - - img = image_ + nimage_; - img->name = strdup(name); - img->copy = 0; - - if (!orig) - { - // See if the image can be found... - if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL) - { - if (name[0] == '/') - { - strcpy(temp, directory_); - if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) - strcpy(tempptr, name); - else - strcat(temp, name); - } - else - sprintf(temp, "%s/%s", directory_, name); - - if (link_) - localname = (*link_)(temp); - else - localname = temp; - } - else if (name[0] != '/' && strchr(name, ':') == NULL) - { - if (directory_[0]) - sprintf(temp, "%s/%s", directory_, name); - else - { - getcwd(dir, sizeof(dir)); - sprintf(temp, "file:%s/%s", dir, name); - } - - if (link_) - localname = (*link_)(temp); - else - localname = temp; - } - else if (link_) - localname = (*link_)(name); - else - localname = name; - - if (!localname) - return ((Fl_HelpImage *)0); - - if (strncmp(localname, "file:", 5) == 0) - localname += 5; - - // Figure out the file type... - if ((fp = fopen(localname, "rb")) == NULL) - return ((Fl_HelpImage *)0); - - if (fread(header, 1, sizeof(header), fp) == 0) - return ((Fl_HelpImage *)0); - - rewind(fp); - - // Load the image as appropriate... - if (memcmp(header, "GIF87a", 6) == 0 || - memcmp(header, "GIF89a", 6) == 0) - status = load_gif(img, fp); - #ifdef HAVE_LIBPNG - else if (memcmp(header, "\211PNG", 4) == 0) - status = load_png(img, fp); - #endif // HAVE_LIBPNG - #ifdef HAVE_LIBJPEG - else if (memcmp(header, "\377\330\377", 3) == 0 && // Start-of-Image - header[3] >= 0xe0 && header[3] <= 0xef) // APPn - status = load_jpeg(img, fp); - #endif // HAVE_LIBJPEG - else - status = 0; - - fclose(fp); - - if (!status) - { - free(img->name); - return ((Fl_HelpImage *)0); - } - - img->wattr[0] = '\0'; - img->hattr[0] = '\0'; - - nimage_ ++; - - // Allocate memory as needed for the new copy... - if (aimage_ == nimage_) - { - aimage_ += 16; - image_ = (Fl_HelpImage *)realloc(image_, sizeof(Fl_HelpImage) * aimage_); - } - - orig = image_ + nimage_ - 1; - img = image_ + nimage_; - img->name = strdup(name); - } - -// printf("orig->data = %p, width = %d, height = %d\n", orig->data, -// orig->w, orig->h); - - // Copy image data from original image... - img->data = orig->data; - img->w = orig->w; - img->h = orig->h; - img->d = orig->d; - img->copy = 1; - - // Figure out the size of the image... - if (wattr[0]) - { - if (wattr[strlen(wattr) - 1] == '%') - width = atoi(wattr) * (w() - 24) / 100; - else - width = atoi(wattr); - } - else - width = 0; - - if (hattr[0]) - { - if (hattr[strlen(hattr) - 1] == '%') - height = atoi(hattr) * h() / 100; - else - height = atoi(hattr); - } - else - height = 0; - - if (width == 0 && height == 0) - { - // Use image size... - width = img->w; - height = img->h; - } - else if (width == 0) - // Scale width to height - width = img->w * height / img->h; - else if (height == 0) - // Scale height to width - height = img->h * width / img->w; - - // Scale the image as needed... - if (width != img->w && height != img->h) - { - unsigned char *scaled, // Scaled image data - *sptr, // Source image data pointer - *dptr; // Destination image data pointer - int sy, // Source coordinates - dx, dy, // Destination coordinates - xerr, yerr, // X & Y errors - xmod, ymod, // X & Y moduli - xstep, ystep; // X & Y step increments - - - xmod = img->w % width; - xstep = (img->w / width) * img->d; - ymod = img->h % height; - ystep = img->h / height; - - if ((scaled = (unsigned char *)malloc(width * height * img->d)) != NULL) - { - img->copy = 0; - - // Scale the image... - for (dy = height, sy = 0, yerr = height / 2, dptr = scaled; dy > 0; dy --) - { - for (dx = width, xerr = width / 2, - sptr = img->data + sy * img->w * img->d; - dx > 0; - dx --) - { - *dptr++ = sptr[0]; - if (img->d > 1) - { - *dptr++ = sptr[1]; - *dptr++ = sptr[2]; - } - - sptr += xstep; - xerr -= xmod; - if (xerr <= 0) - { - xerr += width; - sptr += img->d; - } - } - - sy += ystep; - yerr -= ymod; - if (yerr <= 0) - { - yerr += height; - sy ++; - } - } - - // Finally, copy the new size and data to the image structure... - if (!orig) - free(img->data); - - img->w = width; - img->h = height; - img->data = scaled; - } - } - - strncpy(img->wattr, wattr, sizeof(img->wattr) - 1); - img->wattr[sizeof(img->wattr) - 1] = '\0'; - strncpy(img->hattr, hattr, sizeof(img->hattr) - 1); - img->hattr[sizeof(img->hattr) - 1] = '\0'; - - if (make) - img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d); - else - img->image = (Fl_Image *)0; - - nimage_ ++; - -// printf("img->data = %p, width = %d, height = %d\n", img->data, -// img->w, img->h); - - return (img); -} - - -// -// 'Fl_HelpView::add_link()' - Add a new link to the list. -// - -void -Fl_HelpView::add_link(const char *n, // I - Name of link - int xx, // I - X position of link - int yy, // I - Y position of link - int ww, // I - Width of link text - int hh) // I - Height of link text -{ - Fl_HelpLink *temp; // New link - char *target; // Pointer to target name - - - if (nlinks_ >= alinks_) - { - alinks_ += 16; - - if (alinks_ == 16) - links_ = (Fl_HelpLink *)malloc(sizeof(Fl_HelpLink) * alinks_); - else - links_ = (Fl_HelpLink *)realloc(links_, sizeof(Fl_HelpLink) * alinks_); - } - - temp = links_ + nlinks_; - - temp->x = xx; - temp->y = yy; - temp->w = xx + ww; - temp->h = yy + hh; - - strncpy(temp->filename, n, sizeof(temp->filename)); - temp->filename[sizeof(temp->filename) - 1] = '\0'; - - if ((target = strrchr(temp->filename, '#')) != NULL) - { - *target++ = '\0'; - strncpy(temp->name, target, sizeof(temp->name)); - temp->name[sizeof(temp->name) - 1] = '\0'; - } - else - temp->name[0] = '\0'; - - nlinks_ ++; -} - - -// -// 'Fl_HelpView::add_target()' - Add a new target to the list. -// - -void -Fl_HelpView::add_target(const char *n, // I - Name of target - int yy) // I - Y position of target -{ - Fl_HelpTarget *temp; // New target - - - if (ntargets_ >= atargets_) - { - atargets_ += 16; - - if (atargets_ == 16) - targets_ = (Fl_HelpTarget *)malloc(sizeof(Fl_HelpTarget) * atargets_); - else - targets_ = (Fl_HelpTarget *)realloc(targets_, sizeof(Fl_HelpTarget) * atargets_); - } - - temp = targets_ + ntargets_; - - temp->y = yy; - strncpy(temp->name, n, sizeof(temp->name)); - temp->name[sizeof(temp->name) - 1] = '\0'; - - ntargets_ ++; -} - - -// -// 'Fl_HelpView::compare_targets()' - Compare two targets. -// - -int // O - Result of comparison -Fl_HelpView::compare_targets(const Fl_HelpTarget *t0, // I - First target - const Fl_HelpTarget *t1) // I - Second target -{ - return (strcasecmp(t0->name, t1->name)); -} - - -// -// 'Fl_HelpView::do_align()' - Compute the alignment for a line in a block. -// - -int // O - New line -Fl_HelpView::do_align(Fl_HelpBlock *block, // I - Block to add to - int line, // I - Current line - int xx, // I - Current X position - int a, // I - Current alignment - int &l) // IO - Starting link -{ - int offset; // Alignment offset - - - switch (a) - { - case RIGHT : // Right align - offset = block->w - xx; - break; - case CENTER : // Center - offset = (block->w - xx) / 2; - break; - default : // Left align - offset = 0; - break; - } - - block->line[line] = block->x + offset; - - if (line < 31) - line ++; - - while (l < nlinks_) - { - links_[l].x += offset; - links_[l].w += offset; - l ++; - } - - return (line); -} - - -// -// 'Fl_HelpView::draw()' - Draw the Fl_HelpView widget. -// - -void -Fl_HelpView::draw() -{ - int i; // Looping var - const Fl_HelpBlock *block; // Pointer to current block - const char *ptr, // Pointer to text in block - *attrs; // Pointer to start of element attributes - char *s, // Pointer into buffer - buf[1024], // Text buffer - attr[1024]; // Attribute buffer - int xx, yy, ww, hh; // Current positions and sizes - int line; // Current line - unsigned char font, size; // Current font and size - int head, pre, // Flags for text - needspace; // Do we need whitespace? - Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; - // Box to draw... - Fl_Color tc, c; // Table/cell background color - - - // Draw the scrollbar and box first... - if (scrollbar_.visible()) - { - draw_child(scrollbar_); - draw_box(b, x(), y(), w() - 17, h(), bgcolor_); - } - else - draw_box(b, x(), y(), w(), h(), bgcolor_); - - if (!value_) - return; - - // Clip the drawing to the inside of the box... - fl_push_clip(x() + 4, y() + 4, w() - 28, h() - 8); - fl_color(textcolor_); - - tc = c = bgcolor_; - - // Draw all visible blocks... - for (i = 0, block = blocks_; i < nblocks_ && (block->y - topline_) < h(); i ++, block ++) - if ((block->y + block->h) >= topline_) - { - line = 0; - xx = block->line[line]; - yy = block->y - topline_; - hh = 0; - pre = 0; - head = 0; - needspace = 0; - - initfont(font, size); - - for (ptr = block->start, s = buf; ptr < block->end;) - { - if ((*ptr == '<' || isspace(*ptr)) && s > buf) - { - if (!head && !pre) - { - // Check width... - *s = '\0'; - s = buf; - ww = (int)fl_width(buf); - - if (needspace && xx > block->x) - xx += (int)fl_width(' '); - - if ((xx + ww) > block->w) - { - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = 0; - } - - fl_draw(buf, xx + x(), yy + y()); - - xx += ww; - if ((size + 2) > hh) - hh = size + 2; - - needspace = 0; - } - else if (pre) - { - while (isspace(*ptr)) - { - if (*ptr == '\n') - { - *s = '\0'; - s = buf; - - fl_draw(buf, xx + x(), yy + y()); - - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = size + 2; - } - else if (*ptr == '\t') - { - // Do tabs every 8 columns... - while (((s - buf) & 7)) - *s++ = ' '; - } - else - *s++ = ' '; - - if ((size + 2) > hh) - hh = size + 2; - - ptr ++; - } - - if (s > buf) - { - *s = '\0'; - s = buf; - - fl_draw(buf, xx + x(), yy + y()); - xx += (int)fl_width(buf); - } - - needspace = 0; - } - else - { - s = buf; - - while (isspace(*ptr)) - ptr ++; - } - } - - if (*ptr == '<') - { - ptr ++; - while (*ptr && *ptr != '>' && !isspace(*ptr)) - if (s < (buf + sizeof(buf) - 1)) - *s++ = *ptr++; - else - ptr ++; - - *s = '\0'; - s = buf; - - attrs = ptr; - while (*ptr && *ptr != '>') - ptr ++; - - if (*ptr == '>') - ptr ++; - - if (strcasecmp(buf, "HEAD") == 0) - head = 1; - else if (strcasecmp(buf, "BR") == 0) - { - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = 0; - } - else if (strcasecmp(buf, "HR") == 0) - { - fl_line(block->x + x(), yy + y(), block->w + x(), - yy + y()); - - if (line < 31) - line ++; - xx = block->line[line]; - yy += 2 * hh; - hh = 0; - } - else if (strcasecmp(buf, "CENTER") == 0 || - strcasecmp(buf, "P") == 0 || - strcasecmp(buf, "H1") == 0 || - strcasecmp(buf, "H2") == 0 || - strcasecmp(buf, "H3") == 0 || - strcasecmp(buf, "H4") == 0 || - strcasecmp(buf, "H5") == 0 || - strcasecmp(buf, "H6") == 0 || - strcasecmp(buf, "UL") == 0 || - strcasecmp(buf, "OL") == 0 || - strcasecmp(buf, "DL") == 0 || - strcasecmp(buf, "LI") == 0 || - strcasecmp(buf, "DD") == 0 || - strcasecmp(buf, "DT") == 0 || - strcasecmp(buf, "PRE") == 0) - { - if (tolower(buf[0]) == 'h') - { - font = FL_HELVETICA_BOLD; - size = textsize_ + '7' - buf[1]; - } - else if (strcasecmp(buf, "DT") == 0) - { - font = textfont_ | FL_ITALIC; - size = textsize_; - } - else if (strcasecmp(buf, "PRE") == 0) - { - font = FL_COURIER; - size = textsize_; - pre = 1; - } - - if (strcasecmp(buf, "LI") == 0) - { - fl_font(FL_SYMBOL, size); - fl_draw("\267", xx - size + x(), yy + y()); - } - - pushfont(font, size); - - if (c != bgcolor_) - { - fl_color(c); - fl_rectf(block->x + x() - 4, - block->y - topline_ + y() - size - 3, - block->w - block->x + 7, block->h + size - 5); - fl_color(textcolor_); - } - } - else if (strcasecmp(buf, "A") == 0 && - get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) - fl_color(linkcolor_); - else if (strcasecmp(buf, "/A") == 0) - fl_color(textcolor_); - else if (strcasecmp(buf, "B") == 0) - pushfont(font |= FL_BOLD, size); - else if (strcasecmp(buf, "TABLE") == 0) - tc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_); - else if (strcasecmp(buf, "TD") == 0 || - strcasecmp(buf, "TH") == 0) - { - if (tolower(buf[1]) == 'h') - pushfont(font |= FL_BOLD, size); - else - pushfont(font = textfont_, size); - - c = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc); - - if (c != bgcolor_) - { - fl_color(c); - fl_rectf(block->x + x() - 4, - block->y - topline_ + y() - size - 3, - block->w - block->x + 7, block->h + size - 5); - fl_color(textcolor_); - } - - if (block->border) - fl_rect(block->x + x() - 4, - block->y - topline_ + y() - size - 3, - block->w - block->x + 7, block->h + size - 5); - } - else if (strcasecmp(buf, "I") == 0) - pushfont(font |= FL_ITALIC, size); - else if (strcasecmp(buf, "CODE") == 0) - pushfont(font = FL_COURIER, size); - else if (strcasecmp(buf, "KBD") == 0) - pushfont(font = FL_COURIER_BOLD, size); - else if (strcasecmp(buf, "VAR") == 0) - pushfont(font = FL_COURIER_ITALIC, size); - else if (strcasecmp(buf, "/HEAD") == 0) - head = 0; - else if (strcasecmp(buf, "/H1") == 0 || - strcasecmp(buf, "/H2") == 0 || - strcasecmp(buf, "/H3") == 0 || - strcasecmp(buf, "/H4") == 0 || - strcasecmp(buf, "/H5") == 0 || - strcasecmp(buf, "/H6") == 0 || - strcasecmp(buf, "/B") == 0 || - strcasecmp(buf, "/I") == 0 || - strcasecmp(buf, "/CODE") == 0 || - strcasecmp(buf, "/KBD") == 0 || - strcasecmp(buf, "/VAR") == 0) - popfont(font, size); - else if (strcasecmp(buf, "/TABLE") == 0) - tc = c = bgcolor_; - else if (strcasecmp(buf, "/TD") == 0 || - strcasecmp(buf, "/TH") == 0) - c = tc; - else if (strcasecmp(buf, "/PRE") == 0) - { - popfont(font, size); - pre = 0; - } - else if (strcasecmp(buf, "IMG") == 0) - { - Fl_HelpImage *img = (Fl_HelpImage *)0; - int width = 16; - int height = 24; - char wattr[8], hattr[8]; - - - get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); - get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); - - if (get_attr(attrs, "SRC", attr, sizeof(attr))) - if ((img = add_image(attr, wattr, hattr)) != NULL) - { - if (!img->image) - img = (Fl_HelpImage *)0; - } - - if (img) - { - width = img->w; - height = img->h; - } - else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL) - strcpy(attr, "IMG"); - - ww = width; - - if (needspace && xx > block->x) - xx += (int)fl_width(' '); - - if ((xx + ww) > block->w) - { - if (line < 31) - line ++; - - xx = block->line[line]; - yy += hh; - hh = 0; - } - - if (img) - img->image->draw(xx + x(), - yy + y() - fl_height() + fl_descent() + 2); - else - broken_image->draw(xx + x(), - yy + y() - fl_height() + fl_descent() + 2); - - xx += ww; - if ((height + 2) > hh) - hh = height + 2; - - needspace = 0; - } - } - else if (*ptr == '\n' && pre) - { - *s = '\0'; - s = buf; - - fl_draw(buf, xx + x(), yy + y()); - - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = size + 2; - needspace = 0; - - ptr ++; - } - else if (isspace(*ptr)) - { - if (pre) - { - if (*ptr == ' ') - *s++ = ' '; - else - { - // Do tabs every 8 columns... - while (((s - buf) & 7)) - *s++ = ' '; - } - } - - ptr ++; - needspace = 1; - } - else if (*ptr == '&') - { - ptr ++; - - if (strncasecmp(ptr, "amp;", 4) == 0) - { - *s++ = '&'; - ptr += 4; - } - else if (strncasecmp(ptr, "lt;", 3) == 0) - { - *s++ = '<'; - ptr += 3; - } - else if (strncasecmp(ptr, "gt;", 3) == 0) - { - *s++ = '>'; - ptr += 3; - } - else if (strncasecmp(ptr, "nbsp;", 5) == 0) - { - *s++ = ' '; - ptr += 5; - } - else if (strncasecmp(ptr, "copy;", 5) == 0) - { - *s++ = '\251'; - ptr += 5; - } - else if (strncasecmp(ptr, "reg;", 4) == 0) - { - *s++ = '\256'; - ptr += 4; - } - else if (strncasecmp(ptr, "quot;", 5) == 0) - { - *s++ = '\"'; - ptr += 5; - } - - if ((size + 2) > hh) - hh = size + 2; - } - else - { - *s++ = *ptr++; - - if ((size + 2) > hh) - hh = size + 2; - } - } - - *s = '\0'; - - if (s > buf && !pre && !head) - { - ww = (int)fl_width(buf); - - if (needspace && xx > block->x) - xx += (int)fl_width(' '); - - if ((xx + ww) > block->w) - { - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = 0; - } - } - - if (s > buf && !head) - fl_draw(buf, xx + x(), yy + y()); - } - - fl_pop_clip(); -} - - -// -// 'Fl_HelpView::find_image()' - Find an image by name -// - -Fl_HelpImage * // O - Image or NULL if not found -Fl_HelpView::find_image(const char *name, // I - Path and name of image - const char *wattr, // I - Width attribute of image - const char *hattr) // I - Height attribute of image -{ - int i; // Looping var - Fl_HelpImage *img; // Current image - - - for (i = nimage_, img = image_; i > 0; i --, img ++) - if (strcmp(img->name, name) == 0 && - strcmp(img->wattr, wattr) == 0 && - strcmp(img->hattr, hattr) == 0) - return (img); - - return ((Fl_HelpImage *)0); -} - - -// -// 'Fl_HelpView::format()' - Format the help text. -// - -void -Fl_HelpView::format() -{ - int i; // Looping var - Fl_HelpBlock *block, // Current block - *cell; // Current table cell - int row; // Current table row (block number) - const char *ptr, // Pointer into block - *start, // Pointer to start of element - *attrs; // Pointer to start of element attributes - char *s, // Pointer into buffer - buf[1024], // Text buffer - attr[1024], // Attribute buffer - wattr[1024], // Width attribute buffer - hattr[1024], // Height attribute buffer - link[1024]; // Link destination - int xx, yy, ww, hh; // Size of current text fragment - int line; // Current line in block - int links; // Links for current line - unsigned char font, size; // Current font and size - unsigned char border; // Draw border? - int align, // Current alignment - newalign, // New alignment - head, // In the section? - pre, //
 text?
-		needspace;	// Do we need whitespace?
-  int		table_width;	// Width of table
-  int		column,		// Current table column number
-		columns[MAX_COLUMNS];
-				// Column widths
-
-
-  // Reset state variables...
-  nblocks_   = 0;
-  nlinks_    = 0;
-  ntargets_  = 0;
-  size_      = 0;
-  bgcolor_   = color();
-  textcolor_ = textcolor();
-  linkcolor_ = selection_color();
-
-  strcpy(title_, "Untitled");
-
-  if (!value_)
-    return;
-
-  // Flush images that are scaled by percentage...
-  for (i = 0; i < nimage_; i ++)
-    if (strchr(image_[i].wattr, '%') != NULL ||
-        strchr(image_[i].hattr, '%') != NULL)
-    {
-      // Flush this one...
-      free(image_[i].name);
-      free(image_[i].data);
-      delete image_[i].image;
-      nimage_ --;
-      if (i < nimage_)
-        memcpy(image_ + i, image_ + i + 1, (nimage_ - i) * sizeof(Fl_HelpImage));
-      i --;
-    }
-
-  // Setup for formatting...
-  initfont(font, size);
-
-  line      = 0;
-  links     = 0;
-  xx        = 4;
-  yy        = size + 2;
-  ww        = 0;
-  column    = 0;
-  border    = 0;
-  hh        = 0;
-  block     = add_block(value_, xx, yy, w() - 24, 0);
-  row       = 0;
-  head      = 0;
-  pre       = 0;
-  align     = LEFT;
-  newalign  = LEFT;
-  needspace = 0;
-  link[0]   = '\0';
-
-  for (ptr = value_, s = buf; *ptr;)
-  {
-    if ((*ptr == '<' || isspace(*ptr)) && s > buf)
-    {
-      if (!head && !pre)
-      {
-        // Check width...
-        *s = '\0';
-        ww = (int)fl_width(buf);
-
-        if (needspace && xx > block->x)
-	  ww += (int)fl_width(' ');
-
-//        printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
-//	       line, xx, ww, block->x, block->w);
-
-        if ((xx + ww) > block->w)
-	{
-          line     = do_align(block, line, xx, newalign, links);
-	  xx       = block->x;
-	  yy       += hh;
-	  block->h += hh;
-	  hh       = 0;
-	}
-
-        if (link[0])
-	  add_link(link, xx, yy - size, ww, size);
-
-	xx += ww;
-	if ((size + 2) > hh)
-	  hh = size + 2;
-
-	needspace = 0;
-      }
-      else if (pre)
-      {
-        // Handle preformatted text...
-	while (isspace(*ptr))
-	{
-	  if (*ptr == '\n')
-	  {
-            if (link[0])
-	      add_link(link, xx, yy - hh, ww, hh);
-
-            line     = do_align(block, line, xx, newalign, links);
-            xx       = block->x;
-	    yy       += hh;
-	    block->h += hh;
-	    hh       = size + 2;
-	  }
-
-          if ((size + 2) > hh)
-	    hh = size + 2;
-
-          ptr ++;
-	}
-
-	needspace = 0;
-      }
-      else
-      {
-        // Handle normal text or stuff in the  section...
-	while (isspace(*ptr))
-          ptr ++;
-      }
-
-      s = buf;
-    }
-
-    if (*ptr == '<')
-    {
-      start = ptr;
-      ptr ++;
-      while (*ptr && *ptr != '>' && !isspace(*ptr))
-        if (s < (buf + sizeof(buf) - 1))
-          *s++ = *ptr++;
-	else
-	  ptr ++;
-
-      *s = '\0';
-      s = buf;
-
-//      puts(buf);
-
-      attrs = ptr;
-      while (*ptr && *ptr != '>')
-        ptr ++;
-
-      if (*ptr == '>')
-        ptr ++;
-
-      if (strcasecmp(buf, "HEAD") == 0)
-        head = 1;
-      else if (strcasecmp(buf, "/HEAD") == 0)
-        head = 0;
-      else if (strcasecmp(buf, "TITLE") == 0)
-      {
-        // Copy the title in the document...
-        for (s = title_;
-	     *ptr != '<' && *ptr && s < (title_ + sizeof(title_) - 1);
-	     *s++ = *ptr++);
-
-	*s = '\0';
-	s = buf;
-      }
-      else if (strcasecmp(buf, "A") == 0)
-      {
-        if (get_attr(attrs, "NAME", attr, sizeof(attr)) != NULL)
-	  add_target(attr, yy - size - 2);
-	else if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
-	{
-	  strncpy(link, attr, sizeof(link) - 1);
-	  link[sizeof(link) - 1] = '\0';
-	}
-      }
-      else if (strcasecmp(buf, "/A") == 0)
-        link[0] = '\0';
-      else if (strcasecmp(buf, "BODY") == 0)
-      {
-        bgcolor_   = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)),
-	                       color());
-        textcolor_ = get_color(get_attr(attrs, "TEXT", attr, sizeof(attr)),
-	                       textcolor());
-        linkcolor_ = get_color(get_attr(attrs, "LINK", attr, sizeof(attr)),
-	                       selection_color());
-      }
-      else if (strcasecmp(buf, "BR") == 0)
-      {
-        line     = do_align(block, line, xx, newalign, links);
-        xx       = block->x;
-	block->h += hh;
-        yy       += hh;
-	hh       = 0;
-      }
-      else if (strcasecmp(buf, "CENTER") == 0 ||
-               strcasecmp(buf, "P") == 0 ||
-               strcasecmp(buf, "H1") == 0 ||
-	       strcasecmp(buf, "H2") == 0 ||
-	       strcasecmp(buf, "H3") == 0 ||
-	       strcasecmp(buf, "H4") == 0 ||
-	       strcasecmp(buf, "H5") == 0 ||
-	       strcasecmp(buf, "H6") == 0 ||
-	       strcasecmp(buf, "UL") == 0 ||
-	       strcasecmp(buf, "OL") == 0 ||
-	       strcasecmp(buf, "DL") == 0 ||
-	       strcasecmp(buf, "LI") == 0 ||
-	       strcasecmp(buf, "DD") == 0 ||
-	       strcasecmp(buf, "DT") == 0 ||
-	       strcasecmp(buf, "HR") == 0 ||
-	       strcasecmp(buf, "PRE") == 0 ||
-	       strcasecmp(buf, "TABLE") == 0)
-      {
-        block->end = start;
-        line       = do_align(block, line, xx, newalign, links);
-        xx         = block->x;
-        block->h   += hh;
-
-        if (strcasecmp(buf, "UL") == 0 ||
-	    strcasecmp(buf, "OL") == 0 ||
-	    strcasecmp(buf, "DL") == 0)
-        {
-	  block->h += size + 2;
-	  xx       += 4 * size;
-	}
-        else if (strcasecmp(buf, "TABLE") == 0)
-	{
-	  if (get_attr(attrs, "BORDER", attr, sizeof(attr)))
-	    border = atoi(attr);
-	  else
-	    border = 0;
-
-	  block->h += size + 2;
-
-          format_table(&table_width, columns, start);
-
-	  column = 0;
-	}
-
-        if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
-	{
-	  font = FL_HELVETICA_BOLD;
-	  size = textsize_ + '7' - buf[1];
-	}
-	else if (strcasecmp(buf, "DT") == 0)
-	{
-	  font = textfont_ | FL_ITALIC;
-	  size = textsize_;
-	}
-	else if (strcasecmp(buf, "PRE") == 0)
-	{
-	  font = FL_COURIER;
-	  size = textsize_;
-	  pre  = 1;
-	}
-	else
-	{
-	  font = textfont_;
-	  size = textsize_;
-	}
-
-	pushfont(font, size);
-
-        yy = block->y + block->h;
-        hh = 0;
-
-        if ((tolower(buf[0]) == 'h' && isdigit(buf[1])) ||
-	    strcasecmp(buf, "DD") == 0 ||
-	    strcasecmp(buf, "DT") == 0 ||
-	    strcasecmp(buf, "P") == 0)
-          yy += size + 2;
-	else if (strcasecmp(buf, "HR") == 0)
-	{
-	  hh += 2 * size;
-	  yy += size;
-	}
-
-        if (row)
-	  block = add_block(start, xx, yy, block->w, 0);
-	else
-	  block = add_block(start, xx, yy, w() - 24, 0);
-
-	needspace = 0;
-	line      = 0;
-
-	if (strcasecmp(buf, "CENTER") == 0)
-	  newalign = align = CENTER;
-	else
-	  newalign = get_align(attrs, align);
-      }
-      else if (strcasecmp(buf, "/CENTER") == 0 ||
-	       strcasecmp(buf, "/P") == 0 ||
-	       strcasecmp(buf, "/H1") == 0 ||
-	       strcasecmp(buf, "/H2") == 0 ||
-	       strcasecmp(buf, "/H3") == 0 ||
-	       strcasecmp(buf, "/H4") == 0 ||
-	       strcasecmp(buf, "/H5") == 0 ||
-	       strcasecmp(buf, "/H6") == 0 ||
-	       strcasecmp(buf, "/PRE") == 0 ||
-	       strcasecmp(buf, "/UL") == 0 ||
-	       strcasecmp(buf, "/OL") == 0 ||
-	       strcasecmp(buf, "/DL") == 0 ||
-	       strcasecmp(buf, "/TABLE") == 0)
-      {
-        line       = do_align(block, line, xx, newalign, links);
-        xx         = block->x;
-        block->end = ptr;
-
-        if (strcasecmp(buf, "/UL") == 0 ||
-	    strcasecmp(buf, "/OL") == 0 ||
-	    strcasecmp(buf, "/DL") == 0)
-	{
-	  xx       -= 4 * size;
-	  block->h += size + 2;
-	}
-	else if (strcasecmp(buf, "/TABLE") == 0)
-	  block->h += size + 2;
-	else if (strcasecmp(buf, "/PRE") == 0)
-	{
-	  pre = 0;
-	  hh  = 0;
-	}
-	else if (strcasecmp(buf, "/CENTER") == 0)
-	  align = LEFT;
-
-        popfont(font, size);
-
-        while (isspace(*ptr))
-	  ptr ++;
-
-        block->h += hh;
-        yy       += hh;
-
-        if (tolower(buf[2]) == 'l')
-          yy += size + 2;
-
-        if (row)
-	  block = add_block(ptr, xx, yy, block->w, 0);
-	else
-	  block = add_block(ptr, xx, yy, w() - 24, 0);
-
-	needspace = 0;
-	hh        = 0;
-	line      = 0;
-	newalign  = align;
-      }
-      else if (strcasecmp(buf, "TR") == 0)
-      {
-        block->end = start;
-        line       = do_align(block, line, xx, newalign, links);
-        xx         = block->x;
-        block->h   += hh;
-
-        if (row)
-	{
-          yy = blocks_[row].y + blocks_[row].h;
-
-	  for (cell = blocks_ + row + 1; cell <= block; cell ++)
-	    if ((cell->y + cell->h) > yy)
-	      yy = cell->y + cell->h;
-
-          block->h = yy - block->y + 2;
-
-	  for (cell = blocks_ + row + 1; cell < block; cell ++)
-	    cell->h = block->h;
-	}
-
-	yy        = block->y + block->h - 4;
-	hh        = 0;
-        block     = add_block(start, xx, yy, w() - 24, 0);
-	row       = block - blocks_;
-	needspace = 0;
-	column    = 0;
-	line      = 0;
-      }
-      else if (strcasecmp(buf, "/TR") == 0 && row)
-      {
-        line       = do_align(block, line, xx, newalign, links);
-        block->end = start;
-	block->h   += hh;
-
-        xx = blocks_[row].x;
-
-        yy = blocks_[row].y + blocks_[row].h;
-
-	for (cell = blocks_ + row + 1; cell <= block; cell ++)
-	  if ((cell->y + cell->h) > yy)
-	    yy = cell->y + cell->h;
-
-        block->h = yy - block->y + 2;
-
-	for (cell = blocks_ + row + 1; cell < block; cell ++)
-	  cell->h = block->h;
-
-	yy        = block->y + block->h - 4;
-        block     = add_block(start, xx, yy, w() - 24, 0);
-	needspace = 0;
-	row       = 0;
-	line      = 0;
-      }
-      else if ((strcasecmp(buf, "TD") == 0 ||
-                strcasecmp(buf, "TH") == 0) && row)
-      {
-        int	colspan;		// COLSPAN attribute
-
-
-        line       = do_align(block, line, xx, newalign, links);
-        block->end = start;
-	block->h   += hh;
-
-        if (strcasecmp(buf, "TH") == 0)
-	  font = textfont_ | FL_BOLD;
-	else
-	  font = textfont_;
-
-        size = textsize_;
-
-        xx = blocks_[row].x + size + 3;
-	for (i = 0; i < column; i ++)
-	  xx += columns[i] + 6;
-
-        if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
-	  colspan = atoi(attr);
-	else
-	  colspan = 1;
-
-        for (i = 0, ww = 0; i < colspan; i ++)
-	  ww += columns[column + i];
-
-        if (block->end == block->start && nblocks_ > 1)
-	{
-	  nblocks_ --;
-	  block --;
-	}
-
-	pushfont(font, size);
-
-	yy        = blocks_[row].y;
-	hh        = 0;
-        block     = add_block(start, xx, yy, xx + ww, 0, border);
-	needspace = 0;
-	line      = 0;
-	newalign  = get_align(attrs, tolower(buf[1]) == 'h' ? CENTER : LEFT);
-
-	column ++;
-      }
-      else if ((strcasecmp(buf, "/TD") == 0 ||
-                strcasecmp(buf, "/TH") == 0) && row)
-        popfont(font, size);
-      else if (strcasecmp(buf, "B") == 0)
-	pushfont(font |= FL_BOLD, size);
-      else if (strcasecmp(buf, "I") == 0)
-	pushfont(font |= FL_ITALIC, size);
-      else if (strcasecmp(buf, "CODE") == 0)
-	pushfont(font = FL_COURIER, size);
-      else if (strcasecmp(buf, "KBD") == 0)
-	pushfont(font = FL_COURIER_BOLD, size);
-      else if (strcasecmp(buf, "VAR") == 0)
-	pushfont(font = FL_COURIER_ITALIC, size);
-      else if (strcasecmp(buf, "/B") == 0 ||
-	       strcasecmp(buf, "/I") == 0 ||
-	       strcasecmp(buf, "/CODE") == 0 ||
-	       strcasecmp(buf, "/KBD") == 0 ||
-	       strcasecmp(buf, "/VAR") == 0)
-	popfont(font, size);
-      else if (strcasecmp(buf, "IMG") == 0)
-      {
-	Fl_HelpImage	*img = (Fl_HelpImage *)0;
-	int		width = 16;
-	int		height = 24;
-
-
-        get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
-        get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
-
-	if (get_attr(attrs, "SRC", attr, sizeof(attr))) 
-	  if ((img = add_image(attr, wattr, hattr)) != (Fl_HelpImage *)0 &&
-	      img->image == NULL)
-	    img = (Fl_HelpImage *)0;
-
-	if (img)
-	{
-	  width  = img->w;
-	  height = img->h;
-	}
-	else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL)
-	  strcpy(attr, "IMG");
-
-	ww = width;
-
-	if (needspace && xx > block->x)
-	  ww += (int)fl_width(' ');
-
-	if ((xx + ww) > block->w)
-	{
-	  line     = do_align(block, line, xx, newalign, links);
-	  xx       = block->x;
-	  yy       += hh;
-	  block->h += hh;
-	  hh       = 0;
-	}
-
-	if (link[0])
-	  add_link(link, xx, yy - height, ww, height);
-
-	xx += ww;
-	if ((height + 2) > hh)
-	  hh = height + 2;
-
-	needspace = 0;
-      }
-    }
-    else if (*ptr == '\n' && pre)
-    {
-      if (link[0])
-	add_link(link, xx, yy - hh, ww, hh);
-
-      line      = do_align(block, line, xx, newalign, links);
-      xx        = block->x;
-      yy        += hh;
-      block->h  += hh;
-      needspace = 0;
-      ptr ++;
-    }
-    else if (isspace(*ptr))
-    {
-      needspace = 1;
-
-      ptr ++;
-    }
-    else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
-    {
-      ptr ++;
-
-      if (strncasecmp(ptr, "amp;", 4) == 0)
-      {
-        *s++ = '&';
-	ptr += 4;
-      }
-      else if (strncasecmp(ptr, "lt;", 3) == 0)
-      {
-        *s++ = '<';
-	ptr += 3;
-      }
-      else if (strncasecmp(ptr, "gt;", 3) == 0)
-      {
-        *s++ = '>';
-	ptr += 3;
-      }
-      else if (strncasecmp(ptr, "nbsp;", 5) == 0)
-      {
-        *s++ = '\240';
-	ptr += 5;
-      }
-      else if (strncasecmp(ptr, "copy;", 5) == 0)
-      {
-        *s++ = '\251';
-	ptr += 5;
-      }
-      else if (strncasecmp(ptr, "reg;", 4) == 0)
-      {
-        *s++ = '\256';
-	ptr += 4;
-      }
-      else if (strncasecmp(ptr, "quot;", 5) == 0)
-      {
-        *s++ = '\"';
-	ptr += 5;
-      }
-
-      if ((size + 2) > hh)
-        hh = size + 2;
-    }
-    else
-    {
-      if (s < (buf + sizeof(buf) - 1))
-        *s++ = *ptr++;
-      else
-        ptr ++;
-
-      if ((size + 2) > hh)
-        hh = size + 2;
-    }
-  }
-
-  if (s > buf && !pre && !head)
-  {
-    *s = '\0';
-    ww = (int)fl_width(buf);
-
-//    printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
-//	   line, xx, ww, block->x, block->w);
-
-    if (needspace && xx > block->x)
-      ww += (int)fl_width(' ');
-
-    if ((xx + ww) > block->w)
-    {
-      line     = do_align(block, line, xx, newalign, links);
-      xx       = block->x;
-      yy       += hh;
-      block->h += hh;
-      hh       = 0;
-    }
-
-    if (link[0])
-      add_link(link, xx, yy - size, ww, size);
-
-    xx += ww;
-    if ((size + 2) > hh)
-      hh = size + 2;
-
-    needspace = 0;
-  }
-
-  block->end = ptr;
-  size_      = yy + hh;
-
-  if (ntargets_ > 1)
-    qsort(targets_, ntargets_, sizeof(Fl_HelpTarget),
-          (compare_func_t)compare_targets);
-
-  if (nblocks_ > 1)
-    qsort(blocks_, nblocks_, sizeof(Fl_HelpBlock),
-          (compare_func_t)compare_blocks);
-
-  if (size_ < (h() - 8))
-    scrollbar_.hide();
-  else
-    scrollbar_.show();
-
-  topline(topline_);
-}
-
-
-//
-// 'Fl_HelpView::format_table()' - Format a table...
-//
-
-void
-Fl_HelpView::format_table(int        *table_width,	// O - Total table width
-                          int        *columns,		// O - Column widths
-	                  const char *table)		// I - Pointer to start of table
-{
-  int		column,					// Current column
-		num_columns,				// Number of columns
-		colspan,				// COLSPAN attribute
-		width,					// Current width
-		temp_width,				// Temporary width
-		max_width,				// Maximum width
-		incell,					// In a table cell?
-		pre,					// 
 text?
-		needspace;				// Need whitespace?
-  char		*s,					// Pointer into buffer
-		buf[1024],				// Text buffer
-		attr[1024],				// Other attribute
-		wattr[1024],				// WIDTH attribute
-		hattr[1024];				// HEIGHT attribute
-  const char	*ptr,					// Pointer into table
-		*attrs,					// Pointer to attributes
-		*start;					// Start of element
-  int		minwidths[MAX_COLUMNS];			// Minimum widths for each column
-  unsigned char	font, size;				// Current font and size
-
-
-  // Clear widths...
-  *table_width = 0;
-  for (column = 0; column < MAX_COLUMNS; column ++)
-  {
-    columns[column]   = 0;
-    minwidths[column] = 0;
-  }
-
-  num_columns = 0;
-  colspan     = 0;
-  max_width   = 0;
-  pre         = 0;
-
-  // Scan the table...
-  for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;)
-  {
-    if ((*ptr == '<' || isspace(*ptr)) && s > buf && incell)
-    {
-      // Check width...
-      if (needspace)
-      {
-        *s++      = ' ';
-	needspace = 0;
-      }
-
-      *s         = '\0';
-      temp_width = (int)fl_width(buf);
-      s          = buf;
-
-      if (temp_width > minwidths[column])
-        minwidths[column] = temp_width;
-
-      width += temp_width;
-
-      if (width > max_width)
-        max_width = width;
-    }
-
-    if (*ptr == '<')
-    {
-      start = ptr;
-
-      for (s = buf, ptr ++; *ptr && *ptr != '>' && !isspace(*ptr);)
-        if (s < (buf + sizeof(buf) - 1))
-          *s++ = *ptr++;
-	else
-	  ptr ++;
-
-      *s = '\0';
-      s = buf;
-
-      attrs = ptr;
-      while (*ptr && *ptr != '>')
-        ptr ++;
-
-      if (*ptr == '>')
-        ptr ++;
-
-      if (strcasecmp(buf, "BR") == 0 ||
-	  strcasecmp(buf, "HR") == 0)
-      {
-        width     = 0;
-	needspace = 0;
-      }
-      else if (strcasecmp(buf, "TABLE") == 0 && start > table)
-        break;
-      else if (strcasecmp(buf, "CENTER") == 0 ||
-               strcasecmp(buf, "P") == 0 ||
-               strcasecmp(buf, "H1") == 0 ||
-	       strcasecmp(buf, "H2") == 0 ||
-	       strcasecmp(buf, "H3") == 0 ||
-	       strcasecmp(buf, "H4") == 0 ||
-	       strcasecmp(buf, "H5") == 0 ||
-	       strcasecmp(buf, "H6") == 0 ||
-	       strcasecmp(buf, "UL") == 0 ||
-	       strcasecmp(buf, "OL") == 0 ||
-	       strcasecmp(buf, "DL") == 0 ||
-	       strcasecmp(buf, "LI") == 0 ||
-	       strcasecmp(buf, "DD") == 0 ||
-	       strcasecmp(buf, "DT") == 0 ||
-	       strcasecmp(buf, "PRE") == 0)
-      {
-        width     = 0;
-	needspace = 0;
-
-        if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
-	{
-	  font = FL_HELVETICA_BOLD;
-	  size = textsize_ + '7' - buf[1];
-	}
-	else if (strcasecmp(buf, "DT") == 0)
-	{
-	  font = textfont_ | FL_ITALIC;
-	  size = textsize_;
-	}
-	else if (strcasecmp(buf, "PRE") == 0)
-	{
-	  font = FL_COURIER;
-	  size = textsize_;
-	  pre  = 1;
-	}
-	else if (strcasecmp(buf, "LI") == 0)
-	{
-	  width += 4 * size;
-	  font  = textfont_;
-	  size  = textsize_;
-	}
-	else
-	{
-	  font = textfont_;
-	  size = textsize_;
-	}
-
-	pushfont(font, size);
-      }
-      else if (strcasecmp(buf, "/CENTER") == 0 ||
-	       strcasecmp(buf, "/P") == 0 ||
-	       strcasecmp(buf, "/H1") == 0 ||
-	       strcasecmp(buf, "/H2") == 0 ||
-	       strcasecmp(buf, "/H3") == 0 ||
-	       strcasecmp(buf, "/H4") == 0 ||
-	       strcasecmp(buf, "/H5") == 0 ||
-	       strcasecmp(buf, "/H6") == 0 ||
-	       strcasecmp(buf, "/PRE") == 0 ||
-	       strcasecmp(buf, "/UL") == 0 ||
-	       strcasecmp(buf, "/OL") == 0 ||
-	       strcasecmp(buf, "/DL") == 0)
-      {
-        width     = 0;
-	needspace = 0;
-
-        popfont(font, size);
-      }
-      else if (strcasecmp(buf, "TR") == 0 || strcasecmp(buf, "/TR") == 0 ||
-               strcasecmp(buf, "/TABLE") == 0)
-      {
-//        printf("%s column = %d, colspan = %d, num_columns = %d\n",
-//	       buf, column, colspan, num_columns);
-
-        if (column >= 0)
-	{
-	  // This is a hack to support COLSPAN...
-	  max_width /= colspan;
-
-	  while (colspan > 0)
-	  {
-	    if (max_width > columns[column])
-	      columns[column] = max_width;
-
-	    column ++;
-	    colspan --;
-	  }
-	}
-
-	if (strcasecmp(buf, "/TABLE") == 0)
-	  break;
-
-	needspace = 0;
-	column    = -1;
-	width     = 0;
-	max_width = 0;
-	incell    = 0;
-      }
-      else if (strcasecmp(buf, "TD") == 0 ||
-               strcasecmp(buf, "TH") == 0)
-      {
-//        printf("BEFORE column = %d, colspan = %d, num_columns = %d\n",
-//	       column, colspan, num_columns);
-
-        if (column >= 0)
-	{
-	  // This is a hack to support COLSPAN...
-	  max_width /= colspan;
-
-	  while (colspan > 0)
-	  {
-	    if (max_width > columns[column])
-	      columns[column] = max_width;
-
-	    column ++;
-	    colspan --;
-	  }
-	}
-	else
-	  column ++;
-
-        if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
-	  colspan = atoi(attr);
-	else
-	  colspan = 1;
-
-//        printf("AFTER column = %d, colspan = %d, num_columns = %d\n",
-//	       column, colspan, num_columns);
-
-        if ((column + colspan) >= num_columns)
-	  num_columns = column + colspan;
-
-	needspace = 0;
-	width     = 0;
-	incell    = 1;
-
-        if (strcasecmp(buf, "TH") == 0)
-	  font = textfont_ | FL_BOLD;
-	else
-	  font = textfont_;
-
-        size = textsize_;
-
-	pushfont(font, size);
-
-        if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL)
-	{
-	  max_width = atoi(attr);
-
-	  if (attr[strlen(attr) - 1] == '%')
-	    max_width = max_width * w() / 100;
-	}
-	else
-	  max_width = 0;
-
-//        printf("max_width = %d\n", max_width);
-      }
-      else if (strcasecmp(buf, "/TD") == 0 ||
-               strcasecmp(buf, "/TH") == 0)
-      {
-	incell = 0;
-        popfont(font, size);
-      }
-      else if (strcasecmp(buf, "B") == 0)
-	pushfont(font |= FL_BOLD, size);
-      else if (strcasecmp(buf, "I") == 0)
-	pushfont(font |= FL_ITALIC, size);
-      else if (strcasecmp(buf, "CODE") == 0)
-	pushfont(font = FL_COURIER, size);
-      else if (strcasecmp(buf, "KBD") == 0)
-	pushfont(font = FL_COURIER_BOLD, size);
-      else if (strcasecmp(buf, "VAR") == 0)
-	pushfont(font = FL_COURIER_ITALIC, size);
-      else if (strcasecmp(buf, "/B") == 0 ||
-	       strcasecmp(buf, "/I") == 0 ||
-	       strcasecmp(buf, "/CODE") == 0 ||
-	       strcasecmp(buf, "/KBD") == 0 ||
-	       strcasecmp(buf, "/VAR") == 0)
-	popfont(font, size);
-      else if (strcasecmp(buf, "IMG") == 0 && incell)
-      {
-	Fl_HelpImage	*img = (Fl_HelpImage *)0;
-
-
-        get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
-        get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
-
-        if (get_attr(attrs, "SRC", attr, sizeof(attr))) 
-	  if ((img = add_image(attr, wattr, hattr)) != (Fl_HelpImage *)0 &&
-	      img->image == NULL)
-	    img = (Fl_HelpImage *)0;
-
-	if (img)
-	  temp_width = img->w;
-	else
-	  temp_width = 16;
-
-	if (temp_width > minwidths[column])
-          minwidths[column] = temp_width;
-
-        width += temp_width;
-	if (needspace)
-	  width += (int)fl_width(' ');
-
-	if (width > max_width)
-          max_width = width;
-
-	needspace = 0;
-      }
-    }
-    else if (*ptr == '\n' && pre)
-    {
-      width     = 0;
-      needspace = 0;
-      ptr ++;
-    }
-    else if (isspace(*ptr))
-    {
-      needspace = 1;
-
-      ptr ++;
-    }
-    else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
-    {
-      ptr ++;
-
-      if (strncasecmp(ptr, "amp;", 4) == 0)
-      {
-        *s++ = '&';
-	ptr += 4;
-      }
-      else if (strncasecmp(ptr, "lt;", 3) == 0)
-      {
-        *s++ = '<';
-	ptr += 3;
-      }
-      else if (strncasecmp(ptr, "gt;", 3) == 0)
-      {
-        *s++ = '>';
-	ptr += 3;
-      }
-      else if (strncasecmp(ptr, "nbsp;", 5) == 0)
-      {
-        *s++ = '\240';
-	ptr += 5;
-      }
-      else if (strncasecmp(ptr, "copy;", 5) == 0)
-      {
-        *s++ = '\251';
-	ptr += 5;
-      }
-      else if (strncasecmp(ptr, "reg;", 4) == 0)
-      {
-        *s++ = '\256';
-	ptr += 4;
-      }
-      else if (strncasecmp(ptr, "quot;", 5) == 0)
-      {
-        *s++ = '\"';
-	ptr += 5;
-      }
-    }
-    else
-    {
-      if (s < (buf + sizeof(buf) - 1))
-        *s++ = *ptr++;
-      else
-        ptr ++;
-    }
-  }
-
-  // Now that we have scanned the entire table, adjust the table and
-  // cell widths to fit on the screen...
-  if (get_attr(table + 6, "WIDTH", attr, sizeof(attr)))
-  {
-    if (attr[strlen(attr) - 1] == '%')
-      *table_width = atoi(attr) * w() / 100;
-    else
-      *table_width = atoi(attr);
-  }
-  else
-    *table_width = 0;
-
-//  printf("num_columns = %d, table_width = %d\n", num_columns, *table_width);
-
-  if (num_columns == 0)
-    return;
-
-  // Add up the widths...
-  for (column = 0, width = 0; column < num_columns; column ++)
-    width += columns[column];
-
-//  printf("width = %d, w() = %d\n", width, w());
-//  for (column = 0; column < num_columns; column ++)
-//    printf("    columns[%d] = %d, minwidths[%d] = %d\n", column, columns[column],
-//           column, minwidths[column]);
-
-  // Adjust the width if needed...
-  int scale_width = *table_width;
-
-  if (scale_width == 0 && width > w())
-    scale_width = width;
-
-  if (width > scale_width)
-  {
-    *table_width = 0;
-
-    for (column = 0; column < num_columns; column ++)
-    {
-      if (width > 0)
-      {
-        temp_width = scale_width * columns[column] / width;
-
-	if (temp_width < minwidths[column])
-	  temp_width = minwidths[column];
-      }
-      else
-        temp_width = minwidths[column];
-
-      width           -= columns[column];
-      scale_width     -= temp_width;
-      columns[column] = temp_width;
-      (*table_width)  += temp_width;
-    }
-  }
-  else if (*table_width == 0)
-    *table_width = width;
-
-//  printf("FINAL table_width = %d\n", *table_width);
-//  for (column = 0; column < num_columns; column ++)
-//    printf("    columns[%d] = %d\n", column, columns[column]);
-}
-
-
-//
-// 'Fl_HelpView::get_align()' - Get an alignment attribute.
-//
-
-int					// O - Alignment
-Fl_HelpView::get_align(const char *p,	// I - Pointer to start of attrs
-                       int        a)	// I - Default alignment
-{
-  char	buf[255];			// Alignment value
-
-
-  if (get_attr(p, "ALIGN", buf, sizeof(buf)) == NULL)
-    return (a);
-
-  if (strcasecmp(buf, "CENTER") == 0)
-    return (CENTER);
-  else if (strcasecmp(buf, "RIGHT") == 0)
-    return (RIGHT);
-  else
-    return (LEFT);
-}
-
-
-//
-// 'Fl_HelpView::get_attr()' - Get an attribute value from the string.
-//
-
-const char *					// O - Pointer to buf or NULL
-Fl_HelpView::get_attr(const char *p,		// I - Pointer to start of attributes
-                      const char *n,		// I - Name of attribute
-		      char       *buf,		// O - Buffer for attribute value
-		      int        bufsize)	// I - Size of buffer
-{
-  char	name[255],				// Name from string
-	*ptr,					// Pointer into name or value
-	quote;					// Quote
-
-
-  buf[0] = '\0';
-
-  while (*p && *p != '>')
-  {
-    while (isspace(*p))
-      p ++;
-
-    if (*p == '>' || !*p)
-      return (NULL);
-
-    for (ptr = name; *p && !isspace(*p) && *p != '=' && *p != '>';)
-      if (ptr < (name + sizeof(name) - 1))
-        *ptr++ = *p++;
-      else
-        p ++;
-
-    *ptr = '\0';
-
-    if (isspace(*p) || !*p || *p == '>')
-      buf[0] = '\0';
-    else
-    {
-      if (*p == '=')
-        p ++;
-
-      for (ptr = buf; *p && !isspace(*p) && *p != '>';)
-        if (*p == '\'' || *p == '\"')
-	{
-	  quote = *p++;
-
-	  while (*p && *p != quote)
-	    if ((ptr - buf + 1) < bufsize)
-	      *ptr++ = *p++;
-	    else
-	      p ++;
-
-          if (*p == quote)
-	    p ++;
-	}
-	else if ((ptr - buf + 1) < bufsize)
-	  *ptr++ = *p++;
-	else
-	  p ++;
-
-      *ptr = '\0';
-    }
-
-    if (strcasecmp(n, name) == 0)
-      return (buf);
-    else
-      buf[0] = '\0';
-
-    if (*p == '>')
-      return (NULL);
-  }
-
-  return (NULL);
-}
-
-
-//
-// 'Fl_HelpView::get_color()' - Get an alignment attribute.
-//
-
-Fl_Color				// O - Color value
-Fl_HelpView::get_color(const char *n,	// I - Color name
-                       Fl_Color   c)	// I - Default color value
-{
-  int	rgb, r, g, b;			// RGB values
-
-
-  if (!n)
-    return (c);
-
-  if (n[0] == '#')
-  {
-    // Do hex color lookup
-    rgb = strtol(n + 1, NULL, 16);
-
-    r = rgb >> 16;
-    g = (rgb >> 8) & 255;
-    b = rgb & 255;
-
-    if (r == g && g == b)
-      return (fl_gray_ramp(FL_NUM_GRAY * r / 256));
-    else
-      return (fl_color_cube((FL_NUM_RED - 1) * r / 255,
-                            (FL_NUM_GREEN - 1) * g / 255,
-			    (FL_NUM_BLUE - 1) * b / 255));
-  }
-  else if (strcasecmp(n, "black") == 0)
-    return (FL_BLACK);
-  else if (strcasecmp(n, "red") == 0)
-    return (FL_RED);
-  else if (strcasecmp(n, "green") == 0)
-    return (fl_color_cube(0, 4, 0));
-  else if (strcasecmp(n, "yellow") == 0)
-    return (FL_YELLOW);
-  else if (strcasecmp(n, "blue") == 0)
-    return (FL_BLUE);
-  else if (strcasecmp(n, "magenta") == 0 || strcasecmp(n, "fuchsia") == 0)
-    return (FL_MAGENTA);
-  else if (strcasecmp(n, "cyan") == 0 || strcasecmp(n, "aqua") == 0)
-    return (FL_CYAN);
-  else if (strcasecmp(n, "white") == 0)
-    return (FL_WHITE);
-  else if (strcasecmp(n, "gray") == 0 || strcasecmp(n, "grey") == 0)
-    return (FL_GRAY);
-  else if (strcasecmp(n, "lime") == 0)
-    return (FL_GREEN);
-  else if (strcasecmp(n, "maroon") == 0)
-    return (fl_color_cube(2, 0, 0));
-  else if (strcasecmp(n, "navy") == 0)
-    return (fl_color_cube(0, 0, 2));
-  else if (strcasecmp(n, "olive") == 0)
-    return (fl_color_cube(2, 4, 0));
-  else if (strcasecmp(n, "purple") == 0)
-    return (fl_color_cube(2, 0, 2));
-  else if (strcasecmp(n, "silver") == 0)
-    return (FL_LIGHT2);
-  else if (strcasecmp(n, "teal") == 0)
-    return (fl_color_cube(0, 4, 2));
-  else
-    return (c);
-}
-
-
-//
-// 'Fl_HelpView::handle()' - Handle events in the widget.
-//
-
-int				// O - 1 if we handled it, 0 otherwise
-Fl_HelpView::handle(int event)	// I - Event to handle
-{
-  int		i;		// Looping var
-  int		xx, yy;		// Adjusted mouse position
-  Fl_HelpLink	*link;		// Current link
-  char		target[32];	// Current target
-
-
-  switch (event)
-  {
-    case FL_PUSH :
-	if (Fl_Group::handle(event))
-	  return (1);
-
-    case FL_MOVE :
-        xx = Fl::event_x() - x();
-	yy = Fl::event_y() - y() + topline_;
-	break;
-
-    default :
-	return (Fl_Group::handle(event));
-  }
-
-  // Handle mouse clicks on links...
-  for (i = nlinks_, link = links_; i > 0; i --, link ++)
-    if (xx >= link->x && xx < link->w &&
-        yy >= link->y && yy < link->h)
-      break;
-
-  if (!i)
-  {
-    fl_cursor(FL_CURSOR_DEFAULT);
-    return (1);
-  }
-
-  // Change the cursor for FL_MOTION events, and go to the link for
-  // clicks...
-  if (event == FL_MOVE)
-    fl_cursor(FL_CURSOR_HAND);
-  else
-  {
-    fl_cursor(FL_CURSOR_DEFAULT);
-
-    strncpy(target, link->name, sizeof(target) - 1);
-    target[sizeof(target) - 1] = '\0';
-
-    set_changed();
-
-    if (strcmp(link->filename, filename_) != 0 && link->filename[0])
-    {
-      char	dir[1024];	// Current directory
-      char	temp[1024],	// Temporary filename
-		*tempptr;	// Pointer into temporary filename
-
-
-      if (strchr(directory_, ':') != NULL && strchr(link->filename, ':') == NULL)
-      {
-	if (link->filename[0] == '/')
-	{
-          strcpy(temp, directory_);
-          if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
-	    strcpy(tempptr, link->filename);
-	  else
-	    strcat(temp, link->filename);
-	}
-	else
-	  sprintf(temp, "%s/%s", directory_, link->filename);
-
-	load(temp);
-      }
-      else if (link->filename[0] != '/' && strchr(link->filename, ':') == NULL)
-      {
-	if (directory_[0])
-	  sprintf(temp, "%s/%s", directory_, link->filename);
-	else
-	{
-	  getcwd(dir, sizeof(dir));
-	  sprintf(temp, "file:%s/%s", dir, link->filename);
-	}
-
-        load(temp);
-      }
-      else
-        load(link->filename);
-    }
-    else if (target[0])
-      topline(target);
-    else
-      topline(0);
-  }
-
-  return (1);
-}
-
-
-//
-// 'Fl_HelpView::Fl_HelpView()' - Build a Fl_HelpView widget.
-//
-
-Fl_HelpView::Fl_HelpView(int        xx,	// I - Left position
-                	 int        yy,	// I - Top position
-			 int        ww,	// I - Width in pixels
-			 int        hh,	// I - Height in pixels
-			 const char *l)
-    : Fl_Group(xx, yy, ww, hh, l),
-      scrollbar_(xx + ww - 17, yy, 17, hh)
-{
-  link_        = (Fl_HelpFunc *)0;
-
-  filename_[0] = '\0';
-  value_       = NULL;
-
-  ablocks_     = 0;
-  nblocks_     = 0;
-  blocks_      = (Fl_HelpBlock *)0;
-
-  nimage_      = 0;
-  aimage_      = 0;
-  image_       = (Fl_HelpImage *)0;
-
-  if (!broken_image)
-    broken_image = new Fl_Pixmap((char **)broken_xpm);
-
-  alinks_      = 0;
-  nlinks_      = 0;
-  links_       = (Fl_HelpLink *)0;
-
-  atargets_    = 0;
-  ntargets_    = 0;
-  targets_     = (Fl_HelpTarget *)0;
-
-  nfonts_      = 0;
-  textfont_    = FL_TIMES;
-  textsize_    = 12;
-
-  topline_     = 0;
-  size_        = 0;
-
-  color(FL_WHITE);
-  textcolor(FL_BLACK);
-  selection_color(FL_BLUE);
-
-  scrollbar_.value(0, hh, 0, 1);
-  scrollbar_.step(8.0);
-  scrollbar_.show();
-  scrollbar_.callback(scrollbar_callback);
-
-  end();
-}
-
-
-//
-// 'Fl_HelpView::~Fl_HelpView()' - Destroy a Fl_HelpView widget.
-//
-
-Fl_HelpView::~Fl_HelpView()
-{
-  int		i;		// Looping var
-  Fl_HelpImage	*img;		// Current image
-
-
-  if (nblocks_)
-    free(blocks_);
-  if (nlinks_)
-    free(links_);
-  if (ntargets_)
-    free(targets_);
-  if (value_)
-    free((void *)value_);
-  if (image_)
-  {
-    for (i = nimage_, img = image_; i > 0; i --, img ++)
-    {
-      delete img->image;
-      if (!img->copy)
-        free(img->data);
-      free(img->name);
-    }
-  }
-}
-
-
-//
-// 'Fl_HelpView::load()' - Load the specified file.
-//
-
-int				// O - 0 on success, -1 on error
-Fl_HelpView::load(const char *f)// I - Filename to load (may also have target)
-{
-  FILE		*fp;		// File to read from
-  long		len;		// Length of file
-  char		*target;	// Target in file
-  char		*slash;		// Directory separator
-  const char	*localname;	// Local filename
-  char		error[1024];	// Error buffer
-
-
-  strcpy(filename_, f);
-  strcpy(directory_, filename_);
-
-  if ((slash = strrchr(directory_, '/')) == NULL)
-    directory_[0] = '\0';
-  else if (slash > directory_ && slash[-1] != '/')
-    *slash = '\0';
-
-  if ((target = strrchr(filename_, '#')) != NULL)
-    *target++ = '\0';
-
-  if (link_)
-    localname = (*link_)(filename_);
-  else
-    localname = filename_;
-
-  if (localname != NULL &&
-      (strncmp(localname, "ftp:", 4) == 0 ||
-       strncmp(localname, "http:", 5) == 0 ||
-       strncmp(localname, "https:", 6) == 0 ||
-       strncmp(localname, "ipp:", 4) == 0 ||
-       strncmp(localname, "mailto:", 7) == 0 ||
-       strncmp(localname, "news:", 5) == 0))
-    localname = NULL;	// Remote link wasn't resolved...
-  else if (localname != NULL &&
-           strncmp(localname, "file:", 5) == 0)
-    localname += 5;	// Adjust for local filename...
-      
-  if (value_ != NULL)
-  {
-    free((void *)value_);
-    value_ = NULL;
-  }
-
-  if (localname)
-  {
-    if ((fp = fopen(localname, "rb")) != NULL)
-    {
-      fseek(fp, 0, SEEK_END);
-      len = ftell(fp);
-      rewind(fp);
-
-      value_ = (const char *)calloc(len + 1, 1);
-      fread((void *)value_, 1, len, fp);
-      fclose(fp);
-    }
-    else
-    {
-      sprintf(error, "%s: %s\n", localname, strerror(errno));
-      value_ = strdup(error);
-    }
-  }
-  else
-  {
-    sprintf(error, "%s: %s\n", filename_, strerror(errno));
-    value_ = strdup(error);
-  }
-
-  format();
-
-  if (target)
-    topline(target);
-  else
-    topline(0);
-
-  return (0);
-}
-
-
-//
-// 'Fl_HelpView::load_gif()' - Load a GIF image file...
-//
-
-int					// O - 0 = success, -1 = fail
-Fl_HelpView::load_gif(Fl_HelpImage *img,// I - Image pointer
-        	      FILE         *fp)	// I - File to load from
-{
-  unsigned char	buf[1024];		// Input buffer
-  gif_cmap_t	cmap;			// Colormap
-  int		ncolors,		// Bits per pixel
-		transparent;		// Transparent color index
-
-
-  // Read the header; we already know it is a GIF file...
-  fread(buf, 13, 1, fp);
-
-  img->w  = (buf[7] << 8) | buf[6];
-  img->h  = (buf[9] << 8) | buf[8];
-  ncolors = 2 << (buf[10] & 0x07);
-
-  if (buf[10] & GIF_COLORMAP)
-    if (!gif_read_cmap(fp, ncolors, cmap))
-      return (0);
-
-  transparent = -1;
-
-  for (;;)
-  {
-    switch (getc(fp))
-    {
-      case ';' :	// End of image
-          return (0);	// Early end of file
-
-      case '!' :	// Extension record
-          buf[0] = getc(fp);
-          if (buf[0] == 0xf9)	// Graphic Control Extension
-          {
-            gif_get_block(fp, buf);
-            if (buf[0] & 1)	// Get transparent color index
-              transparent = buf[3];
-          }
-
-          while (gif_get_block(fp, buf) != 0);
-          break;
-
-      case ',' :	// Image data
-          fread(buf, 9, 1, fp);
-
-          if (buf[8] & GIF_COLORMAP)
-          {
-            ncolors = 2 << (buf[8] & 0x07);
-
-	    if (!gif_read_cmap(fp, ncolors, cmap))
-	      return (0);
-	  }
-
-          if (transparent >= 0)
-          {
-	    unsigned	rgba = fltk_colors[bgcolor_];
-
-
-            // Map transparent color to background color...
-	    cmap[transparent][0] = rgba >> 24;
-            cmap[transparent][1] = rgba >> 16;
-            cmap[transparent][2] = rgba >> 8;
-          }
-
-          img->w    = (buf[5] << 8) | buf[4];
-          img->h    = (buf[7] << 8) | buf[6];
-          img->d    = 3;
-          img->data = (unsigned char *)malloc(img->w * img->h * img->d);
-          if (img->data == NULL)
-            return (0);
-
-	  return (gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE));
-    }
-  }
-}
-
-
-#ifdef HAVE_LIBJPEG
-//
-// 'Fl_HelpView::load_jpeg()' - Load a JPEG image file.
-//
-
-int						// O - 0 = success, -1 = fail
-Fl_HelpView::load_jpeg(Fl_HelpImage *img,	// I - Image pointer
-                       FILE         *fp)	// I - File to load from
-{
-  struct jpeg_decompress_struct	cinfo;		// Decompressor info
-  struct jpeg_error_mgr		jerr;		// Error handler info
-  JSAMPROW			row;		// Sample row pointer
-
-
-  cinfo.err = jpeg_std_error(&jerr);
-  jpeg_create_decompress(&cinfo);
-  jpeg_stdio_src(&cinfo, fp);
-  jpeg_read_header(&cinfo, 1);
-
-  cinfo.quantize_colors      = 0;
-  cinfo.out_color_space      = JCS_RGB;
-  cinfo.out_color_components = 3;
-  cinfo.output_components    = 3;
-
-  jpeg_calc_output_dimensions(&cinfo);
-
-  img->w  = cinfo.output_width;
-  img->h = cinfo.output_height;
-  img->d  = cinfo.output_components;
-  img->data = (unsigned char *)malloc(img->w * img->h * img->d);
-
-  if (img->data == NULL)
-  {
-    jpeg_destroy_decompress(&cinfo);
-    return (0);
-  }
-
-  jpeg_start_decompress(&cinfo);
-
-  while (cinfo.output_scanline < cinfo.output_height)
-  {
-    row = (JSAMPROW)(img->data +
-                     cinfo.output_scanline * cinfo.output_width *
-                     cinfo.output_components);
-    jpeg_read_scanlines(&cinfo, &row, (JDIMENSION)1);
-  }
-
-  jpeg_finish_decompress(&cinfo);
-  jpeg_destroy_decompress(&cinfo);
-
-  return (1);
-}
-#endif // HAVE_LIBJPEG
-
-
-#ifdef HAVE_LIBPNG
-//
-// 'Fl_HelpView::load_png()' - Load a PNG image file.
-//
-
-int					// O - 0 = success, -1 = fail
-Fl_HelpView::load_png(Fl_HelpImage *img,// I - Image pointer
-        	      FILE         *fp)	// I - File to read from
-{
-  int		i;			// Looping var
-  png_structp	pp;			// PNG read pointer
-  png_infop	info;			// PNG info pointers
-  png_bytep	*rows;			// PNG row pointers
-  png_color_16	bg;			// Background color
-
-
-  // Setup the PNG data structures...
-  pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-  info = png_create_info_struct(pp);
-
-  // Initialize the PNG read "engine"...
-  png_init_io(pp, fp);
-
-  // Get the image dimensions and convert to grayscale or RGB...
-  png_read_info(pp, info);
-
-  if (info->color_type == PNG_COLOR_TYPE_PALETTE)
-    png_set_expand(pp);
-
-  if (info->color_type == PNG_COLOR_TYPE_GRAY)
-    img->d = 1;
-  else
-    img->d = 3;
-
-  img->w    = (int)info->width;
-  img->h    = (int)info->height;
-  img->data = (unsigned char *)malloc(img->w * img->h * 3);
-
-  if (info->bit_depth < 8)
-  {
-    png_set_packing(pp);
-    png_set_expand(pp);
-
-    if (info->valid & PNG_INFO_sBIT)
-      png_set_shift(pp, &(info->sig_bit));
-  }
-  else if (info->bit_depth == 16)
-    png_set_strip_16(pp);
-
-#ifdef HAVE_PNG_GET_VALID
-  // Handle transparency...
-  if (png_get_valid(pp, info, PNG_INFO_tRNS))
-    png_set_tRNS_to_alpha(pp);
-#endif // HAVE_PNG_GET_VALID
-
-  // Background color...
-  unsigned	rgba = fltk_colors[bgcolor_];
-
-  bg.red   = 65535 * (rgba >> 24) / 255;
-  bg.green = 65535 * ((rgba >> 16) & 255) / 255;
-  bg.blue  = 65535 * ((rgba >> 8) & 255) / 255;
-
-  png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
-
-  // Allocate pointers...
-  rows = (png_bytep *)calloc(info->height, sizeof(png_bytep));
-
-  for (i = 0; i < (int)info->height; i ++)
-    if (info->color_type == PNG_COLOR_TYPE_GRAY)
-      rows[i] = img->data + i * img->w;
-    else
-      rows[i] = img->data + i * img->w * 3;
-
-  // Read the image, handling interlacing as needed...
-  for (i = png_set_interlace_handling(pp); i > 0; i --)
-    png_read_rows(pp, rows, NULL, img->h);
-
-  // Free memory and return...
-  free(rows);
-
-  png_read_end(pp, info);
-  png_read_destroy(pp, info, NULL);
-
-  return (1);
-}
-#endif // HAVE_LIBPNG
-
-
-//
-// 'Fl_HelpView::resize()' - Resize the help widget.
-//
-
-void
-Fl_HelpView::resize(int xx,	// I - New left position
-                    int yy,	// I - New top position
-		    int ww,	// I - New width
-		    int hh)	// I - New height
-{
-  Fl_Widget::resize(xx, yy, ww, hh);
-  scrollbar_.resize(xx + ww - 17, yy, 17, hh);
-
-  format();
-}
-
-
-//
-// 'Fl_HelpView::topline()' - Set the top line to the named target.
-//
-
-void
-Fl_HelpView::topline(const char *n)	// I - Target name
-{
-  Fl_HelpTarget	key,			// Target name key
-		*target;		// Pointer to matching target
-
-
-  if (ntargets_ == 0)
-    return;
-
-  strncpy(key.name, n, sizeof(key.name) - 1);
-  key.name[sizeof(key.name) - 1] = '\0';
-
-  target = (Fl_HelpTarget *)bsearch(&key, targets_, ntargets_, sizeof(Fl_HelpTarget),
-                                 (compare_func_t)compare_targets);
-
-  if (target != NULL)
-    topline(target->y);
-}
-
-
-//
-// 'Fl_HelpView::topline()' - Set the top line by number.
-//
-
-void
-Fl_HelpView::topline(int t)	// I - Top line number
-{
-  if (!value_)
-    return;
-
-  if (size_ < (h() - 8) || t < 0)
-    t = 0;
-  else if (t > size_)
-    t = size_;
-
-  topline_ = t;
-
-  scrollbar_.value(topline_, h(), 0, size_);
-
-  do_callback();
-  clear_changed();
-
-  redraw();
-}
-
-
-//
-// 'Fl_HelpView::value()' - Set the help text directly.
-//
-
-void
-Fl_HelpView::value(const char *v)	// I - Text to view
-{
-  if (!v)
-    return;
-
-  if (value_ != NULL)
-    free((void *)value_);
-
-  value_ = strdup(v);
-
-  format();
-
-  set_changed();
-  topline(0);
-}
-
-
-//
-// 'Fl_HelpView::compare_blocks()' - Compare two blocks.
-//
-
-int						// O - Result of comparison
-Fl_HelpView::compare_blocks(const void *a,	// I - First block
-                            const void *b)	// I - Second block
-{
-  return (((Fl_HelpBlock *)a)->y - ((Fl_HelpBlock *)b)->y);
-}
-
-
-//
-// 'gif_read_cmap()' - Read the colormap from a GIF file...
-//
-
-static int				// O - -1 = error, 0 = success
-gif_read_cmap(FILE       *fp,		// I - File to read from
-  	      int        ncolors,	// I - Number of colors
-	      gif_cmap_t cmap)		// O - Colormap
-{
-  // Read the colormap...
-  if (fread(cmap, 3, ncolors, fp) < (size_t)ncolors)
-    return (0);
-
-  return (1);
-}
-
-
-//
-// 'gif_get_block()' - Read a GIF data block...
-//
-
-static int				// O - Number characters read
-gif_get_block(FILE  *fp,		// I - File to read from
-	      unsigned char *buf)	// I - Input buffer
-{
-  int	count;				// Number of character to read
-
-
-  // Read the count byte followed by the data from the file...
-  if ((count = getc(fp)) == EOF)
-  {
-    gif_eof = 1;
-    return (-1);
-  }
-  else if (count == 0)
-    gif_eof = 1;
-  else if (fread(buf, 1, count, fp) < (size_t)count)
-  {
-    gif_eof = 1;
-    return (-1);
-  }
-  else
-    gif_eof = 0;
-
-  return (count);
-}
-
-
-//
-// 'gif_get_code()' - Get a LZW code from the file...
-//
-
-static int				// O - LZW code
-gif_get_code(FILE *fp,			// I - File to read from
-	     int  code_size,		// I - Size of code in bits
-	     int  first_time)		// I - 1 = first time, 0 = not first time
-{
-  unsigned		i, j,		// Looping vars
-			ret;		// Return value
-  int			count;		// Number of bytes read
-  static unsigned char	buf[280];	// Input buffer
-  static unsigned	curbit,		// Current bit
-			lastbit,	// Last bit in buffer
-			done,		// Done with this buffer?
-			last_byte;	// Last byte in buffer
-  static unsigned	bits[8] =	// Bit masks for codes
-			{
-			  0x01, 0x02, 0x04, 0x08,
-			  0x10, 0x20, 0x40, 0x80
-			};
-
-
-  if (first_time)
-  {
-    // Just initialize the input buffer...
-    curbit  = 0;
-    lastbit = 0;
-    done    = 0;
-
-    return (0);
-  }
-
-
-  if ((curbit + code_size) >= lastbit)
-  {
-    // Don't have enough bits to hold the code...
-    if (done)
-      return (-1);	// Sorry, no more...
-
-    // Move last two bytes to front of buffer...
-    if (last_byte > 1)
-    {
-      buf[0]    = buf[last_byte - 2];
-      buf[1]    = buf[last_byte - 1];
-      last_byte = 2;
-    }
-    else if (last_byte == 1)
-    {
-      buf[0]    = buf[last_byte - 1];
-      last_byte = 1;
-    }
-
-    // Read in another buffer...
-    if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
-    {
-      // Whoops, no more data!
-      done = 1;
-      return (-1);
-    }
-
-    // Update buffer state...
-    curbit    = (curbit - lastbit) + 8 * last_byte;
-    last_byte += count;
-    lastbit   = last_byte * 8;
-  }
-
-  ret = 0;
-  for (ret = 0, i = curbit + code_size - 1, j = code_size;
-       j > 0;
-       i --, j --)
-    ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
-
-  curbit += code_size;
-
-  return ret;
-}
-
-
-//
-// 'gif_read_lzw()' - Read a byte from the LZW stream...
-//
-
-static int				// I - Byte from stream
-gif_read_lzw(FILE *fp,			// I - File to read from
-	     int  first_time,		// I - 1 = first time, 0 = not first time
- 	     int  input_code_size)	// I - Code size in bits
-{
-  int		i,			// Looping var
-		code,			// Current code
-		incode;			// Input code
-  static short	fresh = 0,		// 1 = empty buffers
-		code_size,		// Current code size
-		set_code_size,		// Initial code size set
-		max_code,		// Maximum code used
-		max_code_size,		// Maximum code size
-		firstcode,		// First code read
-		oldcode,		// Last code read
-		clear_code,		// Clear code for LZW input
-		end_code,		// End code for LZW input
-		table[2][4096],		// String table
-		stack[8192],		// Output stack
-		*sp;			// Current stack pointer
-
-
-  if (first_time)
-  {
-    // Setup LZW state...
-    set_code_size = input_code_size;
-    code_size     = set_code_size + 1;
-    clear_code    = 1 << set_code_size;
-    end_code      = clear_code + 1;
-    max_code_size = 2 * clear_code;
-    max_code      = clear_code + 2;
-
-    // Initialize input buffers...
-    gif_get_code(fp, 0, 1);
-
-    // Wipe the decompressor table...
-    fresh = 1;
-
-    for (i = 0; i < clear_code; i ++)
-    {
-      table[0][i] = 0;
-      table[1][i] = i;
-    }
-
-    for (; i < 4096; i ++)
-      table[0][i] = table[1][0] = 0;
-
-    sp = stack;
-
-    return (0);
-  }
-  else if (fresh)
-  {
-    fresh = 0;
-
-    do
-      firstcode = oldcode = gif_get_code(fp, code_size, 0);
-    while (firstcode == clear_code);
-
-    return (firstcode);
-  }
-
-  if (sp > stack)
-    return (*--sp);
-
-  while ((code = gif_get_code (fp, code_size, 0)) >= 0)
-  {
-    if (code == clear_code)
-    {
-      for (i = 0; i < clear_code; i ++)
-      {
-	table[0][i] = 0;
-	table[1][i] = i;
-      }
-
-      for (; i < 4096; i ++)
-	table[0][i] = table[1][i] = 0;
-
-      code_size     = set_code_size + 1;
-      max_code_size = 2 * clear_code;
-      max_code      = clear_code + 2;
-
-      sp = stack;
-
-      firstcode = oldcode = gif_get_code(fp, code_size, 0);
-
-      return (firstcode);
-    }
-    else if (code == end_code)
-    {
-      unsigned char	buf[260];
-
-
-      if (!gif_eof)
-        while (gif_get_block(fp, buf) > 0);
-
-      return (-2);
-    }
-
-    incode = code;
-
-    if (code >= max_code)
-    {
-      *sp++ = firstcode;
-      code  = oldcode;
-    }
-
-    while (code >= clear_code)
-    {
-      *sp++ = table[1][code];
-      if (code == table[0][code])
-	return (255);
-
-      code = table[0][code];
-    }
-
-    *sp++ = firstcode = table[1][code];
-    code  = max_code;
-
-    if (code < 4096)
-    {
-      table[0][code] = oldcode;
-      table[1][code] = firstcode;
-      max_code ++;
-
-      if (max_code >= max_code_size && max_code_size < 4096)
-      {
-	max_code_size *= 2;
-	code_size ++;
-      }
-    }
-
-    oldcode = incode;
-
-    if (sp > stack)
-      return (*--sp);
-  }
-
-  return (code);
-}
-
-
-//
-// 'gif_read_image()' - Read a GIF image stream...
-//
-
-static int				// I - 0 = success, -1 = failure
-gif_read_image(FILE          *fp,	// I - Input file
-	       Fl_HelpImage  *img,	// I - Image pointer
-	       gif_cmap_t    cmap,	// I - Colormap
-	       int           interlace)	// I - Non-zero = interlaced image
-{
-  unsigned char	code_size,		// Code size
-		*temp;			// Current pixel
-  int		xpos,			// Current X position
-		ypos,			// Current Y position
-		pass;			// Current pass
-  int		pixel;			// Current pixel
-  static int	xpasses[4] = { 8, 8, 4, 2 },
-		ypasses[5] = { 0, 4, 2, 1, 999999 };
-
-
-  xpos      = 0;
-  ypos      = 0;
-  pass      = 0;
-  code_size = getc(fp);
-
-  if (gif_read_lzw(fp, 1, code_size) < 0)
-    return (0);
-
-  temp = img->data;
-
-  while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
-  {
-    temp[0] = cmap[pixel][0];
-
-    if (img->d > 1)
-    {
-      temp[1] = cmap[pixel][1];
-      temp[2] = cmap[pixel][2];
-    }
-
-    xpos ++;
-    temp += img->d;
-    if (xpos == img->w)
-    {
-      xpos = 0;
-
-      if (interlace)
-      {
-        ypos += xpasses[pass];
-        temp += (xpasses[pass] - 1) * img->w * img->d;
-
-        if (ypos >= img->h)
-	{
-	  pass ++;
-
-          ypos = ypasses[pass];
-          temp = img->data + ypos * img->w * img->d;
-	}
-      }
-      else
-	ypos ++;
-    }
-
-    if (ypos >= img->h)
-      break;
-  }
-
-  return (1);
-}
-
-
-//
-// 'scrollbar_callback()' - A callback for the scrollbar.
-//
-
-static void
-scrollbar_callback(Fl_Widget *s, void *)
-{
-  ((Fl_HelpView *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value()));
-}
-
-
-//
-// End of "$Id: Fl_HelpView.cxx,v 1.1.2.5 2001/09/10 03:09:43 easysw Exp $".
-//
diff --git a/src/Fl_Help_Dialog.cxx b/src/Fl_Help_Dialog.cxx
new file mode 100644
index 000000000..feacd52de
--- /dev/null
+++ b/src/Fl_Help_Dialog.cxx
@@ -0,0 +1,221 @@
+// generated by Fast Light User Interface Designer (fluid) version 1.0100
+
+#include "../FL/Fl_Help_Dialog.H"
+
+inline void Fl_Help_Dialog::cb_view__i(Fl_Help_View*, void*) {
+  if (view_->changed())
+{
+  index_ ++;
+
+  if (index_ >= 100)
+  {
+    memcpy(line_, line_ + 10, sizeof(line_[0]) * 90);
+    memcpy(file_, file_ + 10, sizeof(file_[0]) * 90);
+    index_ -= 10;
+  }
+
+  max_ = index_;
+
+  strcpy(file_[index_], view_->filename());
+  line_[index_] = view_->topline();
+
+  if (index_ > 0)
+    back_->activate();
+  else
+    back_->deactivate();
+
+  forward_->deactivate();
+  window_->label(view_->title());
+}
+else if (view_->filename())
+{
+  strncpy(file_[index_], view_->filename(), 255);
+  file_[index_][255] = '\0';
+  line_[index_] = view_->topline();
+};
+}
+void Fl_Help_Dialog::cb_view_(Fl_Help_View* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_view__i(o,v);
+}
+
+inline void Fl_Help_Dialog::cb_Close_i(Fl_Button*, void*) {
+  window_->hide();
+}
+void Fl_Help_Dialog::cb_Close(Fl_Button* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_Close_i(o,v);
+}
+
+inline void Fl_Help_Dialog::cb_back__i(Fl_Button*, void*) {
+  if (index_ > 0)
+  index_ --;
+
+if (index_ == 0)
+  back_->deactivate();
+
+forward_->activate();
+
+if (strcmp(view_->filename(), file_[index_]) != 0)
+  view_->load(file_[index_]);
+
+view_->topline(line_[index_]);
+}
+void Fl_Help_Dialog::cb_back_(Fl_Button* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_back__i(o,v);
+}
+
+inline void Fl_Help_Dialog::cb_forward__i(Fl_Button*, void*) {
+  if (index_ < max_)
+  index_ ++;
+
+if (index_ >= max_)
+  forward_->deactivate();
+
+back_->activate();
+
+if (strcmp(view_->filename(), file_[index_]) != 0)
+  view_->load(file_[index_]);
+
+view_->topline(line_[index_]);
+}
+void Fl_Help_Dialog::cb_forward_(Fl_Button* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_forward__i(o,v);
+}
+
+inline void Fl_Help_Dialog::cb_smaller__i(Fl_Button*, void*) {
+  if (view_->textsize() > 8)
+  view_->textsize(view_->textsize() - 2);
+
+if (view_->textsize() <= 8)
+  smaller_->deactivate();
+larger_->activate();
+}
+void Fl_Help_Dialog::cb_smaller_(Fl_Button* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_smaller__i(o,v);
+}
+
+inline void Fl_Help_Dialog::cb_larger__i(Fl_Button*, void*) {
+  if (view_->textsize() < 18)
+  view_->textsize(view_->textsize() + 2);
+
+if (view_->textsize() >= 18)
+  larger_->deactivate();
+smaller_->activate();
+}
+void Fl_Help_Dialog::cb_larger_(Fl_Button* o, void* v) {
+  ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_larger__i(o,v);
+}
+
+Fl_Help_Dialog::Fl_Help_Dialog() {
+  Fl_Double_Window* w;
+  { Fl_Double_Window* o = window_ = new Fl_Double_Window(530, 385, "Help Dialog");
+    w = o;
+    o->user_data((void*)(this));
+    { Fl_Help_View* o = view_ = new Fl_Help_View(10, 10, 510, 330);
+      o->box(FL_DOWN_BOX);
+      o->callback((Fl_Callback*)cb_view_);
+      o->end();
+      Fl_Group::current()->resizable(o);
+    }
+    { Fl_Button* o = new Fl_Button(425, 350, 95, 25, "Close");
+      o->callback((Fl_Callback*)cb_Close);
+    }
+    { Fl_Button* o = back_ = new Fl_Button(365, 350, 25, 25, "@<-");
+      o->shortcut(0xff51);
+      o->labelcolor(2);
+      o->callback((Fl_Callback*)cb_back_);
+    }
+    { Fl_Button* o = forward_ = new Fl_Button(395, 350, 25, 25, "@->");
+      o->shortcut(0xff53);
+      o->labelcolor(2);
+      o->callback((Fl_Callback*)cb_forward_);
+    }
+    { Fl_Button* o = smaller_ = new Fl_Button(305, 350, 25, 25, "F");
+      o->labelfont(1);
+      o->labelsize(10);
+      o->callback((Fl_Callback*)cb_smaller_);
+    }
+    { Fl_Button* o = larger_ = new Fl_Button(335, 350, 25, 25, "F");
+      o->labelfont(1);
+      o->labelsize(16);
+      o->callback((Fl_Callback*)cb_larger_);
+    }
+    o->end();
+  }
+  back_->deactivate();
+forward_->deactivate();
+
+index_ = -1;
+max_  = 0;
+}
+
+Fl_Help_Dialog::~Fl_Help_Dialog() {
+  delete window_;
+}
+
+int Fl_Help_Dialog::h() {
+  return (window_->h());
+}
+
+void Fl_Help_Dialog::hide() {
+  window_->hide();
+}
+
+void Fl_Help_Dialog::load(const char *f) {
+  view_->set_changed();
+view_->load(f);
+window_->label(view_->title());
+}
+
+void Fl_Help_Dialog::position(int xx, int yy) {
+  window_->position(xx, yy);
+}
+
+void Fl_Help_Dialog::resize(int xx, int yy, int ww, int hh) {
+  window_->resize(xx, yy, ww, hh);
+}
+
+void Fl_Help_Dialog::show() {
+  window_->show();
+}
+
+void Fl_Help_Dialog::textsize(uchar s) {
+  view_->textsize(s);
+
+if (s <= 8)
+  smaller_->deactivate();
+else
+  smaller_->activate();
+
+if (s >= 18)
+  larger_->deactivate();
+else
+  larger_->activate();
+}
+
+uchar Fl_Help_Dialog::textsize() {
+  return (view_->textsize());
+}
+
+void Fl_Help_Dialog::topline(const char *n) {
+  view_->topline(n);
+}
+
+void Fl_Help_Dialog::topline(int n) {
+  view_->topline(n);
+}
+
+int Fl_Help_Dialog::visible() {
+  return (window_->visible());
+}
+
+int Fl_Help_Dialog::w() {
+  return (window_->w());
+}
+
+int Fl_Help_Dialog::x() {
+  return (window_->x());
+}
+
+int Fl_Help_Dialog::y() {
+  return (window_->y());
+}
diff --git a/src/Fl_Help_Dialog.fl b/src/Fl_Help_Dialog.fl
new file mode 100644
index 000000000..79b27b012
--- /dev/null
+++ b/src/Fl_Help_Dialog.fl
@@ -0,0 +1,191 @@
+# data file for the Fltk User Interface Designer (fluid)
+version 1.0100 
+header_name {../FL/Fl_Help_Dialog.H} 
+code_name {.cxx} 
+gridx 5 
+gridy 5 
+snap 3
+class Fl_Help_Dialog {open
+} {
+  decl {int index_;} {}
+  decl {int max_;} {}
+  decl {int line_[100];} {}
+  decl {char file_[100][256];} {}
+  Function {Fl_Help_Dialog()} {open
+  } {
+    Fl_Window window_ {
+      label {Help Dialog} open selected
+      private xywh {470 380 530 385} type Double resizable
+      code0 {\#include } visible
+    } {
+      Fl_Group view_ {
+        callback {if (view_->changed())
+{
+  index_ ++;
+
+  if (index_ >= 100)
+  {
+    memcpy(line_, line_ + 10, sizeof(line_[0]) * 90);
+    memcpy(file_, file_ + 10, sizeof(file_[0]) * 90);
+    index_ -= 10;
+  }
+
+  max_ = index_;
+
+  strcpy(file_[index_], view_->filename());
+  line_[index_] = view_->topline();
+
+  if (index_ > 0)
+    back_->activate();
+  else
+    back_->deactivate();
+
+  forward_->deactivate();
+  window_->label(view_->title());
+}
+else if (view_->filename())
+{
+  strncpy(file_[index_], view_->filename(), 255);
+  file_[index_][255] = '\\0';
+  line_[index_] = view_->topline();
+}} open
+        private xywh {10 10 510 330} box DOWN_BOX resizable
+        code0 {\#include }
+        class Fl_Help_View
+      } {}
+      Fl_Button {} {
+        label Close
+        callback {window_->hide();}
+        xywh {425 350 95 25}
+      }
+      Fl_Button back_ {
+        label {@<-}
+        callback {if (index_ > 0)
+  index_ --;
+
+if (index_ == 0)
+  back_->deactivate();
+
+forward_->activate();
+
+if (strcmp(view_->filename(), file_[index_]) != 0)
+  view_->load(file_[index_]);
+
+view_->topline(line_[index_]);}
+        private xywh {365 350 25 25} shortcut 0xff51 labelcolor 2
+      }
+      Fl_Button forward_ {
+        label {@->}
+        callback {if (index_ < max_)
+  index_ ++;
+
+if (index_ >= max_)
+  forward_->deactivate();
+
+back_->activate();
+
+if (strcmp(view_->filename(), file_[index_]) != 0)
+  view_->load(file_[index_]);
+
+view_->topline(line_[index_]);}
+        private xywh {395 350 25 25} shortcut 0xff53 labelcolor 2
+      }
+      Fl_Button smaller_ {
+        label F
+        callback {if (view_->textsize() > 8)
+  view_->textsize(view_->textsize() - 2);
+
+if (view_->textsize() <= 8)
+  smaller_->deactivate();
+larger_->activate();}
+        private xywh {305 350 25 25} labelfont 1 labelsize 10
+      }
+      Fl_Button larger_ {
+        label F
+        callback {if (view_->textsize() < 18)
+  view_->textsize(view_->textsize() + 2);
+
+if (view_->textsize() >= 18)
+  larger_->deactivate();
+smaller_->activate();}
+        private xywh {335 350 25 25} labelfont 1 labelsize 16
+      }
+    }
+    code {back_->deactivate();
+forward_->deactivate();
+
+index_ = -1;
+max_  = 0;} {}
+  }
+  Function {~Fl_Help_Dialog()} {} {
+    code {delete window_;} {}
+  }
+  Function {h()} {return_type int
+  } {
+    code {return (window_->h());} {}
+  }
+  Function {hide()} {return_type void
+  } {
+    code {window_->hide();} {}
+  }
+  Function {load(const char *f)} {return_type void
+  } {
+    code {view_->set_changed();
+view_->load(f);
+window_->label(view_->title());} {}
+  }
+  Function {position(int xx, int yy)} {return_type void
+  } {
+    code {window_->position(xx, yy);} {}
+  }
+  Function {resize(int xx, int yy, int ww, int hh)} {return_type void
+  } {
+    code {window_->resize(xx, yy, ww, hh);} {}
+  }
+  Function {show()} {return_type void
+  } {
+    code {window_->show();} {}
+  }
+  Function {textsize(uchar s)} {return_type void
+  } {
+    code {view_->textsize(s);
+
+if (s <= 8)
+  smaller_->deactivate();
+else
+  smaller_->activate();
+
+if (s >= 18)
+  larger_->deactivate();
+else
+  larger_->activate();} {}
+  }
+  Function {textsize()} {return_type uchar
+  } {
+    code {return (view_->textsize());} {}
+  }
+  Function {topline(const char *n)} {return_type void
+  } {
+    code {view_->topline(n);} {}
+  }
+  Function {topline(int n)} {return_type void
+  } {
+    code {view_->topline(n);} {}
+  }
+  Function {visible()} {return_type int
+  } {
+    code {return (window_->visible());} {}
+  }
+  Function {w()} {return_type int
+  } {
+    code {return (window_->w());} {}
+  }
+  Function {x()} {return_type int
+  } {
+    code {return (window_->x());} {}
+  }
+  Function {y()} {return_type int
+  } {
+    code {return (window_->y());} {}
+  }
+} 
diff --git a/src/Fl_Help_View.cxx b/src/Fl_Help_View.cxx
new file mode 100644
index 000000000..f5b8063ab
--- /dev/null
+++ b/src/Fl_Help_View.cxx
@@ -0,0 +1,3584 @@
+//
+// "$Id: Fl_Help_View.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $"
+//
+// Fl_Help_View widget routines.
+//
+// Copyright 1997-2001 by Easy Software Products.
+// Image support donated by Matthias Melcher, Copyright 2000.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to "fltk-bugs@fltk.org".
+//
+// Contents:
+//
+//   Fl_Help_View::add_block()       - Add a text block to the list.
+//   Fl_Help_View::add_image()       - Add an image to the image cache.
+//   Fl_Help_View::add_link()        - Add a new link to the list.
+//   Fl_Help_View::add_target()      - Add a new target to the list.
+//   Fl_Help_View::compare_targets() - Compare two targets.
+//   Fl_Help_View::do_align()        - Compute the alignment for a line in
+//                                    a block.
+//   Fl_Help_View::draw()            - Draw the Fl_Help_View widget.
+//   Fl_Help_View::find_image()      - Find an image by name 
+//   Fl_Help_View::format()          - Format the help text.
+//   Fl_Help_View::format_table()    - Format a table...
+//   Fl_Help_View::get_align()       - Get an alignment attribute.
+//   Fl_Help_View::get_attr()        - Get an attribute value from the string.
+//   Fl_Help_View::get_color()       - Get an alignment attribute.
+//   Fl_Help_View::handle()          - Handle events in the widget.
+//   Fl_Help_View::Fl_Help_View()     - Build a Fl_Help_View widget.
+//   Fl_Help_View::~Fl_Help_View()    - Destroy a Fl_Help_View widget.
+//   Fl_Help_View::load()            - Load the specified file.
+//   Fl_Help_View::load_gif()        - Load a GIF image file...
+//   Fl_Help_View::load_jpeg()       - Load a JPEG image file.
+//   Fl_Help_View::load_png()        - Load a PNG image file.
+//   Fl_Help_View::resize()          - Resize the help widget.
+//   Fl_Help_View::topline()         - Set the top line to the named target.
+//   Fl_Help_View::topline()         - Set the top line by number.
+//   Fl_Help_View::value()           - Set the help text directly.
+//   Fl_Help_View::compare_blocks()  - Compare two blocks.
+//   gif_read_cmap()                - Read the colormap from a GIF file...
+//   gif_get_block()                - Read a GIF data block...
+//   gif_get_code()                 - Get a LZW code from the file...
+//   gif_read_lzw()                 - Read a byte from the LZW stream...
+//   gif_read_image()               - Read a GIF image stream...
+//   scrollbar_callback()           - A callback for the scrollbar.
+//
+
+//
+// Include necessary header files...
+//
+
+#include 
+#include "config.h"
+#include 
+#include 
+#include 
+#include 
+#ifdef HAVE_STRINGS_H
+#  include 
+#endif /* HAVE_STRINGS_H */
+#include 
+
+#include 
+#include 
+
+#if defined(WIN32)
+#  include 
+#  include 
+#  define strcasecmp(s,t)	stricmp((s), (t))
+#  define strncasecmp(s,t,n)	strnicmp((s), (t), (n))
+#elif defined(__EMX__)
+#  define strcasecmp(s,t)	stricmp((s), (t))
+#  define strncasecmp(s,t,n)	strnicmp((s), (t), (n))
+#else
+#  include 
+#endif // WIN32
+
+extern "C"
+{
+#ifdef HAVE_LIBPNG
+#  include 
+#  include 
+#endif // HAVE_LIBPNG
+
+#ifdef HAVE_LIBJPEG
+#  include 
+#endif // HAVE_LIBJPEG
+}
+
+#define MAX_COLUMNS	200
+
+
+//
+// Typedef the C API sort function type the only way I know how...
+//
+
+extern "C"
+{
+  typedef int (*compare_func_t)(const void *, const void *);
+}
+
+//
+// GIF definitions...
+//
+
+#define GIF_INTERLACE	0x40
+#define GIF_COLORMAP	0x80
+
+typedef unsigned char	gif_cmap_t[256][3];
+
+
+//
+// Local globals...
+//
+
+static const char *broken_xpm[] =
+		{
+		  "16 24 4 1",
+		  "@ c #000000",
+		  "  c #ffffff",
+		  "+ c none",
+		  "x c #ff0000",
+		  // pixels
+		  "@@@@@@@+++++++++",
+		  "@    @++++++++++",
+		  "@   @+++++++++++",
+		  "@   @++@++++++++",
+		  "@    @@+++++++++",
+		  "@     @+++@+++++",
+		  "@     @++@@++++@",
+		  "@ xxx  @@  @++@@",
+		  "@  xxx    xx@@ @",
+		  "@   xxx  xxx   @",
+		  "@    xxxxxx    @",
+		  "@     xxxx     @",
+		  "@    xxxxxx    @",
+		  "@   xxx  xxx   @",
+		  "@  xxx    xxx  @",
+		  "@ xxx      xxx @",
+		  "@              @",
+		  "@              @",
+		  "@              @",
+		  "@              @",
+		  "@              @",
+		  "@              @",
+		  "@              @",
+		  "@@@@@@@@@@@@@@@@",
+		  NULL
+		};
+
+static Fl_Pixmap *broken_image = (Fl_Pixmap *)0;
+static int	gif_eof = 0;		// Did we hit EOF?
+static unsigned	fltk_colors[] =
+		{
+		  0x00000000,
+		  0xff000000,
+		  0x00ff0000,
+		  0xffff0000,
+		  0x0000ff00,
+		  0xff00ff00,
+		  0x00ffff00,
+		  0xffffff00,
+		  0x55555500,
+		  0xc6717100,
+		  0x71c67100,
+		  0x8e8e3800,
+		  0x7171c600,
+		  0x8e388e00,
+		  0x388e8e00,
+		  0xaaaaaa00,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x55555500,
+		  0x00000000,
+		  0x0d0d0d00,
+		  0x1a1a1a00,
+		  0x26262600,
+		  0x31313100,
+		  0x3d3d3d00,
+		  0x48484800,
+		  0x55555500,
+		  0x5f5f5f00,
+		  0x6a6a6a00,
+		  0x75757500,
+		  0x80808000,
+		  0x8a8a8a00,
+		  0x95959500,
+		  0xa0a0a000,
+		  0xaaaaaa00,
+		  0xb5b5b500,
+		  0xc0c0c000,
+		  0xcbcbcb00,
+		  0xd5d5d500,
+		  0xe0e0e000,
+		  0xeaeaea00,
+		  0xf5f5f500,
+		  0xffffff00,
+		  0x00000000,
+		  0x00240000,
+		  0x00480000,
+		  0x006d0000,
+		  0x00910000,
+		  0x00b60000,
+		  0x00da0000,
+		  0x00ff0000,
+		  0x3f000000,
+		  0x3f240000,
+		  0x3f480000,
+		  0x3f6d0000,
+		  0x3f910000,
+		  0x3fb60000,
+		  0x3fda0000,
+		  0x3fff0000,
+		  0x7f000000,
+		  0x7f240000,
+		  0x7f480000,
+		  0x7f6d0000,
+		  0x7f910000,
+		  0x7fb60000,
+		  0x7fda0000,
+		  0x7fff0000,
+		  0xbf000000,
+		  0xbf240000,
+		  0xbf480000,
+		  0xbf6d0000,
+		  0xbf910000,
+		  0xbfb60000,
+		  0xbfda0000,
+		  0xbfff0000,
+		  0xff000000,
+		  0xff240000,
+		  0xff480000,
+		  0xff6d0000,
+		  0xff910000,
+		  0xffb60000,
+		  0xffda0000,
+		  0xffff0000,
+		  0x00003f00,
+		  0x00243f00,
+		  0x00483f00,
+		  0x006d3f00,
+		  0x00913f00,
+		  0x00b63f00,
+		  0x00da3f00,
+		  0x00ff3f00,
+		  0x3f003f00,
+		  0x3f243f00,
+		  0x3f483f00,
+		  0x3f6d3f00,
+		  0x3f913f00,
+		  0x3fb63f00,
+		  0x3fda3f00,
+		  0x3fff3f00,
+		  0x7f003f00,
+		  0x7f243f00,
+		  0x7f483f00,
+		  0x7f6d3f00,
+		  0x7f913f00,
+		  0x7fb63f00,
+		  0x7fda3f00,
+		  0x7fff3f00,
+		  0xbf003f00,
+		  0xbf243f00,
+		  0xbf483f00,
+		  0xbf6d3f00,
+		  0xbf913f00,
+		  0xbfb63f00,
+		  0xbfda3f00,
+		  0xbfff3f00,
+		  0xff003f00,
+		  0xff243f00,
+		  0xff483f00,
+		  0xff6d3f00,
+		  0xff913f00,
+		  0xffb63f00,
+		  0xffda3f00,
+		  0xffff3f00,
+		  0x00007f00,
+		  0x00247f00,
+		  0x00487f00,
+		  0x006d7f00,
+		  0x00917f00,
+		  0x00b67f00,
+		  0x00da7f00,
+		  0x00ff7f00,
+		  0x3f007f00,
+		  0x3f247f00,
+		  0x3f487f00,
+		  0x3f6d7f00,
+		  0x3f917f00,
+		  0x3fb67f00,
+		  0x3fda7f00,
+		  0x3fff7f00,
+		  0x7f007f00,
+		  0x7f247f00,
+		  0x7f487f00,
+		  0x7f6d7f00,
+		  0x7f917f00,
+		  0x7fb67f00,
+		  0x7fda7f00,
+		  0x7fff7f00,
+		  0xbf007f00,
+		  0xbf247f00,
+		  0xbf487f00,
+		  0xbf6d7f00,
+		  0xbf917f00,
+		  0xbfb67f00,
+		  0xbfda7f00,
+		  0xbfff7f00,
+		  0xff007f00,
+		  0xff247f00,
+		  0xff487f00,
+		  0xff6d7f00,
+		  0xff917f00,
+		  0xffb67f00,
+		  0xffda7f00,
+		  0xffff7f00,
+		  0x0000bf00,
+		  0x0024bf00,
+		  0x0048bf00,
+		  0x006dbf00,
+		  0x0091bf00,
+		  0x00b6bf00,
+		  0x00dabf00,
+		  0x00ffbf00,
+		  0x3f00bf00,
+		  0x3f24bf00,
+		  0x3f48bf00,
+		  0x3f6dbf00,
+		  0x3f91bf00,
+		  0x3fb6bf00,
+		  0x3fdabf00,
+		  0x3fffbf00,
+		  0x7f00bf00,
+		  0x7f24bf00,
+		  0x7f48bf00,
+		  0x7f6dbf00,
+		  0x7f91bf00,
+		  0x7fb6bf00,
+		  0x7fdabf00,
+		  0x7fffbf00,
+		  0xbf00bf00,
+		  0xbf24bf00,
+		  0xbf48bf00,
+		  0xbf6dbf00,
+		  0xbf91bf00,
+		  0xbfb6bf00,
+		  0xbfdabf00,
+		  0xbfffbf00,
+		  0xff00bf00,
+		  0xff24bf00,
+		  0xff48bf00,
+		  0xff6dbf00,
+		  0xff91bf00,
+		  0xffb6bf00,
+		  0xffdabf00,
+		  0xffffbf00,
+		  0x0000ff00,
+		  0x0024ff00,
+		  0x0048ff00,
+		  0x006dff00,
+		  0x0091ff00,
+		  0x00b6ff00,
+		  0x00daff00,
+		  0x00ffff00,
+		  0x3f00ff00,
+		  0x3f24ff00,
+		  0x3f48ff00,
+		  0x3f6dff00,
+		  0x3f91ff00,
+		  0x3fb6ff00,
+		  0x3fdaff00,
+		  0x3fffff00,
+		  0x7f00ff00,
+		  0x7f24ff00,
+		  0x7f48ff00,
+		  0x7f6dff00,
+		  0x7f91ff00,
+		  0x7fb6ff00,
+		  0x7fdaff00,
+		  0x7fffff00,
+		  0xbf00ff00,
+		  0xbf24ff00,
+		  0xbf48ff00,
+		  0xbf6dff00,
+		  0xbf91ff00,
+		  0xbfb6ff00,
+		  0xbfdaff00,
+		  0xbfffff00,
+		  0xff00ff00,
+		  0xff24ff00,
+		  0xff48ff00,
+		  0xff6dff00,
+		  0xff91ff00,
+		  0xffb6ff00,
+		  0xffdaff00,
+		  0xffffff00
+		};
+
+
+//
+// Local functions...
+//
+
+static int	gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap);
+static int	gif_get_block(FILE *fp, unsigned char *buffer);
+static int	gif_get_code (FILE *fp, int code_size, int first_time);
+static int	gif_read_lzw(FILE *fp, int first_time, int input_code_size);
+static int	gif_read_image(FILE *fp, Fl_Help_Image *img, gif_cmap_t cmap,
+		               int interlace);
+static void	scrollbar_callback(Fl_Widget *s, void *);
+
+
+//
+// 'Fl_Help_View::add_block()' - Add a text block to the list.
+//
+
+Fl_Help_Block *					// O - Pointer to new block
+Fl_Help_View::add_block(const char    *s,	// I - Pointer to start of block text
+                       int           xx,	// I - X position of block
+		       int           yy,	// I - Y position of block
+		       int           ww,	// I - Right margin of block
+		       int           hh,	// I - Height of block
+		       unsigned char border)	// I - Draw border?
+{
+  Fl_Help_Block	*temp;				// New block
+
+
+//  printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n",
+//         s, xx, yy, ww, hh, border);
+
+  if (nblocks_ >= ablocks_)
+  {
+    ablocks_ += 16;
+
+    if (ablocks_ == 16)
+      blocks_ = (Fl_Help_Block *)malloc(sizeof(Fl_Help_Block) * ablocks_);
+    else
+      blocks_ = (Fl_Help_Block *)realloc(blocks_, sizeof(Fl_Help_Block) * ablocks_);
+  }
+
+  temp = blocks_ + nblocks_;
+  temp->start  = s;
+  temp->x      = xx;
+  temp->y      = yy;
+  temp->w      = ww;
+  temp->h      = hh;
+  temp->border = border;
+  nblocks_ ++;
+
+  return (temp);
+}
+
+
+//
+// 'Fl_Help_View::add_image()' - Add an image to the image cache.
+//
+
+Fl_Help_Image *					// O - Image or NULL if not found
+Fl_Help_View::add_image(const char *name,	// I - Path of image
+                       const char *wattr,	// I - Width attribute
+		       const char *hattr,	// I - Height attribute
+                       int        make)		// I - Make the image?
+{
+  Fl_Help_Image	*img,				// New image
+		*orig;				// Original image
+  FILE		*fp;				// File pointer
+  unsigned char	header[16];			// First 16 bytes of file
+  int		status;				// Status of load...
+  const char	*localname;			// Local filename
+  char		dir[1024];			// Current directory
+  char		temp[1024],			// Temporary filename
+		*tempptr;			// Pointer into temporary name
+  int		width,				// Desired width of image
+		height;				// Desired height of image
+
+
+  // See if the image has already been loaded...
+  if ((img = find_image(name, wattr, hattr)) != (Fl_Help_Image *)0)
+  {
+    // Make the image if needed...
+    if (!img->image)
+      img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d);
+
+    return (img);
+  }
+
+  // See if the image exists with the default size info...
+  orig = find_image(name, "", "");
+
+  // Allocate memory as needed...
+  if (aimage_ == nimage_)
+  {
+    aimage_ += 16;
+
+    if (aimage_ == 16)
+      image_ = (Fl_Help_Image *)malloc(sizeof(Fl_Help_Image) * aimage_);
+    else
+      image_ = (Fl_Help_Image *)realloc(image_, sizeof(Fl_Help_Image) * aimage_);
+  }
+
+  img       = image_ + nimage_;
+  img->name = strdup(name);
+  img->copy = 0;
+
+  if (!orig)
+  {
+    // See if the image can be found...
+    if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL)
+    {
+      if (name[0] == '/')
+      {
+        strcpy(temp, directory_);
+        if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
+	  strcpy(tempptr, name);
+	else
+	  strcat(temp, name);
+      }
+      else
+	sprintf(temp, "%s/%s", directory_, name);
+
+      if (link_)
+	localname = (*link_)(temp);
+      else
+	localname = temp;
+    }
+    else if (name[0] != '/' && strchr(name, ':') == NULL)
+    {
+      if (directory_[0])
+	sprintf(temp, "%s/%s", directory_, name);
+      else
+      {
+	getcwd(dir, sizeof(dir));
+	sprintf(temp, "file:%s/%s", dir, name);
+      }
+
+      if (link_)
+	localname = (*link_)(temp);
+      else
+	localname = temp;
+    }
+    else if (link_)
+      localname = (*link_)(name);
+    else
+      localname = name;
+
+    if (!localname)
+      return ((Fl_Help_Image *)0);
+
+    if (strncmp(localname, "file:", 5) == 0)
+      localname += 5;
+
+    // Figure out the file type...
+    if ((fp = fopen(localname, "rb")) == NULL)
+      return ((Fl_Help_Image *)0);
+
+    if (fread(header, 1, sizeof(header), fp) == 0)
+      return ((Fl_Help_Image *)0);
+
+    rewind(fp);
+
+    // Load the image as appropriate...
+    if (memcmp(header, "GIF87a", 6) == 0 ||
+	memcmp(header, "GIF89a", 6) == 0)
+      status = load_gif(img,  fp);
+  #ifdef HAVE_LIBPNG
+    else if (memcmp(header, "\211PNG", 4) == 0)
+      status = load_png(img, fp);
+  #endif // HAVE_LIBPNG
+  #ifdef HAVE_LIBJPEG
+    else if (memcmp(header, "\377\330\377", 3) == 0 &&	// Start-of-Image
+	     header[3] >= 0xe0 && header[3] <= 0xef)	// APPn
+      status = load_jpeg(img, fp);
+  #endif // HAVE_LIBJPEG
+    else
+      status = 0;
+
+    fclose(fp);
+
+    if (!status)
+    {
+      free(img->name);
+      return ((Fl_Help_Image *)0);
+    }
+
+    img->wattr[0] = '\0';
+    img->hattr[0] = '\0';
+
+    nimage_ ++;
+
+    // Allocate memory as needed for the new copy...
+    if (aimage_ == nimage_)
+    {
+      aimage_ += 16;
+      image_  = (Fl_Help_Image *)realloc(image_, sizeof(Fl_Help_Image) * aimage_);
+    }
+
+    orig      = image_ + nimage_ - 1;
+    img       = image_ + nimage_;
+    img->name = strdup(name);
+  }
+
+//  printf("orig->data = %p, width = %d, height = %d\n", orig->data,
+//         orig->w, orig->h);
+
+  // Copy image data from original image...
+  img->data = orig->data;
+  img->w    = orig->w;
+  img->h    = orig->h;
+  img->d    = orig->d;
+  img->copy = 1;
+
+  // Figure out the size of the image...
+  if (wattr[0])
+  {
+    if (wattr[strlen(wattr) - 1] == '%')
+      width = atoi(wattr) * (w() - 24) / 100;
+    else
+      width = atoi(wattr);
+  }
+  else
+    width = 0;
+
+  if (hattr[0])
+  {
+    if (hattr[strlen(hattr) - 1] == '%')
+      height = atoi(hattr) * h() / 100;
+    else
+      height = atoi(hattr);
+  }
+  else
+    height = 0;
+
+  if (width == 0 && height == 0)
+  {
+    // Use image size...
+    width  = img->w;
+    height = img->h;
+  }
+  else if (width == 0)
+    // Scale width to height
+    width = img->w * height / img->h;
+  else if (height == 0)
+    // Scale height to width
+    height = img->h * width / img->w;
+
+  // Scale the image as needed...
+  if (width != img->w && height != img->h)
+  {
+    unsigned char	*scaled,	// Scaled image data
+			*sptr,		// Source image data pointer
+			*dptr;		// Destination image data pointer
+    int			sy,		// Source coordinates
+			dx, dy,		// Destination coordinates
+			xerr, yerr,	// X & Y errors
+			xmod, ymod,	// X & Y moduli
+			xstep, ystep;	// X & Y step increments
+
+
+     xmod   = img->w % width;
+     xstep  = (img->w / width) * img->d;
+     ymod   = img->h % height;
+     ystep  = img->h / height;
+
+     if ((scaled = (unsigned char *)malloc(width * height * img->d)) != NULL)
+     {
+       img->copy = 0;
+
+       // Scale the image...
+       for (dy = height, sy = 0, yerr = height / 2, dptr = scaled; dy > 0; dy --)
+       {
+         for (dx = width, xerr = width / 2,
+	          sptr = img->data + sy * img->w * img->d;
+	      dx > 0;
+	      dx --)
+         {
+	   *dptr++ = sptr[0];
+	   if (img->d > 1)
+	   {
+	     *dptr++ = sptr[1];
+	     *dptr++ = sptr[2];
+	   }
+
+           sptr += xstep;
+	   xerr -= xmod;
+	   if (xerr <= 0)
+	   {
+	     xerr += width;
+	     sptr += img->d;
+	   }
+	 }
+
+         sy   += ystep;
+	 yerr -= ymod;
+	 if (yerr <= 0)
+	 {
+	   yerr += height;
+	   sy ++;
+	 }
+       }
+
+       // Finally, copy the new size and data to the image structure...
+       if (!orig)
+         free(img->data);
+
+       img->w    = width;
+       img->h    = height;
+       img->data = scaled;
+     }
+  }
+
+  strncpy(img->wattr, wattr, sizeof(img->wattr) - 1);
+  img->wattr[sizeof(img->wattr) - 1] = '\0';
+  strncpy(img->hattr, hattr, sizeof(img->hattr) - 1);
+  img->hattr[sizeof(img->hattr) - 1] = '\0';
+
+  if (make)
+    img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d);
+  else
+    img->image = (Fl_Image *)0;
+
+  nimage_ ++;
+
+//  printf("img->data = %p, width = %d, height = %d\n", img->data,
+//         img->w, img->h);
+
+  return (img);
+}
+
+
+//
+// 'Fl_Help_View::add_link()' - Add a new link to the list.
+//
+
+void
+Fl_Help_View::add_link(const char *n,	// I - Name of link
+                      int        xx,	// I - X position of link
+		      int        yy,	// I - Y position of link
+		      int        ww,	// I - Width of link text
+		      int        hh)	// I - Height of link text
+{
+  Fl_Help_Link	*temp;			// New link
+  char		*target;		// Pointer to target name
+
+
+  if (nlinks_ >= alinks_)
+  {
+    alinks_ += 16;
+
+    if (alinks_ == 16)
+      links_ = (Fl_Help_Link *)malloc(sizeof(Fl_Help_Link) * alinks_);
+    else
+      links_ = (Fl_Help_Link *)realloc(links_, sizeof(Fl_Help_Link) * alinks_);
+  }
+
+  temp = links_ + nlinks_;
+
+  temp->x       = xx;
+  temp->y       = yy;
+  temp->w       = xx + ww;
+  temp->h       = yy + hh;
+
+  strncpy(temp->filename, n, sizeof(temp->filename));
+  temp->filename[sizeof(temp->filename) - 1] = '\0';
+
+  if ((target = strrchr(temp->filename, '#')) != NULL)
+  {
+    *target++ = '\0';
+    strncpy(temp->name, target, sizeof(temp->name));
+    temp->name[sizeof(temp->name) - 1] = '\0';
+  }
+  else
+    temp->name[0] = '\0';
+
+  nlinks_ ++;
+}
+
+
+//
+// 'Fl_Help_View::add_target()' - Add a new target to the list.
+//
+
+void
+Fl_Help_View::add_target(const char *n,	// I - Name of target
+                	int        yy)	// I - Y position of target
+{
+  Fl_Help_Target	*temp;			// New target
+
+
+  if (ntargets_ >= atargets_)
+  {
+    atargets_ += 16;
+
+    if (atargets_ == 16)
+      targets_ = (Fl_Help_Target *)malloc(sizeof(Fl_Help_Target) * atargets_);
+    else
+      targets_ = (Fl_Help_Target *)realloc(targets_, sizeof(Fl_Help_Target) * atargets_);
+  }
+
+  temp = targets_ + ntargets_;
+
+  temp->y = yy;
+  strncpy(temp->name, n, sizeof(temp->name));
+  temp->name[sizeof(temp->name) - 1] = '\0';
+
+  ntargets_ ++;
+}
+
+
+//
+// 'Fl_Help_View::compare_targets()' - Compare two targets.
+//
+
+int							// O - Result of comparison
+Fl_Help_View::compare_targets(const Fl_Help_Target *t0,	// I - First target
+                             const Fl_Help_Target *t1)	// I - Second target
+{
+  return (strcasecmp(t0->name, t1->name));
+}
+
+
+//
+// 'Fl_Help_View::do_align()' - Compute the alignment for a line in a block.
+//
+
+int						// O - New line
+Fl_Help_View::do_align(Fl_Help_Block *block,	// I - Block to add to
+                      int          line,	// I - Current line
+		      int          xx,		// I - Current X position
+		      int          a,		// I - Current alignment
+		      int          &l)		// IO - Starting link
+{
+  int	offset;					// Alignment offset
+
+
+  switch (a)
+  {
+    case RIGHT :	// Right align
+	offset = block->w - xx;
+	break;
+    case CENTER :	// Center
+	offset = (block->w - xx) / 2;
+	break;
+    default :		// Left align
+	offset = 0;
+	break;
+  }
+
+  block->line[line] = block->x + offset;
+
+  if (line < 31)
+    line ++;
+
+  while (l < nlinks_)
+  {
+    links_[l].x += offset;
+    links_[l].w += offset;
+    l ++;
+  }
+
+  return (line);
+}
+
+
+//
+// 'Fl_Help_View::draw()' - Draw the Fl_Help_View widget.
+//
+
+void
+Fl_Help_View::draw()
+{
+  int			i;		// Looping var
+  const Fl_Help_Block	*block;		// Pointer to current block
+  const char		*ptr,		// Pointer to text in block
+			*attrs;		// Pointer to start of element attributes
+  char			*s,		// Pointer into buffer
+			buf[1024],	// Text buffer
+			attr[1024];	// Attribute buffer
+  int			xx, yy, ww, hh;	// Current positions and sizes
+  int			line;		// Current line
+  unsigned char		font, size;	// Current font and size
+  int			head, pre,	// Flags for text
+			needspace;	// Do we need whitespace?
+  Fl_Boxtype		b = box() ? box() : FL_DOWN_BOX;
+					// Box to draw...
+  Fl_Color		tc, c;		// Table/cell background color
+
+
+  // Draw the scrollbar and box first...
+  if (scrollbar_.visible())
+  {
+    draw_child(scrollbar_);
+    draw_box(b, x(), y(), w() - 17, h(), bgcolor_);
+  }
+  else
+    draw_box(b, x(), y(), w(), h(), bgcolor_);
+
+  if (!value_)
+    return;
+
+  // Clip the drawing to the inside of the box...
+  fl_push_clip(x() + 4, y() + 4, w() - 28, h() - 8);
+  fl_color(textcolor_);
+
+  tc = c = bgcolor_;
+
+  // Draw all visible blocks...
+  for (i = 0, block = blocks_; i < nblocks_ && (block->y - topline_) < h(); i ++, block ++)
+    if ((block->y + block->h) >= topline_)
+    {
+      line      = 0;
+      xx        = block->line[line];
+      yy        = block->y - topline_;
+      hh        = 0;
+      pre       = 0;
+      head      = 0;
+      needspace = 0;
+
+      initfont(font, size);
+
+      for (ptr = block->start, s = buf; ptr < block->end;)
+      {
+	if ((*ptr == '<' || isspace(*ptr)) && s > buf)
+	{
+	  if (!head && !pre)
+	  {
+            // Check width...
+            *s = '\0';
+            s  = buf;
+            ww = (int)fl_width(buf);
+
+            if (needspace && xx > block->x)
+	      xx += (int)fl_width(' ');
+
+            if ((xx + ww) > block->w)
+	    {
+	      if (line < 31)
+	        line ++;
+	      xx = block->line[line];
+	      yy += hh;
+	      hh = 0;
+	    }
+
+            fl_draw(buf, xx + x(), yy + y());
+
+            xx += ww;
+	    if ((size + 2) > hh)
+	      hh = size + 2;
+
+	    needspace = 0;
+	  }
+	  else if (pre)
+	  {
+	    while (isspace(*ptr))
+	    {
+	      if (*ptr == '\n')
+	      {
+	        *s = '\0';
+                s = buf;
+
+                fl_draw(buf, xx + x(), yy + y());
+
+		if (line < 31)
+	          line ++;
+		xx = block->line[line];
+		yy += hh;
+		hh = size + 2;
+	      }
+	      else if (*ptr == '\t')
+	      {
+		// Do tabs every 8 columns...
+		while (((s - buf) & 7))
+	          *s++ = ' ';
+	      }
+	      else
+	        *s++ = ' ';
+
+              if ((size + 2) > hh)
+	        hh = size + 2;
+
+              ptr ++;
+	    }
+
+            if (s > buf)
+	    {
+	      *s = '\0';
+	      s = buf;
+
+              fl_draw(buf, xx + x(), yy + y());
+              xx += (int)fl_width(buf);
+	    }
+
+	    needspace = 0;
+	  }
+	  else
+	  {
+            s = buf;
+
+	    while (isspace(*ptr))
+              ptr ++;
+	  }
+	}
+
+	if (*ptr == '<')
+	{
+	  ptr ++;
+	  while (*ptr && *ptr != '>' && !isspace(*ptr))
+            if (s < (buf + sizeof(buf) - 1))
+	      *s++ = *ptr++;
+	    else
+	      ptr ++;
+
+	  *s = '\0';
+	  s = buf;
+
+	  attrs = ptr;
+	  while (*ptr && *ptr != '>')
+            ptr ++;
+
+	  if (*ptr == '>')
+            ptr ++;
+
+	  if (strcasecmp(buf, "HEAD") == 0)
+            head = 1;
+	  else if (strcasecmp(buf, "BR") == 0)
+	  {
+	    if (line < 31)
+	      line ++;
+	    xx = block->line[line];
+            yy += hh;
+	    hh = 0;
+	  }
+	  else if (strcasecmp(buf, "HR") == 0)
+	  {
+	    fl_line(block->x + x(), yy + y(), block->w + x(),
+	            yy + y());
+
+	    if (line < 31)
+	      line ++;
+	    xx = block->line[line];
+            yy += 2 * hh;
+	    hh = 0;
+	  }
+	  else if (strcasecmp(buf, "CENTER") == 0 ||
+        	   strcasecmp(buf, "P") == 0 ||
+        	   strcasecmp(buf, "H1") == 0 ||
+		   strcasecmp(buf, "H2") == 0 ||
+		   strcasecmp(buf, "H3") == 0 ||
+		   strcasecmp(buf, "H4") == 0 ||
+		   strcasecmp(buf, "H5") == 0 ||
+		   strcasecmp(buf, "H6") == 0 ||
+		   strcasecmp(buf, "UL") == 0 ||
+		   strcasecmp(buf, "OL") == 0 ||
+		   strcasecmp(buf, "DL") == 0 ||
+		   strcasecmp(buf, "LI") == 0 ||
+		   strcasecmp(buf, "DD") == 0 ||
+		   strcasecmp(buf, "DT") == 0 ||
+		   strcasecmp(buf, "PRE") == 0)
+	  {
+            if (tolower(buf[0]) == 'h')
+	    {
+	      font = FL_HELVETICA_BOLD;
+	      size = textsize_ + '7' - buf[1];
+	    }
+	    else if (strcasecmp(buf, "DT") == 0)
+	    {
+	      font = textfont_ | FL_ITALIC;
+	      size = textsize_;
+	    }
+	    else if (strcasecmp(buf, "PRE") == 0)
+	    {
+	      font = FL_COURIER;
+	      size = textsize_;
+	      pre  = 1;
+	    }
+
+            if (strcasecmp(buf, "LI") == 0)
+	    {
+	      fl_font(FL_SYMBOL, size);
+	      fl_draw("\267", xx - size + x(), yy + y());
+	    }
+
+	    pushfont(font, size);
+
+            if (c != bgcolor_)
+	    {
+	      fl_color(c);
+              fl_rectf(block->x + x() - 4,
+	               block->y - topline_ + y() - size - 3,
+		       block->w - block->x + 7, block->h + size - 5);
+              fl_color(textcolor_);
+	    }
+	  }
+	  else if (strcasecmp(buf, "A") == 0 &&
+	           get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
+	    fl_color(linkcolor_);
+	  else if (strcasecmp(buf, "/A") == 0)
+	    fl_color(textcolor_);
+	  else if (strcasecmp(buf, "B") == 0)
+	    pushfont(font |= FL_BOLD, size);
+	  else if (strcasecmp(buf, "TABLE") == 0)
+            tc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_);
+	  else if (strcasecmp(buf, "TD") == 0 ||
+	           strcasecmp(buf, "TH") == 0)
+          {
+	    if (tolower(buf[1]) == 'h')
+	      pushfont(font |= FL_BOLD, size);
+	    else
+	      pushfont(font = textfont_, size);
+
+            c = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc);
+
+            if (c != bgcolor_)
+	    {
+	      fl_color(c);
+              fl_rectf(block->x + x() - 4,
+	               block->y - topline_ + y() - size - 3,
+		       block->w - block->x + 7, block->h + size - 5);
+              fl_color(textcolor_);
+	    }
+
+            if (block->border)
+              fl_rect(block->x + x() - 4,
+	              block->y - topline_ + y() - size - 3,
+		      block->w - block->x + 7, block->h + size - 5);
+	  }
+	  else if (strcasecmp(buf, "I") == 0)
+	    pushfont(font |= FL_ITALIC, size);
+	  else if (strcasecmp(buf, "CODE") == 0)
+	    pushfont(font = FL_COURIER, size);
+	  else if (strcasecmp(buf, "KBD") == 0)
+	    pushfont(font = FL_COURIER_BOLD, size);
+	  else if (strcasecmp(buf, "VAR") == 0)
+	    pushfont(font = FL_COURIER_ITALIC, size);
+	  else if (strcasecmp(buf, "/HEAD") == 0)
+            head = 0;
+	  else if (strcasecmp(buf, "/H1") == 0 ||
+		   strcasecmp(buf, "/H2") == 0 ||
+		   strcasecmp(buf, "/H3") == 0 ||
+		   strcasecmp(buf, "/H4") == 0 ||
+		   strcasecmp(buf, "/H5") == 0 ||
+		   strcasecmp(buf, "/H6") == 0 ||
+		   strcasecmp(buf, "/B") == 0 ||
+		   strcasecmp(buf, "/I") == 0 ||
+		   strcasecmp(buf, "/CODE") == 0 ||
+		   strcasecmp(buf, "/KBD") == 0 ||
+		   strcasecmp(buf, "/VAR") == 0)
+	    popfont(font, size);
+	  else if (strcasecmp(buf, "/TABLE") == 0)
+	    tc = c = bgcolor_;
+	  else if (strcasecmp(buf, "/TD") == 0 ||
+	           strcasecmp(buf, "/TH") == 0)
+	    c = tc;
+	  else if (strcasecmp(buf, "/PRE") == 0)
+	  {
+	    popfont(font, size);
+	    pre = 0;
+	  }
+	  else if (strcasecmp(buf, "IMG") == 0)
+	  {
+	    Fl_Help_Image	*img = (Fl_Help_Image *)0;
+	    int		width = 16;
+	    int		height = 24;
+	    char	wattr[8], hattr[8];
+
+
+            get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+            get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+
+	    if (get_attr(attrs, "SRC", attr, sizeof(attr))) 
+	      if ((img = add_image(attr, wattr, hattr)) != NULL)
+	      {
+	        if (!img->image)
+	          img = (Fl_Help_Image *)0;
+              }
+
+	    if (img)
+	    {
+	      width  = img->w;
+	      height = img->h;
+	    }
+	    else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL)
+	      strcpy(attr, "IMG");
+
+	    ww = width;
+
+	    if (needspace && xx > block->x)
+	      xx += (int)fl_width(' ');
+
+	    if ((xx + ww) > block->w)
+	    {
+	      if (line < 31)
+		line ++;
+
+	      xx = block->line[line];
+	      yy += hh;
+	      hh = 0;
+	    }
+
+	    if (img) 
+	      img->image->draw(xx + x(),
+	                       yy + y() - fl_height() + fl_descent() + 2);
+	    else
+	      broken_image->draw(xx + x(),
+	                         yy + y() - fl_height() + fl_descent() + 2);
+
+	    xx += ww;
+	    if ((height + 2) > hh)
+	      hh = height + 2;
+
+	    needspace = 0;
+	  }
+	}
+	else if (*ptr == '\n' && pre)
+	{
+	  *s = '\0';
+	  s = buf;
+
+          fl_draw(buf, xx + x(), yy + y());
+
+	  if (line < 31)
+	    line ++;
+	  xx = block->line[line];
+	  yy += hh;
+	  hh = size + 2;
+	  needspace = 0;
+
+	  ptr ++;
+	}
+	else if (isspace(*ptr))
+	{
+	  if (pre)
+	  {
+	    if (*ptr == ' ')
+	      *s++ = ' ';
+	    else
+	    {
+	      // Do tabs every 8 columns...
+	      while (((s - buf) & 7))
+	        *s++ = ' ';
+            }
+	  }
+
+          ptr ++;
+	  needspace = 1;
+	}
+	else if (*ptr == '&')
+	{
+	  ptr ++;
+
+	  if (strncasecmp(ptr, "amp;", 4) == 0)
+	  {
+            *s++ = '&';
+	    ptr += 4;
+	  }
+	  else if (strncasecmp(ptr, "lt;", 3) == 0)
+	  {
+            *s++ = '<';
+	    ptr += 3;
+	  }
+	  else if (strncasecmp(ptr, "gt;", 3) == 0)
+	  {
+            *s++ = '>';
+	    ptr += 3;
+	  }
+	  else if (strncasecmp(ptr, "nbsp;", 5) == 0)
+	  {
+            *s++ = ' ';
+	    ptr += 5;
+	  }
+	  else if (strncasecmp(ptr, "copy;", 5) == 0)
+	  {
+            *s++ = '\251';
+	    ptr += 5;
+	  }
+	  else if (strncasecmp(ptr, "reg;", 4) == 0)
+	  {
+            *s++ = '\256';
+	    ptr += 4;
+	  }
+	  else if (strncasecmp(ptr, "quot;", 5) == 0)
+	  {
+            *s++ = '\"';
+	    ptr += 5;
+	  }
+
+          if ((size + 2) > hh)
+	    hh = size + 2;
+	}
+	else
+	{
+	  *s++ = *ptr++;
+
+          if ((size + 2) > hh)
+	    hh = size + 2;
+        }
+      }
+
+      *s = '\0';
+
+      if (s > buf && !pre && !head)
+      {
+	ww = (int)fl_width(buf);
+
+        if (needspace && xx > block->x)
+	  xx += (int)fl_width(' ');
+
+	if ((xx + ww) > block->w)
+	{
+	  if (line < 31)
+	    line ++;
+	  xx = block->line[line];
+	  yy += hh;
+	  hh = 0;
+	}
+      }
+
+      if (s > buf && !head)
+        fl_draw(buf, xx + x(), yy + y());
+    }
+
+  fl_pop_clip();
+}
+
+
+//
+// 'Fl_Help_View::find_image()' - Find an image by name 
+//
+
+Fl_Help_Image *					// O - Image or NULL if not found
+Fl_Help_View::find_image(const char *name,	// I - Path and name of image
+                	const char *wattr,	// I - Width attribute of image
+			const char *hattr)	// I - Height attribute of image
+{
+  int		i;				// Looping var
+  Fl_Help_Image	*img;				// Current image
+
+
+  for (i = nimage_, img = image_; i > 0; i --, img ++) 
+    if (strcmp(img->name, name) == 0 &&
+        strcmp(img->wattr, wattr) == 0 &&
+        strcmp(img->hattr, hattr) == 0)
+      return (img);
+
+  return ((Fl_Help_Image *)0);
+}
+
+
+//
+// 'Fl_Help_View::format()' - Format the help text.
+//
+
+void
+Fl_Help_View::format()
+{
+  int		i;		// Looping var
+  Fl_Help_Block	*block,		// Current block
+		*cell;		// Current table cell
+  int		row;		// Current table row (block number)
+  const char	*ptr,		// Pointer into block
+		*start,		// Pointer to start of element
+		*attrs;		// Pointer to start of element attributes
+  char		*s,		// Pointer into buffer
+		buf[1024],	// Text buffer
+		attr[1024],	// Attribute buffer
+		wattr[1024],	// Width attribute buffer
+		hattr[1024],	// Height attribute buffer
+		link[1024];	// Link destination
+  int		xx, yy, ww, hh;	// Size of current text fragment
+  int		line;		// Current line in block
+  int		links;		// Links for current line
+  unsigned char	font, size;	// Current font and size
+  unsigned char	border;		// Draw border?
+  int		align,		// Current alignment
+		newalign,	// New alignment
+		head,		// In the  section?
+		pre,		// 
 text?
+		needspace;	// Do we need whitespace?
+  int		table_width;	// Width of table
+  int		column,		// Current table column number
+		columns[MAX_COLUMNS];
+				// Column widths
+
+
+  // Reset state variables...
+  nblocks_   = 0;
+  nlinks_    = 0;
+  ntargets_  = 0;
+  size_      = 0;
+  bgcolor_   = color();
+  textcolor_ = textcolor();
+  linkcolor_ = selection_color();
+
+  strcpy(title_, "Untitled");
+
+  if (!value_)
+    return;
+
+  // Flush images that are scaled by percentage...
+  for (i = 0; i < nimage_; i ++)
+    if (strchr(image_[i].wattr, '%') != NULL ||
+        strchr(image_[i].hattr, '%') != NULL)
+    {
+      // Flush this one...
+      free(image_[i].name);
+      free(image_[i].data);
+      delete image_[i].image;
+      nimage_ --;
+      if (i < nimage_)
+        memcpy(image_ + i, image_ + i + 1, (nimage_ - i) * sizeof(Fl_Help_Image));
+      i --;
+    }
+
+  // Setup for formatting...
+  initfont(font, size);
+
+  line      = 0;
+  links     = 0;
+  xx        = 4;
+  yy        = size + 2;
+  ww        = 0;
+  column    = 0;
+  border    = 0;
+  hh        = 0;
+  block     = add_block(value_, xx, yy, w() - 24, 0);
+  row       = 0;
+  head      = 0;
+  pre       = 0;
+  align     = LEFT;
+  newalign  = LEFT;
+  needspace = 0;
+  link[0]   = '\0';
+
+  for (ptr = value_, s = buf; *ptr;)
+  {
+    if ((*ptr == '<' || isspace(*ptr)) && s > buf)
+    {
+      if (!head && !pre)
+      {
+        // Check width...
+        *s = '\0';
+        ww = (int)fl_width(buf);
+
+        if (needspace && xx > block->x)
+	  ww += (int)fl_width(' ');
+
+//        printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
+//	       line, xx, ww, block->x, block->w);
+
+        if ((xx + ww) > block->w)
+	{
+          line     = do_align(block, line, xx, newalign, links);
+	  xx       = block->x;
+	  yy       += hh;
+	  block->h += hh;
+	  hh       = 0;
+	}
+
+        if (link[0])
+	  add_link(link, xx, yy - size, ww, size);
+
+	xx += ww;
+	if ((size + 2) > hh)
+	  hh = size + 2;
+
+	needspace = 0;
+      }
+      else if (pre)
+      {
+        // Handle preformatted text...
+	while (isspace(*ptr))
+	{
+	  if (*ptr == '\n')
+	  {
+            if (link[0])
+	      add_link(link, xx, yy - hh, ww, hh);
+
+            line     = do_align(block, line, xx, newalign, links);
+            xx       = block->x;
+	    yy       += hh;
+	    block->h += hh;
+	    hh       = size + 2;
+	  }
+
+          if ((size + 2) > hh)
+	    hh = size + 2;
+
+          ptr ++;
+	}
+
+	needspace = 0;
+      }
+      else
+      {
+        // Handle normal text or stuff in the  section...
+	while (isspace(*ptr))
+          ptr ++;
+      }
+
+      s = buf;
+    }
+
+    if (*ptr == '<')
+    {
+      start = ptr;
+      ptr ++;
+      while (*ptr && *ptr != '>' && !isspace(*ptr))
+        if (s < (buf + sizeof(buf) - 1))
+          *s++ = *ptr++;
+	else
+	  ptr ++;
+
+      *s = '\0';
+      s = buf;
+
+//      puts(buf);
+
+      attrs = ptr;
+      while (*ptr && *ptr != '>')
+        ptr ++;
+
+      if (*ptr == '>')
+        ptr ++;
+
+      if (strcasecmp(buf, "HEAD") == 0)
+        head = 1;
+      else if (strcasecmp(buf, "/HEAD") == 0)
+        head = 0;
+      else if (strcasecmp(buf, "TITLE") == 0)
+      {
+        // Copy the title in the document...
+        for (s = title_;
+	     *ptr != '<' && *ptr && s < (title_ + sizeof(title_) - 1);
+	     *s++ = *ptr++);
+
+	*s = '\0';
+	s = buf;
+      }
+      else if (strcasecmp(buf, "A") == 0)
+      {
+        if (get_attr(attrs, "NAME", attr, sizeof(attr)) != NULL)
+	  add_target(attr, yy - size - 2);
+	else if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
+	{
+	  strncpy(link, attr, sizeof(link) - 1);
+	  link[sizeof(link) - 1] = '\0';
+	}
+      }
+      else if (strcasecmp(buf, "/A") == 0)
+        link[0] = '\0';
+      else if (strcasecmp(buf, "BODY") == 0)
+      {
+        bgcolor_   = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)),
+	                       color());
+        textcolor_ = get_color(get_attr(attrs, "TEXT", attr, sizeof(attr)),
+	                       textcolor());
+        linkcolor_ = get_color(get_attr(attrs, "LINK", attr, sizeof(attr)),
+	                       selection_color());
+      }
+      else if (strcasecmp(buf, "BR") == 0)
+      {
+        line     = do_align(block, line, xx, newalign, links);
+        xx       = block->x;
+	block->h += hh;
+        yy       += hh;
+	hh       = 0;
+      }
+      else if (strcasecmp(buf, "CENTER") == 0 ||
+               strcasecmp(buf, "P") == 0 ||
+               strcasecmp(buf, "H1") == 0 ||
+	       strcasecmp(buf, "H2") == 0 ||
+	       strcasecmp(buf, "H3") == 0 ||
+	       strcasecmp(buf, "H4") == 0 ||
+	       strcasecmp(buf, "H5") == 0 ||
+	       strcasecmp(buf, "H6") == 0 ||
+	       strcasecmp(buf, "UL") == 0 ||
+	       strcasecmp(buf, "OL") == 0 ||
+	       strcasecmp(buf, "DL") == 0 ||
+	       strcasecmp(buf, "LI") == 0 ||
+	       strcasecmp(buf, "DD") == 0 ||
+	       strcasecmp(buf, "DT") == 0 ||
+	       strcasecmp(buf, "HR") == 0 ||
+	       strcasecmp(buf, "PRE") == 0 ||
+	       strcasecmp(buf, "TABLE") == 0)
+      {
+        block->end = start;
+        line       = do_align(block, line, xx, newalign, links);
+        xx         = block->x;
+        block->h   += hh;
+
+        if (strcasecmp(buf, "UL") == 0 ||
+	    strcasecmp(buf, "OL") == 0 ||
+	    strcasecmp(buf, "DL") == 0)
+        {
+	  block->h += size + 2;
+	  xx       += 4 * size;
+	}
+        else if (strcasecmp(buf, "TABLE") == 0)
+	{
+	  if (get_attr(attrs, "BORDER", attr, sizeof(attr)))
+	    border = atoi(attr);
+	  else
+	    border = 0;
+
+	  block->h += size + 2;
+
+          format_table(&table_width, columns, start);
+
+	  column = 0;
+	}
+
+        if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
+	{
+	  font = FL_HELVETICA_BOLD;
+	  size = textsize_ + '7' - buf[1];
+	}
+	else if (strcasecmp(buf, "DT") == 0)
+	{
+	  font = textfont_ | FL_ITALIC;
+	  size = textsize_;
+	}
+	else if (strcasecmp(buf, "PRE") == 0)
+	{
+	  font = FL_COURIER;
+	  size = textsize_;
+	  pre  = 1;
+	}
+	else
+	{
+	  font = textfont_;
+	  size = textsize_;
+	}
+
+	pushfont(font, size);
+
+        yy = block->y + block->h;
+        hh = 0;
+
+        if ((tolower(buf[0]) == 'h' && isdigit(buf[1])) ||
+	    strcasecmp(buf, "DD") == 0 ||
+	    strcasecmp(buf, "DT") == 0 ||
+	    strcasecmp(buf, "P") == 0)
+          yy += size + 2;
+	else if (strcasecmp(buf, "HR") == 0)
+	{
+	  hh += 2 * size;
+	  yy += size;
+	}
+
+        if (row)
+	  block = add_block(start, xx, yy, block->w, 0);
+	else
+	  block = add_block(start, xx, yy, w() - 24, 0);
+
+	needspace = 0;
+	line      = 0;
+
+	if (strcasecmp(buf, "CENTER") == 0)
+	  newalign = align = CENTER;
+	else
+	  newalign = get_align(attrs, align);
+      }
+      else if (strcasecmp(buf, "/CENTER") == 0 ||
+	       strcasecmp(buf, "/P") == 0 ||
+	       strcasecmp(buf, "/H1") == 0 ||
+	       strcasecmp(buf, "/H2") == 0 ||
+	       strcasecmp(buf, "/H3") == 0 ||
+	       strcasecmp(buf, "/H4") == 0 ||
+	       strcasecmp(buf, "/H5") == 0 ||
+	       strcasecmp(buf, "/H6") == 0 ||
+	       strcasecmp(buf, "/PRE") == 0 ||
+	       strcasecmp(buf, "/UL") == 0 ||
+	       strcasecmp(buf, "/OL") == 0 ||
+	       strcasecmp(buf, "/DL") == 0 ||
+	       strcasecmp(buf, "/TABLE") == 0)
+      {
+        line       = do_align(block, line, xx, newalign, links);
+        xx         = block->x;
+        block->end = ptr;
+
+        if (strcasecmp(buf, "/UL") == 0 ||
+	    strcasecmp(buf, "/OL") == 0 ||
+	    strcasecmp(buf, "/DL") == 0)
+	{
+	  xx       -= 4 * size;
+	  block->h += size + 2;
+	}
+	else if (strcasecmp(buf, "/TABLE") == 0)
+	  block->h += size + 2;
+	else if (strcasecmp(buf, "/PRE") == 0)
+	{
+	  pre = 0;
+	  hh  = 0;
+	}
+	else if (strcasecmp(buf, "/CENTER") == 0)
+	  align = LEFT;
+
+        popfont(font, size);
+
+        while (isspace(*ptr))
+	  ptr ++;
+
+        block->h += hh;
+        yy       += hh;
+
+        if (tolower(buf[2]) == 'l')
+          yy += size + 2;
+
+        if (row)
+	  block = add_block(ptr, xx, yy, block->w, 0);
+	else
+	  block = add_block(ptr, xx, yy, w() - 24, 0);
+
+	needspace = 0;
+	hh        = 0;
+	line      = 0;
+	newalign  = align;
+      }
+      else if (strcasecmp(buf, "TR") == 0)
+      {
+        block->end = start;
+        line       = do_align(block, line, xx, newalign, links);
+        xx         = block->x;
+        block->h   += hh;
+
+        if (row)
+	{
+          yy = blocks_[row].y + blocks_[row].h;
+
+	  for (cell = blocks_ + row + 1; cell <= block; cell ++)
+	    if ((cell->y + cell->h) > yy)
+	      yy = cell->y + cell->h;
+
+          block->h = yy - block->y + 2;
+
+	  for (cell = blocks_ + row + 1; cell < block; cell ++)
+	    cell->h = block->h;
+	}
+
+	yy        = block->y + block->h - 4;
+	hh        = 0;
+        block     = add_block(start, xx, yy, w() - 24, 0);
+	row       = block - blocks_;
+	needspace = 0;
+	column    = 0;
+	line      = 0;
+      }
+      else if (strcasecmp(buf, "/TR") == 0 && row)
+      {
+        line       = do_align(block, line, xx, newalign, links);
+        block->end = start;
+	block->h   += hh;
+
+        xx = blocks_[row].x;
+
+        yy = blocks_[row].y + blocks_[row].h;
+
+	for (cell = blocks_ + row + 1; cell <= block; cell ++)
+	  if ((cell->y + cell->h) > yy)
+	    yy = cell->y + cell->h;
+
+        block->h = yy - block->y + 2;
+
+	for (cell = blocks_ + row + 1; cell < block; cell ++)
+	  cell->h = block->h;
+
+	yy        = block->y + block->h - 4;
+        block     = add_block(start, xx, yy, w() - 24, 0);
+	needspace = 0;
+	row       = 0;
+	line      = 0;
+      }
+      else if ((strcasecmp(buf, "TD") == 0 ||
+                strcasecmp(buf, "TH") == 0) && row)
+      {
+        int	colspan;		// COLSPAN attribute
+
+
+        line       = do_align(block, line, xx, newalign, links);
+        block->end = start;
+	block->h   += hh;
+
+        if (strcasecmp(buf, "TH") == 0)
+	  font = textfont_ | FL_BOLD;
+	else
+	  font = textfont_;
+
+        size = textsize_;
+
+        xx = blocks_[row].x + size + 3;
+	for (i = 0; i < column; i ++)
+	  xx += columns[i] + 6;
+
+        if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
+	  colspan = atoi(attr);
+	else
+	  colspan = 1;
+
+        for (i = 0, ww = 0; i < colspan; i ++)
+	  ww += columns[column + i];
+
+        if (block->end == block->start && nblocks_ > 1)
+	{
+	  nblocks_ --;
+	  block --;
+	}
+
+	pushfont(font, size);
+
+	yy        = blocks_[row].y;
+	hh        = 0;
+        block     = add_block(start, xx, yy, xx + ww, 0, border);
+	needspace = 0;
+	line      = 0;
+	newalign  = get_align(attrs, tolower(buf[1]) == 'h' ? CENTER : LEFT);
+
+	column ++;
+      }
+      else if ((strcasecmp(buf, "/TD") == 0 ||
+                strcasecmp(buf, "/TH") == 0) && row)
+        popfont(font, size);
+      else if (strcasecmp(buf, "B") == 0)
+	pushfont(font |= FL_BOLD, size);
+      else if (strcasecmp(buf, "I") == 0)
+	pushfont(font |= FL_ITALIC, size);
+      else if (strcasecmp(buf, "CODE") == 0)
+	pushfont(font = FL_COURIER, size);
+      else if (strcasecmp(buf, "KBD") == 0)
+	pushfont(font = FL_COURIER_BOLD, size);
+      else if (strcasecmp(buf, "VAR") == 0)
+	pushfont(font = FL_COURIER_ITALIC, size);
+      else if (strcasecmp(buf, "/B") == 0 ||
+	       strcasecmp(buf, "/I") == 0 ||
+	       strcasecmp(buf, "/CODE") == 0 ||
+	       strcasecmp(buf, "/KBD") == 0 ||
+	       strcasecmp(buf, "/VAR") == 0)
+	popfont(font, size);
+      else if (strcasecmp(buf, "IMG") == 0)
+      {
+	Fl_Help_Image	*img = (Fl_Help_Image *)0;
+	int		width = 16;
+	int		height = 24;
+
+
+        get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+        get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+
+	if (get_attr(attrs, "SRC", attr, sizeof(attr))) 
+	  if ((img = add_image(attr, wattr, hattr)) != (Fl_Help_Image *)0 &&
+	      img->image == NULL)
+	    img = (Fl_Help_Image *)0;
+
+	if (img)
+	{
+	  width  = img->w;
+	  height = img->h;
+	}
+	else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL)
+	  strcpy(attr, "IMG");
+
+	ww = width;
+
+	if (needspace && xx > block->x)
+	  ww += (int)fl_width(' ');
+
+	if ((xx + ww) > block->w)
+	{
+	  line     = do_align(block, line, xx, newalign, links);
+	  xx       = block->x;
+	  yy       += hh;
+	  block->h += hh;
+	  hh       = 0;
+	}
+
+	if (link[0])
+	  add_link(link, xx, yy - height, ww, height);
+
+	xx += ww;
+	if ((height + 2) > hh)
+	  hh = height + 2;
+
+	needspace = 0;
+      }
+    }
+    else if (*ptr == '\n' && pre)
+    {
+      if (link[0])
+	add_link(link, xx, yy - hh, ww, hh);
+
+      line      = do_align(block, line, xx, newalign, links);
+      xx        = block->x;
+      yy        += hh;
+      block->h  += hh;
+      needspace = 0;
+      ptr ++;
+    }
+    else if (isspace(*ptr))
+    {
+      needspace = 1;
+
+      ptr ++;
+    }
+    else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
+    {
+      ptr ++;
+
+      if (strncasecmp(ptr, "amp;", 4) == 0)
+      {
+        *s++ = '&';
+	ptr += 4;
+      }
+      else if (strncasecmp(ptr, "lt;", 3) == 0)
+      {
+        *s++ = '<';
+	ptr += 3;
+      }
+      else if (strncasecmp(ptr, "gt;", 3) == 0)
+      {
+        *s++ = '>';
+	ptr += 3;
+      }
+      else if (strncasecmp(ptr, "nbsp;", 5) == 0)
+      {
+        *s++ = '\240';
+	ptr += 5;
+      }
+      else if (strncasecmp(ptr, "copy;", 5) == 0)
+      {
+        *s++ = '\251';
+	ptr += 5;
+      }
+      else if (strncasecmp(ptr, "reg;", 4) == 0)
+      {
+        *s++ = '\256';
+	ptr += 4;
+      }
+      else if (strncasecmp(ptr, "quot;", 5) == 0)
+      {
+        *s++ = '\"';
+	ptr += 5;
+      }
+
+      if ((size + 2) > hh)
+        hh = size + 2;
+    }
+    else
+    {
+      if (s < (buf + sizeof(buf) - 1))
+        *s++ = *ptr++;
+      else
+        ptr ++;
+
+      if ((size + 2) > hh)
+        hh = size + 2;
+    }
+  }
+
+  if (s > buf && !pre && !head)
+  {
+    *s = '\0';
+    ww = (int)fl_width(buf);
+
+//    printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
+//	   line, xx, ww, block->x, block->w);
+
+    if (needspace && xx > block->x)
+      ww += (int)fl_width(' ');
+
+    if ((xx + ww) > block->w)
+    {
+      line     = do_align(block, line, xx, newalign, links);
+      xx       = block->x;
+      yy       += hh;
+      block->h += hh;
+      hh       = 0;
+    }
+
+    if (link[0])
+      add_link(link, xx, yy - size, ww, size);
+
+    xx += ww;
+    if ((size + 2) > hh)
+      hh = size + 2;
+
+    needspace = 0;
+  }
+
+  block->end = ptr;
+  size_      = yy + hh;
+
+  if (ntargets_ > 1)
+    qsort(targets_, ntargets_, sizeof(Fl_Help_Target),
+          (compare_func_t)compare_targets);
+
+  if (nblocks_ > 1)
+    qsort(blocks_, nblocks_, sizeof(Fl_Help_Block),
+          (compare_func_t)compare_blocks);
+
+  if (size_ < (h() - 8))
+    scrollbar_.hide();
+  else
+    scrollbar_.show();
+
+  topline(topline_);
+}
+
+
+//
+// 'Fl_Help_View::format_table()' - Format a table...
+//
+
+void
+Fl_Help_View::format_table(int        *table_width,	// O - Total table width
+                          int        *columns,		// O - Column widths
+	                  const char *table)		// I - Pointer to start of table
+{
+  int		column,					// Current column
+		num_columns,				// Number of columns
+		colspan,				// COLSPAN attribute
+		width,					// Current width
+		temp_width,				// Temporary width
+		max_width,				// Maximum width
+		incell,					// In a table cell?
+		pre,					// 
 text?
+		needspace;				// Need whitespace?
+  char		*s,					// Pointer into buffer
+		buf[1024],				// Text buffer
+		attr[1024],				// Other attribute
+		wattr[1024],				// WIDTH attribute
+		hattr[1024];				// HEIGHT attribute
+  const char	*ptr,					// Pointer into table
+		*attrs,					// Pointer to attributes
+		*start;					// Start of element
+  int		minwidths[MAX_COLUMNS];			// Minimum widths for each column
+  unsigned char	font, size;				// Current font and size
+
+
+  // Clear widths...
+  *table_width = 0;
+  for (column = 0; column < MAX_COLUMNS; column ++)
+  {
+    columns[column]   = 0;
+    minwidths[column] = 0;
+  }
+
+  num_columns = 0;
+  colspan     = 0;
+  max_width   = 0;
+  pre         = 0;
+
+  // Scan the table...
+  for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;)
+  {
+    if ((*ptr == '<' || isspace(*ptr)) && s > buf && incell)
+    {
+      // Check width...
+      if (needspace)
+      {
+        *s++      = ' ';
+	needspace = 0;
+      }
+
+      *s         = '\0';
+      temp_width = (int)fl_width(buf);
+      s          = buf;
+
+      if (temp_width > minwidths[column])
+        minwidths[column] = temp_width;
+
+      width += temp_width;
+
+      if (width > max_width)
+        max_width = width;
+    }
+
+    if (*ptr == '<')
+    {
+      start = ptr;
+
+      for (s = buf, ptr ++; *ptr && *ptr != '>' && !isspace(*ptr);)
+        if (s < (buf + sizeof(buf) - 1))
+          *s++ = *ptr++;
+	else
+	  ptr ++;
+
+      *s = '\0';
+      s = buf;
+
+      attrs = ptr;
+      while (*ptr && *ptr != '>')
+        ptr ++;
+
+      if (*ptr == '>')
+        ptr ++;
+
+      if (strcasecmp(buf, "BR") == 0 ||
+	  strcasecmp(buf, "HR") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+      }
+      else if (strcasecmp(buf, "TABLE") == 0 && start > table)
+        break;
+      else if (strcasecmp(buf, "CENTER") == 0 ||
+               strcasecmp(buf, "P") == 0 ||
+               strcasecmp(buf, "H1") == 0 ||
+	       strcasecmp(buf, "H2") == 0 ||
+	       strcasecmp(buf, "H3") == 0 ||
+	       strcasecmp(buf, "H4") == 0 ||
+	       strcasecmp(buf, "H5") == 0 ||
+	       strcasecmp(buf, "H6") == 0 ||
+	       strcasecmp(buf, "UL") == 0 ||
+	       strcasecmp(buf, "OL") == 0 ||
+	       strcasecmp(buf, "DL") == 0 ||
+	       strcasecmp(buf, "LI") == 0 ||
+	       strcasecmp(buf, "DD") == 0 ||
+	       strcasecmp(buf, "DT") == 0 ||
+	       strcasecmp(buf, "PRE") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+
+        if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
+	{
+	  font = FL_HELVETICA_BOLD;
+	  size = textsize_ + '7' - buf[1];
+	}
+	else if (strcasecmp(buf, "DT") == 0)
+	{
+	  font = textfont_ | FL_ITALIC;
+	  size = textsize_;
+	}
+	else if (strcasecmp(buf, "PRE") == 0)
+	{
+	  font = FL_COURIER;
+	  size = textsize_;
+	  pre  = 1;
+	}
+	else if (strcasecmp(buf, "LI") == 0)
+	{
+	  width += 4 * size;
+	  font  = textfont_;
+	  size  = textsize_;
+	}
+	else
+	{
+	  font = textfont_;
+	  size = textsize_;
+	}
+
+	pushfont(font, size);
+      }
+      else if (strcasecmp(buf, "/CENTER") == 0 ||
+	       strcasecmp(buf, "/P") == 0 ||
+	       strcasecmp(buf, "/H1") == 0 ||
+	       strcasecmp(buf, "/H2") == 0 ||
+	       strcasecmp(buf, "/H3") == 0 ||
+	       strcasecmp(buf, "/H4") == 0 ||
+	       strcasecmp(buf, "/H5") == 0 ||
+	       strcasecmp(buf, "/H6") == 0 ||
+	       strcasecmp(buf, "/PRE") == 0 ||
+	       strcasecmp(buf, "/UL") == 0 ||
+	       strcasecmp(buf, "/OL") == 0 ||
+	       strcasecmp(buf, "/DL") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+
+        popfont(font, size);
+      }
+      else if (strcasecmp(buf, "TR") == 0 || strcasecmp(buf, "/TR") == 0 ||
+               strcasecmp(buf, "/TABLE") == 0)
+      {
+//        printf("%s column = %d, colspan = %d, num_columns = %d\n",
+//	       buf, column, colspan, num_columns);
+
+        if (column >= 0)
+	{
+	  // This is a hack to support COLSPAN...
+	  max_width /= colspan;
+
+	  while (colspan > 0)
+	  {
+	    if (max_width > columns[column])
+	      columns[column] = max_width;
+
+	    column ++;
+	    colspan --;
+	  }
+	}
+
+	if (strcasecmp(buf, "/TABLE") == 0)
+	  break;
+
+	needspace = 0;
+	column    = -1;
+	width     = 0;
+	max_width = 0;
+	incell    = 0;
+      }
+      else if (strcasecmp(buf, "TD") == 0 ||
+               strcasecmp(buf, "TH") == 0)
+      {
+//        printf("BEFORE column = %d, colspan = %d, num_columns = %d\n",
+//	       column, colspan, num_columns);
+
+        if (column >= 0)
+	{
+	  // This is a hack to support COLSPAN...
+	  max_width /= colspan;
+
+	  while (colspan > 0)
+	  {
+	    if (max_width > columns[column])
+	      columns[column] = max_width;
+
+	    column ++;
+	    colspan --;
+	  }
+	}
+	else
+	  column ++;
+
+        if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
+	  colspan = atoi(attr);
+	else
+	  colspan = 1;
+
+//        printf("AFTER column = %d, colspan = %d, num_columns = %d\n",
+//	       column, colspan, num_columns);
+
+        if ((column + colspan) >= num_columns)
+	  num_columns = column + colspan;
+
+	needspace = 0;
+	width     = 0;
+	incell    = 1;
+
+        if (strcasecmp(buf, "TH") == 0)
+	  font = textfont_ | FL_BOLD;
+	else
+	  font = textfont_;
+
+        size = textsize_;
+
+	pushfont(font, size);
+
+        if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL)
+	{
+	  max_width = atoi(attr);
+
+	  if (attr[strlen(attr) - 1] == '%')
+	    max_width = max_width * w() / 100;
+	}
+	else
+	  max_width = 0;
+
+//        printf("max_width = %d\n", max_width);
+      }
+      else if (strcasecmp(buf, "/TD") == 0 ||
+               strcasecmp(buf, "/TH") == 0)
+      {
+	incell = 0;
+        popfont(font, size);
+      }
+      else if (strcasecmp(buf, "B") == 0)
+	pushfont(font |= FL_BOLD, size);
+      else if (strcasecmp(buf, "I") == 0)
+	pushfont(font |= FL_ITALIC, size);
+      else if (strcasecmp(buf, "CODE") == 0)
+	pushfont(font = FL_COURIER, size);
+      else if (strcasecmp(buf, "KBD") == 0)
+	pushfont(font = FL_COURIER_BOLD, size);
+      else if (strcasecmp(buf, "VAR") == 0)
+	pushfont(font = FL_COURIER_ITALIC, size);
+      else if (strcasecmp(buf, "/B") == 0 ||
+	       strcasecmp(buf, "/I") == 0 ||
+	       strcasecmp(buf, "/CODE") == 0 ||
+	       strcasecmp(buf, "/KBD") == 0 ||
+	       strcasecmp(buf, "/VAR") == 0)
+	popfont(font, size);
+      else if (strcasecmp(buf, "IMG") == 0 && incell)
+      {
+	Fl_Help_Image	*img = (Fl_Help_Image *)0;
+
+
+        get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+        get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+
+        if (get_attr(attrs, "SRC", attr, sizeof(attr))) 
+	  if ((img = add_image(attr, wattr, hattr)) != (Fl_Help_Image *)0 &&
+	      img->image == NULL)
+	    img = (Fl_Help_Image *)0;
+
+	if (img)
+	  temp_width = img->w;
+	else
+	  temp_width = 16;
+
+	if (temp_width > minwidths[column])
+          minwidths[column] = temp_width;
+
+        width += temp_width;
+	if (needspace)
+	  width += (int)fl_width(' ');
+
+	if (width > max_width)
+          max_width = width;
+
+	needspace = 0;
+      }
+    }
+    else if (*ptr == '\n' && pre)
+    {
+      width     = 0;
+      needspace = 0;
+      ptr ++;
+    }
+    else if (isspace(*ptr))
+    {
+      needspace = 1;
+
+      ptr ++;
+    }
+    else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
+    {
+      ptr ++;
+
+      if (strncasecmp(ptr, "amp;", 4) == 0)
+      {
+        *s++ = '&';
+	ptr += 4;
+      }
+      else if (strncasecmp(ptr, "lt;", 3) == 0)
+      {
+        *s++ = '<';
+	ptr += 3;
+      }
+      else if (strncasecmp(ptr, "gt;", 3) == 0)
+      {
+        *s++ = '>';
+	ptr += 3;
+      }
+      else if (strncasecmp(ptr, "nbsp;", 5) == 0)
+      {
+        *s++ = '\240';
+	ptr += 5;
+      }
+      else if (strncasecmp(ptr, "copy;", 5) == 0)
+      {
+        *s++ = '\251';
+	ptr += 5;
+      }
+      else if (strncasecmp(ptr, "reg;", 4) == 0)
+      {
+        *s++ = '\256';
+	ptr += 4;
+      }
+      else if (strncasecmp(ptr, "quot;", 5) == 0)
+      {
+        *s++ = '\"';
+	ptr += 5;
+      }
+    }
+    else
+    {
+      if (s < (buf + sizeof(buf) - 1))
+        *s++ = *ptr++;
+      else
+        ptr ++;
+    }
+  }
+
+  // Now that we have scanned the entire table, adjust the table and
+  // cell widths to fit on the screen...
+  if (get_attr(table + 6, "WIDTH", attr, sizeof(attr)))
+  {
+    if (attr[strlen(attr) - 1] == '%')
+      *table_width = atoi(attr) * w() / 100;
+    else
+      *table_width = atoi(attr);
+  }
+  else
+    *table_width = 0;
+
+//  printf("num_columns = %d, table_width = %d\n", num_columns, *table_width);
+
+  if (num_columns == 0)
+    return;
+
+  // Add up the widths...
+  for (column = 0, width = 0; column < num_columns; column ++)
+    width += columns[column];
+
+//  printf("width = %d, w() = %d\n", width, w());
+//  for (column = 0; column < num_columns; column ++)
+//    printf("    columns[%d] = %d, minwidths[%d] = %d\n", column, columns[column],
+//           column, minwidths[column]);
+
+  // Adjust the width if needed...
+  int scale_width = *table_width;
+
+  if (scale_width == 0 && width > w())
+    scale_width = width;
+
+  if (width > scale_width)
+  {
+    *table_width = 0;
+
+    for (column = 0; column < num_columns; column ++)
+    {
+      if (width > 0)
+      {
+        temp_width = scale_width * columns[column] / width;
+
+	if (temp_width < minwidths[column])
+	  temp_width = minwidths[column];
+      }
+      else
+        temp_width = minwidths[column];
+
+      width           -= columns[column];
+      scale_width     -= temp_width;
+      columns[column] = temp_width;
+      (*table_width)  += temp_width;
+    }
+  }
+  else if (*table_width == 0)
+    *table_width = width;
+
+//  printf("FINAL table_width = %d\n", *table_width);
+//  for (column = 0; column < num_columns; column ++)
+//    printf("    columns[%d] = %d\n", column, columns[column]);
+}
+
+
+//
+// 'Fl_Help_View::get_align()' - Get an alignment attribute.
+//
+
+int					// O - Alignment
+Fl_Help_View::get_align(const char *p,	// I - Pointer to start of attrs
+                       int        a)	// I - Default alignment
+{
+  char	buf[255];			// Alignment value
+
+
+  if (get_attr(p, "ALIGN", buf, sizeof(buf)) == NULL)
+    return (a);
+
+  if (strcasecmp(buf, "CENTER") == 0)
+    return (CENTER);
+  else if (strcasecmp(buf, "RIGHT") == 0)
+    return (RIGHT);
+  else
+    return (LEFT);
+}
+
+
+//
+// 'Fl_Help_View::get_attr()' - Get an attribute value from the string.
+//
+
+const char *					// O - Pointer to buf or NULL
+Fl_Help_View::get_attr(const char *p,		// I - Pointer to start of attributes
+                      const char *n,		// I - Name of attribute
+		      char       *buf,		// O - Buffer for attribute value
+		      int        bufsize)	// I - Size of buffer
+{
+  char	name[255],				// Name from string
+	*ptr,					// Pointer into name or value
+	quote;					// Quote
+
+
+  buf[0] = '\0';
+
+  while (*p && *p != '>')
+  {
+    while (isspace(*p))
+      p ++;
+
+    if (*p == '>' || !*p)
+      return (NULL);
+
+    for (ptr = name; *p && !isspace(*p) && *p != '=' && *p != '>';)
+      if (ptr < (name + sizeof(name) - 1))
+        *ptr++ = *p++;
+      else
+        p ++;
+
+    *ptr = '\0';
+
+    if (isspace(*p) || !*p || *p == '>')
+      buf[0] = '\0';
+    else
+    {
+      if (*p == '=')
+        p ++;
+
+      for (ptr = buf; *p && !isspace(*p) && *p != '>';)
+        if (*p == '\'' || *p == '\"')
+	{
+	  quote = *p++;
+
+	  while (*p && *p != quote)
+	    if ((ptr - buf + 1) < bufsize)
+	      *ptr++ = *p++;
+	    else
+	      p ++;
+
+          if (*p == quote)
+	    p ++;
+	}
+	else if ((ptr - buf + 1) < bufsize)
+	  *ptr++ = *p++;
+	else
+	  p ++;
+
+      *ptr = '\0';
+    }
+
+    if (strcasecmp(n, name) == 0)
+      return (buf);
+    else
+      buf[0] = '\0';
+
+    if (*p == '>')
+      return (NULL);
+  }
+
+  return (NULL);
+}
+
+
+//
+// 'Fl_Help_View::get_color()' - Get an alignment attribute.
+//
+
+Fl_Color				// O - Color value
+Fl_Help_View::get_color(const char *n,	// I - Color name
+                       Fl_Color   c)	// I - Default color value
+{
+  int	rgb, r, g, b;			// RGB values
+
+
+  if (!n)
+    return (c);
+
+  if (n[0] == '#')
+  {
+    // Do hex color lookup
+    rgb = strtol(n + 1, NULL, 16);
+
+    r = rgb >> 16;
+    g = (rgb >> 8) & 255;
+    b = rgb & 255;
+
+    if (r == g && g == b)
+      return (fl_gray_ramp(FL_NUM_GRAY * r / 256));
+    else
+      return (fl_color_cube((FL_NUM_RED - 1) * r / 255,
+                            (FL_NUM_GREEN - 1) * g / 255,
+			    (FL_NUM_BLUE - 1) * b / 255));
+  }
+  else if (strcasecmp(n, "black") == 0)
+    return (FL_BLACK);
+  else if (strcasecmp(n, "red") == 0)
+    return (FL_RED);
+  else if (strcasecmp(n, "green") == 0)
+    return (fl_color_cube(0, 4, 0));
+  else if (strcasecmp(n, "yellow") == 0)
+    return (FL_YELLOW);
+  else if (strcasecmp(n, "blue") == 0)
+    return (FL_BLUE);
+  else if (strcasecmp(n, "magenta") == 0 || strcasecmp(n, "fuchsia") == 0)
+    return (FL_MAGENTA);
+  else if (strcasecmp(n, "cyan") == 0 || strcasecmp(n, "aqua") == 0)
+    return (FL_CYAN);
+  else if (strcasecmp(n, "white") == 0)
+    return (FL_WHITE);
+  else if (strcasecmp(n, "gray") == 0 || strcasecmp(n, "grey") == 0)
+    return (FL_GRAY);
+  else if (strcasecmp(n, "lime") == 0)
+    return (FL_GREEN);
+  else if (strcasecmp(n, "maroon") == 0)
+    return (fl_color_cube(2, 0, 0));
+  else if (strcasecmp(n, "navy") == 0)
+    return (fl_color_cube(0, 0, 2));
+  else if (strcasecmp(n, "olive") == 0)
+    return (fl_color_cube(2, 4, 0));
+  else if (strcasecmp(n, "purple") == 0)
+    return (fl_color_cube(2, 0, 2));
+  else if (strcasecmp(n, "silver") == 0)
+    return (FL_LIGHT2);
+  else if (strcasecmp(n, "teal") == 0)
+    return (fl_color_cube(0, 4, 2));
+  else
+    return (c);
+}
+
+
+//
+// 'Fl_Help_View::handle()' - Handle events in the widget.
+//
+
+int				// O - 1 if we handled it, 0 otherwise
+Fl_Help_View::handle(int event)	// I - Event to handle
+{
+  int		i;		// Looping var
+  int		xx, yy;		// Adjusted mouse position
+  Fl_Help_Link	*link;		// Current link
+  char		target[32];	// Current target
+
+
+  switch (event)
+  {
+    case FL_PUSH :
+	if (Fl_Group::handle(event))
+	  return (1);
+
+    case FL_MOVE :
+        xx = Fl::event_x() - x();
+	yy = Fl::event_y() - y() + topline_;
+	break;
+
+    default :
+	return (Fl_Group::handle(event));
+  }
+
+  // Handle mouse clicks on links...
+  for (i = nlinks_, link = links_; i > 0; i --, link ++)
+    if (xx >= link->x && xx < link->w &&
+        yy >= link->y && yy < link->h)
+      break;
+
+  if (!i)
+  {
+    fl_cursor(FL_CURSOR_DEFAULT);
+    return (1);
+  }
+
+  // Change the cursor for FL_MOTION events, and go to the link for
+  // clicks...
+  if (event == FL_MOVE)
+    fl_cursor(FL_CURSOR_HAND);
+  else
+  {
+    fl_cursor(FL_CURSOR_DEFAULT);
+
+    strncpy(target, link->name, sizeof(target) - 1);
+    target[sizeof(target) - 1] = '\0';
+
+    set_changed();
+
+    if (strcmp(link->filename, filename_) != 0 && link->filename[0])
+    {
+      char	dir[1024];	// Current directory
+      char	temp[1024],	// Temporary filename
+		*tempptr;	// Pointer into temporary filename
+
+
+      if (strchr(directory_, ':') != NULL && strchr(link->filename, ':') == NULL)
+      {
+	if (link->filename[0] == '/')
+	{
+          strcpy(temp, directory_);
+          if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
+	    strcpy(tempptr, link->filename);
+	  else
+	    strcat(temp, link->filename);
+	}
+	else
+	  sprintf(temp, "%s/%s", directory_, link->filename);
+
+	load(temp);
+      }
+      else if (link->filename[0] != '/' && strchr(link->filename, ':') == NULL)
+      {
+	if (directory_[0])
+	  sprintf(temp, "%s/%s", directory_, link->filename);
+	else
+	{
+	  getcwd(dir, sizeof(dir));
+	  sprintf(temp, "file:%s/%s", dir, link->filename);
+	}
+
+        load(temp);
+      }
+      else
+        load(link->filename);
+    }
+    else if (target[0])
+      topline(target);
+    else
+      topline(0);
+  }
+
+  return (1);
+}
+
+
+//
+// 'Fl_Help_View::Fl_Help_View()' - Build a Fl_Help_View widget.
+//
+
+Fl_Help_View::Fl_Help_View(int        xx,	// I - Left position
+                	 int        yy,	// I - Top position
+			 int        ww,	// I - Width in pixels
+			 int        hh,	// I - Height in pixels
+			 const char *l)
+    : Fl_Group(xx, yy, ww, hh, l),
+      scrollbar_(xx + ww - 17, yy, 17, hh)
+{
+  link_        = (Fl_Help_Func *)0;
+
+  filename_[0] = '\0';
+  value_       = NULL;
+
+  ablocks_     = 0;
+  nblocks_     = 0;
+  blocks_      = (Fl_Help_Block *)0;
+
+  nimage_      = 0;
+  aimage_      = 0;
+  image_       = (Fl_Help_Image *)0;
+
+  if (!broken_image)
+    broken_image = new Fl_Pixmap((char **)broken_xpm);
+
+  alinks_      = 0;
+  nlinks_      = 0;
+  links_       = (Fl_Help_Link *)0;
+
+  atargets_    = 0;
+  ntargets_    = 0;
+  targets_     = (Fl_Help_Target *)0;
+
+  nfonts_      = 0;
+  textfont_    = FL_TIMES;
+  textsize_    = 12;
+
+  topline_     = 0;
+  size_        = 0;
+
+  color(FL_WHITE);
+  textcolor(FL_BLACK);
+  selection_color(FL_BLUE);
+
+  scrollbar_.value(0, hh, 0, 1);
+  scrollbar_.step(8.0);
+  scrollbar_.show();
+  scrollbar_.callback(scrollbar_callback);
+
+  end();
+}
+
+
+//
+// 'Fl_Help_View::~Fl_Help_View()' - Destroy a Fl_Help_View widget.
+//
+
+Fl_Help_View::~Fl_Help_View()
+{
+  int		i;		// Looping var
+  Fl_Help_Image	*img;		// Current image
+
+
+  if (nblocks_)
+    free(blocks_);
+  if (nlinks_)
+    free(links_);
+  if (ntargets_)
+    free(targets_);
+  if (value_)
+    free((void *)value_);
+  if (image_)
+  {
+    for (i = nimage_, img = image_; i > 0; i --, img ++)
+    {
+      delete img->image;
+      if (!img->copy)
+        free(img->data);
+      free(img->name);
+    }
+  }
+}
+
+
+//
+// 'Fl_Help_View::load()' - Load the specified file.
+//
+
+int				// O - 0 on success, -1 on error
+Fl_Help_View::load(const char *f)// I - Filename to load (may also have target)
+{
+  FILE		*fp;		// File to read from
+  long		len;		// Length of file
+  char		*target;	// Target in file
+  char		*slash;		// Directory separator
+  const char	*localname;	// Local filename
+  char		error[1024];	// Error buffer
+
+
+  strcpy(filename_, f);
+  strcpy(directory_, filename_);
+
+  if ((slash = strrchr(directory_, '/')) == NULL)
+    directory_[0] = '\0';
+  else if (slash > directory_ && slash[-1] != '/')
+    *slash = '\0';
+
+  if ((target = strrchr(filename_, '#')) != NULL)
+    *target++ = '\0';
+
+  if (link_)
+    localname = (*link_)(filename_);
+  else
+    localname = filename_;
+
+  if (localname != NULL &&
+      (strncmp(localname, "ftp:", 4) == 0 ||
+       strncmp(localname, "http:", 5) == 0 ||
+       strncmp(localname, "https:", 6) == 0 ||
+       strncmp(localname, "ipp:", 4) == 0 ||
+       strncmp(localname, "mailto:", 7) == 0 ||
+       strncmp(localname, "news:", 5) == 0))
+    localname = NULL;	// Remote link wasn't resolved...
+  else if (localname != NULL &&
+           strncmp(localname, "file:", 5) == 0)
+    localname += 5;	// Adjust for local filename...
+      
+  if (value_ != NULL)
+  {
+    free((void *)value_);
+    value_ = NULL;
+  }
+
+  if (localname)
+  {
+    if ((fp = fopen(localname, "rb")) != NULL)
+    {
+      fseek(fp, 0, SEEK_END);
+      len = ftell(fp);
+      rewind(fp);
+
+      value_ = (const char *)calloc(len + 1, 1);
+      fread((void *)value_, 1, len, fp);
+      fclose(fp);
+    }
+    else
+    {
+      sprintf(error, "%s: %s\n", localname, strerror(errno));
+      value_ = strdup(error);
+    }
+  }
+  else
+  {
+    sprintf(error, "%s: %s\n", filename_, strerror(errno));
+    value_ = strdup(error);
+  }
+
+  format();
+
+  if (target)
+    topline(target);
+  else
+    topline(0);
+
+  return (0);
+}
+
+
+//
+// 'Fl_Help_View::load_gif()' - Load a GIF image file...
+//
+
+int					// O - 0 = success, -1 = fail
+Fl_Help_View::load_gif(Fl_Help_Image *img,// I - Image pointer
+        	      FILE         *fp)	// I - File to load from
+{
+  unsigned char	buf[1024];		// Input buffer
+  gif_cmap_t	cmap;			// Colormap
+  int		ncolors,		// Bits per pixel
+		transparent;		// Transparent color index
+
+
+  // Read the header; we already know it is a GIF file...
+  fread(buf, 13, 1, fp);
+
+  img->w  = (buf[7] << 8) | buf[6];
+  img->h  = (buf[9] << 8) | buf[8];
+  ncolors = 2 << (buf[10] & 0x07);
+
+  if (buf[10] & GIF_COLORMAP)
+    if (!gif_read_cmap(fp, ncolors, cmap))
+      return (0);
+
+  transparent = -1;
+
+  for (;;)
+  {
+    switch (getc(fp))
+    {
+      case ';' :	// End of image
+          return (0);	// Early end of file
+
+      case '!' :	// Extension record
+          buf[0] = getc(fp);
+          if (buf[0] == 0xf9)	// Graphic Control Extension
+          {
+            gif_get_block(fp, buf);
+            if (buf[0] & 1)	// Get transparent color index
+              transparent = buf[3];
+          }
+
+          while (gif_get_block(fp, buf) != 0);
+          break;
+
+      case ',' :	// Image data
+          fread(buf, 9, 1, fp);
+
+          if (buf[8] & GIF_COLORMAP)
+          {
+            ncolors = 2 << (buf[8] & 0x07);
+
+	    if (!gif_read_cmap(fp, ncolors, cmap))
+	      return (0);
+	  }
+
+          if (transparent >= 0)
+          {
+	    unsigned	rgba = fltk_colors[bgcolor_];
+
+
+            // Map transparent color to background color...
+	    cmap[transparent][0] = rgba >> 24;
+            cmap[transparent][1] = rgba >> 16;
+            cmap[transparent][2] = rgba >> 8;
+          }
+
+          img->w    = (buf[5] << 8) | buf[4];
+          img->h    = (buf[7] << 8) | buf[6];
+          img->d    = 3;
+          img->data = (unsigned char *)malloc(img->w * img->h * img->d);
+          if (img->data == NULL)
+            return (0);
+
+	  return (gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE));
+    }
+  }
+}
+
+
+#ifdef HAVE_LIBJPEG
+//
+// 'Fl_Help_View::load_jpeg()' - Load a JPEG image file.
+//
+
+int						// O - 0 = success, -1 = fail
+Fl_Help_View::load_jpeg(Fl_Help_Image *img,	// I - Image pointer
+                       FILE         *fp)	// I - File to load from
+{
+  struct jpeg_decompress_struct	cinfo;		// Decompressor info
+  struct jpeg_error_mgr		jerr;		// Error handler info
+  JSAMPROW			row;		// Sample row pointer
+
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo);
+  jpeg_stdio_src(&cinfo, fp);
+  jpeg_read_header(&cinfo, 1);
+
+  cinfo.quantize_colors      = 0;
+  cinfo.out_color_space      = JCS_RGB;
+  cinfo.out_color_components = 3;
+  cinfo.output_components    = 3;
+
+  jpeg_calc_output_dimensions(&cinfo);
+
+  img->w  = cinfo.output_width;
+  img->h = cinfo.output_height;
+  img->d  = cinfo.output_components;
+  img->data = (unsigned char *)malloc(img->w * img->h * img->d);
+
+  if (img->data == NULL)
+  {
+    jpeg_destroy_decompress(&cinfo);
+    return (0);
+  }
+
+  jpeg_start_decompress(&cinfo);
+
+  while (cinfo.output_scanline < cinfo.output_height)
+  {
+    row = (JSAMPROW)(img->data +
+                     cinfo.output_scanline * cinfo.output_width *
+                     cinfo.output_components);
+    jpeg_read_scanlines(&cinfo, &row, (JDIMENSION)1);
+  }
+
+  jpeg_finish_decompress(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+
+  return (1);
+}
+#endif // HAVE_LIBJPEG
+
+
+#ifdef HAVE_LIBPNG
+//
+// 'Fl_Help_View::load_png()' - Load a PNG image file.
+//
+
+int					// O - 0 = success, -1 = fail
+Fl_Help_View::load_png(Fl_Help_Image *img,// I - Image pointer
+        	      FILE         *fp)	// I - File to read from
+{
+  int		i;			// Looping var
+  png_structp	pp;			// PNG read pointer
+  png_infop	info;			// PNG info pointers
+  png_bytep	*rows;			// PNG row pointers
+  png_color_16	bg;			// Background color
+
+
+  // Setup the PNG data structures...
+  pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  info = png_create_info_struct(pp);
+
+  // Initialize the PNG read "engine"...
+  png_init_io(pp, fp);
+
+  // Get the image dimensions and convert to grayscale or RGB...
+  png_read_info(pp, info);
+
+  if (info->color_type == PNG_COLOR_TYPE_PALETTE)
+    png_set_expand(pp);
+
+  if (info->color_type == PNG_COLOR_TYPE_GRAY)
+    img->d = 1;
+  else
+    img->d = 3;
+
+  img->w    = (int)info->width;
+  img->h    = (int)info->height;
+  img->data = (unsigned char *)malloc(img->w * img->h * 3);
+
+  if (info->bit_depth < 8)
+  {
+    png_set_packing(pp);
+    png_set_expand(pp);
+
+    if (info->valid & PNG_INFO_sBIT)
+      png_set_shift(pp, &(info->sig_bit));
+  }
+  else if (info->bit_depth == 16)
+    png_set_strip_16(pp);
+
+#ifdef HAVE_PNG_GET_VALID
+  // Handle transparency...
+  if (png_get_valid(pp, info, PNG_INFO_tRNS))
+    png_set_tRNS_to_alpha(pp);
+#endif // HAVE_PNG_GET_VALID
+
+  // Background color...
+  unsigned	rgba = fltk_colors[bgcolor_];
+
+  bg.red   = 65535 * (rgba >> 24) / 255;
+  bg.green = 65535 * ((rgba >> 16) & 255) / 255;
+  bg.blue  = 65535 * ((rgba >> 8) & 255) / 255;
+
+  png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+  // Allocate pointers...
+  rows = (png_bytep *)calloc(info->height, sizeof(png_bytep));
+
+  for (i = 0; i < (int)info->height; i ++)
+    if (info->color_type == PNG_COLOR_TYPE_GRAY)
+      rows[i] = img->data + i * img->w;
+    else
+      rows[i] = img->data + i * img->w * 3;
+
+  // Read the image, handling interlacing as needed...
+  for (i = png_set_interlace_handling(pp); i > 0; i --)
+    png_read_rows(pp, rows, NULL, img->h);
+
+  // Free memory and return...
+  free(rows);
+
+  png_read_end(pp, info);
+  png_read_destroy(pp, info, NULL);
+
+  return (1);
+}
+#endif // HAVE_LIBPNG
+
+
+//
+// 'Fl_Help_View::resize()' - Resize the help widget.
+//
+
+void
+Fl_Help_View::resize(int xx,	// I - New left position
+                    int yy,	// I - New top position
+		    int ww,	// I - New width
+		    int hh)	// I - New height
+{
+  Fl_Widget::resize(xx, yy, ww, hh);
+  scrollbar_.resize(xx + ww - 17, yy, 17, hh);
+
+  format();
+}
+
+
+//
+// 'Fl_Help_View::topline()' - Set the top line to the named target.
+//
+
+void
+Fl_Help_View::topline(const char *n)	// I - Target name
+{
+  Fl_Help_Target	key,			// Target name key
+		*target;		// Pointer to matching target
+
+
+  if (ntargets_ == 0)
+    return;
+
+  strncpy(key.name, n, sizeof(key.name) - 1);
+  key.name[sizeof(key.name) - 1] = '\0';
+
+  target = (Fl_Help_Target *)bsearch(&key, targets_, ntargets_, sizeof(Fl_Help_Target),
+                                 (compare_func_t)compare_targets);
+
+  if (target != NULL)
+    topline(target->y);
+}
+
+
+//
+// 'Fl_Help_View::topline()' - Set the top line by number.
+//
+
+void
+Fl_Help_View::topline(int t)	// I - Top line number
+{
+  if (!value_)
+    return;
+
+  if (size_ < (h() - 8) || t < 0)
+    t = 0;
+  else if (t > size_)
+    t = size_;
+
+  topline_ = t;
+
+  scrollbar_.value(topline_, h(), 0, size_);
+
+  do_callback();
+  clear_changed();
+
+  redraw();
+}
+
+
+//
+// 'Fl_Help_View::value()' - Set the help text directly.
+//
+
+void
+Fl_Help_View::value(const char *v)	// I - Text to view
+{
+  if (!v)
+    return;
+
+  if (value_ != NULL)
+    free((void *)value_);
+
+  value_ = strdup(v);
+
+  format();
+
+  set_changed();
+  topline(0);
+}
+
+
+//
+// 'Fl_Help_View::compare_blocks()' - Compare two blocks.
+//
+
+int						// O - Result of comparison
+Fl_Help_View::compare_blocks(const void *a,	// I - First block
+                            const void *b)	// I - Second block
+{
+  return (((Fl_Help_Block *)a)->y - ((Fl_Help_Block *)b)->y);
+}
+
+
+//
+// 'gif_read_cmap()' - Read the colormap from a GIF file...
+//
+
+static int				// O - -1 = error, 0 = success
+gif_read_cmap(FILE       *fp,		// I - File to read from
+  	      int        ncolors,	// I - Number of colors
+	      gif_cmap_t cmap)		// O - Colormap
+{
+  // Read the colormap...
+  if (fread(cmap, 3, ncolors, fp) < (size_t)ncolors)
+    return (0);
+
+  return (1);
+}
+
+
+//
+// 'gif_get_block()' - Read a GIF data block...
+//
+
+static int				// O - Number characters read
+gif_get_block(FILE  *fp,		// I - File to read from
+	      unsigned char *buf)	// I - Input buffer
+{
+  int	count;				// Number of character to read
+
+
+  // Read the count byte followed by the data from the file...
+  if ((count = getc(fp)) == EOF)
+  {
+    gif_eof = 1;
+    return (-1);
+  }
+  else if (count == 0)
+    gif_eof = 1;
+  else if (fread(buf, 1, count, fp) < (size_t)count)
+  {
+    gif_eof = 1;
+    return (-1);
+  }
+  else
+    gif_eof = 0;
+
+  return (count);
+}
+
+
+//
+// 'gif_get_code()' - Get a LZW code from the file...
+//
+
+static int				// O - LZW code
+gif_get_code(FILE *fp,			// I - File to read from
+	     int  code_size,		// I - Size of code in bits
+	     int  first_time)		// I - 1 = first time, 0 = not first time
+{
+  unsigned		i, j,		// Looping vars
+			ret;		// Return value
+  int			count;		// Number of bytes read
+  static unsigned char	buf[280];	// Input buffer
+  static unsigned	curbit,		// Current bit
+			lastbit,	// Last bit in buffer
+			done,		// Done with this buffer?
+			last_byte;	// Last byte in buffer
+  static unsigned	bits[8] =	// Bit masks for codes
+			{
+			  0x01, 0x02, 0x04, 0x08,
+			  0x10, 0x20, 0x40, 0x80
+			};
+
+
+  if (first_time)
+  {
+    // Just initialize the input buffer...
+    curbit  = 0;
+    lastbit = 0;
+    done    = 0;
+
+    return (0);
+  }
+
+
+  if ((curbit + code_size) >= lastbit)
+  {
+    // Don't have enough bits to hold the code...
+    if (done)
+      return (-1);	// Sorry, no more...
+
+    // Move last two bytes to front of buffer...
+    if (last_byte > 1)
+    {
+      buf[0]    = buf[last_byte - 2];
+      buf[1]    = buf[last_byte - 1];
+      last_byte = 2;
+    }
+    else if (last_byte == 1)
+    {
+      buf[0]    = buf[last_byte - 1];
+      last_byte = 1;
+    }
+
+    // Read in another buffer...
+    if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
+    {
+      // Whoops, no more data!
+      done = 1;
+      return (-1);
+    }
+
+    // Update buffer state...
+    curbit    = (curbit - lastbit) + 8 * last_byte;
+    last_byte += count;
+    lastbit   = last_byte * 8;
+  }
+
+  ret = 0;
+  for (ret = 0, i = curbit + code_size - 1, j = code_size;
+       j > 0;
+       i --, j --)
+    ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
+
+  curbit += code_size;
+
+  return ret;
+}
+
+
+//
+// 'gif_read_lzw()' - Read a byte from the LZW stream...
+//
+
+static int				// I - Byte from stream
+gif_read_lzw(FILE *fp,			// I - File to read from
+	     int  first_time,		// I - 1 = first time, 0 = not first time
+ 	     int  input_code_size)	// I - Code size in bits
+{
+  int		i,			// Looping var
+		code,			// Current code
+		incode;			// Input code
+  static short	fresh = 0,		// 1 = empty buffers
+		code_size,		// Current code size
+		set_code_size,		// Initial code size set
+		max_code,		// Maximum code used
+		max_code_size,		// Maximum code size
+		firstcode,		// First code read
+		oldcode,		// Last code read
+		clear_code,		// Clear code for LZW input
+		end_code,		// End code for LZW input
+		table[2][4096],		// String table
+		stack[8192],		// Output stack
+		*sp;			// Current stack pointer
+
+
+  if (first_time)
+  {
+    // Setup LZW state...
+    set_code_size = input_code_size;
+    code_size     = set_code_size + 1;
+    clear_code    = 1 << set_code_size;
+    end_code      = clear_code + 1;
+    max_code_size = 2 * clear_code;
+    max_code      = clear_code + 2;
+
+    // Initialize input buffers...
+    gif_get_code(fp, 0, 1);
+
+    // Wipe the decompressor table...
+    fresh = 1;
+
+    for (i = 0; i < clear_code; i ++)
+    {
+      table[0][i] = 0;
+      table[1][i] = i;
+    }
+
+    for (; i < 4096; i ++)
+      table[0][i] = table[1][0] = 0;
+
+    sp = stack;
+
+    return (0);
+  }
+  else if (fresh)
+  {
+    fresh = 0;
+
+    do
+      firstcode = oldcode = gif_get_code(fp, code_size, 0);
+    while (firstcode == clear_code);
+
+    return (firstcode);
+  }
+
+  if (sp > stack)
+    return (*--sp);
+
+  while ((code = gif_get_code (fp, code_size, 0)) >= 0)
+  {
+    if (code == clear_code)
+    {
+      for (i = 0; i < clear_code; i ++)
+      {
+	table[0][i] = 0;
+	table[1][i] = i;
+      }
+
+      for (; i < 4096; i ++)
+	table[0][i] = table[1][i] = 0;
+
+      code_size     = set_code_size + 1;
+      max_code_size = 2 * clear_code;
+      max_code      = clear_code + 2;
+
+      sp = stack;
+
+      firstcode = oldcode = gif_get_code(fp, code_size, 0);
+
+      return (firstcode);
+    }
+    else if (code == end_code)
+    {
+      unsigned char	buf[260];
+
+
+      if (!gif_eof)
+        while (gif_get_block(fp, buf) > 0);
+
+      return (-2);
+    }
+
+    incode = code;
+
+    if (code >= max_code)
+    {
+      *sp++ = firstcode;
+      code  = oldcode;
+    }
+
+    while (code >= clear_code)
+    {
+      *sp++ = table[1][code];
+      if (code == table[0][code])
+	return (255);
+
+      code = table[0][code];
+    }
+
+    *sp++ = firstcode = table[1][code];
+    code  = max_code;
+
+    if (code < 4096)
+    {
+      table[0][code] = oldcode;
+      table[1][code] = firstcode;
+      max_code ++;
+
+      if (max_code >= max_code_size && max_code_size < 4096)
+      {
+	max_code_size *= 2;
+	code_size ++;
+      }
+    }
+
+    oldcode = incode;
+
+    if (sp > stack)
+      return (*--sp);
+  }
+
+  return (code);
+}
+
+
+//
+// 'gif_read_image()' - Read a GIF image stream...
+//
+
+static int				// I - 0 = success, -1 = failure
+gif_read_image(FILE          *fp,	// I - Input file
+	       Fl_Help_Image  *img,	// I - Image pointer
+	       gif_cmap_t    cmap,	// I - Colormap
+	       int           interlace)	// I - Non-zero = interlaced image
+{
+  unsigned char	code_size,		// Code size
+		*temp;			// Current pixel
+  int		xpos,			// Current X position
+		ypos,			// Current Y position
+		pass;			// Current pass
+  int		pixel;			// Current pixel
+  static int	xpasses[4] = { 8, 8, 4, 2 },
+		ypasses[5] = { 0, 4, 2, 1, 999999 };
+
+
+  xpos      = 0;
+  ypos      = 0;
+  pass      = 0;
+  code_size = getc(fp);
+
+  if (gif_read_lzw(fp, 1, code_size) < 0)
+    return (0);
+
+  temp = img->data;
+
+  while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
+  {
+    temp[0] = cmap[pixel][0];
+
+    if (img->d > 1)
+    {
+      temp[1] = cmap[pixel][1];
+      temp[2] = cmap[pixel][2];
+    }
+
+    xpos ++;
+    temp += img->d;
+    if (xpos == img->w)
+    {
+      xpos = 0;
+
+      if (interlace)
+      {
+        ypos += xpasses[pass];
+        temp += (xpasses[pass] - 1) * img->w * img->d;
+
+        if (ypos >= img->h)
+	{
+	  pass ++;
+
+          ypos = ypasses[pass];
+          temp = img->data + ypos * img->w * img->d;
+	}
+      }
+      else
+	ypos ++;
+    }
+
+    if (ypos >= img->h)
+      break;
+  }
+
+  return (1);
+}
+
+
+//
+// 'scrollbar_callback()' - A callback for the scrollbar.
+//
+
+static void
+scrollbar_callback(Fl_Widget *s, void *)
+{
+  ((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value()));
+}
+
+
+//
+// End of "$Id: Fl_Help_View.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $".
+//
diff --git a/src/Makefile b/src/Makefile
index 6f1097bc4..1f3982d48 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
 #
-# "$Id: Makefile,v 1.18.2.14.2.9 2001/08/11 14:49:51 easysw Exp $"
+# "$Id: Makefile,v 1.18.2.14.2.10 2001/09/29 14:38:59 easysw Exp $"
 #
 # Library makefile for the Fast Light Tool Kit (FLTK).
 #
@@ -41,13 +41,13 @@ CPPFILES = \
 	Fl_Counter.cxx \
 	Fl_Dial.cxx \
 	Fl_Double_Window.cxx \
-	Fl_FileBrowser.cxx \
-	Fl_FileChooser.cxx \
-	Fl_FileChooser2.cxx \
-	Fl_FileIcon.cxx \
+	Fl_File_Browser.cxx \
+	Fl_File_Chooser.cxx \
+	Fl_File_Chooser2.cxx \
+	Fl_File_Icon.cxx \
 	Fl_Group.cxx \
-	Fl_HelpDialog.cxx \
-	Fl_HelpView.cxx \
+	Fl_Help_Dialog.cxx \
+	Fl_Help_View.cxx \
 	Fl_Image.cxx \
 	Fl_Input.cxx \
 	Fl_Input_.cxx \
@@ -258,5 +258,5 @@ install: $(LIBNAME) $(DSONAME) $(GLLIBNAME) $(GLDSONAME)
 	ln -s FL $(includedir)/Fl
 
 #
-# End of "$Id: Makefile,v 1.18.2.14.2.9 2001/08/11 14:49:51 easysw Exp $".
+# End of "$Id: Makefile,v 1.18.2.14.2.10 2001/09/29 14:38:59 easysw Exp $".
 #
diff --git a/src/fl_file_chooser.cxx b/src/fl_file_chooser.cxx
index 0b3c99b9f..a7e721824 100644
--- a/src/fl_file_chooser.cxx
+++ b/src/fl_file_chooser.cxx
@@ -1,5 +1,5 @@
 //
-// "$Id: fl_file_chooser.cxx,v 1.10.2.10.2.4 2001/08/04 12:21:33 easysw Exp $"
+// "$Id: fl_file_chooser.cxx,v 1.10.2.10.2.5 2001/09/29 14:38:59 easysw Exp $"
 //
 // File chooser widget for the Fast Light Tool Kit (FLTK).
 //
@@ -25,13 +25,13 @@
 
 #include 
 #include 
-#include 
+#include 
 
-static Fl_FileChooser	*fc = (Fl_FileChooser *)0;
+static Fl_File_Chooser	*fc = (Fl_File_Chooser *)0;
 static void		(*current_callback)(const char*) = 0;
 
 
-static void callback(Fl_FileChooser *, void*) {
+static void callback(Fl_File_Chooser *, void*) {
   if (current_callback)
     (*current_callback)(fc->value(0));
 }
@@ -47,9 +47,10 @@ char* fl_file_chooser(const char* message, const char* pat, const char* fname)
   if (!fname || !*fname) fname = ".";
 
   if (!fc) {
-    fc = new Fl_FileChooser(fname, pat, Fl_FileChooser::CREATE, message);
+    fc = new Fl_File_Chooser(fname, pat, Fl_File_Chooser::CREATE, message);
     fc->callback(callback, 0);
   } else {
+    fc->type(Fl_File_Chooser::CREATE);
     fc->filter(pat);
     fc->value(fname);
     fc->label(message);
@@ -64,6 +65,30 @@ char* fl_file_chooser(const char* message, const char* pat, const char* fname)
 }
 
 
+char* fl_dir_chooser(const char* message, const char* fname)
+{
+  if (!fname || !*fname) fname = ".";
+
+  if (!fc) {
+    fc = new Fl_File_Chooser(fname, "*", Fl_File_Chooser::CREATE |
+                                         Fl_File_Chooser::DIRECTORY, message);
+    fc->callback(callback, 0);
+  } else {
+    fc->type(Fl_File_Chooser::CREATE | Fl_File_Chooser::DIRECTORY);
+    fc->filter("*");
+    fc->value(fname);
+    fc->label(message);
+  }
+
+  fc->show();
+
+  while (fc->visible())
+    Fl::wait();
+
+  return ((char *)fc->value());
+}
+
+
 //
-// End of "$Id: fl_file_chooser.cxx,v 1.10.2.10.2.4 2001/08/04 12:21:33 easysw Exp $".
+// End of "$Id: fl_file_chooser.cxx,v 1.10.2.10.2.5 2001/09/29 14:38:59 easysw Exp $".
 //
diff --git a/src/makedepend b/src/makedepend
index da088b55a..1b2f1adf2 100644
--- a/src/makedepend
+++ b/src/makedepend
@@ -57,47 +57,50 @@ Fl_Dial.o: ../FL/Fl_Valuator.H ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/math.h
 Fl_Double_Window.o: ../config.h ../FL/Fl.H ../FL/Enumerations.H
 Fl_Double_Window.o: ../FL/Fl_Export.H ../FL/Fl_Double_Window.H
 Fl_Double_Window.o: ../FL/Fl_Window.H ../FL/x.H ../FL/fl_draw.H
-Fl_FileBrowser.o: ../FL/Fl_FileBrowser.H ../FL/Fl_Browser.H
-Fl_FileBrowser.o: ../FL/Fl_Browser_.H ../FL/Fl_Group.H ../FL/Fl_Widget.H
-Fl_FileBrowser.o: ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Scrollbar.H
-Fl_FileBrowser.o: ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_FileIcon.H
-Fl_FileBrowser.o: ../FL/Fl.H ../FL/fl_draw.H ../FL/filename.H ../config.h
-Fl_FileChooser.o: ../FL/Fl_FileChooser.H ../FL/Fl.H ../FL/Enumerations.H
-Fl_FileChooser.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H
-Fl_FileChooser.o: ../FL/Fl_Widget.H ../FL/Fl_FileBrowser.H ../FL/Fl_Browser.H
-Fl_FileChooser.o: ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H
-Fl_FileChooser.o: ../FL/Fl_Valuator.H ../FL/Fl_FileIcon.H ../FL/Fl.H
-Fl_FileChooser.o: ../FL/Fl_Button.H ../FL/Fl_Return_Button.H
-Fl_FileChooser.o: ../FL/Fl_Button.H ../FL/fl_ask.H ../FL/Fl_Input.H
-Fl_FileChooser.o: ../FL/Fl_Input_.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H
-Fl_FileChooser.o: ../FL/Fl_Menu_Item.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H
-Fl_FileChooser2.o: ../FL/Fl_FileChooser.H ../FL/Fl.H ../FL/Enumerations.H
-Fl_FileChooser2.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H
-Fl_FileChooser2.o: ../FL/Fl_Widget.H ../FL/Fl_FileBrowser.H
-Fl_FileChooser2.o: ../FL/Fl_Browser.H ../FL/Fl_Browser_.H
-Fl_FileChooser2.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H
-Fl_FileChooser2.o: ../FL/Fl_FileIcon.H ../FL/Fl.H ../FL/Fl_Button.H
-Fl_FileChooser2.o: ../FL/Fl_Return_Button.H ../FL/Fl_Button.H ../FL/fl_ask.H
-Fl_FileChooser2.o: ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Choice.H
-Fl_FileChooser2.o: ../FL/Fl_Menu_.H ../FL/Fl_Menu_Item.H ../FL/filename.H
-Fl_FileChooser2.o: ../FL/x.H ../FL/Fl_Window.H
-Fl_FileIcon.o: ../config.h ../FL/Fl_FileIcon.H ../FL/Fl.H
-Fl_FileIcon.o: ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Widget.H
-Fl_FileIcon.o: ../FL/fl_draw.H ../FL/filename.H
+Fl_File_Browser.o: ../FL/Fl_File_Browser.H ../FL/Fl_Browser.H
+Fl_File_Browser.o: ../FL/Fl_Browser_.H ../FL/Fl_Group.H ../FL/Fl_Widget.H
+Fl_File_Browser.o: ../FL/Enumerations.H ../FL/Fl_Export.H
+Fl_File_Browser.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H
+Fl_File_Browser.o: ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/fl_draw.H
+Fl_File_Browser.o: ../FL/filename.H ../config.h
+Fl_File_Chooser.o: ../FL/Fl_File_Chooser.H ../FL/Fl.H ../FL/Enumerations.H
+Fl_File_Chooser.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H
+Fl_File_Chooser.o: ../FL/Fl_Widget.H ../FL/Fl_File_Browser.H
+Fl_File_Chooser.o: ../FL/Fl_Browser.H ../FL/Fl_Browser_.H
+Fl_File_Chooser.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H
+Fl_File_Chooser.o: ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/Fl_Button.H
+Fl_File_Chooser.o: ../FL/Fl_Return_Button.H ../FL/Fl_Button.H ../FL/fl_ask.H
+Fl_File_Chooser.o: ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Choice.H
+Fl_File_Chooser.o: ../FL/Fl_Menu_.H ../FL/Fl_Menu_Item.H ../FL/Fl_Bitmap.H
+Fl_File_Chooser.o: ../FL/Fl_Image.H
+Fl_File_Chooser2.o: ../FL/Fl_File_Chooser.H ../FL/Fl.H ../FL/Enumerations.H
+Fl_File_Chooser2.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H
+Fl_File_Chooser2.o: ../FL/Fl_Widget.H ../FL/Fl_File_Browser.H
+Fl_File_Chooser2.o: ../FL/Fl_Browser.H ../FL/Fl_Browser_.H
+Fl_File_Chooser2.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H
+Fl_File_Chooser2.o: ../FL/Fl_Valuator.H ../FL/Fl_File_Icon.H ../FL/Fl.H
+Fl_File_Chooser2.o: ../FL/Fl_Button.H ../FL/Fl_Return_Button.H
+Fl_File_Chooser2.o: ../FL/Fl_Button.H ../FL/fl_ask.H ../FL/Fl_Input.H
+Fl_File_Chooser2.o: ../FL/Fl_Input_.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H
+Fl_File_Chooser2.o: ../FL/Fl_Menu_Item.H ../FL/filename.H ../FL/x.H
+Fl_File_Chooser2.o: ../FL/Fl_Window.H
+Fl_File_Icon.o: ../config.h ../FL/Fl_File_Icon.H ../FL/Fl.H
+Fl_File_Icon.o: ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Widget.H
+Fl_File_Icon.o: ../FL/fl_draw.H ../FL/filename.H
 Fl_Group.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H
 Fl_Group.o: ../FL/Fl_Group.H ../FL/Fl_Window.H ../FL/Fl_Group.H
 Fl_Group.o: ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/Fl_Tooltip.H
 Fl_Group.o: ../FL/Fl_Widget.H
-Fl_HelpDialog.o: ../FL/Fl_HelpDialog.H ../FL/Fl.H ../FL/Enumerations.H
-Fl_HelpDialog.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H
-Fl_HelpDialog.o: ../FL/Fl_Widget.H ../FL/Fl_HelpView.H ../FL/Fl_Group.H
-Fl_HelpDialog.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H
-Fl_HelpDialog.o: ../FL/fl_draw.H ../FL/Fl_Button.H
-Fl_HelpView.o: ../FL/Fl_HelpView.H ../FL/Fl.H ../FL/Enumerations.H
-Fl_HelpView.o: ../FL/Fl_Export.H ../FL/Fl_Group.H ../FL/Fl_Scrollbar.H
-Fl_HelpView.o: ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Widget.H
-Fl_HelpView.o: ../FL/fl_draw.H ../config.h ../FL/Fl_Image.H ../FL/Fl_Pixmap.H
-Fl_HelpView.o: ../FL/Fl_Image.H
+Fl_Help_Dialog.o: ../FL/Fl_Help_Dialog.H ../FL/Fl.H ../FL/Enumerations.H
+Fl_Help_Dialog.o: ../FL/Fl_Export.H ../FL/Fl_Double_Window.H
+Fl_Help_Dialog.o: ../FL/Fl_Window.H ../FL/Fl_Help_View.H ../FL/Fl_Group.H
+Fl_Help_Dialog.o: ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H
+Fl_Help_Dialog.o: ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/Fl_Button.H
+Fl_Help_View.o: ../FL/Fl_Help_View.H ../FL/Fl.H ../FL/Enumerations.H
+Fl_Help_View.o: ../FL/Fl_Export.H ../FL/Fl_Group.H ../FL/Fl_Scrollbar.H
+Fl_Help_View.o: ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Widget.H
+Fl_Help_View.o: ../FL/fl_draw.H ../config.h ../FL/Fl_Image.H
+Fl_Help_View.o: ../FL/Fl_Pixmap.H ../FL/Fl_Image.H
 Fl_Image.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/fl_draw.H
 Fl_Image.o: ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Widget.H
 Fl_Image.o: ../FL/Fl_Menu_Item.H ../FL/Fl_Widget.H ../FL/Fl_Image.H
@@ -275,11 +278,11 @@ fl_draw_pixmap.o: ../FL/Fl_Window.H
 fl_engraved_label.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H
 fl_engraved_label.o: ../FL/Fl_Widget.H ../FL/fl_draw.H
 fl_file_chooser.o: ../config.h ../FL/fl_file_chooser.H ../FL/Enumerations.H
-fl_file_chooser.o: ../FL/Fl_Export.H ../FL/Fl_FileChooser.H ../FL/Fl.H
+fl_file_chooser.o: ../FL/Fl_Export.H ../FL/Fl_File_Chooser.H ../FL/Fl.H
 fl_file_chooser.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H
-fl_file_chooser.o: ../FL/Fl_FileBrowser.H ../FL/Fl_Browser.H
+fl_file_chooser.o: ../FL/Fl_File_Browser.H ../FL/Fl_Browser.H
 fl_file_chooser.o: ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H
-fl_file_chooser.o: ../FL/Fl_Valuator.H ../FL/Fl_FileIcon.H ../FL/Fl.H
+fl_file_chooser.o: ../FL/Fl_Valuator.H ../FL/Fl_File_Icon.H ../FL/Fl.H
 fl_file_chooser.o: ../FL/Fl_Button.H ../FL/Fl_Return_Button.H
 fl_file_chooser.o: ../FL/Fl_Button.H ../FL/fl_ask.H ../FL/Fl_Input.H
 fl_file_chooser.o: ../FL/Fl_Input_.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H
-- 
cgit v1.2.3