diff options
Diffstat (limited to 'SrcUnix/espws-2.0/HelpView.cxx')
-rw-r--r-- | SrcUnix/espws-2.0/HelpView.cxx | 1799 |
1 files changed, 1799 insertions, 0 deletions
diff --git a/SrcUnix/espws-2.0/HelpView.cxx b/SrcUnix/espws-2.0/HelpView.cxx new file mode 100644 index 0000000..2370338 --- /dev/null +++ b/SrcUnix/espws-2.0/HelpView.cxx @@ -0,0 +1,1799 @@ +// +// "$Id: HelpView.cxx,v 1.22 2000/03/19 23:27:14 mike Exp $" +// +// Help Viewer widget routines. +// +// Copyright 1997-2000 by Easy Software Products. +// +// These coded instructions, statements, and computer programs are the +// property of Easy Software Products and are protected by Federal +// copyright law. Distribution and use rights are outblockd in the file +// "COPYING" which should have been included with this file. If this +// file is missing or damaged please contact Easy Software Products +// at: +// +// Attn: ESP Licensing Information +// Easy Software Products +// 44141 Airport View Drive, Suite 204 +// Hollywood, Maryland 20636-3111 USA +// +// Voice: (301) 373-9600 +// EMail: info@easysw.com +// WWW: http://www.easysw.com +// +// Contents: +// +// HelpView::add_block() - Add a text block to the list. +// HelpView::add_link() - Add a new link to the list. +// HelpView::add_target() - Add a new target to the list. +// HelpView::compare_targets() - Compare two targets. +// HelpView::do_align() - Compute the alignment for a line in a block. +// HelpView::draw() - Draw the HelpView widget. +// HelpView::format() - Format the help text. +// HelpView::get_align() - Get an alignment attribute. +// HelpView::get_attr() - Get an attribute value from the string. +// HelpView::get_color() - Get an alignment attribute. +// HelpView::handle() - Handle events in the widget. +// HelpView::HelpView() - Build a HelpView widget. +// HelpView::~HelpView() - Destroy a HelpView widget. +// HelpView::load() - Load the specified file. +// HelpView::resize() - Resize the help widget. +// HelpView::topline() - Set the top line to the named target. +// HelpView::topline() - Set the top line by number. +// HelpView::value() - Set the help text directly. +// scrollbar_callback() - A callback for the scrollbar. +// + +// +// Include necessary header files... +// + +#include "HelpView.h" +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <errno.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 + + +// +// Local functions... +// + +static void scrollbar_callback(Fl_Widget *s, void *); + + +// +// 'HelpView::add_block()' - Add a text block to the list. +// + +HelpBlock * // O - Pointer to new block +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 + uchar border) // I - Draw border? +{ + HelpBlock *temp; // New block + + + if (nblocks_ >= ablocks_) + { + ablocks_ += 16; + + if (ablocks_ == 16) + blocks_ = (HelpBlock *)malloc(sizeof(HelpBlock) * ablocks_); + else + blocks_ = (HelpBlock *)realloc(blocks_, sizeof(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); +} + + +// +// 'HelpView::add_link()' - Add a new link to the list. +// + +void +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 +{ + HelpLink *temp; // New link + char *target; // Pointer to target name + + + if (nlinks_ >= alinks_) + { + alinks_ += 16; + + if (alinks_ == 16) + links_ = (HelpLink *)malloc(sizeof(HelpLink) * alinks_); + else + links_ = (HelpLink *)realloc(links_, sizeof(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_ ++; +} + + +// +// 'HelpView::add_target()' - Add a new target to the list. +// + +void +HelpView::add_target(const char *n, // I - Name of target + int yy) // I - Y position of target +{ + HelpTarget *temp; // New target + + + if (ntargets_ >= atargets_) + { + atargets_ += 16; + + if (atargets_ == 16) + targets_ = (HelpTarget *)malloc(sizeof(HelpTarget) * atargets_); + else + targets_ = (HelpTarget *)realloc(targets_, sizeof(HelpTarget) * atargets_); + } + + temp = targets_ + ntargets_; + + temp->y = yy; + strncpy(temp->name, n, sizeof(temp->name)); + temp->name[sizeof(temp->name) - 1] = '\0'; + + ntargets_ ++; +} + + +// +// 'HelpView::compare_targets()' - Compare two targets. +// + +int // O - Result of comparison +HelpView::compare_targets(const HelpTarget *t0, // I - First target + const HelpTarget *t1) // I - Second target +{ + return (strcasecmp(t0->name, t1->name)); +} + + +// +// 'HelpView::do_align()' - Compute the alignment for a line in a block. +// + +int // O - New line +HelpView::do_align(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; + case LEFT : // 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); +} + + +// +// 'HelpView::draw()' - Draw the HelpView widget. +// + +void +HelpView::draw() +{ + int i; // Looping var + const 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 + uchar 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 && + get_attr(attrs, "ALT", attr, sizeof(attr)) != NULL) + { + // Show alt text... + sprintf(buf, "[%s]", attr); + 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 (*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(); +} + + +// +// 'HelpView::format()' - Format the help text. +// + +void +HelpView::format() +{ + 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 + 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 + uchar font, size; // Current font and size + uchar border; // Draw border? + int align, // Current 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[200]; // Column widths + + + nblocks_ = 0; + nlinks_ = 0; + ntargets_ = 0; + size_ = 0; + bgcolor_ = color(); + textcolor_ = textcolor(); + linkcolor_ = selection_color(); + + strcpy(title_, "Untitled"); + + if (!value_) + return; + + initfont(font, size); + + line = 0; + links = 0; + xx = 4; + yy = size + 2; + hh = 0; + block = add_block(value_, xx, yy, w() - 24, 0); + row = 0; + head = 0; + pre = 0; + align = 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, align, 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, align, 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; + + 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, align, 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, align, 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) + align = CENTER; + else + align = get_align(attrs, LEFT); + } + else if (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, align, 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; + } + + 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; + align = LEFT; + } + else if (strcasecmp(buf, "TR") == 0) + { + block->end = start; + line = do_align(block, line, xx, align, 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, align, 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, align, 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; + + align = 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 && + get_attr(attrs, "ALT", attr, sizeof(attr)) != NULL) + { + // Show alt text... + ww = (int)(fl_width(attr) + fl_width('[') + fl_width(']')); + + if (needspace && xx > block->x) + ww += (int)fl_width(' '); + + if ((xx + ww) > block->w) + { + line = do_align(block, line, xx, align, 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 (*ptr == '\n' && pre) + { + if (link[0]) + add_link(link, xx, yy - hh, ww, hh); + + line = do_align(block, line, xx, align, 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, align, 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(HelpTarget), + (int (*)(const void *, const void *))compare_targets); + + if (size_ < (h() - 8)) + scrollbar_.hide(); + else + scrollbar_.show(); + + topline(topline_); +} + + +// +// 'HelpView::get_align()' - Get an alignment attribute. +// + +int // O - Alignment +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); +} + + +// +// 'HelpView::get_attr()' - Get an attribute value from the string. +// + +const char * // O - Pointer to buf or NULL +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 + + + 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); + + if (*p == '>') + return (NULL); + } + + return (NULL); +} + + +// +// 'HelpView::get_color()' - Get an alignment attribute. +// + +Fl_Color // O - Color value +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); +} + + +// +// 'HelpView::handle()' - Handle events in the widget. +// + +int // O - 1 if we handled it, 0 otherwise +HelpView::handle(int event) // I - Event to handle +{ + int i; // Looping var + int xx, yy; // Adjusted mouse position + HelpLink *link; // Current link + char target[32]; // Current target + + + switch (event) + { + case FL_MOVE : + case FL_PUSH : + 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 + + + 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); +} + + +// +// 'HelpView::HelpView()' - Build a HelpView widget. +// + +HelpView::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) +{ + filename_[0] = '\0'; + value_ = NULL; + + ablocks_ = 0; + nblocks_ = 0; + blocks_ = (HelpBlock *)0; + + alinks_ = 0; + nlinks_ = 0; + links_ = (HelpLink *)0; + + atargets_ = 0; + ntargets_ = 0; + targets_ = (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(); +} + + +// +// 'HelpView::~HelpView()' - Destroy a HelpView widget. +// + +HelpView::~HelpView() +{ + if (nblocks_) + free(blocks_); + if (nlinks_) + free(links_); + if (ntargets_) + free(targets_); + if (value_) + free((void *)value_); +} + + +// +// 'HelpView::load()' - Load the specified file. +// + +int // O - 0 on success, -1 on error +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 + value_ = strdup("File or link could not be opened.\n"); + + format(); + + if (target) + topline(target); + else + topline(0); + + return (0); +} + + +// +// 'HelpView::resize()' - Resize the help widget. +// + +void +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(); +} + + +// +// 'HelpView::topline()' - Set the top line to the named target. +// + +void +HelpView::topline(const char *n) // I - Target name +{ + 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 = (HelpTarget *)bsearch(&key, targets_, ntargets_, sizeof(HelpTarget), + (int (*)(const void *, const void *))compare_targets); + + if (target != NULL) + topline(target->y); +} + + +// +// 'HelpView::topline()' - Set the top line by number. +// + +void +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(); +} + + +// +// 'HelpView::value()' - Set the help text directly. +// + +void +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); +} + + +// +// 'scrollbar_callback()' - A callback for the scrollbar. +// + +static void +scrollbar_callback(Fl_Widget *s, void *) +{ + ((HelpView *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value())); +} + + +// +// End of "$Id: HelpView.cxx,v 1.22 2000/03/19 23:27:14 mike Exp $". +// |