git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1630 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
3586 lines
79 KiB
C++
3586 lines
79 KiB
C++
//
|
|
// "$Id: Fl_Help_View.cxx,v 1.1.2.2 2001/10/01 19:33:22 easysw Exp $"
|
|
//
|
|
// Fl_Help_View widget routines.
|
|
//
|
|
// Copyright 1997-2001 by Easy Software Products.
|
|
// Image support donated by Matthias Melcher, Copyright 2000.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
// USA.
|
|
//
|
|
// Please report all bugs and problems to "fltk-bugs@fltk.org".
|
|
//
|
|
// Contents:
|
|
//
|
|
// Fl_Help_View::add_block() - Add a text block to the list.
|
|
// Fl_Help_View::add_image() - Add an image to the image cache.
|
|
// Fl_Help_View::add_link() - Add a new link to the list.
|
|
// Fl_Help_View::add_target() - Add a new target to the list.
|
|
// Fl_Help_View::compare_targets() - Compare two targets.
|
|
// Fl_Help_View::do_align() - Compute the alignment for a line in
|
|
// a block.
|
|
// Fl_Help_View::draw() - Draw the Fl_Help_View widget.
|
|
// Fl_Help_View::find_image() - Find an image by name
|
|
// Fl_Help_View::format() - Format the help text.
|
|
// Fl_Help_View::format_table() - Format a table...
|
|
// Fl_Help_View::get_align() - Get an alignment attribute.
|
|
// Fl_Help_View::get_attr() - Get an attribute value from the string.
|
|
// Fl_Help_View::get_color() - Get an alignment attribute.
|
|
// Fl_Help_View::handle() - Handle events in the widget.
|
|
// Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget.
|
|
// Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget.
|
|
// Fl_Help_View::load() - Load the specified file.
|
|
// Fl_Help_View::load_gif() - Load a GIF image file...
|
|
// Fl_Help_View::load_jpeg() - Load a JPEG image file.
|
|
// Fl_Help_View::load_png() - Load a PNG image file.
|
|
// Fl_Help_View::resize() - Resize the help widget.
|
|
// Fl_Help_View::topline() - Set the top line to the named target.
|
|
// Fl_Help_View::topline() - Set the top line by number.
|
|
// Fl_Help_View::value() - Set the help text directly.
|
|
// Fl_Help_View::compare_blocks() - Compare two blocks.
|
|
// gif_read_cmap() - Read the colormap from a GIF file...
|
|
// gif_get_block() - Read a GIF data block...
|
|
// gif_get_code() - Get a LZW code from the file...
|
|
// gif_read_lzw() - Read a byte from the LZW stream...
|
|
// gif_read_image() - Read a GIF image stream...
|
|
// scrollbar_callback() - A callback for the scrollbar.
|
|
//
|
|
|
|
//
|
|
// Include necessary header files...
|
|
//
|
|
|
|
#include <FL/Fl_Help_View.H>
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif /* HAVE_STRINGS_H */
|
|
#include <errno.h>
|
|
|
|
#include <FL/Fl_Image.H>
|
|
#include <FL/Fl_Pixmap.H>
|
|
|
|
#if defined(WIN32)
|
|
# include <io.h>
|
|
# include <direct.h>
|
|
# 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 <unistd.h>
|
|
#endif // WIN32
|
|
|
|
extern "C"
|
|
{
|
|
#ifdef HAVE_LIBPNG
|
|
# include <zlib.h>
|
|
# include <png.h>
|
|
#endif // HAVE_LIBPNG
|
|
|
|
#ifdef HAVE_LIBJPEG
|
|
# include <jpeglib.h>
|
|
#endif // HAVE_LIBJPEG
|
|
}
|
|
|
|
#define MAX_COLUMNS 200
|
|
|
|
|
|
//
|
|
// Typedef the C API sort function type the only way I know how...
|
|
//
|
|
|
|
extern "C"
|
|
{
|
|
typedef int (*compare_func_t)(const void *, const void *);
|
|
}
|
|
|
|
//
|
|
// GIF definitions...
|
|
//
|
|
|
|
#define GIF_INTERLACE 0x40
|
|
#define GIF_COLORMAP 0x80
|
|
|
|
typedef unsigned char gif_cmap_t[256][3];
|
|
|
|
|
|
//
|
|
// Local globals...
|
|
//
|
|
|
|
static const char *broken_xpm[] =
|
|
{
|
|
"16 24 4 1",
|
|
"@ c #000000",
|
|
" c #ffffff",
|
|
"+ c none",
|
|
"x c #ff0000",
|
|
// pixels
|
|
"@@@@@@@+++++++++",
|
|
"@ @++++++++++",
|
|
"@ @+++++++++++",
|
|
"@ @++@++++++++",
|
|
"@ @@+++++++++",
|
|
"@ @+++@+++++",
|
|
"@ @++@@++++@",
|
|
"@ xxx @@ @++@@",
|
|
"@ xxx xx@@ @",
|
|
"@ xxx xxx @",
|
|
"@ xxxxxx @",
|
|
"@ xxxx @",
|
|
"@ xxxxxx @",
|
|
"@ xxx xxx @",
|
|
"@ xxx xxx @",
|
|
"@ xxx xxx @",
|
|
"@ @",
|
|
"@ @",
|
|
"@ @",
|
|
"@ @",
|
|
"@ @",
|
|
"@ @",
|
|
"@ @",
|
|
"@@@@@@@@@@@@@@@@",
|
|
NULL
|
|
};
|
|
|
|
static Fl_Pixmap *broken_image = (Fl_Pixmap *)0;
|
|
static int gif_eof = 0; // Did we hit EOF?
|
|
static unsigned fltk_colors[] =
|
|
{
|
|
0x00000000,
|
|
0xff000000,
|
|
0x00ff0000,
|
|
0xffff0000,
|
|
0x0000ff00,
|
|
0xff00ff00,
|
|
0x00ffff00,
|
|
0xffffff00,
|
|
0x55555500,
|
|
0xc6717100,
|
|
0x71c67100,
|
|
0x8e8e3800,
|
|
0x7171c600,
|
|
0x8e388e00,
|
|
0x388e8e00,
|
|
0xaaaaaa00,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x55555500,
|
|
0x00000000,
|
|
0x0d0d0d00,
|
|
0x1a1a1a00,
|
|
0x26262600,
|
|
0x31313100,
|
|
0x3d3d3d00,
|
|
0x48484800,
|
|
0x55555500,
|
|
0x5f5f5f00,
|
|
0x6a6a6a00,
|
|
0x75757500,
|
|
0x80808000,
|
|
0x8a8a8a00,
|
|
0x95959500,
|
|
0xa0a0a000,
|
|
0xaaaaaa00,
|
|
0xb5b5b500,
|
|
0xc0c0c000,
|
|
0xcbcbcb00,
|
|
0xd5d5d500,
|
|
0xe0e0e000,
|
|
0xeaeaea00,
|
|
0xf5f5f500,
|
|
0xffffff00,
|
|
0x00000000,
|
|
0x00240000,
|
|
0x00480000,
|
|
0x006d0000,
|
|
0x00910000,
|
|
0x00b60000,
|
|
0x00da0000,
|
|
0x00ff0000,
|
|
0x3f000000,
|
|
0x3f240000,
|
|
0x3f480000,
|
|
0x3f6d0000,
|
|
0x3f910000,
|
|
0x3fb60000,
|
|
0x3fda0000,
|
|
0x3fff0000,
|
|
0x7f000000,
|
|
0x7f240000,
|
|
0x7f480000,
|
|
0x7f6d0000,
|
|
0x7f910000,
|
|
0x7fb60000,
|
|
0x7fda0000,
|
|
0x7fff0000,
|
|
0xbf000000,
|
|
0xbf240000,
|
|
0xbf480000,
|
|
0xbf6d0000,
|
|
0xbf910000,
|
|
0xbfb60000,
|
|
0xbfda0000,
|
|
0xbfff0000,
|
|
0xff000000,
|
|
0xff240000,
|
|
0xff480000,
|
|
0xff6d0000,
|
|
0xff910000,
|
|
0xffb60000,
|
|
0xffda0000,
|
|
0xffff0000,
|
|
0x00003f00,
|
|
0x00243f00,
|
|
0x00483f00,
|
|
0x006d3f00,
|
|
0x00913f00,
|
|
0x00b63f00,
|
|
0x00da3f00,
|
|
0x00ff3f00,
|
|
0x3f003f00,
|
|
0x3f243f00,
|
|
0x3f483f00,
|
|
0x3f6d3f00,
|
|
0x3f913f00,
|
|
0x3fb63f00,
|
|
0x3fda3f00,
|
|
0x3fff3f00,
|
|
0x7f003f00,
|
|
0x7f243f00,
|
|
0x7f483f00,
|
|
0x7f6d3f00,
|
|
0x7f913f00,
|
|
0x7fb63f00,
|
|
0x7fda3f00,
|
|
0x7fff3f00,
|
|
0xbf003f00,
|
|
0xbf243f00,
|
|
0xbf483f00,
|
|
0xbf6d3f00,
|
|
0xbf913f00,
|
|
0xbfb63f00,
|
|
0xbfda3f00,
|
|
0xbfff3f00,
|
|
0xff003f00,
|
|
0xff243f00,
|
|
0xff483f00,
|
|
0xff6d3f00,
|
|
0xff913f00,
|
|
0xffb63f00,
|
|
0xffda3f00,
|
|
0xffff3f00,
|
|
0x00007f00,
|
|
0x00247f00,
|
|
0x00487f00,
|
|
0x006d7f00,
|
|
0x00917f00,
|
|
0x00b67f00,
|
|
0x00da7f00,
|
|
0x00ff7f00,
|
|
0x3f007f00,
|
|
0x3f247f00,
|
|
0x3f487f00,
|
|
0x3f6d7f00,
|
|
0x3f917f00,
|
|
0x3fb67f00,
|
|
0x3fda7f00,
|
|
0x3fff7f00,
|
|
0x7f007f00,
|
|
0x7f247f00,
|
|
0x7f487f00,
|
|
0x7f6d7f00,
|
|
0x7f917f00,
|
|
0x7fb67f00,
|
|
0x7fda7f00,
|
|
0x7fff7f00,
|
|
0xbf007f00,
|
|
0xbf247f00,
|
|
0xbf487f00,
|
|
0xbf6d7f00,
|
|
0xbf917f00,
|
|
0xbfb67f00,
|
|
0xbfda7f00,
|
|
0xbfff7f00,
|
|
0xff007f00,
|
|
0xff247f00,
|
|
0xff487f00,
|
|
0xff6d7f00,
|
|
0xff917f00,
|
|
0xffb67f00,
|
|
0xffda7f00,
|
|
0xffff7f00,
|
|
0x0000bf00,
|
|
0x0024bf00,
|
|
0x0048bf00,
|
|
0x006dbf00,
|
|
0x0091bf00,
|
|
0x00b6bf00,
|
|
0x00dabf00,
|
|
0x00ffbf00,
|
|
0x3f00bf00,
|
|
0x3f24bf00,
|
|
0x3f48bf00,
|
|
0x3f6dbf00,
|
|
0x3f91bf00,
|
|
0x3fb6bf00,
|
|
0x3fdabf00,
|
|
0x3fffbf00,
|
|
0x7f00bf00,
|
|
0x7f24bf00,
|
|
0x7f48bf00,
|
|
0x7f6dbf00,
|
|
0x7f91bf00,
|
|
0x7fb6bf00,
|
|
0x7fdabf00,
|
|
0x7fffbf00,
|
|
0xbf00bf00,
|
|
0xbf24bf00,
|
|
0xbf48bf00,
|
|
0xbf6dbf00,
|
|
0xbf91bf00,
|
|
0xbfb6bf00,
|
|
0xbfdabf00,
|
|
0xbfffbf00,
|
|
0xff00bf00,
|
|
0xff24bf00,
|
|
0xff48bf00,
|
|
0xff6dbf00,
|
|
0xff91bf00,
|
|
0xffb6bf00,
|
|
0xffdabf00,
|
|
0xffffbf00,
|
|
0x0000ff00,
|
|
0x0024ff00,
|
|
0x0048ff00,
|
|
0x006dff00,
|
|
0x0091ff00,
|
|
0x00b6ff00,
|
|
0x00daff00,
|
|
0x00ffff00,
|
|
0x3f00ff00,
|
|
0x3f24ff00,
|
|
0x3f48ff00,
|
|
0x3f6dff00,
|
|
0x3f91ff00,
|
|
0x3fb6ff00,
|
|
0x3fdaff00,
|
|
0x3fffff00,
|
|
0x7f00ff00,
|
|
0x7f24ff00,
|
|
0x7f48ff00,
|
|
0x7f6dff00,
|
|
0x7f91ff00,
|
|
0x7fb6ff00,
|
|
0x7fdaff00,
|
|
0x7fffff00,
|
|
0xbf00ff00,
|
|
0xbf24ff00,
|
|
0xbf48ff00,
|
|
0xbf6dff00,
|
|
0xbf91ff00,
|
|
0xbfb6ff00,
|
|
0xbfdaff00,
|
|
0xbfffff00,
|
|
0xff00ff00,
|
|
0xff24ff00,
|
|
0xff48ff00,
|
|
0xff6dff00,
|
|
0xff91ff00,
|
|
0xffb6ff00,
|
|
0xffdaff00,
|
|
0xffffff00
|
|
};
|
|
|
|
|
|
//
|
|
// Local functions...
|
|
//
|
|
|
|
static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap);
|
|
static int gif_get_block(FILE *fp, unsigned char *buffer);
|
|
static int gif_get_code (FILE *fp, int code_size, int first_time);
|
|
static int gif_read_lzw(FILE *fp, int first_time, int input_code_size);
|
|
static int gif_read_image(FILE *fp, Fl_Help_Image *img, gif_cmap_t cmap,
|
|
int interlace);
|
|
static void scrollbar_callback(Fl_Widget *s, void *);
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::add_block()' - Add a text block to the list.
|
|
//
|
|
|
|
Fl_Help_Block * // O - Pointer to new block
|
|
Fl_Help_View::add_block(const char *s, // I - Pointer to start of block text
|
|
int xx, // I - X position of block
|
|
int yy, // I - Y position of block
|
|
int ww, // I - Right margin of block
|
|
int hh, // I - Height of block
|
|
unsigned char border) // I - Draw border?
|
|
{
|
|
Fl_Help_Block *temp; // New block
|
|
|
|
|
|
// printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n",
|
|
// s, xx, yy, ww, hh, border);
|
|
|
|
if (nblocks_ >= ablocks_)
|
|
{
|
|
ablocks_ += 16;
|
|
|
|
if (ablocks_ == 16)
|
|
blocks_ = (Fl_Help_Block *)malloc(sizeof(Fl_Help_Block) * ablocks_);
|
|
else
|
|
blocks_ = (Fl_Help_Block *)realloc(blocks_, sizeof(Fl_Help_Block) * ablocks_);
|
|
}
|
|
|
|
temp = blocks_ + nblocks_;
|
|
temp->start = s;
|
|
temp->x = xx;
|
|
temp->y = yy;
|
|
temp->w = ww;
|
|
temp->h = hh;
|
|
temp->border = border;
|
|
nblocks_ ++;
|
|
|
|
return (temp);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::add_image()' - Add an image to the image cache.
|
|
//
|
|
|
|
Fl_Help_Image * // O - Image or NULL if not found
|
|
Fl_Help_View::add_image(const char *name, // I - Path of image
|
|
const char *wattr, // I - Width attribute
|
|
const char *hattr, // I - Height attribute
|
|
int make) // I - Make the image?
|
|
{
|
|
Fl_Help_Image *img, // New image
|
|
*orig; // Original image
|
|
FILE *fp; // File pointer
|
|
unsigned char header[16]; // First 16 bytes of file
|
|
int status; // Status of load...
|
|
const char *localname; // Local filename
|
|
char dir[1024]; // Current directory
|
|
char temp[1024], // Temporary filename
|
|
*tempptr; // Pointer into temporary name
|
|
int width, // Desired width of image
|
|
height; // Desired height of image
|
|
|
|
|
|
// See if the image has already been loaded...
|
|
if ((img = find_image(name, wattr, hattr)) != (Fl_Help_Image *)0)
|
|
{
|
|
// Make the image if needed...
|
|
if (!img->image)
|
|
img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d);
|
|
|
|
return (img);
|
|
}
|
|
|
|
// See if the image exists with the default size info...
|
|
orig = find_image(name, "", "");
|
|
|
|
// Allocate memory as needed...
|
|
if (aimage_ == nimage_)
|
|
{
|
|
aimage_ += 16;
|
|
|
|
if (aimage_ == 16)
|
|
image_ = (Fl_Help_Image *)malloc(sizeof(Fl_Help_Image) * aimage_);
|
|
else
|
|
image_ = (Fl_Help_Image *)realloc(image_, sizeof(Fl_Help_Image) * aimage_);
|
|
}
|
|
|
|
img = image_ + nimage_;
|
|
img->name = strdup(name);
|
|
img->copy = 0;
|
|
|
|
if (!orig)
|
|
{
|
|
// See if the image can be found...
|
|
if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL)
|
|
{
|
|
if (name[0] == '/')
|
|
{
|
|
strcpy(temp, directory_);
|
|
if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
|
|
strcpy(tempptr, name);
|
|
else
|
|
strcat(temp, name);
|
|
}
|
|
else
|
|
sprintf(temp, "%s/%s", directory_, name);
|
|
|
|
if (link_)
|
|
localname = (*link_)(temp);
|
|
else
|
|
localname = temp;
|
|
}
|
|
else if (name[0] != '/' && strchr(name, ':') == NULL)
|
|
{
|
|
if (directory_[0])
|
|
sprintf(temp, "%s/%s", directory_, name);
|
|
else
|
|
{
|
|
getcwd(dir, sizeof(dir));
|
|
sprintf(temp, "file:%s/%s", dir, name);
|
|
}
|
|
|
|
if (link_)
|
|
localname = (*link_)(temp);
|
|
else
|
|
localname = temp;
|
|
}
|
|
else if (link_)
|
|
localname = (*link_)(name);
|
|
else
|
|
localname = name;
|
|
|
|
if (!localname)
|
|
return ((Fl_Help_Image *)0);
|
|
|
|
if (strncmp(localname, "file:", 5) == 0)
|
|
localname += 5;
|
|
|
|
// Figure out the file type...
|
|
if ((fp = fopen(localname, "rb")) == NULL)
|
|
return ((Fl_Help_Image *)0);
|
|
|
|
if (fread(header, 1, sizeof(header), fp) == 0)
|
|
return ((Fl_Help_Image *)0);
|
|
|
|
rewind(fp);
|
|
|
|
// Load the image as appropriate...
|
|
if (memcmp(header, "GIF87a", 6) == 0 ||
|
|
memcmp(header, "GIF89a", 6) == 0)
|
|
status = load_gif(img, fp);
|
|
#ifdef HAVE_LIBPNG
|
|
else if (memcmp(header, "\211PNG", 4) == 0)
|
|
status = load_png(img, fp);
|
|
#endif // HAVE_LIBPNG
|
|
#ifdef HAVE_LIBJPEG
|
|
else if (memcmp(header, "\377\330\377", 3) == 0 && // Start-of-Image
|
|
header[3] >= 0xe0 && header[3] <= 0xef) // APPn
|
|
status = load_jpeg(img, fp);
|
|
#endif // HAVE_LIBJPEG
|
|
else
|
|
status = 0;
|
|
|
|
fclose(fp);
|
|
|
|
if (!status)
|
|
{
|
|
free(img->name);
|
|
return ((Fl_Help_Image *)0);
|
|
}
|
|
|
|
img->wattr[0] = '\0';
|
|
img->hattr[0] = '\0';
|
|
img->image = 0;
|
|
|
|
nimage_ ++;
|
|
|
|
// Allocate memory as needed for the new copy...
|
|
if (aimage_ == nimage_)
|
|
{
|
|
aimage_ += 16;
|
|
image_ = (Fl_Help_Image *)realloc(image_, sizeof(Fl_Help_Image) * aimage_);
|
|
}
|
|
|
|
orig = image_ + nimage_ - 1;
|
|
img = image_ + nimage_;
|
|
img->name = strdup(name);
|
|
}
|
|
|
|
// printf("orig->data = %p, width = %d, height = %d\n", orig->data,
|
|
// orig->w, orig->h);
|
|
|
|
// Copy image data from original image...
|
|
img->data = orig->data;
|
|
img->w = orig->w;
|
|
img->h = orig->h;
|
|
img->d = orig->d;
|
|
img->copy = 1;
|
|
|
|
// Figure out the size of the image...
|
|
if (wattr[0])
|
|
{
|
|
if (wattr[strlen(wattr) - 1] == '%')
|
|
width = atoi(wattr) * (w() - 24) / 100;
|
|
else
|
|
width = atoi(wattr);
|
|
}
|
|
else
|
|
width = 0;
|
|
|
|
if (hattr[0])
|
|
{
|
|
if (hattr[strlen(hattr) - 1] == '%')
|
|
height = atoi(hattr) * h() / 100;
|
|
else
|
|
height = atoi(hattr);
|
|
}
|
|
else
|
|
height = 0;
|
|
|
|
if (width == 0 && height == 0)
|
|
{
|
|
// Use image size...
|
|
width = img->w;
|
|
height = img->h;
|
|
}
|
|
else if (width == 0)
|
|
// Scale width to height
|
|
width = img->w * height / img->h;
|
|
else if (height == 0)
|
|
// Scale height to width
|
|
height = img->h * width / img->w;
|
|
|
|
// Scale the image as needed...
|
|
if (width != img->w && height != img->h)
|
|
{
|
|
unsigned char *scaled, // Scaled image data
|
|
*sptr, // Source image data pointer
|
|
*dptr; // Destination image data pointer
|
|
int sy, // Source coordinates
|
|
dx, dy, // Destination coordinates
|
|
xerr, yerr, // X & Y errors
|
|
xmod, ymod, // X & Y moduli
|
|
xstep, ystep; // X & Y step increments
|
|
|
|
|
|
xmod = img->w % width;
|
|
xstep = (img->w / width) * img->d;
|
|
ymod = img->h % height;
|
|
ystep = img->h / height;
|
|
|
|
if ((scaled = (unsigned char *)malloc(width * height * img->d)) != NULL)
|
|
{
|
|
img->copy = 0;
|
|
|
|
// Scale the image...
|
|
for (dy = height, sy = 0, yerr = height / 2, dptr = scaled; dy > 0; dy --)
|
|
{
|
|
for (dx = width, xerr = width / 2,
|
|
sptr = img->data + sy * img->w * img->d;
|
|
dx > 0;
|
|
dx --)
|
|
{
|
|
*dptr++ = sptr[0];
|
|
if (img->d > 1)
|
|
{
|
|
*dptr++ = sptr[1];
|
|
*dptr++ = sptr[2];
|
|
}
|
|
|
|
sptr += xstep;
|
|
xerr -= xmod;
|
|
if (xerr <= 0)
|
|
{
|
|
xerr += width;
|
|
sptr += img->d;
|
|
}
|
|
}
|
|
|
|
sy += ystep;
|
|
yerr -= ymod;
|
|
if (yerr <= 0)
|
|
{
|
|
yerr += height;
|
|
sy ++;
|
|
}
|
|
}
|
|
|
|
// Finally, copy the new size and data to the image structure...
|
|
if (!orig)
|
|
free(img->data);
|
|
|
|
img->w = width;
|
|
img->h = height;
|
|
img->data = scaled;
|
|
}
|
|
}
|
|
|
|
strncpy(img->wattr, wattr, sizeof(img->wattr) - 1);
|
|
img->wattr[sizeof(img->wattr) - 1] = '\0';
|
|
strncpy(img->hattr, hattr, sizeof(img->hattr) - 1);
|
|
img->hattr[sizeof(img->hattr) - 1] = '\0';
|
|
|
|
if (make)
|
|
img->image = new Fl_RGB_Image(img->data, img->w, img->h, img->d);
|
|
else
|
|
img->image = (Fl_Image *)0;
|
|
|
|
nimage_ ++;
|
|
|
|
// printf("img->data = %p, width = %d, height = %d\n", img->data,
|
|
// img->w, img->h);
|
|
|
|
return (img);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::add_link()' - Add a new link to the list.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::add_link(const char *n, // I - Name of link
|
|
int xx, // I - X position of link
|
|
int yy, // I - Y position of link
|
|
int ww, // I - Width of link text
|
|
int hh) // I - Height of link text
|
|
{
|
|
Fl_Help_Link *temp; // New link
|
|
char *target; // Pointer to target name
|
|
|
|
|
|
if (nlinks_ >= alinks_)
|
|
{
|
|
alinks_ += 16;
|
|
|
|
if (alinks_ == 16)
|
|
links_ = (Fl_Help_Link *)malloc(sizeof(Fl_Help_Link) * alinks_);
|
|
else
|
|
links_ = (Fl_Help_Link *)realloc(links_, sizeof(Fl_Help_Link) * alinks_);
|
|
}
|
|
|
|
temp = links_ + nlinks_;
|
|
|
|
temp->x = xx;
|
|
temp->y = yy;
|
|
temp->w = xx + ww;
|
|
temp->h = yy + hh;
|
|
|
|
strncpy(temp->filename, n, sizeof(temp->filename));
|
|
temp->filename[sizeof(temp->filename) - 1] = '\0';
|
|
|
|
if ((target = strrchr(temp->filename, '#')) != NULL)
|
|
{
|
|
*target++ = '\0';
|
|
strncpy(temp->name, target, sizeof(temp->name));
|
|
temp->name[sizeof(temp->name) - 1] = '\0';
|
|
}
|
|
else
|
|
temp->name[0] = '\0';
|
|
|
|
nlinks_ ++;
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::add_target()' - Add a new target to the list.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::add_target(const char *n, // I - Name of target
|
|
int yy) // I - Y position of target
|
|
{
|
|
Fl_Help_Target *temp; // New target
|
|
|
|
|
|
if (ntargets_ >= atargets_)
|
|
{
|
|
atargets_ += 16;
|
|
|
|
if (atargets_ == 16)
|
|
targets_ = (Fl_Help_Target *)malloc(sizeof(Fl_Help_Target) * atargets_);
|
|
else
|
|
targets_ = (Fl_Help_Target *)realloc(targets_, sizeof(Fl_Help_Target) * atargets_);
|
|
}
|
|
|
|
temp = targets_ + ntargets_;
|
|
|
|
temp->y = yy;
|
|
strncpy(temp->name, n, sizeof(temp->name));
|
|
temp->name[sizeof(temp->name) - 1] = '\0';
|
|
|
|
ntargets_ ++;
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::compare_targets()' - Compare two targets.
|
|
//
|
|
|
|
int // O - Result of comparison
|
|
Fl_Help_View::compare_targets(const Fl_Help_Target *t0, // I - First target
|
|
const Fl_Help_Target *t1) // I - Second target
|
|
{
|
|
return (strcasecmp(t0->name, t1->name));
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::do_align()' - Compute the alignment for a line in a block.
|
|
//
|
|
|
|
int // O - New line
|
|
Fl_Help_View::do_align(Fl_Help_Block *block, // I - Block to add to
|
|
int line, // I - Current line
|
|
int xx, // I - Current X position
|
|
int a, // I - Current alignment
|
|
int &l) // IO - Starting link
|
|
{
|
|
int offset; // Alignment offset
|
|
|
|
|
|
switch (a)
|
|
{
|
|
case RIGHT : // Right align
|
|
offset = block->w - xx;
|
|
break;
|
|
case CENTER : // Center
|
|
offset = (block->w - xx) / 2;
|
|
break;
|
|
default : // Left align
|
|
offset = 0;
|
|
break;
|
|
}
|
|
|
|
block->line[line] = block->x + offset;
|
|
|
|
if (line < 31)
|
|
line ++;
|
|
|
|
while (l < nlinks_)
|
|
{
|
|
links_[l].x += offset;
|
|
links_[l].w += offset;
|
|
l ++;
|
|
}
|
|
|
|
return (line);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::draw()' - Draw the Fl_Help_View widget.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::draw()
|
|
{
|
|
int i; // Looping var
|
|
const Fl_Help_Block *block; // Pointer to current block
|
|
const char *ptr, // Pointer to text in block
|
|
*attrs; // Pointer to start of element attributes
|
|
char *s, // Pointer into buffer
|
|
buf[1024], // Text buffer
|
|
attr[1024]; // Attribute buffer
|
|
int xx, yy, ww, hh; // Current positions and sizes
|
|
int line; // Current line
|
|
unsigned char font, size; // Current font and size
|
|
int head, pre, // Flags for text
|
|
needspace; // Do we need whitespace?
|
|
Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
|
|
// Box to draw...
|
|
Fl_Color tc, c; // Table/cell background color
|
|
|
|
|
|
// Draw the scrollbar and box first...
|
|
if (scrollbar_.visible())
|
|
{
|
|
draw_child(scrollbar_);
|
|
draw_box(b, x(), y(), w() - 17, h(), bgcolor_);
|
|
}
|
|
else
|
|
draw_box(b, x(), y(), w(), h(), bgcolor_);
|
|
|
|
if (!value_)
|
|
return;
|
|
|
|
// Clip the drawing to the inside of the box...
|
|
fl_push_clip(x() + 4, y() + 4, w() - 28, h() - 8);
|
|
fl_color(textcolor_);
|
|
|
|
tc = c = bgcolor_;
|
|
|
|
// Draw all visible blocks...
|
|
for (i = 0, block = blocks_; i < nblocks_ && (block->y - topline_) < h(); i ++, block ++)
|
|
if ((block->y + block->h) >= topline_)
|
|
{
|
|
line = 0;
|
|
xx = block->line[line];
|
|
yy = block->y - topline_;
|
|
hh = 0;
|
|
pre = 0;
|
|
head = 0;
|
|
needspace = 0;
|
|
|
|
initfont(font, size);
|
|
|
|
for (ptr = block->start, s = buf; ptr < block->end;)
|
|
{
|
|
if ((*ptr == '<' || isspace(*ptr)) && s > buf)
|
|
{
|
|
if (!head && !pre)
|
|
{
|
|
// Check width...
|
|
*s = '\0';
|
|
s = buf;
|
|
ww = (int)fl_width(buf);
|
|
|
|
if (needspace && xx > block->x)
|
|
xx += (int)fl_width(' ');
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = 0;
|
|
}
|
|
|
|
fl_draw(buf, xx + x(), yy + y());
|
|
|
|
xx += ww;
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
|
|
needspace = 0;
|
|
}
|
|
else if (pre)
|
|
{
|
|
while (isspace(*ptr))
|
|
{
|
|
if (*ptr == '\n')
|
|
{
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
fl_draw(buf, xx + x(), yy + y());
|
|
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = size + 2;
|
|
}
|
|
else if (*ptr == '\t')
|
|
{
|
|
// Do tabs every 8 columns...
|
|
while (((s - buf) & 7))
|
|
*s++ = ' ';
|
|
}
|
|
else
|
|
*s++ = ' ';
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
|
|
ptr ++;
|
|
}
|
|
|
|
if (s > buf)
|
|
{
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
fl_draw(buf, xx + x(), yy + y());
|
|
xx += (int)fl_width(buf);
|
|
}
|
|
|
|
needspace = 0;
|
|
}
|
|
else
|
|
{
|
|
s = buf;
|
|
|
|
while (isspace(*ptr))
|
|
ptr ++;
|
|
}
|
|
}
|
|
|
|
if (*ptr == '<')
|
|
{
|
|
ptr ++;
|
|
while (*ptr && *ptr != '>' && !isspace(*ptr))
|
|
if (s < (buf + sizeof(buf) - 1))
|
|
*s++ = *ptr++;
|
|
else
|
|
ptr ++;
|
|
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
attrs = ptr;
|
|
while (*ptr && *ptr != '>')
|
|
ptr ++;
|
|
|
|
if (*ptr == '>')
|
|
ptr ++;
|
|
|
|
if (strcasecmp(buf, "HEAD") == 0)
|
|
head = 1;
|
|
else if (strcasecmp(buf, "BR") == 0)
|
|
{
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = 0;
|
|
}
|
|
else if (strcasecmp(buf, "HR") == 0)
|
|
{
|
|
fl_line(block->x + x(), yy + y(), block->w + x(),
|
|
yy + y());
|
|
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += 2 * hh;
|
|
hh = 0;
|
|
}
|
|
else if (strcasecmp(buf, "CENTER") == 0 ||
|
|
strcasecmp(buf, "P") == 0 ||
|
|
strcasecmp(buf, "H1") == 0 ||
|
|
strcasecmp(buf, "H2") == 0 ||
|
|
strcasecmp(buf, "H3") == 0 ||
|
|
strcasecmp(buf, "H4") == 0 ||
|
|
strcasecmp(buf, "H5") == 0 ||
|
|
strcasecmp(buf, "H6") == 0 ||
|
|
strcasecmp(buf, "UL") == 0 ||
|
|
strcasecmp(buf, "OL") == 0 ||
|
|
strcasecmp(buf, "DL") == 0 ||
|
|
strcasecmp(buf, "LI") == 0 ||
|
|
strcasecmp(buf, "DD") == 0 ||
|
|
strcasecmp(buf, "DT") == 0 ||
|
|
strcasecmp(buf, "PRE") == 0)
|
|
{
|
|
if (tolower(buf[0]) == 'h')
|
|
{
|
|
font = FL_HELVETICA_BOLD;
|
|
size = textsize_ + '7' - buf[1];
|
|
}
|
|
else if (strcasecmp(buf, "DT") == 0)
|
|
{
|
|
font = textfont_ | FL_ITALIC;
|
|
size = textsize_;
|
|
}
|
|
else if (strcasecmp(buf, "PRE") == 0)
|
|
{
|
|
font = FL_COURIER;
|
|
size = textsize_;
|
|
pre = 1;
|
|
}
|
|
|
|
if (strcasecmp(buf, "LI") == 0)
|
|
{
|
|
fl_font(FL_SYMBOL, size);
|
|
fl_draw("\267", xx - size + x(), yy + y());
|
|
}
|
|
|
|
pushfont(font, size);
|
|
|
|
if (c != bgcolor_)
|
|
{
|
|
fl_color(c);
|
|
fl_rectf(block->x + x() - 4,
|
|
block->y - topline_ + y() - size - 3,
|
|
block->w - block->x + 7, block->h + size - 5);
|
|
fl_color(textcolor_);
|
|
}
|
|
}
|
|
else if (strcasecmp(buf, "A") == 0 &&
|
|
get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
|
|
fl_color(linkcolor_);
|
|
else if (strcasecmp(buf, "/A") == 0)
|
|
fl_color(textcolor_);
|
|
else if (strcasecmp(buf, "B") == 0)
|
|
pushfont(font |= FL_BOLD, size);
|
|
else if (strcasecmp(buf, "TABLE") == 0)
|
|
tc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_);
|
|
else if (strcasecmp(buf, "TD") == 0 ||
|
|
strcasecmp(buf, "TH") == 0)
|
|
{
|
|
if (tolower(buf[1]) == 'h')
|
|
pushfont(font |= FL_BOLD, size);
|
|
else
|
|
pushfont(font = textfont_, size);
|
|
|
|
c = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc);
|
|
|
|
if (c != bgcolor_)
|
|
{
|
|
fl_color(c);
|
|
fl_rectf(block->x + x() - 4,
|
|
block->y - topline_ + y() - size - 3,
|
|
block->w - block->x + 7, block->h + size - 5);
|
|
fl_color(textcolor_);
|
|
}
|
|
|
|
if (block->border)
|
|
fl_rect(block->x + x() - 4,
|
|
block->y - topline_ + y() - size - 3,
|
|
block->w - block->x + 7, block->h + size - 5);
|
|
}
|
|
else if (strcasecmp(buf, "I") == 0)
|
|
pushfont(font |= FL_ITALIC, size);
|
|
else if (strcasecmp(buf, "CODE") == 0)
|
|
pushfont(font = FL_COURIER, size);
|
|
else if (strcasecmp(buf, "KBD") == 0)
|
|
pushfont(font = FL_COURIER_BOLD, size);
|
|
else if (strcasecmp(buf, "VAR") == 0)
|
|
pushfont(font = FL_COURIER_ITALIC, size);
|
|
else if (strcasecmp(buf, "/HEAD") == 0)
|
|
head = 0;
|
|
else if (strcasecmp(buf, "/H1") == 0 ||
|
|
strcasecmp(buf, "/H2") == 0 ||
|
|
strcasecmp(buf, "/H3") == 0 ||
|
|
strcasecmp(buf, "/H4") == 0 ||
|
|
strcasecmp(buf, "/H5") == 0 ||
|
|
strcasecmp(buf, "/H6") == 0 ||
|
|
strcasecmp(buf, "/B") == 0 ||
|
|
strcasecmp(buf, "/I") == 0 ||
|
|
strcasecmp(buf, "/CODE") == 0 ||
|
|
strcasecmp(buf, "/KBD") == 0 ||
|
|
strcasecmp(buf, "/VAR") == 0)
|
|
popfont(font, size);
|
|
else if (strcasecmp(buf, "/TABLE") == 0)
|
|
tc = c = bgcolor_;
|
|
else if (strcasecmp(buf, "/TD") == 0 ||
|
|
strcasecmp(buf, "/TH") == 0)
|
|
c = tc;
|
|
else if (strcasecmp(buf, "/PRE") == 0)
|
|
{
|
|
popfont(font, size);
|
|
pre = 0;
|
|
}
|
|
else if (strcasecmp(buf, "IMG") == 0)
|
|
{
|
|
Fl_Help_Image *img = (Fl_Help_Image *)0;
|
|
int width = 16;
|
|
int height = 24;
|
|
char wattr[8], hattr[8];
|
|
|
|
|
|
get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
|
|
get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
|
|
|
|
if (get_attr(attrs, "SRC", attr, sizeof(attr)))
|
|
if ((img = add_image(attr, wattr, hattr)) != NULL)
|
|
{
|
|
if (!img->image)
|
|
img = (Fl_Help_Image *)0;
|
|
}
|
|
|
|
if (img)
|
|
{
|
|
width = img->w;
|
|
height = img->h;
|
|
}
|
|
else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL)
|
|
strcpy(attr, "IMG");
|
|
|
|
ww = width;
|
|
|
|
if (needspace && xx > block->x)
|
|
xx += (int)fl_width(' ');
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
if (line < 31)
|
|
line ++;
|
|
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = 0;
|
|
}
|
|
|
|
if (img)
|
|
img->image->draw(xx + x(),
|
|
yy + y() - fl_height() + fl_descent() + 2);
|
|
else
|
|
broken_image->draw(xx + x(),
|
|
yy + y() - fl_height() + fl_descent() + 2);
|
|
|
|
xx += ww;
|
|
if ((height + 2) > hh)
|
|
hh = height + 2;
|
|
|
|
needspace = 0;
|
|
}
|
|
}
|
|
else if (*ptr == '\n' && pre)
|
|
{
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
fl_draw(buf, xx + x(), yy + y());
|
|
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = size + 2;
|
|
needspace = 0;
|
|
|
|
ptr ++;
|
|
}
|
|
else if (isspace(*ptr))
|
|
{
|
|
if (pre)
|
|
{
|
|
if (*ptr == ' ')
|
|
*s++ = ' ';
|
|
else
|
|
{
|
|
// Do tabs every 8 columns...
|
|
while (((s - buf) & 7))
|
|
*s++ = ' ';
|
|
}
|
|
}
|
|
|
|
ptr ++;
|
|
needspace = 1;
|
|
}
|
|
else if (*ptr == '&')
|
|
{
|
|
ptr ++;
|
|
|
|
if (strncasecmp(ptr, "amp;", 4) == 0)
|
|
{
|
|
*s++ = '&';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "lt;", 3) == 0)
|
|
{
|
|
*s++ = '<';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "gt;", 3) == 0)
|
|
{
|
|
*s++ = '>';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "nbsp;", 5) == 0)
|
|
{
|
|
*s++ = ' ';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "copy;", 5) == 0)
|
|
{
|
|
*s++ = '\251';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "reg;", 4) == 0)
|
|
{
|
|
*s++ = '\256';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "quot;", 5) == 0)
|
|
{
|
|
*s++ = '\"';
|
|
ptr += 5;
|
|
}
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
}
|
|
else
|
|
{
|
|
*s++ = *ptr++;
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
}
|
|
}
|
|
|
|
*s = '\0';
|
|
|
|
if (s > buf && !pre && !head)
|
|
{
|
|
ww = (int)fl_width(buf);
|
|
|
|
if (needspace && xx > block->x)
|
|
xx += (int)fl_width(' ');
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
if (line < 31)
|
|
line ++;
|
|
xx = block->line[line];
|
|
yy += hh;
|
|
hh = 0;
|
|
}
|
|
}
|
|
|
|
if (s > buf && !head)
|
|
fl_draw(buf, xx + x(), yy + y());
|
|
}
|
|
|
|
fl_pop_clip();
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::find_image()' - Find an image by name
|
|
//
|
|
|
|
Fl_Help_Image * // O - Image or NULL if not found
|
|
Fl_Help_View::find_image(const char *name, // I - Path and name of image
|
|
const char *wattr, // I - Width attribute of image
|
|
const char *hattr) // I - Height attribute of image
|
|
{
|
|
int i; // Looping var
|
|
Fl_Help_Image *img; // Current image
|
|
|
|
|
|
for (i = nimage_, img = image_; i > 0; i --, img ++)
|
|
if (strcmp(img->name, name) == 0 &&
|
|
strcmp(img->wattr, wattr) == 0 &&
|
|
strcmp(img->hattr, hattr) == 0)
|
|
return (img);
|
|
|
|
return ((Fl_Help_Image *)0);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::format()' - Format the help text.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::format()
|
|
{
|
|
int i; // Looping var
|
|
Fl_Help_Block *block, // Current block
|
|
*cell; // Current table cell
|
|
int row; // Current table row (block number)
|
|
const char *ptr, // Pointer into block
|
|
*start, // Pointer to start of element
|
|
*attrs; // Pointer to start of element attributes
|
|
char *s, // Pointer into buffer
|
|
buf[1024], // Text buffer
|
|
attr[1024], // Attribute buffer
|
|
wattr[1024], // Width attribute buffer
|
|
hattr[1024], // Height attribute buffer
|
|
link[1024]; // Link destination
|
|
int xx, yy, ww, hh; // Size of current text fragment
|
|
int line; // Current line in block
|
|
int links; // Links for current line
|
|
unsigned char font, size; // Current font and size
|
|
unsigned char border; // Draw border?
|
|
int align, // Current alignment
|
|
newalign, // New alignment
|
|
head, // In the <HEAD> section?
|
|
pre, // <PRE> text?
|
|
needspace; // Do we need whitespace?
|
|
int table_width; // Width of table
|
|
int column, // Current table column number
|
|
columns[MAX_COLUMNS];
|
|
// Column widths
|
|
|
|
|
|
// Reset state variables...
|
|
nblocks_ = 0;
|
|
nlinks_ = 0;
|
|
ntargets_ = 0;
|
|
size_ = 0;
|
|
bgcolor_ = color();
|
|
textcolor_ = textcolor();
|
|
linkcolor_ = selection_color();
|
|
|
|
strcpy(title_, "Untitled");
|
|
|
|
if (!value_)
|
|
return;
|
|
|
|
// Flush images that are scaled by percentage...
|
|
for (i = 0; i < nimage_; i ++)
|
|
if (strchr(image_[i].wattr, '%') != NULL ||
|
|
strchr(image_[i].hattr, '%') != NULL)
|
|
{
|
|
// Flush this one...
|
|
free(image_[i].name);
|
|
free(image_[i].data);
|
|
delete image_[i].image;
|
|
nimage_ --;
|
|
if (i < nimage_)
|
|
memcpy(image_ + i, image_ + i + 1, (nimage_ - i) * sizeof(Fl_Help_Image));
|
|
i --;
|
|
}
|
|
|
|
// Setup for formatting...
|
|
initfont(font, size);
|
|
|
|
line = 0;
|
|
links = 0;
|
|
xx = 4;
|
|
yy = size + 2;
|
|
ww = 0;
|
|
column = 0;
|
|
border = 0;
|
|
hh = 0;
|
|
block = add_block(value_, xx, yy, w() - 24, 0);
|
|
row = 0;
|
|
head = 0;
|
|
pre = 0;
|
|
align = LEFT;
|
|
newalign = LEFT;
|
|
needspace = 0;
|
|
link[0] = '\0';
|
|
|
|
for (ptr = value_, s = buf; *ptr;)
|
|
{
|
|
if ((*ptr == '<' || isspace(*ptr)) && s > buf)
|
|
{
|
|
if (!head && !pre)
|
|
{
|
|
// Check width...
|
|
*s = '\0';
|
|
ww = (int)fl_width(buf);
|
|
|
|
if (needspace && xx > block->x)
|
|
ww += (int)fl_width(' ');
|
|
|
|
// printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
|
|
// line, xx, ww, block->x, block->w);
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
yy += hh;
|
|
block->h += hh;
|
|
hh = 0;
|
|
}
|
|
|
|
if (link[0])
|
|
add_link(link, xx, yy - size, ww, size);
|
|
|
|
xx += ww;
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
|
|
needspace = 0;
|
|
}
|
|
else if (pre)
|
|
{
|
|
// Handle preformatted text...
|
|
while (isspace(*ptr))
|
|
{
|
|
if (*ptr == '\n')
|
|
{
|
|
if (link[0])
|
|
add_link(link, xx, yy - hh, ww, hh);
|
|
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
yy += hh;
|
|
block->h += hh;
|
|
hh = size + 2;
|
|
}
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
|
|
ptr ++;
|
|
}
|
|
|
|
needspace = 0;
|
|
}
|
|
else
|
|
{
|
|
// Handle normal text or stuff in the <HEAD> section...
|
|
while (isspace(*ptr))
|
|
ptr ++;
|
|
}
|
|
|
|
s = buf;
|
|
}
|
|
|
|
if (*ptr == '<')
|
|
{
|
|
start = ptr;
|
|
ptr ++;
|
|
while (*ptr && *ptr != '>' && !isspace(*ptr))
|
|
if (s < (buf + sizeof(buf) - 1))
|
|
*s++ = *ptr++;
|
|
else
|
|
ptr ++;
|
|
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
// puts(buf);
|
|
|
|
attrs = ptr;
|
|
while (*ptr && *ptr != '>')
|
|
ptr ++;
|
|
|
|
if (*ptr == '>')
|
|
ptr ++;
|
|
|
|
if (strcasecmp(buf, "HEAD") == 0)
|
|
head = 1;
|
|
else if (strcasecmp(buf, "/HEAD") == 0)
|
|
head = 0;
|
|
else if (strcasecmp(buf, "TITLE") == 0)
|
|
{
|
|
// Copy the title in the document...
|
|
for (s = title_;
|
|
*ptr != '<' && *ptr && s < (title_ + sizeof(title_) - 1);
|
|
*s++ = *ptr++);
|
|
|
|
*s = '\0';
|
|
s = buf;
|
|
}
|
|
else if (strcasecmp(buf, "A") == 0)
|
|
{
|
|
if (get_attr(attrs, "NAME", attr, sizeof(attr)) != NULL)
|
|
add_target(attr, yy - size - 2);
|
|
else if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
|
|
{
|
|
strncpy(link, attr, sizeof(link) - 1);
|
|
link[sizeof(link) - 1] = '\0';
|
|
}
|
|
}
|
|
else if (strcasecmp(buf, "/A") == 0)
|
|
link[0] = '\0';
|
|
else if (strcasecmp(buf, "BODY") == 0)
|
|
{
|
|
bgcolor_ = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)),
|
|
color());
|
|
textcolor_ = get_color(get_attr(attrs, "TEXT", attr, sizeof(attr)),
|
|
textcolor());
|
|
linkcolor_ = get_color(get_attr(attrs, "LINK", attr, sizeof(attr)),
|
|
selection_color());
|
|
}
|
|
else if (strcasecmp(buf, "BR") == 0)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
block->h += hh;
|
|
yy += hh;
|
|
hh = 0;
|
|
}
|
|
else if (strcasecmp(buf, "CENTER") == 0 ||
|
|
strcasecmp(buf, "P") == 0 ||
|
|
strcasecmp(buf, "H1") == 0 ||
|
|
strcasecmp(buf, "H2") == 0 ||
|
|
strcasecmp(buf, "H3") == 0 ||
|
|
strcasecmp(buf, "H4") == 0 ||
|
|
strcasecmp(buf, "H5") == 0 ||
|
|
strcasecmp(buf, "H6") == 0 ||
|
|
strcasecmp(buf, "UL") == 0 ||
|
|
strcasecmp(buf, "OL") == 0 ||
|
|
strcasecmp(buf, "DL") == 0 ||
|
|
strcasecmp(buf, "LI") == 0 ||
|
|
strcasecmp(buf, "DD") == 0 ||
|
|
strcasecmp(buf, "DT") == 0 ||
|
|
strcasecmp(buf, "HR") == 0 ||
|
|
strcasecmp(buf, "PRE") == 0 ||
|
|
strcasecmp(buf, "TABLE") == 0)
|
|
{
|
|
block->end = start;
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
block->h += hh;
|
|
|
|
if (strcasecmp(buf, "UL") == 0 ||
|
|
strcasecmp(buf, "OL") == 0 ||
|
|
strcasecmp(buf, "DL") == 0)
|
|
{
|
|
block->h += size + 2;
|
|
xx += 4 * size;
|
|
}
|
|
else if (strcasecmp(buf, "TABLE") == 0)
|
|
{
|
|
if (get_attr(attrs, "BORDER", attr, sizeof(attr)))
|
|
border = atoi(attr);
|
|
else
|
|
border = 0;
|
|
|
|
block->h += size + 2;
|
|
|
|
format_table(&table_width, columns, start);
|
|
|
|
column = 0;
|
|
}
|
|
|
|
if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
|
|
{
|
|
font = FL_HELVETICA_BOLD;
|
|
size = textsize_ + '7' - buf[1];
|
|
}
|
|
else if (strcasecmp(buf, "DT") == 0)
|
|
{
|
|
font = textfont_ | FL_ITALIC;
|
|
size = textsize_;
|
|
}
|
|
else if (strcasecmp(buf, "PRE") == 0)
|
|
{
|
|
font = FL_COURIER;
|
|
size = textsize_;
|
|
pre = 1;
|
|
}
|
|
else
|
|
{
|
|
font = textfont_;
|
|
size = textsize_;
|
|
}
|
|
|
|
pushfont(font, size);
|
|
|
|
yy = block->y + block->h;
|
|
hh = 0;
|
|
|
|
if ((tolower(buf[0]) == 'h' && isdigit(buf[1])) ||
|
|
strcasecmp(buf, "DD") == 0 ||
|
|
strcasecmp(buf, "DT") == 0 ||
|
|
strcasecmp(buf, "P") == 0)
|
|
yy += size + 2;
|
|
else if (strcasecmp(buf, "HR") == 0)
|
|
{
|
|
hh += 2 * size;
|
|
yy += size;
|
|
}
|
|
|
|
if (row)
|
|
block = add_block(start, xx, yy, block->w, 0);
|
|
else
|
|
block = add_block(start, xx, yy, w() - 24, 0);
|
|
|
|
needspace = 0;
|
|
line = 0;
|
|
|
|
if (strcasecmp(buf, "CENTER") == 0)
|
|
newalign = align = CENTER;
|
|
else
|
|
newalign = get_align(attrs, align);
|
|
}
|
|
else if (strcasecmp(buf, "/CENTER") == 0 ||
|
|
strcasecmp(buf, "/P") == 0 ||
|
|
strcasecmp(buf, "/H1") == 0 ||
|
|
strcasecmp(buf, "/H2") == 0 ||
|
|
strcasecmp(buf, "/H3") == 0 ||
|
|
strcasecmp(buf, "/H4") == 0 ||
|
|
strcasecmp(buf, "/H5") == 0 ||
|
|
strcasecmp(buf, "/H6") == 0 ||
|
|
strcasecmp(buf, "/PRE") == 0 ||
|
|
strcasecmp(buf, "/UL") == 0 ||
|
|
strcasecmp(buf, "/OL") == 0 ||
|
|
strcasecmp(buf, "/DL") == 0 ||
|
|
strcasecmp(buf, "/TABLE") == 0)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
block->end = ptr;
|
|
|
|
if (strcasecmp(buf, "/UL") == 0 ||
|
|
strcasecmp(buf, "/OL") == 0 ||
|
|
strcasecmp(buf, "/DL") == 0)
|
|
{
|
|
xx -= 4 * size;
|
|
block->h += size + 2;
|
|
}
|
|
else if (strcasecmp(buf, "/TABLE") == 0)
|
|
block->h += size + 2;
|
|
else if (strcasecmp(buf, "/PRE") == 0)
|
|
{
|
|
pre = 0;
|
|
hh = 0;
|
|
}
|
|
else if (strcasecmp(buf, "/CENTER") == 0)
|
|
align = LEFT;
|
|
|
|
popfont(font, size);
|
|
|
|
while (isspace(*ptr))
|
|
ptr ++;
|
|
|
|
block->h += hh;
|
|
yy += hh;
|
|
|
|
if (tolower(buf[2]) == 'l')
|
|
yy += size + 2;
|
|
|
|
if (row)
|
|
block = add_block(ptr, xx, yy, block->w, 0);
|
|
else
|
|
block = add_block(ptr, xx, yy, w() - 24, 0);
|
|
|
|
needspace = 0;
|
|
hh = 0;
|
|
line = 0;
|
|
newalign = align;
|
|
}
|
|
else if (strcasecmp(buf, "TR") == 0)
|
|
{
|
|
block->end = start;
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
block->h += hh;
|
|
|
|
if (row)
|
|
{
|
|
yy = blocks_[row].y + blocks_[row].h;
|
|
|
|
for (cell = blocks_ + row + 1; cell <= block; cell ++)
|
|
if ((cell->y + cell->h) > yy)
|
|
yy = cell->y + cell->h;
|
|
|
|
block->h = yy - block->y + 2;
|
|
|
|
for (cell = blocks_ + row + 1; cell < block; cell ++)
|
|
cell->h = block->h;
|
|
}
|
|
|
|
yy = block->y + block->h - 4;
|
|
hh = 0;
|
|
block = add_block(start, xx, yy, w() - 24, 0);
|
|
row = block - blocks_;
|
|
needspace = 0;
|
|
column = 0;
|
|
line = 0;
|
|
}
|
|
else if (strcasecmp(buf, "/TR") == 0 && row)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
block->end = start;
|
|
block->h += hh;
|
|
|
|
xx = blocks_[row].x;
|
|
|
|
yy = blocks_[row].y + blocks_[row].h;
|
|
|
|
for (cell = blocks_ + row + 1; cell <= block; cell ++)
|
|
if ((cell->y + cell->h) > yy)
|
|
yy = cell->y + cell->h;
|
|
|
|
block->h = yy - block->y + 2;
|
|
|
|
for (cell = blocks_ + row + 1; cell < block; cell ++)
|
|
cell->h = block->h;
|
|
|
|
yy = block->y + block->h - 4;
|
|
block = add_block(start, xx, yy, w() - 24, 0);
|
|
needspace = 0;
|
|
row = 0;
|
|
line = 0;
|
|
}
|
|
else if ((strcasecmp(buf, "TD") == 0 ||
|
|
strcasecmp(buf, "TH") == 0) && row)
|
|
{
|
|
int colspan; // COLSPAN attribute
|
|
|
|
|
|
line = do_align(block, line, xx, newalign, links);
|
|
block->end = start;
|
|
block->h += hh;
|
|
|
|
if (strcasecmp(buf, "TH") == 0)
|
|
font = textfont_ | FL_BOLD;
|
|
else
|
|
font = textfont_;
|
|
|
|
size = textsize_;
|
|
|
|
xx = blocks_[row].x + size + 3;
|
|
for (i = 0; i < column; i ++)
|
|
xx += columns[i] + 6;
|
|
|
|
if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
|
|
colspan = atoi(attr);
|
|
else
|
|
colspan = 1;
|
|
|
|
for (i = 0, ww = 0; i < colspan; i ++)
|
|
ww += columns[column + i];
|
|
|
|
if (block->end == block->start && nblocks_ > 1)
|
|
{
|
|
nblocks_ --;
|
|
block --;
|
|
}
|
|
|
|
pushfont(font, size);
|
|
|
|
yy = blocks_[row].y;
|
|
hh = 0;
|
|
block = add_block(start, xx, yy, xx + ww, 0, border);
|
|
needspace = 0;
|
|
line = 0;
|
|
newalign = get_align(attrs, tolower(buf[1]) == 'h' ? CENTER : LEFT);
|
|
|
|
column ++;
|
|
}
|
|
else if ((strcasecmp(buf, "/TD") == 0 ||
|
|
strcasecmp(buf, "/TH") == 0) && row)
|
|
popfont(font, size);
|
|
else if (strcasecmp(buf, "B") == 0)
|
|
pushfont(font |= FL_BOLD, size);
|
|
else if (strcasecmp(buf, "I") == 0)
|
|
pushfont(font |= FL_ITALIC, size);
|
|
else if (strcasecmp(buf, "CODE") == 0)
|
|
pushfont(font = FL_COURIER, size);
|
|
else if (strcasecmp(buf, "KBD") == 0)
|
|
pushfont(font = FL_COURIER_BOLD, size);
|
|
else if (strcasecmp(buf, "VAR") == 0)
|
|
pushfont(font = FL_COURIER_ITALIC, size);
|
|
else if (strcasecmp(buf, "/B") == 0 ||
|
|
strcasecmp(buf, "/I") == 0 ||
|
|
strcasecmp(buf, "/CODE") == 0 ||
|
|
strcasecmp(buf, "/KBD") == 0 ||
|
|
strcasecmp(buf, "/VAR") == 0)
|
|
popfont(font, size);
|
|
else if (strcasecmp(buf, "IMG") == 0)
|
|
{
|
|
Fl_Help_Image *img = (Fl_Help_Image *)0;
|
|
int width = 16;
|
|
int height = 24;
|
|
|
|
|
|
get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
|
|
get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
|
|
|
|
if (get_attr(attrs, "SRC", attr, sizeof(attr)))
|
|
if ((img = add_image(attr, wattr, hattr)) != (Fl_Help_Image *)0 &&
|
|
img->image == NULL)
|
|
img = (Fl_Help_Image *)0;
|
|
|
|
if (img)
|
|
{
|
|
width = img->w;
|
|
height = img->h;
|
|
}
|
|
else if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL)
|
|
strcpy(attr, "IMG");
|
|
|
|
ww = width;
|
|
|
|
if (needspace && xx > block->x)
|
|
ww += (int)fl_width(' ');
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
yy += hh;
|
|
block->h += hh;
|
|
hh = 0;
|
|
}
|
|
|
|
if (link[0])
|
|
add_link(link, xx, yy - height, ww, height);
|
|
|
|
xx += ww;
|
|
if ((height + 2) > hh)
|
|
hh = height + 2;
|
|
|
|
needspace = 0;
|
|
}
|
|
}
|
|
else if (*ptr == '\n' && pre)
|
|
{
|
|
if (link[0])
|
|
add_link(link, xx, yy - hh, ww, hh);
|
|
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
yy += hh;
|
|
block->h += hh;
|
|
needspace = 0;
|
|
ptr ++;
|
|
}
|
|
else if (isspace(*ptr))
|
|
{
|
|
needspace = 1;
|
|
|
|
ptr ++;
|
|
}
|
|
else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
|
|
{
|
|
ptr ++;
|
|
|
|
if (strncasecmp(ptr, "amp;", 4) == 0)
|
|
{
|
|
*s++ = '&';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "lt;", 3) == 0)
|
|
{
|
|
*s++ = '<';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "gt;", 3) == 0)
|
|
{
|
|
*s++ = '>';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "nbsp;", 5) == 0)
|
|
{
|
|
*s++ = '\240';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "copy;", 5) == 0)
|
|
{
|
|
*s++ = '\251';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "reg;", 4) == 0)
|
|
{
|
|
*s++ = '\256';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "quot;", 5) == 0)
|
|
{
|
|
*s++ = '\"';
|
|
ptr += 5;
|
|
}
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
}
|
|
else
|
|
{
|
|
if (s < (buf + sizeof(buf) - 1))
|
|
*s++ = *ptr++;
|
|
else
|
|
ptr ++;
|
|
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
}
|
|
}
|
|
|
|
if (s > buf && !pre && !head)
|
|
{
|
|
*s = '\0';
|
|
ww = (int)fl_width(buf);
|
|
|
|
// printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
|
|
// line, xx, ww, block->x, block->w);
|
|
|
|
if (needspace && xx > block->x)
|
|
ww += (int)fl_width(' ');
|
|
|
|
if ((xx + ww) > block->w)
|
|
{
|
|
line = do_align(block, line, xx, newalign, links);
|
|
xx = block->x;
|
|
yy += hh;
|
|
block->h += hh;
|
|
hh = 0;
|
|
}
|
|
|
|
if (link[0])
|
|
add_link(link, xx, yy - size, ww, size);
|
|
|
|
xx += ww;
|
|
if ((size + 2) > hh)
|
|
hh = size + 2;
|
|
|
|
needspace = 0;
|
|
}
|
|
|
|
block->end = ptr;
|
|
size_ = yy + hh;
|
|
|
|
if (ntargets_ > 1)
|
|
qsort(targets_, ntargets_, sizeof(Fl_Help_Target),
|
|
(compare_func_t)compare_targets);
|
|
|
|
if (nblocks_ > 1)
|
|
qsort(blocks_, nblocks_, sizeof(Fl_Help_Block),
|
|
(compare_func_t)compare_blocks);
|
|
|
|
if (size_ < (h() - 8))
|
|
scrollbar_.hide();
|
|
else
|
|
scrollbar_.show();
|
|
|
|
topline(topline_);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::format_table()' - Format a table...
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::format_table(int *table_width, // O - Total table width
|
|
int *columns, // O - Column widths
|
|
const char *table) // I - Pointer to start of table
|
|
{
|
|
int column, // Current column
|
|
num_columns, // Number of columns
|
|
colspan, // COLSPAN attribute
|
|
width, // Current width
|
|
temp_width, // Temporary width
|
|
max_width, // Maximum width
|
|
incell, // In a table cell?
|
|
pre, // <PRE> text?
|
|
needspace; // Need whitespace?
|
|
char *s, // Pointer into buffer
|
|
buf[1024], // Text buffer
|
|
attr[1024], // Other attribute
|
|
wattr[1024], // WIDTH attribute
|
|
hattr[1024]; // HEIGHT attribute
|
|
const char *ptr, // Pointer into table
|
|
*attrs, // Pointer to attributes
|
|
*start; // Start of element
|
|
int minwidths[MAX_COLUMNS]; // Minimum widths for each column
|
|
unsigned char font, size; // Current font and size
|
|
|
|
|
|
// Clear widths...
|
|
*table_width = 0;
|
|
for (column = 0; column < MAX_COLUMNS; column ++)
|
|
{
|
|
columns[column] = 0;
|
|
minwidths[column] = 0;
|
|
}
|
|
|
|
num_columns = 0;
|
|
colspan = 0;
|
|
max_width = 0;
|
|
pre = 0;
|
|
|
|
// Scan the table...
|
|
for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;)
|
|
{
|
|
if ((*ptr == '<' || isspace(*ptr)) && s > buf && incell)
|
|
{
|
|
// Check width...
|
|
if (needspace)
|
|
{
|
|
*s++ = ' ';
|
|
needspace = 0;
|
|
}
|
|
|
|
*s = '\0';
|
|
temp_width = (int)fl_width(buf);
|
|
s = buf;
|
|
|
|
if (temp_width > minwidths[column])
|
|
minwidths[column] = temp_width;
|
|
|
|
width += temp_width;
|
|
|
|
if (width > max_width)
|
|
max_width = width;
|
|
}
|
|
|
|
if (*ptr == '<')
|
|
{
|
|
start = ptr;
|
|
|
|
for (s = buf, ptr ++; *ptr && *ptr != '>' && !isspace(*ptr);)
|
|
if (s < (buf + sizeof(buf) - 1))
|
|
*s++ = *ptr++;
|
|
else
|
|
ptr ++;
|
|
|
|
*s = '\0';
|
|
s = buf;
|
|
|
|
attrs = ptr;
|
|
while (*ptr && *ptr != '>')
|
|
ptr ++;
|
|
|
|
if (*ptr == '>')
|
|
ptr ++;
|
|
|
|
if (strcasecmp(buf, "BR") == 0 ||
|
|
strcasecmp(buf, "HR") == 0)
|
|
{
|
|
width = 0;
|
|
needspace = 0;
|
|
}
|
|
else if (strcasecmp(buf, "TABLE") == 0 && start > table)
|
|
break;
|
|
else if (strcasecmp(buf, "CENTER") == 0 ||
|
|
strcasecmp(buf, "P") == 0 ||
|
|
strcasecmp(buf, "H1") == 0 ||
|
|
strcasecmp(buf, "H2") == 0 ||
|
|
strcasecmp(buf, "H3") == 0 ||
|
|
strcasecmp(buf, "H4") == 0 ||
|
|
strcasecmp(buf, "H5") == 0 ||
|
|
strcasecmp(buf, "H6") == 0 ||
|
|
strcasecmp(buf, "UL") == 0 ||
|
|
strcasecmp(buf, "OL") == 0 ||
|
|
strcasecmp(buf, "DL") == 0 ||
|
|
strcasecmp(buf, "LI") == 0 ||
|
|
strcasecmp(buf, "DD") == 0 ||
|
|
strcasecmp(buf, "DT") == 0 ||
|
|
strcasecmp(buf, "PRE") == 0)
|
|
{
|
|
width = 0;
|
|
needspace = 0;
|
|
|
|
if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
|
|
{
|
|
font = FL_HELVETICA_BOLD;
|
|
size = textsize_ + '7' - buf[1];
|
|
}
|
|
else if (strcasecmp(buf, "DT") == 0)
|
|
{
|
|
font = textfont_ | FL_ITALIC;
|
|
size = textsize_;
|
|
}
|
|
else if (strcasecmp(buf, "PRE") == 0)
|
|
{
|
|
font = FL_COURIER;
|
|
size = textsize_;
|
|
pre = 1;
|
|
}
|
|
else if (strcasecmp(buf, "LI") == 0)
|
|
{
|
|
width += 4 * size;
|
|
font = textfont_;
|
|
size = textsize_;
|
|
}
|
|
else
|
|
{
|
|
font = textfont_;
|
|
size = textsize_;
|
|
}
|
|
|
|
pushfont(font, size);
|
|
}
|
|
else if (strcasecmp(buf, "/CENTER") == 0 ||
|
|
strcasecmp(buf, "/P") == 0 ||
|
|
strcasecmp(buf, "/H1") == 0 ||
|
|
strcasecmp(buf, "/H2") == 0 ||
|
|
strcasecmp(buf, "/H3") == 0 ||
|
|
strcasecmp(buf, "/H4") == 0 ||
|
|
strcasecmp(buf, "/H5") == 0 ||
|
|
strcasecmp(buf, "/H6") == 0 ||
|
|
strcasecmp(buf, "/PRE") == 0 ||
|
|
strcasecmp(buf, "/UL") == 0 ||
|
|
strcasecmp(buf, "/OL") == 0 ||
|
|
strcasecmp(buf, "/DL") == 0)
|
|
{
|
|
width = 0;
|
|
needspace = 0;
|
|
|
|
popfont(font, size);
|
|
}
|
|
else if (strcasecmp(buf, "TR") == 0 || strcasecmp(buf, "/TR") == 0 ||
|
|
strcasecmp(buf, "/TABLE") == 0)
|
|
{
|
|
// printf("%s column = %d, colspan = %d, num_columns = %d\n",
|
|
// buf, column, colspan, num_columns);
|
|
|
|
if (column >= 0)
|
|
{
|
|
// This is a hack to support COLSPAN...
|
|
max_width /= colspan;
|
|
|
|
while (colspan > 0)
|
|
{
|
|
if (max_width > columns[column])
|
|
columns[column] = max_width;
|
|
|
|
column ++;
|
|
colspan --;
|
|
}
|
|
}
|
|
|
|
if (strcasecmp(buf, "/TABLE") == 0)
|
|
break;
|
|
|
|
needspace = 0;
|
|
column = -1;
|
|
width = 0;
|
|
max_width = 0;
|
|
incell = 0;
|
|
}
|
|
else if (strcasecmp(buf, "TD") == 0 ||
|
|
strcasecmp(buf, "TH") == 0)
|
|
{
|
|
// printf("BEFORE column = %d, colspan = %d, num_columns = %d\n",
|
|
// column, colspan, num_columns);
|
|
|
|
if (column >= 0)
|
|
{
|
|
// This is a hack to support COLSPAN...
|
|
max_width /= colspan;
|
|
|
|
while (colspan > 0)
|
|
{
|
|
if (max_width > columns[column])
|
|
columns[column] = max_width;
|
|
|
|
column ++;
|
|
colspan --;
|
|
}
|
|
}
|
|
else
|
|
column ++;
|
|
|
|
if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
|
|
colspan = atoi(attr);
|
|
else
|
|
colspan = 1;
|
|
|
|
// printf("AFTER column = %d, colspan = %d, num_columns = %d\n",
|
|
// column, colspan, num_columns);
|
|
|
|
if ((column + colspan) >= num_columns)
|
|
num_columns = column + colspan;
|
|
|
|
needspace = 0;
|
|
width = 0;
|
|
incell = 1;
|
|
|
|
if (strcasecmp(buf, "TH") == 0)
|
|
font = textfont_ | FL_BOLD;
|
|
else
|
|
font = textfont_;
|
|
|
|
size = textsize_;
|
|
|
|
pushfont(font, size);
|
|
|
|
if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL)
|
|
{
|
|
max_width = atoi(attr);
|
|
|
|
if (attr[strlen(attr) - 1] == '%')
|
|
max_width = max_width * w() / 100;
|
|
}
|
|
else
|
|
max_width = 0;
|
|
|
|
// printf("max_width = %d\n", max_width);
|
|
}
|
|
else if (strcasecmp(buf, "/TD") == 0 ||
|
|
strcasecmp(buf, "/TH") == 0)
|
|
{
|
|
incell = 0;
|
|
popfont(font, size);
|
|
}
|
|
else if (strcasecmp(buf, "B") == 0)
|
|
pushfont(font |= FL_BOLD, size);
|
|
else if (strcasecmp(buf, "I") == 0)
|
|
pushfont(font |= FL_ITALIC, size);
|
|
else if (strcasecmp(buf, "CODE") == 0)
|
|
pushfont(font = FL_COURIER, size);
|
|
else if (strcasecmp(buf, "KBD") == 0)
|
|
pushfont(font = FL_COURIER_BOLD, size);
|
|
else if (strcasecmp(buf, "VAR") == 0)
|
|
pushfont(font = FL_COURIER_ITALIC, size);
|
|
else if (strcasecmp(buf, "/B") == 0 ||
|
|
strcasecmp(buf, "/I") == 0 ||
|
|
strcasecmp(buf, "/CODE") == 0 ||
|
|
strcasecmp(buf, "/KBD") == 0 ||
|
|
strcasecmp(buf, "/VAR") == 0)
|
|
popfont(font, size);
|
|
else if (strcasecmp(buf, "IMG") == 0 && incell)
|
|
{
|
|
Fl_Help_Image *img = (Fl_Help_Image *)0;
|
|
|
|
|
|
get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
|
|
get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
|
|
|
|
if (get_attr(attrs, "SRC", attr, sizeof(attr)))
|
|
if ((img = add_image(attr, wattr, hattr)) != (Fl_Help_Image *)0 &&
|
|
img->image == NULL)
|
|
img = (Fl_Help_Image *)0;
|
|
|
|
if (img)
|
|
temp_width = img->w;
|
|
else
|
|
temp_width = 16;
|
|
|
|
if (temp_width > minwidths[column])
|
|
minwidths[column] = temp_width;
|
|
|
|
width += temp_width;
|
|
if (needspace)
|
|
width += (int)fl_width(' ');
|
|
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
needspace = 0;
|
|
}
|
|
}
|
|
else if (*ptr == '\n' && pre)
|
|
{
|
|
width = 0;
|
|
needspace = 0;
|
|
ptr ++;
|
|
}
|
|
else if (isspace(*ptr))
|
|
{
|
|
needspace = 1;
|
|
|
|
ptr ++;
|
|
}
|
|
else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
|
|
{
|
|
ptr ++;
|
|
|
|
if (strncasecmp(ptr, "amp;", 4) == 0)
|
|
{
|
|
*s++ = '&';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "lt;", 3) == 0)
|
|
{
|
|
*s++ = '<';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "gt;", 3) == 0)
|
|
{
|
|
*s++ = '>';
|
|
ptr += 3;
|
|
}
|
|
else if (strncasecmp(ptr, "nbsp;", 5) == 0)
|
|
{
|
|
*s++ = '\240';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "copy;", 5) == 0)
|
|
{
|
|
*s++ = '\251';
|
|
ptr += 5;
|
|
}
|
|
else if (strncasecmp(ptr, "reg;", 4) == 0)
|
|
{
|
|
*s++ = '\256';
|
|
ptr += 4;
|
|
}
|
|
else if (strncasecmp(ptr, "quot;", 5) == 0)
|
|
{
|
|
*s++ = '\"';
|
|
ptr += 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (s < (buf + sizeof(buf) - 1))
|
|
*s++ = *ptr++;
|
|
else
|
|
ptr ++;
|
|
}
|
|
}
|
|
|
|
// Now that we have scanned the entire table, adjust the table and
|
|
// cell widths to fit on the screen...
|
|
if (get_attr(table + 6, "WIDTH", attr, sizeof(attr)))
|
|
{
|
|
if (attr[strlen(attr) - 1] == '%')
|
|
*table_width = atoi(attr) * w() / 100;
|
|
else
|
|
*table_width = atoi(attr);
|
|
}
|
|
else
|
|
*table_width = 0;
|
|
|
|
// printf("num_columns = %d, table_width = %d\n", num_columns, *table_width);
|
|
|
|
if (num_columns == 0)
|
|
return;
|
|
|
|
// Add up the widths...
|
|
for (column = 0, width = 0; column < num_columns; column ++)
|
|
width += columns[column];
|
|
|
|
// printf("width = %d, w() = %d\n", width, w());
|
|
// for (column = 0; column < num_columns; column ++)
|
|
// printf(" columns[%d] = %d, minwidths[%d] = %d\n", column, columns[column],
|
|
// column, minwidths[column]);
|
|
|
|
// Adjust the width if needed...
|
|
int scale_width = *table_width;
|
|
|
|
if (scale_width == 0 && width > w())
|
|
scale_width = width;
|
|
|
|
if (width > scale_width)
|
|
{
|
|
*table_width = 0;
|
|
|
|
for (column = 0; column < num_columns; column ++)
|
|
{
|
|
if (width > 0)
|
|
{
|
|
temp_width = scale_width * columns[column] / width;
|
|
|
|
if (temp_width < minwidths[column])
|
|
temp_width = minwidths[column];
|
|
}
|
|
else
|
|
temp_width = minwidths[column];
|
|
|
|
width -= columns[column];
|
|
scale_width -= temp_width;
|
|
columns[column] = temp_width;
|
|
(*table_width) += temp_width;
|
|
}
|
|
}
|
|
else if (*table_width == 0)
|
|
*table_width = width;
|
|
|
|
// printf("FINAL table_width = %d\n", *table_width);
|
|
// for (column = 0; column < num_columns; column ++)
|
|
// printf(" columns[%d] = %d\n", column, columns[column]);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::get_align()' - Get an alignment attribute.
|
|
//
|
|
|
|
int // O - Alignment
|
|
Fl_Help_View::get_align(const char *p, // I - Pointer to start of attrs
|
|
int a) // I - Default alignment
|
|
{
|
|
char buf[255]; // Alignment value
|
|
|
|
|
|
if (get_attr(p, "ALIGN", buf, sizeof(buf)) == NULL)
|
|
return (a);
|
|
|
|
if (strcasecmp(buf, "CENTER") == 0)
|
|
return (CENTER);
|
|
else if (strcasecmp(buf, "RIGHT") == 0)
|
|
return (RIGHT);
|
|
else
|
|
return (LEFT);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::get_attr()' - Get an attribute value from the string.
|
|
//
|
|
|
|
const char * // O - Pointer to buf or NULL
|
|
Fl_Help_View::get_attr(const char *p, // I - Pointer to start of attributes
|
|
const char *n, // I - Name of attribute
|
|
char *buf, // O - Buffer for attribute value
|
|
int bufsize) // I - Size of buffer
|
|
{
|
|
char name[255], // Name from string
|
|
*ptr, // Pointer into name or value
|
|
quote; // Quote
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
while (*p && *p != '>')
|
|
{
|
|
while (isspace(*p))
|
|
p ++;
|
|
|
|
if (*p == '>' || !*p)
|
|
return (NULL);
|
|
|
|
for (ptr = name; *p && !isspace(*p) && *p != '=' && *p != '>';)
|
|
if (ptr < (name + sizeof(name) - 1))
|
|
*ptr++ = *p++;
|
|
else
|
|
p ++;
|
|
|
|
*ptr = '\0';
|
|
|
|
if (isspace(*p) || !*p || *p == '>')
|
|
buf[0] = '\0';
|
|
else
|
|
{
|
|
if (*p == '=')
|
|
p ++;
|
|
|
|
for (ptr = buf; *p && !isspace(*p) && *p != '>';)
|
|
if (*p == '\'' || *p == '\"')
|
|
{
|
|
quote = *p++;
|
|
|
|
while (*p && *p != quote)
|
|
if ((ptr - buf + 1) < bufsize)
|
|
*ptr++ = *p++;
|
|
else
|
|
p ++;
|
|
|
|
if (*p == quote)
|
|
p ++;
|
|
}
|
|
else if ((ptr - buf + 1) < bufsize)
|
|
*ptr++ = *p++;
|
|
else
|
|
p ++;
|
|
|
|
*ptr = '\0';
|
|
}
|
|
|
|
if (strcasecmp(n, name) == 0)
|
|
return (buf);
|
|
else
|
|
buf[0] = '\0';
|
|
|
|
if (*p == '>')
|
|
return (NULL);
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::get_color()' - Get an alignment attribute.
|
|
//
|
|
|
|
Fl_Color // O - Color value
|
|
Fl_Help_View::get_color(const char *n, // I - Color name
|
|
Fl_Color c) // I - Default color value
|
|
{
|
|
int rgb, r, g, b; // RGB values
|
|
|
|
|
|
if (!n)
|
|
return (c);
|
|
|
|
if (n[0] == '#')
|
|
{
|
|
// Do hex color lookup
|
|
rgb = strtol(n + 1, NULL, 16);
|
|
|
|
r = rgb >> 16;
|
|
g = (rgb >> 8) & 255;
|
|
b = rgb & 255;
|
|
|
|
if (r == g && g == b)
|
|
return (fl_gray_ramp(FL_NUM_GRAY * r / 256));
|
|
else
|
|
return (fl_color_cube((FL_NUM_RED - 1) * r / 255,
|
|
(FL_NUM_GREEN - 1) * g / 255,
|
|
(FL_NUM_BLUE - 1) * b / 255));
|
|
}
|
|
else if (strcasecmp(n, "black") == 0)
|
|
return (FL_BLACK);
|
|
else if (strcasecmp(n, "red") == 0)
|
|
return (FL_RED);
|
|
else if (strcasecmp(n, "green") == 0)
|
|
return (fl_color_cube(0, 4, 0));
|
|
else if (strcasecmp(n, "yellow") == 0)
|
|
return (FL_YELLOW);
|
|
else if (strcasecmp(n, "blue") == 0)
|
|
return (FL_BLUE);
|
|
else if (strcasecmp(n, "magenta") == 0 || strcasecmp(n, "fuchsia") == 0)
|
|
return (FL_MAGENTA);
|
|
else if (strcasecmp(n, "cyan") == 0 || strcasecmp(n, "aqua") == 0)
|
|
return (FL_CYAN);
|
|
else if (strcasecmp(n, "white") == 0)
|
|
return (FL_WHITE);
|
|
else if (strcasecmp(n, "gray") == 0 || strcasecmp(n, "grey") == 0)
|
|
return (FL_GRAY);
|
|
else if (strcasecmp(n, "lime") == 0)
|
|
return (FL_GREEN);
|
|
else if (strcasecmp(n, "maroon") == 0)
|
|
return (fl_color_cube(2, 0, 0));
|
|
else if (strcasecmp(n, "navy") == 0)
|
|
return (fl_color_cube(0, 0, 2));
|
|
else if (strcasecmp(n, "olive") == 0)
|
|
return (fl_color_cube(2, 4, 0));
|
|
else if (strcasecmp(n, "purple") == 0)
|
|
return (fl_color_cube(2, 0, 2));
|
|
else if (strcasecmp(n, "silver") == 0)
|
|
return (FL_LIGHT2);
|
|
else if (strcasecmp(n, "teal") == 0)
|
|
return (fl_color_cube(0, 4, 2));
|
|
else
|
|
return (c);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::handle()' - Handle events in the widget.
|
|
//
|
|
|
|
int // O - 1 if we handled it, 0 otherwise
|
|
Fl_Help_View::handle(int event) // I - Event to handle
|
|
{
|
|
int i; // Looping var
|
|
int xx, yy; // Adjusted mouse position
|
|
Fl_Help_Link *link; // Current link
|
|
char target[32]; // Current target
|
|
|
|
|
|
switch (event)
|
|
{
|
|
case FL_PUSH :
|
|
if (Fl_Group::handle(event))
|
|
return (1);
|
|
|
|
case FL_MOVE :
|
|
xx = Fl::event_x() - x();
|
|
yy = Fl::event_y() - y() + topline_;
|
|
break;
|
|
|
|
default :
|
|
return (Fl_Group::handle(event));
|
|
}
|
|
|
|
// Handle mouse clicks on links...
|
|
for (i = nlinks_, link = links_; i > 0; i --, link ++)
|
|
if (xx >= link->x && xx < link->w &&
|
|
yy >= link->y && yy < link->h)
|
|
break;
|
|
|
|
if (!i)
|
|
{
|
|
fl_cursor(FL_CURSOR_DEFAULT);
|
|
return (1);
|
|
}
|
|
|
|
// Change the cursor for FL_MOTION events, and go to the link for
|
|
// clicks...
|
|
if (event == FL_MOVE)
|
|
fl_cursor(FL_CURSOR_HAND);
|
|
else
|
|
{
|
|
fl_cursor(FL_CURSOR_DEFAULT);
|
|
|
|
strncpy(target, link->name, sizeof(target) - 1);
|
|
target[sizeof(target) - 1] = '\0';
|
|
|
|
set_changed();
|
|
|
|
if (strcmp(link->filename, filename_) != 0 && link->filename[0])
|
|
{
|
|
char dir[1024]; // Current directory
|
|
char temp[1024], // Temporary filename
|
|
*tempptr; // Pointer into temporary filename
|
|
|
|
|
|
if (strchr(directory_, ':') != NULL && strchr(link->filename, ':') == NULL)
|
|
{
|
|
if (link->filename[0] == '/')
|
|
{
|
|
strcpy(temp, directory_);
|
|
if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
|
|
strcpy(tempptr, link->filename);
|
|
else
|
|
strcat(temp, link->filename);
|
|
}
|
|
else
|
|
sprintf(temp, "%s/%s", directory_, link->filename);
|
|
|
|
load(temp);
|
|
}
|
|
else if (link->filename[0] != '/' && strchr(link->filename, ':') == NULL)
|
|
{
|
|
if (directory_[0])
|
|
sprintf(temp, "%s/%s", directory_, link->filename);
|
|
else
|
|
{
|
|
getcwd(dir, sizeof(dir));
|
|
sprintf(temp, "file:%s/%s", dir, link->filename);
|
|
}
|
|
|
|
load(temp);
|
|
}
|
|
else
|
|
load(link->filename);
|
|
}
|
|
else if (target[0])
|
|
topline(target);
|
|
else
|
|
topline(0);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::Fl_Help_View()' - Build a Fl_Help_View widget.
|
|
//
|
|
|
|
Fl_Help_View::Fl_Help_View(int xx, // I - Left position
|
|
int yy, // I - Top position
|
|
int ww, // I - Width in pixels
|
|
int hh, // I - Height in pixels
|
|
const char *l)
|
|
: Fl_Group(xx, yy, ww, hh, l),
|
|
scrollbar_(xx + ww - 17, yy, 17, hh)
|
|
{
|
|
link_ = (Fl_Help_Func *)0;
|
|
|
|
filename_[0] = '\0';
|
|
value_ = NULL;
|
|
|
|
ablocks_ = 0;
|
|
nblocks_ = 0;
|
|
blocks_ = (Fl_Help_Block *)0;
|
|
|
|
nimage_ = 0;
|
|
aimage_ = 0;
|
|
image_ = (Fl_Help_Image *)0;
|
|
|
|
if (!broken_image)
|
|
broken_image = new Fl_Pixmap((char **)broken_xpm);
|
|
|
|
alinks_ = 0;
|
|
nlinks_ = 0;
|
|
links_ = (Fl_Help_Link *)0;
|
|
|
|
atargets_ = 0;
|
|
ntargets_ = 0;
|
|
targets_ = (Fl_Help_Target *)0;
|
|
|
|
nfonts_ = 0;
|
|
textfont_ = FL_TIMES;
|
|
textsize_ = 12;
|
|
|
|
topline_ = 0;
|
|
size_ = 0;
|
|
|
|
color(FL_WHITE);
|
|
textcolor(FL_BLACK);
|
|
selection_color(FL_BLUE);
|
|
|
|
scrollbar_.value(0, hh, 0, 1);
|
|
scrollbar_.step(8.0);
|
|
scrollbar_.show();
|
|
scrollbar_.callback(scrollbar_callback);
|
|
|
|
end();
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::~Fl_Help_View()' - Destroy a Fl_Help_View widget.
|
|
//
|
|
|
|
Fl_Help_View::~Fl_Help_View()
|
|
{
|
|
int i; // Looping var
|
|
Fl_Help_Image *img; // Current image
|
|
|
|
|
|
if (nblocks_)
|
|
free(blocks_);
|
|
if (nlinks_)
|
|
free(links_);
|
|
if (ntargets_)
|
|
free(targets_);
|
|
if (value_)
|
|
free((void *)value_);
|
|
if (image_)
|
|
{
|
|
for (i = nimage_, img = image_; i > 0; i --, img ++)
|
|
{
|
|
delete img->image;
|
|
if (!img->copy)
|
|
free(img->data);
|
|
free(img->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::load()' - Load the specified file.
|
|
//
|
|
|
|
int // O - 0 on success, -1 on error
|
|
Fl_Help_View::load(const char *f)// I - Filename to load (may also have target)
|
|
{
|
|
FILE *fp; // File to read from
|
|
long len; // Length of file
|
|
char *target; // Target in file
|
|
char *slash; // Directory separator
|
|
const char *localname; // Local filename
|
|
char error[1024]; // Error buffer
|
|
|
|
|
|
strcpy(filename_, f);
|
|
strcpy(directory_, filename_);
|
|
|
|
if ((slash = strrchr(directory_, '/')) == NULL)
|
|
directory_[0] = '\0';
|
|
else if (slash > directory_ && slash[-1] != '/')
|
|
*slash = '\0';
|
|
|
|
if ((target = strrchr(filename_, '#')) != NULL)
|
|
*target++ = '\0';
|
|
|
|
if (link_)
|
|
localname = (*link_)(filename_);
|
|
else
|
|
localname = filename_;
|
|
|
|
if (localname != NULL &&
|
|
(strncmp(localname, "ftp:", 4) == 0 ||
|
|
strncmp(localname, "http:", 5) == 0 ||
|
|
strncmp(localname, "https:", 6) == 0 ||
|
|
strncmp(localname, "ipp:", 4) == 0 ||
|
|
strncmp(localname, "mailto:", 7) == 0 ||
|
|
strncmp(localname, "news:", 5) == 0))
|
|
localname = NULL; // Remote link wasn't resolved...
|
|
else if (localname != NULL &&
|
|
strncmp(localname, "file:", 5) == 0)
|
|
localname += 5; // Adjust for local filename...
|
|
|
|
if (value_ != NULL)
|
|
{
|
|
free((void *)value_);
|
|
value_ = NULL;
|
|
}
|
|
|
|
if (localname)
|
|
{
|
|
if ((fp = fopen(localname, "rb")) != NULL)
|
|
{
|
|
fseek(fp, 0, SEEK_END);
|
|
len = ftell(fp);
|
|
rewind(fp);
|
|
|
|
value_ = (const char *)calloc(len + 1, 1);
|
|
fread((void *)value_, 1, len, fp);
|
|
fclose(fp);
|
|
}
|
|
else
|
|
{
|
|
sprintf(error, "%s: %s\n", localname, strerror(errno));
|
|
value_ = strdup(error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(error, "%s: %s\n", filename_, strerror(errno));
|
|
value_ = strdup(error);
|
|
}
|
|
|
|
format();
|
|
|
|
if (target)
|
|
topline(target);
|
|
else
|
|
topline(0);
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::load_gif()' - Load a GIF image file...
|
|
//
|
|
|
|
int // O - 0 = success, -1 = fail
|
|
Fl_Help_View::load_gif(Fl_Help_Image *img,// I - Image pointer
|
|
FILE *fp) // I - File to load from
|
|
{
|
|
unsigned char buf[1024]; // Input buffer
|
|
gif_cmap_t cmap; // Colormap
|
|
int ncolors, // Bits per pixel
|
|
transparent; // Transparent color index
|
|
|
|
|
|
// Read the header; we already know it is a GIF file...
|
|
fread(buf, 13, 1, fp);
|
|
|
|
img->w = (buf[7] << 8) | buf[6];
|
|
img->h = (buf[9] << 8) | buf[8];
|
|
ncolors = 2 << (buf[10] & 0x07);
|
|
|
|
if (buf[10] & GIF_COLORMAP)
|
|
if (!gif_read_cmap(fp, ncolors, cmap))
|
|
return (0);
|
|
|
|
transparent = -1;
|
|
|
|
for (;;)
|
|
{
|
|
switch (getc(fp))
|
|
{
|
|
case ';' : // End of image
|
|
return (0); // Early end of file
|
|
|
|
case '!' : // Extension record
|
|
buf[0] = getc(fp);
|
|
if (buf[0] == 0xf9) // Graphic Control Extension
|
|
{
|
|
gif_get_block(fp, buf);
|
|
if (buf[0] & 1) // Get transparent color index
|
|
transparent = buf[3];
|
|
}
|
|
|
|
while (gif_get_block(fp, buf) != 0);
|
|
break;
|
|
|
|
case ',' : // Image data
|
|
fread(buf, 9, 1, fp);
|
|
|
|
if (buf[8] & GIF_COLORMAP)
|
|
{
|
|
ncolors = 2 << (buf[8] & 0x07);
|
|
|
|
if (!gif_read_cmap(fp, ncolors, cmap))
|
|
return (0);
|
|
}
|
|
|
|
if (transparent >= 0)
|
|
{
|
|
unsigned rgba = fltk_colors[bgcolor_];
|
|
|
|
|
|
// Map transparent color to background color...
|
|
cmap[transparent][0] = rgba >> 24;
|
|
cmap[transparent][1] = rgba >> 16;
|
|
cmap[transparent][2] = rgba >> 8;
|
|
}
|
|
|
|
img->w = (buf[5] << 8) | buf[4];
|
|
img->h = (buf[7] << 8) | buf[6];
|
|
img->d = 3;
|
|
img->data = (unsigned char *)malloc(img->w * img->h * img->d);
|
|
if (img->data == NULL)
|
|
return (0);
|
|
|
|
return (gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef HAVE_LIBJPEG
|
|
//
|
|
// 'Fl_Help_View::load_jpeg()' - Load a JPEG image file.
|
|
//
|
|
|
|
int // O - 0 = success, -1 = fail
|
|
Fl_Help_View::load_jpeg(Fl_Help_Image *img, // I - Image pointer
|
|
FILE *fp) // I - File to load from
|
|
{
|
|
struct jpeg_decompress_struct cinfo; // Decompressor info
|
|
struct jpeg_error_mgr jerr; // Error handler info
|
|
JSAMPROW row; // Sample row pointer
|
|
|
|
|
|
cinfo.err = jpeg_std_error(&jerr);
|
|
jpeg_create_decompress(&cinfo);
|
|
jpeg_stdio_src(&cinfo, fp);
|
|
jpeg_read_header(&cinfo, 1);
|
|
|
|
cinfo.quantize_colors = 0;
|
|
cinfo.out_color_space = JCS_RGB;
|
|
cinfo.out_color_components = 3;
|
|
cinfo.output_components = 3;
|
|
|
|
jpeg_calc_output_dimensions(&cinfo);
|
|
|
|
img->w = cinfo.output_width;
|
|
img->h = cinfo.output_height;
|
|
img->d = cinfo.output_components;
|
|
img->data = (unsigned char *)malloc(img->w * img->h * img->d);
|
|
|
|
if (img->data == NULL)
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
return (0);
|
|
}
|
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
while (cinfo.output_scanline < cinfo.output_height)
|
|
{
|
|
row = (JSAMPROW)(img->data +
|
|
cinfo.output_scanline * cinfo.output_width *
|
|
cinfo.output_components);
|
|
jpeg_read_scanlines(&cinfo, &row, (JDIMENSION)1);
|
|
}
|
|
|
|
jpeg_finish_decompress(&cinfo);
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return (1);
|
|
}
|
|
#endif // HAVE_LIBJPEG
|
|
|
|
|
|
#ifdef HAVE_LIBPNG
|
|
//
|
|
// 'Fl_Help_View::load_png()' - Load a PNG image file.
|
|
//
|
|
|
|
int // O - 0 = success, -1 = fail
|
|
Fl_Help_View::load_png(Fl_Help_Image *img,// I - Image pointer
|
|
FILE *fp) // I - File to read from
|
|
{
|
|
int i; // Looping var
|
|
png_structp pp; // PNG read pointer
|
|
png_infop info; // PNG info pointers
|
|
png_bytep *rows; // PNG row pointers
|
|
png_color_16 bg; // Background color
|
|
|
|
|
|
// Setup the PNG data structures...
|
|
pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
info = png_create_info_struct(pp);
|
|
|
|
// Initialize the PNG read "engine"...
|
|
png_init_io(pp, fp);
|
|
|
|
// Get the image dimensions and convert to grayscale or RGB...
|
|
png_read_info(pp, info);
|
|
|
|
if (info->color_type == PNG_COLOR_TYPE_PALETTE)
|
|
png_set_expand(pp);
|
|
|
|
if (info->color_type == PNG_COLOR_TYPE_GRAY)
|
|
img->d = 1;
|
|
else
|
|
img->d = 3;
|
|
|
|
img->w = (int)info->width;
|
|
img->h = (int)info->height;
|
|
img->data = (unsigned char *)malloc(img->w * img->h * 3);
|
|
|
|
if (info->bit_depth < 8)
|
|
{
|
|
png_set_packing(pp);
|
|
png_set_expand(pp);
|
|
|
|
if (info->valid & PNG_INFO_sBIT)
|
|
png_set_shift(pp, &(info->sig_bit));
|
|
}
|
|
else if (info->bit_depth == 16)
|
|
png_set_strip_16(pp);
|
|
|
|
#ifdef HAVE_PNG_GET_VALID
|
|
// Handle transparency...
|
|
if (png_get_valid(pp, info, PNG_INFO_tRNS))
|
|
png_set_tRNS_to_alpha(pp);
|
|
#endif // HAVE_PNG_GET_VALID
|
|
|
|
// Background color...
|
|
unsigned rgba = fltk_colors[bgcolor_];
|
|
|
|
bg.red = 65535 * (rgba >> 24) / 255;
|
|
bg.green = 65535 * ((rgba >> 16) & 255) / 255;
|
|
bg.blue = 65535 * ((rgba >> 8) & 255) / 255;
|
|
|
|
png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
|
|
|
|
// Allocate pointers...
|
|
rows = (png_bytep *)calloc(info->height, sizeof(png_bytep));
|
|
|
|
for (i = 0; i < (int)info->height; i ++)
|
|
if (info->color_type == PNG_COLOR_TYPE_GRAY)
|
|
rows[i] = img->data + i * img->w;
|
|
else
|
|
rows[i] = img->data + i * img->w * 3;
|
|
|
|
// Read the image, handling interlacing as needed...
|
|
for (i = png_set_interlace_handling(pp); i > 0; i --)
|
|
png_read_rows(pp, rows, NULL, img->h);
|
|
|
|
// Free memory and return...
|
|
free(rows);
|
|
|
|
png_read_end(pp, info);
|
|
png_read_destroy(pp, info, NULL);
|
|
|
|
return (1);
|
|
}
|
|
#endif // HAVE_LIBPNG
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::resize()' - Resize the help widget.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::resize(int xx, // I - New left position
|
|
int yy, // I - New top position
|
|
int ww, // I - New width
|
|
int hh) // I - New height
|
|
{
|
|
Fl_Widget::resize(xx, yy, ww, hh);
|
|
scrollbar_.resize(xx + ww - 17, yy, 17, hh);
|
|
|
|
format();
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::topline()' - Set the top line to the named target.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::topline(const char *n) // I - Target name
|
|
{
|
|
Fl_Help_Target key, // Target name key
|
|
*target; // Pointer to matching target
|
|
|
|
|
|
if (ntargets_ == 0)
|
|
return;
|
|
|
|
strncpy(key.name, n, sizeof(key.name) - 1);
|
|
key.name[sizeof(key.name) - 1] = '\0';
|
|
|
|
target = (Fl_Help_Target *)bsearch(&key, targets_, ntargets_, sizeof(Fl_Help_Target),
|
|
(compare_func_t)compare_targets);
|
|
|
|
if (target != NULL)
|
|
topline(target->y);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::topline()' - Set the top line by number.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::topline(int t) // I - Top line number
|
|
{
|
|
if (!value_)
|
|
return;
|
|
|
|
if (size_ < (h() - 8) || t < 0)
|
|
t = 0;
|
|
else if (t > size_)
|
|
t = size_;
|
|
|
|
topline_ = t;
|
|
|
|
scrollbar_.value(topline_, h(), 0, size_);
|
|
|
|
do_callback();
|
|
clear_changed();
|
|
|
|
redraw();
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::value()' - Set the help text directly.
|
|
//
|
|
|
|
void
|
|
Fl_Help_View::value(const char *v) // I - Text to view
|
|
{
|
|
if (!v)
|
|
return;
|
|
|
|
if (value_ != NULL)
|
|
free((void *)value_);
|
|
|
|
value_ = strdup(v);
|
|
|
|
format();
|
|
|
|
set_changed();
|
|
topline(0);
|
|
}
|
|
|
|
|
|
//
|
|
// 'Fl_Help_View::compare_blocks()' - Compare two blocks.
|
|
//
|
|
|
|
int // O - Result of comparison
|
|
Fl_Help_View::compare_blocks(const void *a, // I - First block
|
|
const void *b) // I - Second block
|
|
{
|
|
return (((Fl_Help_Block *)a)->y - ((Fl_Help_Block *)b)->y);
|
|
}
|
|
|
|
|
|
//
|
|
// 'gif_read_cmap()' - Read the colormap from a GIF file...
|
|
//
|
|
|
|
static int // O - -1 = error, 0 = success
|
|
gif_read_cmap(FILE *fp, // I - File to read from
|
|
int ncolors, // I - Number of colors
|
|
gif_cmap_t cmap) // O - Colormap
|
|
{
|
|
// Read the colormap...
|
|
if (fread(cmap, 3, ncolors, fp) < (size_t)ncolors)
|
|
return (0);
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
//
|
|
// 'gif_get_block()' - Read a GIF data block...
|
|
//
|
|
|
|
static int // O - Number characters read
|
|
gif_get_block(FILE *fp, // I - File to read from
|
|
unsigned char *buf) // I - Input buffer
|
|
{
|
|
int count; // Number of character to read
|
|
|
|
|
|
// Read the count byte followed by the data from the file...
|
|
if ((count = getc(fp)) == EOF)
|
|
{
|
|
gif_eof = 1;
|
|
return (-1);
|
|
}
|
|
else if (count == 0)
|
|
gif_eof = 1;
|
|
else if (fread(buf, 1, count, fp) < (size_t)count)
|
|
{
|
|
gif_eof = 1;
|
|
return (-1);
|
|
}
|
|
else
|
|
gif_eof = 0;
|
|
|
|
return (count);
|
|
}
|
|
|
|
|
|
//
|
|
// 'gif_get_code()' - Get a LZW code from the file...
|
|
//
|
|
|
|
static int // O - LZW code
|
|
gif_get_code(FILE *fp, // I - File to read from
|
|
int code_size, // I - Size of code in bits
|
|
int first_time) // I - 1 = first time, 0 = not first time
|
|
{
|
|
unsigned i, j, // Looping vars
|
|
ret; // Return value
|
|
int count; // Number of bytes read
|
|
static unsigned char buf[280]; // Input buffer
|
|
static unsigned curbit, // Current bit
|
|
lastbit, // Last bit in buffer
|
|
done, // Done with this buffer?
|
|
last_byte; // Last byte in buffer
|
|
static unsigned bits[8] = // Bit masks for codes
|
|
{
|
|
0x01, 0x02, 0x04, 0x08,
|
|
0x10, 0x20, 0x40, 0x80
|
|
};
|
|
|
|
|
|
if (first_time)
|
|
{
|
|
// Just initialize the input buffer...
|
|
curbit = 0;
|
|
lastbit = 0;
|
|
done = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
if ((curbit + code_size) >= lastbit)
|
|
{
|
|
// Don't have enough bits to hold the code...
|
|
if (done)
|
|
return (-1); // Sorry, no more...
|
|
|
|
// Move last two bytes to front of buffer...
|
|
if (last_byte > 1)
|
|
{
|
|
buf[0] = buf[last_byte - 2];
|
|
buf[1] = buf[last_byte - 1];
|
|
last_byte = 2;
|
|
}
|
|
else if (last_byte == 1)
|
|
{
|
|
buf[0] = buf[last_byte - 1];
|
|
last_byte = 1;
|
|
}
|
|
|
|
// Read in another buffer...
|
|
if ((count = gif_get_block (fp, buf + last_byte)) <= 0)
|
|
{
|
|
// Whoops, no more data!
|
|
done = 1;
|
|
return (-1);
|
|
}
|
|
|
|
// Update buffer state...
|
|
curbit = (curbit - lastbit) + 8 * last_byte;
|
|
last_byte += count;
|
|
lastbit = last_byte * 8;
|
|
}
|
|
|
|
ret = 0;
|
|
for (ret = 0, i = curbit + code_size - 1, j = code_size;
|
|
j > 0;
|
|
i --, j --)
|
|
ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0);
|
|
|
|
curbit += code_size;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
//
|
|
// 'gif_read_lzw()' - Read a byte from the LZW stream...
|
|
//
|
|
|
|
static int // I - Byte from stream
|
|
gif_read_lzw(FILE *fp, // I - File to read from
|
|
int first_time, // I - 1 = first time, 0 = not first time
|
|
int input_code_size) // I - Code size in bits
|
|
{
|
|
int i, // Looping var
|
|
code, // Current code
|
|
incode; // Input code
|
|
static short fresh = 0, // 1 = empty buffers
|
|
code_size, // Current code size
|
|
set_code_size, // Initial code size set
|
|
max_code, // Maximum code used
|
|
max_code_size, // Maximum code size
|
|
firstcode, // First code read
|
|
oldcode, // Last code read
|
|
clear_code, // Clear code for LZW input
|
|
end_code, // End code for LZW input
|
|
table[2][4096], // String table
|
|
stack[8192], // Output stack
|
|
*sp; // Current stack pointer
|
|
|
|
|
|
if (first_time)
|
|
{
|
|
// Setup LZW state...
|
|
set_code_size = input_code_size;
|
|
code_size = set_code_size + 1;
|
|
clear_code = 1 << set_code_size;
|
|
end_code = clear_code + 1;
|
|
max_code_size = 2 * clear_code;
|
|
max_code = clear_code + 2;
|
|
|
|
// Initialize input buffers...
|
|
gif_get_code(fp, 0, 1);
|
|
|
|
// Wipe the decompressor table...
|
|
fresh = 1;
|
|
|
|
for (i = 0; i < clear_code; i ++)
|
|
{
|
|
table[0][i] = 0;
|
|
table[1][i] = i;
|
|
}
|
|
|
|
for (; i < 4096; i ++)
|
|
table[0][i] = table[1][0] = 0;
|
|
|
|
sp = stack;
|
|
|
|
return (0);
|
|
}
|
|
else if (fresh)
|
|
{
|
|
fresh = 0;
|
|
|
|
do
|
|
firstcode = oldcode = gif_get_code(fp, code_size, 0);
|
|
while (firstcode == clear_code);
|
|
|
|
return (firstcode);
|
|
}
|
|
|
|
if (sp > stack)
|
|
return (*--sp);
|
|
|
|
while ((code = gif_get_code (fp, code_size, 0)) >= 0)
|
|
{
|
|
if (code == clear_code)
|
|
{
|
|
for (i = 0; i < clear_code; i ++)
|
|
{
|
|
table[0][i] = 0;
|
|
table[1][i] = i;
|
|
}
|
|
|
|
for (; i < 4096; i ++)
|
|
table[0][i] = table[1][i] = 0;
|
|
|
|
code_size = set_code_size + 1;
|
|
max_code_size = 2 * clear_code;
|
|
max_code = clear_code + 2;
|
|
|
|
sp = stack;
|
|
|
|
firstcode = oldcode = gif_get_code(fp, code_size, 0);
|
|
|
|
return (firstcode);
|
|
}
|
|
else if (code == end_code)
|
|
{
|
|
unsigned char buf[260];
|
|
|
|
|
|
if (!gif_eof)
|
|
while (gif_get_block(fp, buf) > 0);
|
|
|
|
return (-2);
|
|
}
|
|
|
|
incode = code;
|
|
|
|
if (code >= max_code)
|
|
{
|
|
*sp++ = firstcode;
|
|
code = oldcode;
|
|
}
|
|
|
|
while (code >= clear_code)
|
|
{
|
|
*sp++ = table[1][code];
|
|
if (code == table[0][code])
|
|
return (255);
|
|
|
|
code = table[0][code];
|
|
}
|
|
|
|
*sp++ = firstcode = table[1][code];
|
|
code = max_code;
|
|
|
|
if (code < 4096)
|
|
{
|
|
table[0][code] = oldcode;
|
|
table[1][code] = firstcode;
|
|
max_code ++;
|
|
|
|
if (max_code >= max_code_size && max_code_size < 4096)
|
|
{
|
|
max_code_size *= 2;
|
|
code_size ++;
|
|
}
|
|
}
|
|
|
|
oldcode = incode;
|
|
|
|
if (sp > stack)
|
|
return (*--sp);
|
|
}
|
|
|
|
return (code);
|
|
}
|
|
|
|
|
|
//
|
|
// 'gif_read_image()' - Read a GIF image stream...
|
|
//
|
|
|
|
static int // I - 0 = success, -1 = failure
|
|
gif_read_image(FILE *fp, // I - Input file
|
|
Fl_Help_Image *img, // I - Image pointer
|
|
gif_cmap_t cmap, // I - Colormap
|
|
int interlace) // I - Non-zero = interlaced image
|
|
{
|
|
unsigned char code_size, // Code size
|
|
*temp; // Current pixel
|
|
int xpos, // Current X position
|
|
ypos, // Current Y position
|
|
pass; // Current pass
|
|
int pixel; // Current pixel
|
|
static int xpasses[4] = { 8, 8, 4, 2 },
|
|
ypasses[5] = { 0, 4, 2, 1, 999999 };
|
|
|
|
|
|
xpos = 0;
|
|
ypos = 0;
|
|
pass = 0;
|
|
code_size = getc(fp);
|
|
|
|
if (gif_read_lzw(fp, 1, code_size) < 0)
|
|
return (0);
|
|
|
|
temp = img->data;
|
|
|
|
while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0)
|
|
{
|
|
temp[0] = cmap[pixel][0];
|
|
|
|
if (img->d > 1)
|
|
{
|
|
temp[1] = cmap[pixel][1];
|
|
temp[2] = cmap[pixel][2];
|
|
}
|
|
|
|
xpos ++;
|
|
temp += img->d;
|
|
if (xpos == img->w)
|
|
{
|
|
xpos = 0;
|
|
|
|
if (interlace)
|
|
{
|
|
ypos += xpasses[pass];
|
|
temp += (xpasses[pass] - 1) * img->w * img->d;
|
|
|
|
if (ypos >= img->h)
|
|
{
|
|
pass ++;
|
|
|
|
ypos = ypasses[pass];
|
|
temp = img->data + ypos * img->w * img->d;
|
|
}
|
|
}
|
|
else
|
|
ypos ++;
|
|
}
|
|
|
|
if (ypos >= img->h)
|
|
break;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
//
|
|
// 'scrollbar_callback()' - A callback for the scrollbar.
|
|
//
|
|
|
|
static void
|
|
scrollbar_callback(Fl_Widget *s, void *)
|
|
{
|
|
((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value()));
|
|
}
|
|
|
|
|
|
//
|
|
// End of "$Id: Fl_Help_View.cxx,v 1.1.2.2 2001/10/01 19:33:22 easysw Exp $".
|
|
//
|