diff --git a/FL/Fl_HelpDialog.H b/FL/Fl_HelpDialog.H new file mode 100644 index 000000000..05756cbe0 --- /dev/null +++ b/FL/Fl_HelpDialog.H @@ -0,0 +1,54 @@ +// generated by Fast Light User Interface Designer (fluid) version 1.0100 + +#ifndef Fl_HelpDialog_H +#define Fl_HelpDialog_H +#include +#include +#include +#include +#include + +class Fl_HelpDialog { + int index_; + int max_; + int line_[100]; + char file_[100][256]; +public: + Fl_HelpDialog(); +private: + Fl_Window *window_; + Fl_HelpView *view_; + inline void cb_view__i(Fl_HelpView*, void*); + static void cb_view_(Fl_HelpView*, void*); + inline void cb_Close_i(Fl_Button*, void*); + static void cb_Close(Fl_Button*, void*); + Fl_Button *back_; + inline void cb_back__i(Fl_Button*, void*); + static void cb_back_(Fl_Button*, void*); + Fl_Button *forward_; + inline void cb_forward__i(Fl_Button*, void*); + static void cb_forward_(Fl_Button*, void*); + Fl_Button *smaller_; + inline void cb_smaller__i(Fl_Button*, void*); + static void cb_smaller_(Fl_Button*, void*); + Fl_Button *larger_; + inline void cb_larger__i(Fl_Button*, void*); + static void cb_larger_(Fl_Button*, void*); +public: + ~Fl_HelpDialog(); + int h(); + void hide(); + void load(const char *f); + void position(int xx, int yy); + void resize(int xx, int yy, int ww, int hh); + void show(); + void textsize(uchar s); + uchar textsize(); + void topline(const char *n); + void topline(int n); + int visible(); + int w(); + int x(); + int y(); +}; +#endif diff --git a/FL/Fl_HelpView.H b/FL/Fl_HelpView.H new file mode 100644 index 000000000..6ed53a4a2 --- /dev/null +++ b/FL/Fl_HelpView.H @@ -0,0 +1,212 @@ +// +// "$Id: Fl_HelpView.H,v 1.1.2.1 2001/08/02 19:43:49 easysw Exp $" +// +// Help Viewer widget definitions. +// +// 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". +// + +#ifndef _Fl_HelpView_H_ +# define _Fl_HelpView_H_ + +// +// Include necessary header files... +// + +# include +# include +# include +# include +# include + + +// +// Fl_HelpFunc type - link callback function for files... +// + + +typedef const char *(Fl_HelpFunc)(const char *); + + +// +// Fl_HelpBlock structure... +// + +struct Fl_HelpBlock +{ + const char *start, // Start of text + *end; // End of text + uchar font, // Text font + size, // Text size + border; // Draw border? + int x, // Indentation/starting X coordinate + y, // Starting Y coordinate + w, // Width + h; // Height + int line[32]; // Left starting position for each line +}; + +// +// Fl_HelpLink structure... +// + +struct Fl_HelpLink +{ + char filename[192], // Reference filename + name[32]; // Link target (blank if none) + int x, // X offset of link text + y, // Y offset of link text + w, // Width of link text + h; // Height of link text +}; + +// +// Fl_HelpTarget structure... +// + +struct Fl_HelpTarget +{ + char name[32]; // Target name + int y; // Y offset of target +}; + +// +// Fl_HelpImage structure... +// + +struct Fl_Pixmap; +struct Fl_Image; + +struct Fl_HelpImage +{ + char *name, // Path and name of the image + wattr[8], // Width attribute + hattr[8]; // Height attribute + Fl_Image *image; // FLTK image representation + unsigned char *data; // Raw image data + int w, h, d; // Image size & depth +}; + +// +// Fl_HelpView class... +// + +class Fl_HelpView : public Fl_Group //// Help viewer widget +{ + enum { RIGHT = -1, CENTER, LEFT }; // Alignments + + char title_[1024]; // Title string + Fl_Color defcolor_, // Default text color + bgcolor_, // Background color + textcolor_, // Text color + linkcolor_; // Link color + uchar textfont_, // Default font for text + textsize_; // Default font size + const char *value_; // HTML text value + + int nblocks_, // Number of blocks/paragraphs + ablocks_; // Allocated blocks + Fl_HelpBlock *blocks_; // Blocks + + int nfonts_; // Number of fonts in stack + uchar fonts_[100][2]; // Font stack + + Fl_HelpFunc *link_; // Link transform function + + int nlinks_, // Number of links + alinks_; // Allocated links + Fl_HelpLink *links_; // Links + + int ntargets_, // Number of targets + atargets_; // Allocated targets + Fl_HelpTarget *targets_; // Targets + + char directory_[1024]; // Directory for current file + char filename_[1024]; // Current filename + int topline_, // Top line in document + size_; // Total document length + Fl_Scrollbar scrollbar_; // Vertical scrollbar for document + + int nimage_, // Number of images in a page + aimage_; // Allocated blocks + Fl_HelpImage *image_; // list of image descriptors + + Fl_HelpImage *add_image(const char *name, const char *wattr, + const char *hattr, int make = 1); + Fl_HelpImage *find_image(const char *name, const char *wattr, + const char *hattr); + int load_gif(Fl_HelpImage *img, FILE *fp); + int load_jpeg(Fl_HelpImage *img, FILE *fp); + int load_png(Fl_HelpImage *img, FILE *fp); + + Fl_HelpBlock *add_block(const char *s, int xx, int yy, int ww, int hh, uchar border = 0); + void add_link(const char *n, int xx, int yy, int ww, int hh); + void add_target(const char *n, int yy); + static int compare_targets(const Fl_HelpTarget *t0, const Fl_HelpTarget *t1); + int do_align(Fl_HelpBlock *block, int line, int xx, int a, int &l); + void draw(); + void format(); + int get_align(const char *p, int a); + const char *get_attr(const char *p, const char *n, char *buf, int bufsize); + Fl_Color get_color(const char *n, Fl_Color c); + int handle(int); + + void initfont(uchar &f, uchar &s) { nfonts_ = 0; + fl_font(f = fonts_[0][0] = textfont_, + s = fonts_[0][1] = textsize_); } + void pushfont(uchar f, uchar s) { if (nfonts_ < 99) nfonts_ ++; + fl_font(fonts_[nfonts_][0] = f, + fonts_[nfonts_][1] = s); } + void popfont(uchar &f, uchar &s) { if (nfonts_ > 0) nfonts_ --; + fl_font(f = fonts_[nfonts_][0], + s = fonts_[nfonts_][1]); } + + public: + + Fl_HelpView(int xx, int yy, int ww, int hh, const char *l = 0); + ~Fl_HelpView(); + const char *directory() const { if (directory_[0]) return (directory_); + else return ((const char *)0); } + const char *filename() const { if (filename_[0]) return (filename_); + else return ((const char *)0); } + void link(Fl_HelpFunc *fn) { link_ = fn; } + int load(const char *f); + void resize(int,int,int,int); + int size() const { return (size_); } + void textcolor(Fl_Color c) { if (textcolor_ == defcolor_) textcolor_ = c; defcolor_ = c; } + Fl_Color textcolor() const { return (defcolor_); } + void textfont(uchar f) { textfont_ = f; format(); } + uchar textfont() const { return (textfont_); } + void textsize(uchar s) { textsize_ = s; format(); } + uchar textsize() const { return (textsize_); } + const char *title() { return (title_); } + void topline(const char *n); + void topline(int); + int topline() const { return (topline_); } + void value(const char *v); + const char *value() const { return (value_); } +}; + +#endif // !_Fl_HelpView_H_ + +// +// End of "$Id: Fl_HelpView.H,v 1.1.2.1 2001/08/02 19:43:49 easysw Exp $". +// diff --git a/configh.in b/configh.in index 22e9a0c49..0785b6ebe 100644 --- a/configh.in +++ b/configh.in @@ -1,5 +1,5 @@ /* - * "$Id: configh.in,v 1.11.2.11 2001/04/30 17:17:01 easysw Exp $" + * "$Id: configh.in,v 1.11.2.11.2.1 2001/08/02 19:43:49 easysw Exp $" * * Configuration file for the Fast Light Tool Kit (FLTK). * @configure_input@ @@ -177,5 +177,20 @@ #define USE_POLL 0 /* - * End of "$Id: configh.in,v 1.11.2.11 2001/04/30 17:17:01 easysw Exp $". + * Do we have various image libraries? + */ + +#undef HAVE_LIBPNG +#undef HAVE_LIBZ +#undef HAVE_LIBJPEG + +/* + * Do we have the png_get_valid() function? + */ + +#undef HAVE_PNG_GET_VALID + + +/* + * End of "$Id: configh.in,v 1.11.2.11.2.1 2001/08/02 19:43:49 easysw Exp $". */ diff --git a/configure.in b/configure.in index a750e4a10..9ab9704eb 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- sh -*- dnl the "configure" script is made from this by running GNU "autoconf" dnl -dnl "$Id: configure.in,v 1.33.2.31.2.2 2001/08/02 18:15:44 easysw Exp $" +dnl "$Id: configure.in,v 1.33.2.31.2.3 2001/08/02 19:43:49 easysw Exp $" dnl dnl Configuration script for the Fast Light Tool Kit (FLTK). dnl @@ -159,6 +159,36 @@ AC_CHECK_FUNCS(vsprintf) AC_CHECK_HEADER(strings.h,AC_DEFINE(HAVE_STRINGS_H)) AC_CHECK_FUNCS(strcasecmp) +dnl Check for image libraries... +SAVELIBS="$LIBS" +IMAGELIBS="" + +AC_SUBST(IMAGELIBS) + +AC_CHECK_HEADER(jpeglib.h, + AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + AC_DEFINE(HAVE_LIBJPEG) + IMAGELIBS="$IMAGELIBS -ljpeg")) + +AC_CHECK_HEADER(zlib.h, + AC_CHECK_LIB(z, gzopen, + AC_DEFINE(HAVE_LIBZ) + IMAGELIBS="$IMAGELIBS -lz" + LIBS="$LIBS -lz")) + +dnl PNG library uses math library functions... +AC_CHECK_LIB(m, pow) + +AC_CHECK_HEADER(png.h, + AC_CHECK_LIB(png, png_read_rows, + AC_DEFINE(HAVE_LIBPNG) + IMAGELIBS="-lpng -lm$IMAGELIBS" + LIBS="-lpng -lm $LIBS" + AC_CHECK_FUNCS(png_get_valid))) + +dnl Restore original LIBS settings... +LIBS="$SAVELIBS" + dnl Check for X11... AC_PATH_XTRA @@ -403,5 +433,5 @@ AC_CONFIG_HEADER(config.h:configh.in) AC_OUTPUT(makeinclude) dnl -dnl End of "$Id: configure.in,v 1.33.2.31.2.2 2001/08/02 18:15:44 easysw Exp $". +dnl End of "$Id: configure.in,v 1.33.2.31.2.3 2001/08/02 19:43:49 easysw Exp $". dnl diff --git a/documentation/index.html b/documentation/index.html index a9ea4d072..90e20318c 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -1,20 +1,21 @@ - FLTK 1.0.11 Programming Manual + FLTK 1.1.0 Programming Manual
- - + +
FL -

FLTK 1.0.11 Programming Manual

-Revision 18 by Michael Sweet, Craig P. Earls, and Bill Spitzak
+
FL +

FLTK 1.1.0 Programming Manual

+Revision 0 by Michael Sweet, Craig P. Earls, and Bill Spitzak
Copyright 1998-2001 by Bill Spitzak and others.
- @@ -23,7 +24,7 @@ Public License.
+ This software is provided under the terms of the GNU Library General Public License.
- -
+ Preface

@@ -55,7 +56,7 @@ Public License. 7 - Adding and Extending Widgets
+ 8 - Programming with FLUID
  • Widget Attributes
  • diff --git a/documentation/preface.html b/documentation/preface.html index 7d24de52d..9635d16d8 100644 --- a/documentation/preface.html +++ b/documentation/preface.html @@ -2,13 +2,13 @@ - - FLTK 1.0.11 Programming Manual + + FLTK 1.1.0 Programming Manual

    Preface

    This manual describes the Fast Light Tool Kit ("FLTK") -version 1.0.11, a C++ Graphical User Interface +version 1.1.0, a C++ Graphical User Interface ("GUI") toolkit for UNIX and Microsoft Windows. Each of the chapters in this manual is designed as a tutorial for using FLTK, while the appendices provide a convenient reference @@ -57,7 +57,7 @@ Reference
    The Microsoft Windows 32-bit Application Programmer's Interface.

    Copyrights and Trademarks

    - FLTK is Copyright 1998-2000 by Bill Spitzak and others. Use and + FLTK is Copyright 1998-2001 by Bill Spitzak and others. Use and distribution of FLTK is governed by the GNU Library General Public License, located in Appendix G.

    UNIX is a registered trademark of the X Open Group, Inc. Microsoft diff --git a/makeinclude.in b/makeinclude.in index 97d543bd9..e48b94f07 100644 --- a/makeinclude.in +++ b/makeinclude.in @@ -1,5 +1,5 @@ # -# "$Id: makeinclude.in,v 1.7.2.11.2.2 2001/08/02 18:15:44 easysw Exp $" +# "$Id: makeinclude.in,v 1.7.2.11.2.3 2001/08/02 19:43:49 easysw Exp $" # # Make include file for the Fast Light Tool Kit (FLTK). # @configure_input@ @@ -61,6 +61,7 @@ LDLIBS =@LDFLAGS@ @LIBS@ -lX11 -lXext @X_EXTRA_LIBS@ -lm GLDLIBS =@LDFLAGS@ @LIBS@ @GLLIB@ -lX11 -lXext @X_EXTRA_LIBS@ -lm LINKFLTK =-L../lib @LINKFLTK@ LINKFLTKGL =-L../lib @LINKFLTKGL@ +IMAGELIBS =@IMAGELIBS@ # Do we build the OpenGL demos? GLDEMOS =@GLDEMOS@ @@ -100,5 +101,5 @@ CAT3EXT =@CAT3EXT@ mv t.z $@ # -# End of "$Id: makeinclude.in,v 1.7.2.11.2.2 2001/08/02 18:15:44 easysw Exp $". +# End of "$Id: makeinclude.in,v 1.7.2.11.2.3 2001/08/02 19:43:49 easysw Exp $". # diff --git a/src/Fl_HelpDialog.cxx b/src/Fl_HelpDialog.cxx new file mode 100644 index 000000000..731961d24 --- /dev/null +++ b/src/Fl_HelpDialog.cxx @@ -0,0 +1,223 @@ +// 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_Window* w; + { Fl_Window* o = window_ = new Fl_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->labeltype(FL_SYMBOL_LABEL); + o->labelcolor(2); + o->callback((Fl_Callback*)cb_back_); + } + { Fl_Button* o = forward_ = new Fl_Button(395, 350, 25, 25, "@->"); + o->shortcut(0xff53); + o->labeltype(FL_SYMBOL_LABEL); + 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 new file mode 100644 index 000000000..a9fc18c71 --- /dev/null +++ b/src/Fl_HelpDialog.fl @@ -0,0 +1,192 @@ +# 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 + private xywh {470 402 530 385} 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 labeltype SYMBOL_LABEL 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 labeltype SYMBOL_LABEL 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()} {selected + } { + 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 new file mode 100644 index 000000000..6b074f932 --- /dev/null +++ b/src/Fl_HelpView.cxx @@ -0,0 +1,3139 @@ +// +// "$Id: Fl_HelpView.cxx,v 1.1.2.1 2001/08/02 19:43:49 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::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. +// 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 +} + +// +// 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 + + + 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_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; + image_ = (Fl_HelpImage *)realloc(image_, sizeof(Fl_HelpImage) * aimage_); + } + + img = image_ + nimage_; + img->name = strdup(name); + + 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); + } + + // Copy image data from original image... + img->data = orig->data; + img->w = orig->w; + img->h = orig->h; + img->d = orig->d; + + // 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) + { + // 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_Image(img->data, img->w, img->h, img->d); + else + img->image = (Fl_Image *)0; + + nimage_ ++; + + 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 = find_image(attr, wattr, hattr)) != NULL && !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[200];	// 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(' ');
    +
    +        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;
    +
    +      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 (!block->h && nblocks_ > 1)
    +	{
    +	  nblocks_ --;
    +	  block --;
    +	}
    +
    +        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)
    +	{
    +	  if (get_attr(attrs, "BORDER", attr, sizeof(attr)))
    +	    border = atoi(attr);
    +	  else
    +	    border = 0;
    +
    +	  block->h += size + 2;
    +
    +          if (get_attr(attrs, "WIDTH", attr, sizeof(attr)))
    +	  {
    +	    if (attr[strlen(attr) - 1] == '%')
    +	      table_width = atoi(attr) * w() / 100;
    +	    else
    +	      table_width = atoi(attr);
    +	  }
    +	  else
    +	    table_width = w();
    +
    +          for (column = 0; column < 200; column ++)
    +	    columns[column] = table_width / 3;
    +
    +	  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, "UL") == 0 ||
    +	    strcasecmp(buf, "OL") == 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, block->x, 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;
    +
    +        initfont(font, size);
    +
    +        while (isspace(*ptr))
    +	  ptr ++;
    +
    +        block->h += hh;
    +        yy       += hh;
    +
    +        if (tolower(buf[2]) == 'l')
    +          yy += size + 2;
    +
    +        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;
    +
    +        if (block->end == block->start && nblocks_ > 1)
    +	{
    +	  nblocks_ --;
    +	  block --;
    +	}
    +
    +        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)
    +      {
    +        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_;
    +
    +        if (column == 0)
    +          xx = block->x + size + 3;
    +	else
    +          xx = block->w + 6;
    +
    +        if (block->end == block->start && nblocks_ > 1)
    +	{
    +	  nblocks_ --;
    +	  block --;
    +	}
    +
    +	pushfont(font, size);
    +
    +        if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL)
    +	{
    +	  ww = atoi(attr);
    +
    +	  if (attr[strlen(attr) - 1] == '%')
    +	    ww = ww * w() / 100;
    +
    +          columns[column] = ww;
    +	}
    +	else
    +	  ww = columns[column];
    +
    +	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);
    +
    +    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 (size_ < (h() - 8))
    +    scrollbar_.hide();
    +  else
    +    scrollbar_.show();
    +
    +  topline(topline_);
    +}
    +
    +
    +//
    +// '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_MOVE :
    +    case FL_PUSH :
    +        if (Fl::event_button() == 4)
    +	{
    +	  // XFree86 maps button 4 to the "wheel up" motion...
    +	  topline(topline() - textsize_ * 3);
    +	  return (1);
    +	}
    +	else if (Fl::event_button() == 5)
    +	{
    +	  // XFree86 maps button 5 to the "wheel down" motion...
    +	  topline(topline() + textsize_ * 3);
    +	  return (1);
    +	}
    +
    +        xx = Fl::event_x() - x();
    +	yy = Fl::event_y() - y() + topline_;
    +        if (!scrollbar_.visible() || xx < (w() - 20))
    +	  break;
    +
    +    default :
    +	// Use the Fl_Group handler...
    +	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;
    +      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);
    +}
    +
    +
    +//
    +// '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.1 2001/08/02 19:43:49 easysw Exp $".
    +//
    diff --git a/src/Makefile b/src/Makefile
    index 9ef41161e..96c2f8783 100644
    --- a/src/Makefile
    +++ b/src/Makefile
    @@ -1,5 +1,5 @@
     #
    -# "$Id: Makefile,v 1.18.2.14.2.6 2001/08/02 18:39:01 easysw Exp $"
    +# "$Id: Makefile,v 1.18.2.14.2.7 2001/08/02 19:43:49 easysw Exp $"
     #
     # Library makefile for the Fast Light Tool Kit (FLTK).
     #
    @@ -45,6 +45,8 @@ CPPFILES = \
     	Fl_FileChooser2.cxx \
     	Fl_FileIcon.cxx \
     	Fl_Group.cxx \
    +	Fl_HelpDialog.cxx \
    +	Fl_HelpView.cxx \
     	Fl_Image.cxx \
     	Fl_Input.cxx \
     	Fl_Input_.cxx \
    @@ -168,11 +170,11 @@ $(LIBNAME): $(OBJECTS)
     
     libfltk.so.1.1 libfltk.sl.1.1: $(OBJECTS)
     	echo $(DSOCOMMAND) $@ ...
    -	$(DSOCOMMAND) $@ $(OBJECTS)
    +	$(DSOCOMMAND) $@ $(OBJECTS) $(IMAGELIBS)
     
     libfltk_s.a: $(OBJECTS)
     	echo $(DSOCOMMAND) libfltk_s.o ...
    -	$(DSOCOMMAND) libfltk_s.o $(OBJECTS)
    +	$(DSOCOMMAND) libfltk_s.o $(OBJECTS) $(IMAGELIBS)
     	echo $(LIBCOMMAND) libfltk_s.a libfltk_s.o
     	$(LIBCOMMAND) libfltk_s.a libfltk_s.o
     	chmod +x libfltk_s.a
    @@ -251,5 +253,5 @@ install: $(LIBNAME) $(DSONAME) $(GLLIBNAME) $(GLDSONAME)
     	ln -s FL $(includedir)/Fl
     
     #
    -# End of "$Id: Makefile,v 1.18.2.14.2.6 2001/08/02 18:39:01 easysw Exp $".
    +# End of "$Id: Makefile,v 1.18.2.14.2.7 2001/08/02 19:43:49 easysw Exp $".
     #
    diff --git a/test/Makefile b/test/Makefile
    index b32d59c55..da2f3b07d 100644
    --- a/test/Makefile
    +++ b/test/Makefile
    @@ -1,5 +1,5 @@
     #
    -# "$Id: Makefile,v 1.19.2.7.2.3 2001/08/02 18:15:44 easysw Exp $"
    +# "$Id: Makefile,v 1.19.2.7.2.4 2001/08/02 19:43:49 easysw Exp $"
     #
     # Test/example program makefile for the Fast Light Tool Kit (FLTK).
     #
    @@ -30,7 +30,7 @@ CPPFILES =\
     	color_chooser.cxx cube.cxx cursor.cxx curve.cxx demo.cxx \
     	doublebuffer.cxx editor.cxx file_chooser.cxx fonts.cxx \
     	forms.cxx fractals.cxx fullscreen.cxx gl_overlay.cxx \
    -	glpuzzle.cxx hello.cxx iconize.cxx image.cxx input.cxx \
    +	glpuzzle.cxx hello.cxx help.cxx iconize.cxx image.cxx input.cxx \
     	keyboard.cxx label.cxx list_visuals.cxx mandelbrot.cxx \
     	menubar.cxx message.cxx minimum.cxx navigation.cxx \
     	output.cxx overlay.cxx pixmap.cxx pixmap_browser.cxx \
    @@ -42,7 +42,7 @@ CPPFILES =\
     ALL =	adjuster arc ask bitmap boxtype browser button buttons \
     	checkers clock colbrowser color_chooser cursor curve \
     	demo doublebuffer editor file_chooser fonts forms hello \
    -	iconize image input keyboard label list_visuals \
    +	help iconize image input keyboard label list_visuals \
     	mandelbrot menubar message minimum navigation output \
     	overlay pixmap pixmap_browser radio resizebox scroll \
     	subwindow symbols tabs tile valuators fast_slow resize \
    @@ -70,6 +70,10 @@ include ../makeinclude
     $(ALL):  ../lib/$(LIBNAME)
     
     # Programs needing special instructions...
    +help: help.cxx
    +	echo Compiling and linking $@...
    +	echo $(CXX) -I.. $(CXXFLAGS) help.cxx -o $@ $(LINKFLTK) $(LDLIBS) $(IMAGELIBS)
    +	$(CXX) -I.. $(CXXFLAGS) help.cxx -o $@ $(LINKFLTK) $(LDLIBS) $(IMAGELIBS)
     keyboard: keyboard.cxx keyboard_ui.cxx
     	echo Compiling and linking $@...
     	$(CXX) -I.. $(CXXFLAGS) keyboard.cxx $(LINKFLTK) $(LDLIBS) -o $@
    @@ -124,5 +128,5 @@ install:
     	@echo Nothing to install in test directory.
     
     #
    -# End of "$Id: Makefile,v 1.19.2.7.2.3 2001/08/02 18:15:44 easysw Exp $".
    +# End of "$Id: Makefile,v 1.19.2.7.2.4 2001/08/02 19:43:49 easysw Exp $".
     #
    diff --git a/test/demo.menu b/test/demo.menu
    index ae377e4ca..caf2282a7 100644
    --- a/test/demo.menu
    +++ b/test/demo.menu
    @@ -64,6 +64,7 @@
     	@o:file chooser:file_chooser
     	@o:XForms Emulation:forms
     	@o:fonts:fonts
    +	@o:HelpDialog:help
     
     @main:Tutorial\nfrom\nManual:@j
     	@j:ask\n(modified):ask
    diff --git a/test/help.cxx b/test/help.cxx
    new file mode 100644
    index 000000000..04a0be6c1
    --- /dev/null
    +++ b/test/help.cxx
    @@ -0,0 +1,67 @@
    +//
    +// "$Id: help.cxx,v 1.1.2.1 2001/08/02 19:43:49 easysw Exp $"
    +//
    +// Fl_HelpDialog test program.
    +//
    +// Copyright 1999-2001 by Easy Software Products.
    +//
    +// 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:
    +//
    +//   main() - Display the help GUI...
    +//
    +
    +//
    +// Include necessary headers...
    +//
    +
    +#include 
    +
    +
    +//
    +// 'main()' - Display the help GUI...
    +//
    +
    +int				// O - Exit status
    +main(int  argc,			// I - Number of command-line arguments
    +     char *argv[])		// I - Command-line arguments
    +{
    +  Fl_HelpDialog	*help;		// Help dialog
    +
    +
    +  help = new Fl_HelpDialog;
    +
    +  if (argc < 2)
    +    help->load("../documentation/index.html");
    +  else
    +    help->load(argv[1]);
    +
    +  help->show();
    +
    +  Fl::run();
    +
    +  delete help;
    +
    +  return (0);
    +}
    +
    +
    +//
    +// End of "$Id: help.cxx,v 1.1.2.1 2001/08/02 19:43:49 easysw Exp $".
    +//