diff options
Diffstat (limited to 'branch-3.0-2011/src/Fl_Help_View.cxx')
| -rw-r--r-- | branch-3.0-2011/src/Fl_Help_View.cxx | 3519 |
1 files changed, 0 insertions, 3519 deletions
diff --git a/branch-3.0-2011/src/Fl_Help_View.cxx b/branch-3.0-2011/src/Fl_Help_View.cxx deleted file mode 100644 index caa25b46a..000000000 --- a/branch-3.0-2011/src/Fl_Help_View.cxx +++ /dev/null @@ -1,3519 +0,0 @@ -// -// "$Id$" -// -// Fl_Help_View widget routines. -// -// Copyright 1997-2010 by Easy Software Products. -// Image support by Matthias Melcher, Copyright 2000-2009. -// -// 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 on the following page: -// -// http://www.fltk.org/str.php -// -// Contents: -// -// Fl_Help_View::add_block() - Add a text block to the list. -// 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::format() - Format the help text. -// Fl_Help_View::format_table() - Format a table... -// Fl_Help_View::free_data() - Free memory used for the document. -// 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::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. -// scrollbar_callback() - A callback for the scrollbar. -// - -// -// Include necessary header files... -// - -#include <FL/Fl_Help_View.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Pixmap.H> -#include <FL/x.H> -#include <stdio.h> -#include <stdlib.h> -#include <FL/fl_utf8.h> -#include <FL/filename.H> // fl_open_uri() -#include "flstring.h" -#include <ctype.h> -#include <errno.h> -#include <math.h> - -#if defined(WIN32) && ! defined(__CYGWIN__) -# include <io.h> -# include <direct.h> -#else -# include <unistd.h> -#endif // WIN32 - -#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 *); -} - - -// -// Local functions... -// - -static int quote_char(const char *); -static void scrollbar_callback(Fl_Widget *s, void *); -static void hscrollbar_callback(Fl_Widget *s, void *); - -// -// global flag for image loading (see get_image). -// - -static char initial_load = 0; - -// -// Broken image... -// - -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(broken_xpm); - -// -// Simple margin stack for Fl_Help_View::format()... -// - -struct fl_margins { - int depth_; - int margins_[100]; - - fl_margins() { clear(); } - - int clear() { -// puts("fl_margins::clear()"); - - depth_ = 0; - return margins_[0] = 4; - } - - int current() { return margins_[depth_]; } - - int pop() { -// printf("fl_margins::pop(): depth_=%d, xx=%d\n", depth_, -// depth_ > 0 ? margins_[depth_ - 1] : 4); - - if (depth_ > 0) { - depth_ --; - return margins_[depth_]; - } else return 4; - } - - int push(int indent) { - int xx; - - xx = margins_[depth_] + indent; - -// printf("fl_margins::push(indent=%d): depth_=%d, xx=%d\n", indent, -// depth_ + 1, xx); - - if (depth_ < 99) { - depth_ ++; - margins_[depth_] = xx; - } - - return xx; - } -}; - -// -// All the stuff needed to implement text selection in Fl_Help_View -// - -/* matt: - * We are trying to keep binary compatibility with previous versions - * of FLTK. This means that we are limited to adding static variables - * only to not enlarge the Fl_Help_View class. Lucky for us, only one - * text can be selected system wide, so we can remember the selection - * in a single set of variables. - * - * Still to do: - * - &word; style characters mess up our count inside a word boundary - * - we can only select words, no individual characters - * - no dragging of the selection into another widget - * - selection must be cleared if another widget get focus! - * - write a comment for every new function - */ - -/* -The following functions are also used to draw stuff and should be replaced with -local copies that are much faster when merely counting: - -fl_color(Fl_Color); -fl_rectf(int, int, int, int); -fl_push_clip(int, int, int, int); -fl_xyline(int, int, int); -fl_rect() -fl_line() -img->draw() -*/ - -// We don't put the offscreen buffer in the help view class because -// we'd need to include x.H in the header... -static Fl_Offscreen fl_help_view_buffer; -int Fl_Help_View::selection_first = 0; -int Fl_Help_View::selection_last = 0; -int Fl_Help_View::selection_push_first = 0; -int Fl_Help_View::selection_push_last = 0; -int Fl_Help_View::selection_drag_first = 0; -int Fl_Help_View::selection_drag_last = 0; -int Fl_Help_View::selected = 0; -int Fl_Help_View::draw_mode = 0; -int Fl_Help_View::mouse_x = 0; -int Fl_Help_View::mouse_y = 0; -int Fl_Help_View::current_pos = 0; -Fl_Help_View *Fl_Help_View::current_view = 0L; -Fl_Color Fl_Help_View::hv_selection_color; -Fl_Color Fl_Help_View::hv_selection_text_color; - -/* - * Limitation: if a word contains &code; notations, we will calculate a wrong length. - * - * This function must be optimized for speed! - */ -void Fl_Help_View::hv_draw(const char *t, int x, int y) -{ - if (selected && current_view==this && current_pos<selection_last && current_pos>=selection_first) { - Fl_Color c = fl_color(); - fl_color(hv_selection_color); - int w = (int)fl_width(t); - if (current_pos+(int)strlen(t)<selection_last) - w += (int)fl_width(' '); - fl_rectf(x, y+fl_descent()-fl_height(), w, fl_height()); - fl_color(hv_selection_text_color); - fl_draw(t, x, y); - fl_color(c); - } else { - fl_draw(t, x, y); - } - if (draw_mode) { - int w = (int)fl_width(t); - if (mouse_x>=x && mouse_x<x+w) { - if (mouse_y>=y-fl_height()+fl_descent()&&mouse_y<=y+fl_descent()) { - int f = current_pos; - int l = f+strlen(t); // use 'quote_char' to calculate the true length of the HTML string - if (draw_mode==1) { - selection_push_first = f; - selection_push_last = l; - } else { - selection_drag_first = f; - selection_drag_last = l; - } - } - } - } -} - - -/** Adds 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_; - memset(temp, 0, sizeof(Fl_Help_Block)); - temp->start = s; - temp->end = s; - temp->x = xx; - temp->y = yy; - temp->w = ww; - temp->h = hh; - temp->border = border; - temp->bgcolor = bgcolor_; - nblocks_ ++; - - return (temp); -} - - -/** Adds 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; - - strlcpy(temp->filename, n, sizeof(temp->filename)); - - if ((target = strrchr(temp->filename, '#')) != NULL) - { - *target++ = '\0'; - strlcpy(temp->name, target, sizeof(temp->name)); - } - else - temp->name[0] = '\0'; - - nlinks_ ++; -} - - -/** Adds 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; - strlcpy(temp->name, n, sizeof(temp->name)); - - ntargets_ ++; -} - -/** Compares 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)); -} - -/** Computes 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); -} - -/** Draws 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 - Fl_Font font; - Fl_Fontsize fsize; // Current font and size - Fl_Color fcolor; // current font color - int head, pre, // Flags for text - needspace; // Do we need whitespace? - Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; - // Box to draw... - int underline, // Underline text? - xtra_ww; // Extra width for underlined space between words - - // Draw the scrollbar(s) and box first... - ww = w(); - hh = h(); - i = 0; - - draw_box(b, x(), y(), ww, hh, bgcolor_); - - if ( hscrollbar_.visible() || scrollbar_.visible() ) { - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - int hor_vis = hscrollbar_.visible(); - int ver_vis = scrollbar_.visible(); - // Scrollbar corner - int scorn_x = x() + ww - (ver_vis?scrollsize:0) - Fl::box_dw(b) + Fl::box_dx(b); - int scorn_y = y() + hh - (hor_vis?scrollsize:0) - Fl::box_dh(b) + Fl::box_dy(b); - if ( hor_vis ) { - if ( hscrollbar_.h() != scrollsize ) { // scrollsize changed? - hscrollbar_.resize(x(), scorn_y, scorn_x - x(), scrollsize); - init_sizes(); - } - draw_child(hscrollbar_); - hh -= scrollsize; - } - if ( ver_vis ) { - if ( scrollbar_.w() != scrollsize ) { // scrollsize changed? - scrollbar_.resize(scorn_x, y(), scrollsize, scorn_y - y()); - init_sizes(); - } - draw_child(scrollbar_); - ww -= scrollsize; - } - if ( hor_vis && ver_vis ) { - // Both scrollbars visible? Draw little gray box in corner - fl_color(FL_GRAY); - fl_rectf(scorn_x, scorn_y, scrollsize, scrollsize); - } - } - - if (!value_) - return; - - if (current_view == this && selected) { - hv_selection_color = FL_SELECTION_COLOR; - hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR); - } - current_pos = 0; - - // Clip the drawing to the inside of the box... - fl_push_clip(x() + Fl::box_dx(b), y() + Fl::box_dy(b), - ww - Fl::box_dw(b), hh - Fl::box_dh(b)); - fl_color(textcolor_); - - // Draw all visible blocks... - for (i = 0, block = blocks_; i < nblocks_; i ++, block ++) - if ((block->y + block->h) >= topline_ && block->y < (topline_ + h())) - { - line = 0; - xx = block->line[line]; - yy = block->y - topline_; - hh = 0; - pre = 0; - head = 0; - needspace = 0; - underline = 0; - - initfont(font, fsize, fcolor); - - for (ptr = block->start, s = buf; ptr < block->end;) - { - if ((*ptr == '<' || isspace((*ptr)&255)) && 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; - } - - hv_draw(buf, xx + x() - leftline_, yy + y()); - if (underline) { - xtra_ww = isspace((*ptr)&255)?(int)fl_width(' '):0; - fl_xyline(xx + x() - leftline_, yy + y() + 1, - xx + x() - leftline_ + ww + xtra_ww); - } - current_pos = ptr-value_; - - xx += ww; - if ((fsize + 2) > hh) - hh = fsize + 2; - - needspace = 0; - } - else if (pre) - { - while (isspace((*ptr)&255)) - { - if (*ptr == '\n') - { - *s = '\0'; - s = buf; - - hv_draw(buf, xx + x() - leftline_, yy + y()); - if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, - xx + x() - leftline_ + - (int)fl_width(buf)); - - current_pos = ptr-value_; - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = fsize + 2; - } - else if (*ptr == '\t') - { - // Do tabs every 8 columns... - while (((s - buf) & 7)) - *s++ = ' '; - } - else - *s++ = ' '; - - if ((fsize + 2) > hh) - hh = fsize + 2; - - ptr ++; - } - - if (s > buf) - { - *s = '\0'; - s = buf; - - hv_draw(buf, xx + x() - leftline_, yy + y()); - ww = (int)fl_width(buf); - if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, - xx + x() - leftline_ + ww); - xx += ww; - current_pos = ptr-value_; - } - - needspace = 0; - } - else - { - s = buf; - - while (isspace((*ptr)&255)) - ptr ++; - current_pos = ptr-value_; - } - } - - if (*ptr == '<') - { - ptr ++; - - if (strncmp(ptr, "!--", 3) == 0) - { - // Comment... - ptr += 3; - if ((ptr = strstr(ptr, "-->")) != NULL) - { - ptr += 3; - continue; - } - else - break; - } - - while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) - if (s < (buf + sizeof(buf) - 1)) - *s++ = *ptr++; - else - ptr ++; - - *s = '\0'; - s = buf; - - attrs = ptr; - while (*ptr && *ptr != '>') - ptr ++; - - if (*ptr == '>') - ptr ++; - - // end of command reached, set the supposed start of printed eord here - current_pos = ptr-value_; - 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; - fsize = textsize_ + '7' - buf[1]; - } - else if (strcasecmp(buf, "DT") == 0) - { - font = textfont_ | FL_ITALIC; - fsize = textsize_; - } - else if (strcasecmp(buf, "PRE") == 0) - { - font = FL_COURIER; - fsize = textsize_; - pre = 1; - } - - if (strcasecmp(buf, "LI") == 0) - { -// fl_font(FL_SYMBOL, fsize); // The default SYMBOL font on my XP box is not Unicode... - char buf[8]; - wchar_t b[] = {0x2022, 0x0}; -// buf[fl_unicode2utf(b, 1, buf)] = 0; - unsigned dstlen = fl_utf8fromwc(buf, 8, b, 1); - buf[dstlen] = 0; - hv_draw(buf, xx - fsize + x() - leftline_, yy + y()); - } - - pushfont(font, fsize); - } - else if (strcasecmp(buf, "A") == 0 && - get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) - { - fl_color(linkcolor_); - underline = 1; - } - else if (strcasecmp(buf, "/A") == 0) - { - fl_color(textcolor_); - underline = 0; - } - else if (strcasecmp(buf, "FONT") == 0) - { - if (get_attr(attrs, "COLOR", attr, sizeof(attr)) != NULL) { - textcolor_ = get_color(attr, textcolor_); - } - - if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) { - if (!strncasecmp(attr, "helvetica", 9) || - !strncasecmp(attr, "arial", 5) || - !strncasecmp(attr, "sans", 4)) font = FL_HELVETICA; - else if (!strncasecmp(attr, "times", 5) || - !strncasecmp(attr, "serif", 5)) font = FL_TIMES; - else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL; - else font = FL_COURIER; - } - - if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) { - if (isdigit(attr[0] & 255)) { - // Absolute size - fsize = (int)(textsize_ * pow(1.2, atof(attr) - 3.0)); - } else { - // Relative size - fsize = (int)(fsize * pow(1.2, atof(attr) - 3.0)); - } - } - - pushfont(font, fsize); - } - else if (strcasecmp(buf, "/FONT") == 0) - { - popfont(font, fsize, textcolor_); - } - else if (strcasecmp(buf, "U") == 0) - underline = 1; - else if (strcasecmp(buf, "/U") == 0) - underline = 0; - else if (strcasecmp(buf, "B") == 0 || - strcasecmp(buf, "STRONG") == 0) - pushfont(font |= FL_BOLD, fsize); - else if (strcasecmp(buf, "TD") == 0 || - strcasecmp(buf, "TH") == 0) - { - int tx, ty, tw, th; - - if (tolower(buf[1]) == 'h') - pushfont(font |= FL_BOLD, fsize); - else - pushfont(font = textfont_, fsize); - - tx = block->x - 4 - leftline_; - ty = block->y - topline_ - fsize - 3; - tw = block->w - block->x + 7; - th = block->h + fsize - 5; - - if (tx < 0) - { - tw += tx; - tx = 0; - } - - if (ty < 0) - { - th += ty; - ty = 0; - } - - tx += x(); - ty += y(); - - if (block->bgcolor != bgcolor_) - { - fl_color(block->bgcolor); - fl_rectf(tx, ty, tw, th); - fl_color(textcolor_); - } - - if (block->border) - fl_rect(tx, ty, tw, th); - } - else if (strcasecmp(buf, "I") == 0 || - strcasecmp(buf, "EM") == 0) - pushfont(font |= FL_ITALIC, fsize); - else if (strcasecmp(buf, "CODE") == 0 || - strcasecmp(buf, "TT") == 0) - pushfont(font = FL_COURIER, fsize); - else if (strcasecmp(buf, "KBD") == 0) - pushfont(font = FL_COURIER_BOLD, fsize); - else if (strcasecmp(buf, "VAR") == 0) - pushfont(font = FL_COURIER_ITALIC, fsize); - 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, "/STRONG") == 0 || - strcasecmp(buf, "/I") == 0 || - strcasecmp(buf, "/EM") == 0 || - strcasecmp(buf, "/CODE") == 0 || - strcasecmp(buf, "/TT") == 0 || - strcasecmp(buf, "/KBD") == 0 || - strcasecmp(buf, "/VAR") == 0) - popfont(font, fsize, fcolor); - else if (strcasecmp(buf, "/PRE") == 0) - { - popfont(font, fsize, fcolor); - pre = 0; - } - else if (strcasecmp(buf, "IMG") == 0) - { - Fl_Shared_Image *img = 0; - int width, height; - char wattr[8], hattr[8]; - - - get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); - get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); - width = get_length(wattr); - height = get_length(hattr); - - if (get_attr(attrs, "SRC", attr, sizeof(attr))) { - img = get_image(attr, width, height); - if (!width) width = img->w(); - if (!height) height = img->h(); - } - - if (!width || !height) { - 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->draw(xx + x() - leftline_, - 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; - - hv_draw(buf, xx + x() - leftline_, yy + y()); - - if (line < 31) - line ++; - xx = block->line[line]; - yy += hh; - hh = fsize + 2; - needspace = 0; - - ptr ++; - current_pos = ptr-value_; - } - else if (isspace((*ptr)&255)) - { - if (pre) - { - if (*ptr == ' ') - *s++ = ' '; - else - { - // Do tabs every 8 columns... - while (((s - buf) & 7)) - *s++ = ' '; - } - } - - ptr ++; - if (!pre) current_pos = ptr-value_; - needspace = 1; - } - else if (*ptr == '&') - { - ptr ++; - - int qch = quote_char(ptr); - - if (qch < 0) - *s++ = '&'; - else { - int l; - l = fl_utf8encode((unsigned int) qch, s); - if (l < 1) l = 1; - s += l; - ptr = strchr(ptr, ';') + 1; - } - - if ((fsize + 2) > hh) - hh = fsize + 2; - } - else - { - *s++ = *ptr++; - - if ((fsize + 2) > hh) - hh = fsize + 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) - { - hv_draw(buf, xx + x() - leftline_, yy + y()); - if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, - xx + x() - leftline_ + ww); - current_pos = ptr-value_; - } - } - - fl_pop_clip(); -} - - - -/** Finds the specified string \p s at starting position \p p. - - \return the matching position or -1 if not found -*/ -int // O - Matching position or -1 if not found -Fl_Help_View::find(const char *s, // I - String to find - int p) // I - Starting position -{ - int i, // Looping var - c; // Current character - Fl_Help_Block *b; // Current block - const char *bp, // Block matching pointer - *bs, // Start of current comparison - *sp; // Search string pointer - - - // Range check input and value... - if (!s || !value_) return -1; - - if (p < 0 || p >= (int)strlen(value_)) p = 0; - else if (p > 0) p ++; - - // Look for the string... - for (i = nblocks_, b = blocks_; i > 0; i --, b ++) { - if (b->end < (value_ + p)) - continue; - - if (b->start < (value_ + p)) bp = value_ + p; - else bp = b->start; - - for (sp = s, bs = bp; *sp && *bp && bp < b->end; bp ++) { - if (*bp == '<') { - // skip to end of element... - while (*bp && bp < b->end && *bp != '>') bp ++; - continue; - } else if (*bp == '&') { - // decode HTML entity... - if ((c = quote_char(bp + 1)) < 0) c = '&'; - else bp = strchr(bp + 1, ';') + 1; - } else c = *bp; - - if (tolower(*sp) == tolower(c)) sp ++; - else { - // No match, so reset to start of search... - sp = s; - bs ++; - bp = bs; - } - } - - if (!*sp) { - // Found a match! - topline(b->y - b->h); - return (b->end - value_); - } - } - - // No match! - return (-1); -} - -/** Formats the help text. */ -void Fl_Help_View::format() { - int i; // Looping var - int done; // Are we done yet? - Fl_Help_Block *block, // Current block - *cell; // Current table cell - int cells[MAX_COLUMNS], - // Cells in the current row... - 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 - linkdest[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 - Fl_Font font; - Fl_Fontsize fsize; // Current font and size - Fl_Color fcolor; // Current font color - unsigned char border; // Draw border? - int talign, // Current alignment - newalign, // New alignment - head, // In the <HEAD> section? - pre, // <PRE> text? - needspace; // Do we need whitespace? - int table_width, // Width of table - table_offset; // Offset of table - int column, // Current table column number - columns[MAX_COLUMNS]; - // Column widths - Fl_Color tc, rc; // Table/row background color - Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; - // Box to draw... - fl_margins margins; // Left margin stack... - - - // Reset document width... - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - hsize_ = w() - scrollsize - Fl::box_dw(b); - - done = 0; - while (!done) - { - // Reset state variables... - done = 1; - nblocks_ = 0; - nlinks_ = 0; - ntargets_ = 0; - size_ = 0; - bgcolor_ = color(); - textcolor_ = textcolor(); - linkcolor_ = fl_contrast(FL_BLUE, color()); - - tc = rc = bgcolor_; - - strcpy(title_, "Untitled"); - - if (!value_) - return; - - // Setup for formatting... - initfont(font, fsize, fcolor); - - line = 0; - links = 0; - xx = margins.clear(); - yy = fsize + 2; - ww = 0; - column = 0; - border = 0; - hh = 0; - block = add_block(value_, xx, yy, hsize_, 0); - row = 0; - head = 0; - pre = 0; - talign = LEFT; - newalign = LEFT; - needspace = 0; - linkdest[0] = '\0'; - table_offset = 0; - - // Html text character loop - for (ptr = value_, s = buf; *ptr;) - { - // End of word? - if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf) - { - // Get width of word parsed so far... - *s = '\0'; - ww = (int)fl_width(buf); - - if (!head && !pre) - { - // Check width... - if (ww > hsize_) { - hsize_ = ww; - done = 0; - break; - } - - 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 (linkdest[0]) - add_link(linkdest, xx, yy - fsize, ww, fsize); - - xx += ww; - if ((fsize + 2) > hh) - hh = fsize + 2; - - needspace = 0; - } - else if (pre) - { - // Add a link as needed... - if (linkdest[0]) - add_link(linkdest, xx, yy - hh, ww, hh); - - xx += ww; - if ((fsize + 2) > hh) - hh = fsize + 2; - - // Handle preformatted text... - while (isspace((*ptr)&255)) - { - if (*ptr == '\n') - { - if (xx > hsize_) break; - - line = do_align(block, line, xx, newalign, links); - xx = block->x; - yy += hh; - block->h += hh; - hh = fsize + 2; - } - else - xx += (int)fl_width(' '); - - if ((fsize + 2) > hh) - hh = fsize + 2; - - ptr ++; - } - - if (xx > hsize_) { - hsize_ = xx; - done = 0; - break; - } - - needspace = 0; - } - else - { - // Handle normal text or stuff in the <HEAD> section... - while (isspace((*ptr)&255)) - ptr ++; - } - - s = buf; - } - - if (*ptr == '<') - { - // Handle html tags.. - start = ptr; - ptr ++; - - if (strncmp(ptr, "!--", 3) == 0) - { - // Comment... - ptr += 3; - if ((ptr = strstr(ptr, "-->")) != NULL) - { - ptr += 3; - continue; - } - else - break; - } - - while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) - 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 - fsize - 2); - - if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) - strlcpy(linkdest, attr, sizeof(linkdest)); - } - else if (strcasecmp(buf, "/A") == 0) - linkdest[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)), - fl_contrast(FL_BLUE, 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); - newalign = strcasecmp(buf, "CENTER") ? LEFT : CENTER; - xx = block->x; - block->h += hh; - - if (strcasecmp(buf, "UL") == 0 || - strcasecmp(buf, "OL") == 0 || - strcasecmp(buf, "DL") == 0) - { - block->h += fsize + 2; - xx = margins.push(4 * fsize); - } - else if (strcasecmp(buf, "TABLE") == 0) - { - if (get_attr(attrs, "BORDER", attr, sizeof(attr))) - border = (uchar)atoi(attr); - else - border = 0; - - tc = rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_); - - block->h += fsize + 2; - - format_table(&table_width, columns, start); - - if ((xx + table_width) > hsize_) { -#ifdef DEBUG - printf("xx=%d, table_width=%d, hsize_=%d\n", xx, table_width, - hsize_); -#endif // DEBUG - hsize_ = xx + table_width; - done = 0; - break; - } - - switch (get_align(attrs, talign)) - { - default : - table_offset = 0; - break; - - case CENTER : - table_offset = (hsize_ - table_width) / 2 - textsize_; - break; - - case RIGHT : - table_offset = hsize_ - table_width - textsize_; - break; - } - - column = 0; - } - - if (tolower(buf[0]) == 'h' && isdigit(buf[1])) - { - font = FL_HELVETICA_BOLD; - fsize = textsize_ + '7' - buf[1]; - } - else if (strcasecmp(buf, "DT") == 0) - { - font = textfont_ | FL_ITALIC; - fsize = textsize_; - } - else if (strcasecmp(buf, "PRE") == 0) - { - font = FL_COURIER; - fsize = textsize_; - pre = 1; - } - else - { - font = textfont_; - fsize = textsize_; - } - - pushfont(font, fsize); - - 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 += fsize + 2; - else if (strcasecmp(buf, "HR") == 0) - { - hh += 2 * fsize; - yy += fsize; - } - - if (row) - block = add_block(start, xx, yy, block->w, 0); - else - block = add_block(start, xx, yy, hsize_, 0); - - needspace = 0; - line = 0; - - if (strcasecmp(buf, "CENTER") == 0) - newalign = talign = CENTER; - else - newalign = get_align(attrs, talign); - } - 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 = margins.pop(); - block->h += fsize + 2; - } - else if (strcasecmp(buf, "/TABLE") == 0) - { - block->h += fsize + 2; - xx = margins.current(); - } - else if (strcasecmp(buf, "/PRE") == 0) - { - pre = 0; - hh = 0; - } - else if (strcasecmp(buf, "/CENTER") == 0) - talign = LEFT; - - popfont(font, fsize, fcolor); - - //#if defined(__GNUC__) - //#warning FIXME this isspace & 255 test will probably not work on a utf8 stream... And we use it everywhere! - //#endif /*__GNUC__*/ - while (isspace((*ptr)&255)) - ptr ++; - - block->h += hh; - yy += hh; - - if (tolower(buf[2]) == 'l') - yy += fsize + 2; - - if (row) - block = add_block(ptr, xx, yy, block->w, 0); - else - block = add_block(ptr, xx, yy, hsize_, 0); - - needspace = 0; - hh = 0; - line = 0; - newalign = talign; - } - 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 = blocks_ + row; - - block->h = yy - block->y + 2; - - for (i = 0; i < column; i ++) - if (cells[i]) - { - cell = blocks_ + cells[i]; - cell->h = block->h; - } - } - - memset(cells, 0, sizeof(cells)); - - yy = block->y + block->h - 4; - hh = 0; - block = add_block(start, xx, yy, hsize_, 0); - row = block - blocks_; - needspace = 0; - column = 0; - line = 0; - - rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc); - } - else if (strcasecmp(buf, "/TR") == 0 && row) - { - line = do_align(block, line, xx, newalign, links); - block->end = start; - block->h += hh; - talign = LEFT; - - 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 = blocks_ + row; - - block->h = yy - block->y + 2; - - for (i = 0; i < column; i ++) - if (cells[i]) - { - cell = blocks_ + cells[i]; - cell->h = block->h; - } - - yy = block->y + block->h /*- 4*/; - block = add_block(start, xx, yy, hsize_, 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_; - - fsize = textsize_; - - xx = blocks_[row].x + fsize + 3 + table_offset; - for (i = 0; i < column; i ++) - xx += columns[i] + 6; - - margins.push(xx - margins.current()); - - if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL) - colspan = atoi(attr); - else - colspan = 1; - - for (i = 0, ww = -6; i < colspan; i ++) - ww += columns[column + i] + 6; - - if (block->end == block->start && nblocks_ > 1) - { - nblocks_ --; - block --; - } - - pushfont(font, fsize); - - 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); - talign = newalign; - - cells[column] = block - blocks_; - - column += colspan; - - block->bgcolor = get_color(get_attr(attrs, "BGCOLOR", attr, - sizeof(attr)), rc); - } - else if ((strcasecmp(buf, "/TD") == 0 || - strcasecmp(buf, "/TH") == 0) && row) - { - line = do_align(block, line, xx, newalign, links); - popfont(font, fsize, fcolor); - xx = margins.pop(); - talign = LEFT; - } - else if (strcasecmp(buf, "FONT") == 0) - { - if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) { - if (!strncasecmp(attr, "helvetica", 9) || - !strncasecmp(attr, "arial", 5) || - !strncasecmp(attr, "sans", 4)) font = FL_HELVETICA; - else if (!strncasecmp(attr, "times", 5) || - !strncasecmp(attr, "serif", 5)) font = FL_TIMES; - else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL; - else font = FL_COURIER; - } - - if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) { - if (isdigit(attr[0] & 255)) { - // Absolute size - fsize = (int)(textsize_ * pow(1.2, atoi(attr) - 3.0)); - } else { - // Relative size - fsize = (int)(fsize * pow(1.2, atoi(attr))); - } - } - - pushfont(font, fsize); - } - else if (strcasecmp(buf, "/FONT") == 0) - popfont(font, fsize, fcolor); - else if (strcasecmp(buf, "B") == 0 || - strcasecmp(buf, "STRONG") == 0) - pushfont(font |= FL_BOLD, fsize); - else if (strcasecmp(buf, "I") == 0 || - strcasecmp(buf, "EM") == 0) - pushfont(font |= FL_ITALIC, fsize); - else if (strcasecmp(buf, "CODE") == 0 || - strcasecmp(buf, "TT") == 0) - pushfont(font = FL_COURIER, fsize); - else if (strcasecmp(buf, "KBD") == 0) - pushfont(font = FL_COURIER_BOLD, fsize); - else if (strcasecmp(buf, "VAR") == 0) - pushfont(font = FL_COURIER_ITALIC, fsize); - else if (strcasecmp(buf, "/B") == 0 || - strcasecmp(buf, "/STRONG") == 0 || - strcasecmp(buf, "/I") == 0 || - strcasecmp(buf, "/EM") == 0 || - strcasecmp(buf, "/CODE") == 0 || - strcasecmp(buf, "/TT") == 0 || - strcasecmp(buf, "/KBD") == 0 || - strcasecmp(buf, "/VAR") == 0) - popfont(font, fsize, fcolor); - else if (strcasecmp(buf, "IMG") == 0) - { - Fl_Shared_Image *img = 0; - int width; - int height; - - - get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); - get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); - width = get_length(wattr); - height = get_length(hattr); - - if (get_attr(attrs, "SRC", attr, sizeof(attr))) { - img = get_image(attr, width, height); - width = img->w(); - height = img->h(); - } - - ww = width; - - if (ww > hsize_) { - hsize_ = ww; - done = 0; - break; - } - - 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 (linkdest[0]) - add_link(linkdest, xx, yy - height, ww, height); - - xx += ww; - if ((height + 2) > hh) - hh = height + 2; - - needspace = 0; - } - } - else if (*ptr == '\n' && pre) - { - if (linkdest[0]) - add_link(linkdest, xx, yy - hh, ww, hh); - - if (xx > hsize_) { - hsize_ = xx; - done = 0; - break; - } - - line = do_align(block, line, xx, newalign, links); - xx = block->x; - yy += hh; - block->h += hh; - needspace = 0; - ptr ++; - } - else if (isspace((*ptr)&255)) - { - needspace = 1; - if ( pre ) { - xx += (int)fl_width(' '); - } - ptr ++; - } - else if (*ptr == '&' && s < (buf + sizeof(buf) - 1)) - { - // Handle html '&' codes, eg. "&" - ptr ++; - - int qch = quote_char(ptr); - - if (qch < 0) - *s++ = '&'; - else { - int l; - l = fl_utf8encode((unsigned int) qch, s); - if (l < 1) l = 1; - s += l; - ptr = strchr(ptr, ';') + 1; - } - - if ((fsize + 2) > hh) - hh = fsize + 2; - } - else - { - if (s < (buf + sizeof(buf) - 1)) - *s++ = *ptr++; - else - ptr ++; - - if ((fsize + 2) > hh) - hh = fsize + 2; - } - } - - if (s > buf && !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 (ww > hsize_) { - hsize_ = ww; - done = 0; - break; - } - - 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 (linkdest[0]) - add_link(linkdest, xx, yy - fsize, ww, fsize); - - xx += ww; - } - - do_align(block, line, xx, newalign, links); - - block->end = ptr; - size_ = yy + hh; - } - -// printf("margins.depth_=%d\n", margins.depth_); - - if (ntargets_ > 1) - qsort(targets_, ntargets_, sizeof(Fl_Help_Target), - (compare_func_t)compare_targets); - - int dx = Fl::box_dw(b) - Fl::box_dx(b); - int dy = Fl::box_dh(b) - Fl::box_dy(b); - int ss = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - int dw = Fl::box_dw(b) + ss; - int dh = Fl::box_dh(b); - - if (hsize_ > (w() - dw)) { - hscrollbar_.show(); - - dh += ss; - - if (size_ < (h() - dh)) { - scrollbar_.hide(); - hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy, - w() - Fl::box_dw(b), ss); - } else { - scrollbar_.show(); - scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b), - ss, h() - ss - Fl::box_dh(b)); - hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy, - w() - ss - Fl::box_dw(b), ss); - } - } else { - hscrollbar_.hide(); - - if (size_ < (h() - dh)) scrollbar_.hide(); - else { - scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b), - ss, h() - Fl::box_dh(b)); - scrollbar_.show(); - } - } - - // Reset scrolling if it needs to be... - if (scrollbar_.visible()) { - int temph = h() - Fl::box_dh(b); - if (hscrollbar_.visible()) temph -= ss; - if ((topline_ + temph) > size_) topline(size_ - temph); - else topline(topline_); - } else topline(0); - - if (hscrollbar_.visible()) { - int tempw = w() - ss - Fl::box_dw(b); - if ((leftline_ + tempw) > hsize_) leftline(hsize_ - tempw); - else leftline(leftline_); - } else leftline(0); -} - - -/** Formats 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 - Fl_Font font; - Fl_Fontsize fsize; // Current font and size - Fl_Color fcolor; // Currrent font color - - // 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; - needspace = 0; - fstack_.top(font, fsize, fcolor); - - // Scan the table... - for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;) - { - if ((*ptr == '<' || isspace((*ptr)&255)) && 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)&255);) - 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; - fsize = textsize_ + '7' - buf[1]; - } - else if (strcasecmp(buf, "DT") == 0) - { - font = textfont_ | FL_ITALIC; - fsize = textsize_; - } - else if (strcasecmp(buf, "PRE") == 0) - { - font = FL_COURIER; - fsize = textsize_; - pre = 1; - } - else if (strcasecmp(buf, "LI") == 0) - { - width += 4 * fsize; - font = textfont_; - fsize = textsize_; - } - else - { - font = textfont_; - fsize = textsize_; - } - - pushfont(font, fsize); - } - 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, fsize, fcolor); - } - 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_; - - fsize = textsize_; - - pushfont(font, fsize); - - if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL) - max_width = get_length(attr); - 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, fsize, fcolor); - } - else if (strcasecmp(buf, "B") == 0 || - strcasecmp(buf, "STRONG") == 0) - pushfont(font |= FL_BOLD, fsize); - else if (strcasecmp(buf, "I") == 0 || - strcasecmp(buf, "EM") == 0) - pushfont(font |= FL_ITALIC, fsize); - else if (strcasecmp(buf, "CODE") == 0 || - strcasecmp(buf, "TT") == 0) - pushfont(font = FL_COURIER, fsize); - else if (strcasecmp(buf, "KBD") == 0) - pushfont(font = FL_COURIER_BOLD, fsize); - else if (strcasecmp(buf, "VAR") == 0) - pushfont(font = FL_COURIER_ITALIC, fsize); - else if (strcasecmp(buf, "/B") == 0 || - strcasecmp(buf, "/STRONG") == 0 || - strcasecmp(buf, "/I") == 0 || - strcasecmp(buf, "/EM") == 0 || - strcasecmp(buf, "/CODE") == 0 || - strcasecmp(buf, "/TT") == 0 || - strcasecmp(buf, "/KBD") == 0 || - strcasecmp(buf, "/VAR") == 0) - popfont(font, fsize, fcolor); - else if (strcasecmp(buf, "IMG") == 0 && incell) - { - Fl_Shared_Image *img = 0; - int iwidth, iheight; - - - get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); - get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); - iwidth = get_length(wattr); - iheight = get_length(hattr); - - if (get_attr(attrs, "SRC", attr, sizeof(attr))) { - img = get_image(attr, iwidth, iheight); - iwidth = img->w(); - iheight = img->h(); - } - - if (iwidth > minwidths[column]) - minwidths[column] = iwidth; - - width += iwidth; - 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)&255)) - { - needspace = 1; - - ptr ++; - } - else if (*ptr == '&' && s < (buf + sizeof(buf) - 1)) - { - ptr ++; - - int qch = quote_char(ptr); - - if (qch < 0) - *s++ = '&'; - else { -// int l; -// l = fl_utf8encode((unsigned int) qch, s); -// if (l < 1) l = 1; -// s += l; - *s++ = qch; - ptr = strchr(ptr, ';') + 1; - } - } - 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))) - *table_width = get_length(attr); - else - *table_width = 0; - -#ifdef DEBUG - printf("num_columns = %d, table_width = %d\n", num_columns, *table_width); -#endif // DEBUG - - if (num_columns == 0) - return; - - // Add up the widths... - for (column = 0, width = 0; column < num_columns; column ++) - width += columns[column]; - -#ifdef DEBUG - 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]); -#endif // DEBUG - - // Adjust the width if needed... - int scale_width = *table_width; - - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - if (scale_width == 0) { - if (width > (hsize_ - scrollsize)) scale_width = hsize_ - scrollsize; - else scale_width = width; - } - - if (width < scale_width) { -#ifdef DEBUG - printf("Scaling table up to %d from %d...\n", scale_width, width); -#endif // DEBUG - - *table_width = 0; - - scale_width = (scale_width - width) / num_columns; - -#ifdef DEBUG - printf("adjusted scale_width = %d\n", scale_width); -#endif // DEBUG - - for (column = 0; column < num_columns; column ++) { - columns[column] += scale_width; - - (*table_width) += columns[column]; - } - } - else if (width > scale_width) { -#ifdef DEBUG - printf("Scaling table down to %d from %d...\n", scale_width, width); -#endif // DEBUG - - for (column = 0; column < num_columns; column ++) { - width -= minwidths[column]; - scale_width -= minwidths[column]; - } - -#ifdef DEBUG - printf("adjusted width = %d, scale_width = %d\n", width, scale_width); -#endif // DEBUG - - if (width > 0) { - for (column = 0; column < num_columns; column ++) { - columns[column] -= minwidths[column]; - columns[column] = scale_width * columns[column] / width; - columns[column] += minwidths[column]; - } - } - - *table_width = 0; - for (column = 0; column < num_columns; column ++) { - (*table_width) += columns[column]; - } - } - else if (*table_width == 0) - *table_width = width; - -#ifdef DEBUG - printf("FINAL table_width = %d\n", *table_width); - for (column = 0; column < num_columns; column ++) - printf(" columns[%d] = %d\n", column, columns[column]); -#endif // DEBUG -} - - -/** Frees memory used for the document. */ -void -Fl_Help_View::free_data() { - // Release all images... - if (value_) { - const char *ptr, // Pointer into block - *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 - - for (ptr = value_; *ptr;) - { - if (*ptr == '<') - { - ptr ++; - - if (strncmp(ptr, "!--", 3) == 0) - { - // Comment... - ptr += 3; - if ((ptr = strstr(ptr, "-->")) != NULL) - { - ptr += 3; - continue; - } - else - break; - } - - s = buf; - - while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) - if (s < (buf + sizeof(buf) - 1)) - *s++ = *ptr++; - else - ptr ++; - - *s = '\0'; - - attrs = ptr; - while (*ptr && *ptr != '>') - ptr ++; - - if (*ptr == '>') - ptr ++; - - if (strcasecmp(buf, "IMG") == 0) - { - Fl_Shared_Image *img; - int width; - int height; - - get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); - get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); - width = get_length(wattr); - height = get_length(hattr); - - if (get_attr(attrs, "SRC", attr, sizeof(attr))) { - // Get and release the image to free it from memory... - img = get_image(attr, width, height); - if ((void*)img != &broken_image) { - img->release(); - } - } - } - } - else - ptr ++; - } - - free((void *)value_); - value_ = 0; - } - - // Free all of the arrays... - if (nblocks_) { - free(blocks_); - - ablocks_ = 0; - nblocks_ = 0; - blocks_ = 0; - } - - if (nlinks_) { - free(links_); - - alinks_ = 0; - nlinks_ = 0; - links_ = 0; - } - - if (ntargets_) { - free(targets_); - - atargets_ = 0; - ntargets_ = 0; - targets_ = 0; - } -} - -/** Gets 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); -} - - -/** Gets 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)&255)) - p ++; - - if (*p == '>' || !*p) - return (NULL); - - for (ptr = name; *p && !isspace((*p)&255) && *p != '=' && *p != '>';) - if (ptr < (name + sizeof(name) - 1)) - *ptr++ = *p++; - else - p ++; - - *ptr = '\0'; - - if (isspace((*p)&255) || !*p || *p == '>') - buf[0] = '\0'; - else - { - if (*p == '=') - p ++; - - for (ptr = buf; *p && !isspace((*p)&255) && *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); -} - - -/** Gets a color 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 i; // Looping var - int rgb, r, g, b; // RGB values - static const struct { // Color name table - const char *name; - int r, g, b; - } colors[] = { - { "black", 0x00, 0x00, 0x00 }, - { "red", 0xff, 0x00, 0x00 }, - { "green", 0x00, 0x80, 0x00 }, - { "yellow", 0xff, 0xff, 0x00 }, - { "blue", 0x00, 0x00, 0xff }, - { "magenta", 0xff, 0x00, 0xff }, - { "fuchsia", 0xff, 0x00, 0xff }, - { "cyan", 0x00, 0xff, 0xff }, - { "aqua", 0x00, 0xff, 0xff }, - { "white", 0xff, 0xff, 0xff }, - { "gray", 0x80, 0x80, 0x80 }, - { "grey", 0x80, 0x80, 0x80 }, - { "lime", 0x00, 0xff, 0x00 }, - { "maroon", 0x80, 0x00, 0x00 }, - { "navy", 0x00, 0x00, 0x80 }, - { "olive", 0x80, 0x80, 0x00 }, - { "purple", 0x80, 0x00, 0x80 }, - { "silver", 0xc0, 0xc0, 0xc0 }, - { "teal", 0x00, 0x80, 0x80 } - }; - - - if (!n || !n[0]) return c; - - if (n[0] == '#') { - // Do hex color lookup - rgb = strtol(n + 1, NULL, 16); - - if (strlen(n) > 4) { - r = rgb >> 16; - g = (rgb >> 8) & 255; - b = rgb & 255; - } else { - r = (rgb >> 8) * 17; - g = ((rgb >> 4) & 15) * 17; - b = (rgb & 15) * 17; - } - return (fl_rgb_color((uchar)r, (uchar)g, (uchar)b)); - } else { - for (i = 0; i < (int)(sizeof(colors) / sizeof(colors[0])); i ++) - if (!strcasecmp(n, colors[i].name)) { - return fl_rgb_color(colors[i].r, colors[i].g, colors[i].b); - } - return c; - } -} - - -/** Gets an inline image. - - The image reference count is maintained accordingly, such that - the image can be released exactly once when the document is closed. - - \return a pointer to a cached Fl_Shared_Image, if the image can be loaded, - otherwise a pointer to an internal Fl_Pixmap (broken_image). - - \todo Fl_Help_View::get_image() returns a pointer to the internal - Fl_Pixmap broken_image, but this is _not_ compatible with the - return type Fl_Shared_Image (release() must not be called). -*/ - -/* Implementation note: (A.S. Apr 05, 2009) - - Fl_Help_View::get_image() uses a static global flag (initial_load) - to determine, if it is called from the initial loading of a document - (load() or value()), or from resize() or draw(). - - A better solution would be to manage all loaded images in an own - structure like Fl_Help_Target (Fl_Help_Image ?) to avoid using this - global flag, but this would break the ABI ! - - This should be fixed in FLTK 1.3 ! - - - If initial_load is true, then Fl_Shared_Image::get() is called to - load the image, and the reference count of the shared image is - increased by one. - - If initial_load is false, then Fl_Shared_Image::find() is called to - load the image, and the image is released immediately. This avoids - increasing the reference count when calling get_image() from draw() - or resize(). - - Calling Fl_Shared_Image::find() instead of Fl_Shared_Image::get() avoids - doing unnecessary i/o for "broken images" within each resize/redraw. - - Each image must be released exactly once in the destructor or before - a new document is loaded: see free_data(). -*/ - -Fl_Shared_Image * -Fl_Help_View::get_image(const char *name, int W, int H) { - const char *localname; // Local filename - char dir[FL_PATH_MAX]; // Current directory - char temp[FL_PATH_MAX], // Temporary filename - *tempptr; // Pointer into temporary name - Fl_Shared_Image *ip; // Image pointer... - - // See if the image can be found... - if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL) { - if (name[0] == '/') { - strlcpy(temp, directory_, sizeof(temp)); - - if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) { - strlcpy(tempptr, name, sizeof(temp) - (tempptr - temp)); - } else { - strlcat(temp, name, sizeof(temp)); - } - } else { - snprintf(temp, sizeof(temp), "%s/%s", directory_, name); - } - - if (link_) localname = (*link_)(this, temp); - else localname = temp; - } else if (name[0] != '/' && strchr(name, ':') == NULL) { - if (directory_[0]) snprintf(temp, sizeof(temp), "%s/%s", directory_, name); - else { - fl_getcwd(dir, sizeof(dir)); - snprintf(temp, sizeof(temp), "file:%s/%s", dir, name); - } - - if (link_) localname = (*link_)(this, temp); - else localname = temp; - } else if (link_) localname = (*link_)(this, name); - else localname = name; - - if (!localname) return 0; - - if (strncmp(localname, "file:", 5) == 0) localname += 5; - - if (initial_load) { - if ((ip = Fl_Shared_Image::get(localname, W, H)) == NULL) { - ip = (Fl_Shared_Image *)&broken_image; - } - } else { // draw or resize - if ((ip = Fl_Shared_Image::find(localname, W, H)) == NULL) { - ip = (Fl_Shared_Image *)&broken_image; - } else { - ip->release(); - } - } - - return ip; -} - - -/** Gets a length value, either absolute or %. */ -int -Fl_Help_View::get_length(const char *l) { // I - Value - int val; // Integer value - - if (!l[0]) return 0; - - val = atoi(l); - if (l[strlen(l) - 1] == '%') { - if (val > 100) val = 100; - else if (val < 0) val = 0; - - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - val = val * (hsize_ - scrollsize) / 100; - } - - return val; -} - - -Fl_Help_Link *Fl_Help_View::find_link(int xx, int yy) -{ - int i; - Fl_Help_Link *linkp; - for (i = nlinks_, linkp = links_; i > 0; i --, linkp ++) { - if (xx >= linkp->x && xx < linkp->w && - yy >= linkp->y && yy < linkp->h) - break; - } - return i ? linkp : 0L; -} - -void Fl_Help_View::follow_link(Fl_Help_Link *linkp) -{ - char target[32]; // Current target - - clear_selection(); - - strlcpy(target, linkp->name, sizeof(target)); - - set_changed(); - - if (strcmp(linkp->filename, filename_) != 0 && linkp->filename[0]) - { - char dir[FL_PATH_MAX]; // Current directory - char temp[FL_PATH_MAX], // Temporary filename - *tempptr; // Pointer into temporary filename - - - if (strchr(directory_, ':') != NULL && - strchr(linkp->filename, ':') == NULL) - { - if (linkp->filename[0] == '/') - { - strlcpy(temp, directory_, sizeof(temp)); - if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) - strlcpy(tempptr, linkp->filename, sizeof(temp)); - else - strlcat(temp, linkp->filename, sizeof(temp)); - } - else - snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename); - } - else if (linkp->filename[0] != '/' && strchr(linkp->filename, ':') == NULL) - { - if (directory_[0]) - snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename); - else - { - fl_getcwd(dir, sizeof(dir)); - snprintf(temp, sizeof(temp), "file:%s/%s", dir, linkp->filename); - } - } - else - strlcpy(temp, linkp->filename, sizeof(temp)); - - if (linkp->name[0]) - snprintf(temp + strlen(temp), sizeof(temp) - strlen(temp), "#%s", - linkp->name); - - load(temp); - } - else if (target[0]) - topline(target); - else - topline(0); - - leftline(0); -} - -/** Removes the current text selection. */ -void Fl_Help_View::clear_selection() -{ - if (current_view==this) - clear_global_selection(); -} -/** Selects all the text in the view. */ -void Fl_Help_View::select_all() -{ - clear_global_selection(); - if (!value_) return; - current_view = this; - selection_drag_last = selection_last = strlen(value_); - selected = 1; -} - -void Fl_Help_View::clear_global_selection() -{ - if (selected) redraw(); - selection_push_first = selection_push_last = 0; - selection_drag_first = selection_drag_last = 0; - selection_first = selection_last = 0; - selected = 0; -} - -char Fl_Help_View::begin_selection() -{ - clear_global_selection(); - - if (!fl_help_view_buffer) fl_help_view_buffer = fl_create_offscreen(1, 1); - - mouse_x = Fl::event_x(); - mouse_y = Fl::event_y(); - draw_mode = 1; - - current_view = this; - fl_begin_offscreen(fl_help_view_buffer); - draw(); - fl_end_offscreen(); - - draw_mode = 0; - - if (selection_push_last) return 1; - else return 0; -} - -char Fl_Help_View::extend_selection() -{ - if (Fl::event_is_click()) - return 0; - -// printf("old selection_first=%d, selection_last=%d\n", -// selection_first, selection_last); - - int sf = selection_first, sl = selection_last; - - selected = 1; - mouse_x = Fl::event_x(); - mouse_y = Fl::event_y(); - draw_mode = 2; - - fl_begin_offscreen(fl_help_view_buffer); - draw(); - fl_end_offscreen(); - - draw_mode = 0; - - if (selection_push_first < selection_drag_first) { - selection_first = selection_push_first; - } else { - selection_first = selection_drag_first; - } - - if (selection_push_last > selection_drag_last) { - selection_last = selection_push_last; - } else { - selection_last = selection_drag_last; - } - -// printf("new selection_first=%d, selection_last=%d\n", -// selection_first, selection_last); - - if (sf!=selection_first || sl!=selection_last) { -// puts("REDRAW!!!\n"); - return 1; - } else { -// puts(""); - return 0; - } -} - -// convert a command with up to four letters into an unsigned int -static unsigned int command(const char *cmd) -{ - unsigned int ret = (tolower(cmd[0])<<24); - char c = cmd[1]; - if (c=='>' || c==' ' || c==0) return ret; - ret |= (tolower(c)<<16); - c = cmd[2]; - if (c=='>' || c==' ' || c==0) return ret; - ret |= (tolower(c)<<8); - c = cmd[3]; - if (c=='>' || c==' ' || c==0) return ret; - ret |= tolower(c); - c = cmd[4]; - if (c=='>' || c==' ' || c==0) return ret; - return 0; -} - -#define CMD(a, b, c, d) ((a<<24)|(b<<16)|(c<<8)|d) - -void Fl_Help_View::end_selection(int clipboard) -{ - if (!selected || current_view!=this) - return; - // convert the select part of our html text into some kind of somewhat readable ASCII - // and store it in the selection buffer - char p = 0, pre = 0;; - int len = strlen(value_); - char *txt = (char*)malloc(len+1), *d = txt; - const char *s = value_, *cmd, *src; - for (;;) { - char c = *s++; - if (c==0) break; - if (c=='<') { // begin of some html command. Skip until we find a '>' - cmd = s; - for (;;) { - c = *s++; - if (c==0 || c=='>') break; - } - if (c==0) break; - // do something with this command... . - // the replacement string must not be longer that the command itself plus '<' and '>' - src = 0; - switch (command(cmd)) { - case CMD('p','r','e', 0 ): pre = 1; break; - case CMD('/','p','r','e'): pre = 0; break; - case CMD('t','d', 0 , 0 ): - case CMD('p', 0 , 0 , 0 ): - case CMD('/','p', 0 , 0 ): - case CMD('b','r', 0 , 0 ): src = "\n"; break; - case CMD('l','i', 0 , 0 ): src = "\n * "; break; - case CMD('/','h','1', 0 ): - case CMD('/','h','2', 0 ): - case CMD('/','h','3', 0 ): - case CMD('/','h','4', 0 ): - case CMD('/','h','5', 0 ): - case CMD('/','h','6', 0 ): src = "\n\n"; break; - case CMD('t','r', 0 , 0 ): - case CMD('h','1', 0 , 0 ): - case CMD('h','2', 0 , 0 ): - case CMD('h','3', 0 , 0 ): - case CMD('h','4', 0 , 0 ): - case CMD('h','5', 0 , 0 ): - case CMD('h','6', 0 , 0 ): src = "\n\n"; break; - case CMD('d','t', 0 , 0 ): src = "\n "; break; - case CMD('d','d', 0 , 0 ): src = "\n - "; break; - } - int n = s-value_; - if (src && n>selection_first && n<=selection_last) { - while (*src) { - *d++ = *src++; - } - c = src[-1]; - p = isspace(c&255) ? ' ' : c; - } - continue; - } - if (c=='&') { // special characters - int xx = quote_char(s); - if (xx>=0) { - c = (char)xx; - for (;;) { - char cc = *s++; - if (!cc || cc==';') break; - } - } - } - int n = s-value_; - if (n>selection_first && n<=selection_last) { - if (!pre && isspace(c&255)) c = ' '; - if (p!=' '||c!=' ') - *d++ = c; - p = c; - } - } - *d = 0; - Fl::copy(txt, strlen(txt), clipboard); - free(txt); -} - -#define ctrl(x) ((x)&0x1f) - -/** Handles events in the widget. */ -int // O - 1 if we handled it, 0 otherwise -Fl_Help_View::handle(int event) // I - Event to handle -{ - static Fl_Help_Link *linkp; // currently clicked link - - int xx = Fl::event_x() - x() + leftline_; - int yy = Fl::event_y() - y() + topline_; - - switch (event) - { - case FL_FOCUS: - redraw(); - return 1; - case FL_UNFOCUS: - clear_selection(); - redraw(); - return 1; - case FL_ENTER : - Fl_Group::handle(event); - return 1; - case FL_LEAVE : - fl_cursor(FL_CURSOR_DEFAULT); - break; - case FL_MOVE: - if (find_link(xx, yy)) fl_cursor(FL_CURSOR_HAND); - else fl_cursor(FL_CURSOR_DEFAULT); - return 1; - case FL_PUSH: - if (Fl_Group::handle(event)) return 1; - linkp = find_link(xx, yy); - if (linkp) { - fl_cursor(FL_CURSOR_HAND); - return 1; - } - if (begin_selection()) { - fl_cursor(FL_CURSOR_INSERT); - return 1; - } - fl_cursor(FL_CURSOR_DEFAULT); - return 1; - case FL_DRAG: - if (linkp) { - if (Fl::event_is_click()) { - fl_cursor(FL_CURSOR_HAND); - } else { - fl_cursor(FL_CURSOR_DEFAULT); // should be "FL_CURSOR_CANCEL" if we had it - } - return 1; - } - if (current_view==this && selection_push_last) { - if (extend_selection()) redraw(); - fl_cursor(FL_CURSOR_INSERT); - return 1; - } - fl_cursor(FL_CURSOR_DEFAULT); - return 1; - case FL_RELEASE: - if (linkp) { - if (Fl::event_is_click()) { - follow_link(linkp); - } - fl_cursor(FL_CURSOR_DEFAULT); - linkp = 0; - return 1; - } - if (current_view==this && selection_push_last) { - end_selection(); - return 1; - } - return 1; - case FL_SHORTCUT: { - char ascii = Fl::event_text()[0]; - switch (ascii) { - case ctrl('A'): select_all(); redraw(); return 1; - case ctrl('C'): - case ctrl('X'): end_selection(1); return 1; - } - break; } - } - return (Fl_Group::handle(event)); -} - -/** - The constructor creates the Fl_Help_View widget at the specified - position and size. -*/ -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 - Fl::scrollbar_size(), yy, - Fl::scrollbar_size(), hh - Fl::scrollbar_size()), - hscrollbar_(xx, yy + hh - Fl::scrollbar_size(), - ww - Fl::scrollbar_size(), Fl::scrollbar_size()) -{ - color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); - - title_[0] = '\0'; - defcolor_ = FL_FOREGROUND_COLOR; - bgcolor_ = FL_BACKGROUND_COLOR; - textcolor_ = FL_FOREGROUND_COLOR; - linkcolor_ = FL_SELECTION_COLOR; - textfont_ = FL_TIMES; - textsize_ = 12; - value_ = NULL; - - ablocks_ = 0; - nblocks_ = 0; - blocks_ = (Fl_Help_Block *)0; - - link_ = (Fl_Help_Func *)0; - - alinks_ = 0; - nlinks_ = 0; - links_ = (Fl_Help_Link *)0; - - atargets_ = 0; - ntargets_ = 0; - targets_ = (Fl_Help_Target *)0; - - directory_[0] = '\0'; - filename_[0] = '\0'; - - topline_ = 0; - leftline_ = 0; - size_ = 0; - hsize_ = 0; - scrollbar_size_ = 0; - - scrollbar_.value(0, hh, 0, 1); - scrollbar_.step(8.0); - scrollbar_.show(); - scrollbar_.callback(scrollbar_callback); - - hscrollbar_.value(0, ww, 0, 1); - hscrollbar_.step(8.0); - hscrollbar_.show(); - hscrollbar_.callback(hscrollbar_callback); - hscrollbar_.type(FL_HORIZONTAL); - end(); - - resize(xx, yy, ww, hh); -} - - -/** Destroys the Fl_Help_View widget. - - The destructor destroys the widget and frees all memory that has been - allocated for the current document. -*/ -Fl_Help_View::~Fl_Help_View() -{ - clear_selection(); - free_data(); -} - - -/** Loads the specified file. - - This method loads the specified file or URL. -*/ -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 - char newname[FL_PATH_MAX]; // New filename buffer - - // printf("load(%s)\n",f); fflush(stdout); - - if (strncmp(f, "ftp:", 4) == 0 || - strncmp(f, "http:", 5) == 0 || - strncmp(f, "https:", 6) == 0 || - strncmp(f, "ipp:", 4) == 0 || - strncmp(f, "mailto:", 7) == 0 || - strncmp(f, "news:", 5) == 0) { - char urimsg[FL_PATH_MAX]; - if ( fl_open_uri(f, urimsg, sizeof(urimsg)) == 0 ) { - clear_selection(); - - strlcpy(newname, f, sizeof(newname)); - if ((target = strrchr(newname, '#')) != NULL) - *target++ = '\0'; - - if (link_) - localname = (*link_)(this, newname); - else - localname = filename_; - - if (!localname) - return (0); - - free_data(); - - strlcpy(filename_, newname, sizeof(filename_)); - strlcpy(directory_, newname, sizeof(directory_)); - - // Note: We do not support Windows backslashes, since they are illegal - // in URLs... - if ((slash = strrchr(directory_, '/')) == NULL) - directory_[0] = '\0'; - else if (slash > directory_ && slash[-1] != '/') - *slash = '\0'; - - snprintf(error, sizeof(error), - "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" - "<BODY><H1>Error</H1>" - "<P>Unable to follow the link \"%s\" - " - "%s.</P></BODY>", - f, urimsg); - value(error); - //return(-1); - } - return(0); - } - - clear_selection(); - - strlcpy(newname, f, sizeof(newname)); - if ((target = strrchr(newname, '#')) != NULL) - *target++ = '\0'; - - if (link_) - localname = (*link_)(this, newname); - else - localname = filename_; - - if (!localname) - return (0); - - free_data(); - - strlcpy(filename_, newname, sizeof(filename_)); - strlcpy(directory_, newname, sizeof(directory_)); - - // Note: We do not support Windows backslashes, since they are illegal - // in URLs... - if ((slash = strrchr(directory_, '/')) == NULL) - directory_[0] = '\0'; - else if (slash > directory_ && slash[-1] != '/') - *slash = '\0'; - - if (strncmp(localname, "file:", 5) == 0) - localname += 5; // Adjust for local filename... - - if ((fp = fl_fopen(localname, "rb")) != NULL) - { - fseek(fp, 0, SEEK_END); - len = ftell(fp); - rewind(fp); - - value_ = (const char *)calloc(len + 1, 1); - if (fread((void *)value_, 1, len, fp)==0) { /* use default 0 */ } - fclose(fp); - } - else - { - snprintf(error, sizeof(error), - "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" - "<BODY><H1>Error</H1>" - "<P>Unable to follow the link \"%s\" - " - "%s.</P></BODY>", - localname, strerror(errno)); - value_ = strdup(error); - } - - initial_load = 1; - format(); - initial_load = 0; - - if (target) - topline(target); - else - topline(0); - - return (0); -} - - -/** Resizes 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_Boxtype b = box() ? box() : FL_DOWN_BOX; - // Box to draw... - - - Fl_Widget::resize(xx, yy, ww, hh); - - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - scrollbar_.resize(x() + w() - scrollsize - Fl::box_dw(b) + Fl::box_dx(b), - y() + Fl::box_dy(b), scrollsize, h() - scrollsize - Fl::box_dh(b)); - hscrollbar_.resize(x() + Fl::box_dx(b), - y() + h() - scrollsize - Fl::box_dh(b) + Fl::box_dy(b), - w() - scrollsize - Fl::box_dw(b), scrollsize); - - format(); -} - - -/** Scrolls the text to the indicated position, given a named destination. - - \param[in] n target name -*/ -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; - - strlcpy(key.name, n, sizeof(key.name)); - - target = (Fl_Help_Target *)bsearch(&key, targets_, ntargets_, sizeof(Fl_Help_Target), - (compare_func_t)compare_targets); - - if (target != NULL) - topline(target->y); -} - - -/** Scrolls the text to the indicated position, given a pixel line. - - If the given pixel value \p top is out of range, then the text is - scrolled to the top or bottom of the document, resp. - - \param[in] top top line number in pixels (0 = start of document) -*/ -void -Fl_Help_View::topline(int top) // I - Top line number -{ - if (!value_) - return; - - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - if (size_ < (h() - scrollsize) || top < 0) - top = 0; - else if (top > size_) - top = size_; - - topline_ = top; - - scrollbar_.value(topline_, h() - scrollsize, 0, size_); - - do_callback(); - - redraw(); -} - - -/** Scrolls the text to the indicated position, given a pixel column. - - If the given pixel value \p left is out of range, then the text is - scrolled to the left or right side of the document, resp. - - \param[in] left left column number in pixels (0 = left side) -*/ -void -Fl_Help_View::leftline(int left) // I - Left position -{ - if (!value_) - return; - - int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); - if (hsize_ < (w() - scrollsize) || left < 0) - left = 0; - else if (left > hsize_) - left = hsize_; - - leftline_ = left; - - hscrollbar_.value(leftline_, w() - scrollsize, 0, hsize_); - - redraw(); -} - - -/** Sets the current help text buffer to the string provided and reformats the text. - - The provided character string \p val is copied internally and will be - freed when value() is called again, or when the widget is destroyed. - - If \p val is NULL, then the widget is cleared. -*/ -void -Fl_Help_View::value(const char *val) // I - Text to view -{ - clear_selection(); - free_data(); - set_changed(); - - if (!val) - return; - - value_ = strdup(val); - - initial_load = 1; - format(); - initial_load = 0; - - topline(0); - leftline(0); -} - - -#ifdef ENC -# undef ENC -#endif -// part b in the table seems to be mac_roman - beku -# define ENC(a, b) a - - -/** Returns the character code associated with a quoted char. */ -static int // O - Code or -1 on error -quote_char(const char *p) { // I - Quoted string - int i; // Looping var - static struct { - const char *name; - int namelen; - int code; - } *nameptr, // Pointer into name array - names[] = { // Quoting names - { "Aacute;", 7, ENC(193,231) }, - { "aacute;", 7, ENC(225,135) }, - { "Acirc;", 6, ENC(194,229) }, - { "acirc;", 6, ENC(226,137) }, - { "acute;", 6, ENC(180,171) }, - { "AElig;", 6, ENC(198,174) }, - { "aelig;", 6, ENC(230,190) }, - { "Agrave;", 7, ENC(192,203) }, - { "agrave;", 7, ENC(224,136) }, - { "amp;", 4, ENC('&','&') }, - { "Aring;", 6, ENC(197,129) }, - { "aring;", 6, ENC(229,140) }, - { "Atilde;", 7, ENC(195,204) }, - { "atilde;", 7, ENC(227,139) }, - { "Auml;", 5, ENC(196,128) }, - { "auml;", 5, ENC(228,138) }, - { "brvbar;", 7, ENC(166, -1) }, - { "bull;", 5, ENC(149,165) }, - { "Ccedil;", 7, ENC(199,199) }, - { "ccedil;", 7, ENC(231,141) }, - { "cedil;", 6, ENC(184,252) }, - { "cent;", 5, ENC(162,162) }, - { "copy;", 5, ENC(169,169) }, - { "curren;", 7, ENC(164, -1) }, - { "deg;", 4, ENC(176,161) }, - { "divide;", 7, ENC(247,214) }, - { "Eacute;", 7, ENC(201,131) }, - { "eacute;", 7, ENC(233,142) }, - { "Ecirc;", 6, ENC(202,230) }, - { "ecirc;", 6, ENC(234,144) }, - { "Egrave;", 7, ENC(200,233) }, - { "egrave;", 7, ENC(232,143) }, - { "ETH;", 4, ENC(208, -1) }, - { "eth;", 4, ENC(240, -1) }, - { "Euml;", 5, ENC(203,232) }, - { "euml;", 5, ENC(235,145) }, - { "euro;", 5, ENC(128,219) }, - { "frac12;", 7, ENC(189, -1) }, - { "frac14;", 7, ENC(188, -1) }, - { "frac34;", 7, ENC(190, -1) }, - { "gt;", 3, ENC('>','>') }, - { "Iacute;", 7, ENC(205,234) }, - { "iacute;", 7, ENC(237,146) }, - { "Icirc;", 6, ENC(206,235) }, - { "icirc;", 6, ENC(238,148) }, - { "iexcl;", 6, ENC(161,193) }, - { "Igrave;", 7, ENC(204,237) }, - { "igrave;", 7, ENC(236,147) }, - { "iquest;", 7, ENC(191,192) }, - { "Iuml;", 5, ENC(207,236) }, - { "iuml;", 5, ENC(239,149) }, - { "laquo;", 6, ENC(171,199) }, - { "lt;", 3, ENC('<','<') }, - { "macr;", 5, ENC(175,248) }, - { "micro;", 6, ENC(181,181) }, - { "middot;", 7, ENC(183,225) }, - { "nbsp;", 5, ENC(' ',' ') }, - { "not;", 4, ENC(172,194) }, - { "Ntilde;", 7, ENC(209,132) }, - { "ntilde;", 7, ENC(241,150) }, - { "Oacute;", 7, ENC(211,238) }, - { "oacute;", 7, ENC(243,151) }, - { "Ocirc;", 6, ENC(212,239) }, - { "ocirc;", 6, ENC(244,153) }, - { "Ograve;", 7, ENC(210,241) }, - { "ograve;", 7, ENC(242,152) }, - { "ordf;", 5, ENC(170,187) }, - { "ordm;", 5, ENC(186,188) }, - { "Oslash;", 7, ENC(216,175) }, - { "oslash;", 7, ENC(248,191) }, - { "Otilde;", 7, ENC(213,205) }, - { "otilde;", 7, ENC(245,155) }, - { "Ouml;", 5, ENC(214,133) }, - { "ouml;", 5, ENC(246,154) }, - { "para;", 5, ENC(182,166) }, - { "premil;", 7, ENC(137,228) }, - { "plusmn;", 7, ENC(177,177) }, - { "pound;", 6, ENC(163,163) }, - { "quot;", 5, ENC('\"','\"') }, - { "raquo;", 6, ENC(187,200) }, - { "reg;", 4, ENC(174,168) }, - { "sect;", 5, ENC(167,164) }, - { "shy;", 4, ENC(173,'-') }, - { "sup1;", 5, ENC(185, -1) }, - { "sup2;", 5, ENC(178, -1) }, - { "sup3;", 5, ENC(179, -1) }, - { "szlig;", 6, ENC(223,167) }, - { "THORN;", 6, ENC(222, -1) }, - { "thorn;", 6, ENC(254, -1) }, - { "times;", 6, ENC(215,'x') }, - { "trade;", 6, ENC(153,170) }, - { "Uacute;", 7, ENC(218,242) }, - { "uacute;", 7, ENC(250,156) }, - { "Ucirc;", 6, ENC(219,243) }, - { "ucirc;", 6, ENC(251,158) }, - { "Ugrave;", 7, ENC(217,244) }, - { "ugrave;", 7, ENC(249,157) }, - { "uml;", 4, ENC(168,172) }, - { "Uuml;", 5, ENC(220,134) }, - { "uuml;", 5, ENC(252,159) }, - { "Yacute;", 7, ENC(221, -1) }, - { "yacute;", 7, ENC(253, -1) }, - { "yen;", 4, ENC(165,180) }, - { "Yuml;", 5, ENC(159,217) }, - { "yuml;", 5, ENC(255,216) } - }; - - if (!strchr(p, ';')) return -1; - if (*p == '#') { - if (*(p+1) == 'x' || *(p+1) == 'X') return strtol(p+2, NULL, 16); - else return atoi(p+1); - } - for (i = (int)(sizeof(names) / sizeof(names[0])), nameptr = names; i > 0; i --, nameptr ++) - if (strncmp(p, nameptr->name, nameptr->namelen) == 0) - return nameptr->code; - - return -1; -} - - -/** The vertical scrollbar callback. */ -static void -scrollbar_callback(Fl_Widget *s, void *) -{ - ((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value())); -} - - -/** The horizontal scrollbar callback. */ -static void -hscrollbar_callback(Fl_Widget *s, void *) -{ - ((Fl_Help_View *)(s->parent()))->leftline(int(((Fl_Scrollbar*)s)->value())); -} - - -// -// End of "$Id$". -// |
