a8fdff552b
to help this developer get his bearings.. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6776 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
3520 lines
87 KiB
C++
3520 lines
87 KiB
C++
//
|
|
// "$Id$"
|
|
//
|
|
// Fl_Help_View widget routines.
|
|
//
|
|
// Copyright 1997-2009 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[1024]; // Current directory
|
|
char temp[1024], // 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[1024]; // Current directory
|
|
char temp[1024], // 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[1024]; // 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[256];
|
|
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);
|
|
fread((void *)value_, 1, len, fp);
|
|
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$".
|
|
//
|