#include <FL/Fl_Help_View.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Pixmap.H>
#include <FL/Fl_Menu_Item.H>
#include "Fl_Int_Vector.H"
#include "Fl_String.H"
#include <stdio.h>
#include <stdlib.h>
#include <FL/fl_utf8.h>
#include <FL/filename.H>
#include <FL/fl_string_functions.h>
#include "flstring.h"
#include <ctype.h>
#include <errno.h>
#include <math.h>
#define MAX_COLUMNS 200
extern "C"
{
typedef int (*compare_func_t)(const void *, const void *);
}
static int quote_char(const char *);
static void scrollbar_callback(Fl_Widget *s, void *);
static void hscrollbar_callback(Fl_Widget *s, void *);
static char *skip_bytes(const char *p, int n) {
for (int i = 0; i < n; ++i) {
if (*p == '\0') break;
++p;
}
return const_cast<char *>(p);
}
static char initial_load = 0;
static const char * const broken_xpm[] =
{
"16 24 4 1",
"@ c #000000",
" c #ffffff",
"+ c none",
"x c #ff0000",
"@@@@@@@+++++++++",
"@ @++++++++++",
"@ @+++++++++++",
"@ @++@++++++++",
"@ @@+++++++++",
"@ @+++@+++++",
"@ @++@@++++@",
"@ xxx @@ @++@@",
"@ xxx xx@@ @",
"@ xxx xxx @",
"@ xxxxxx @",
"@ xxxx @",
"@ xxxxxx @",
"@ xxx xxx @",
"@ xxx xxx @",
"@ xxx xxx @",
"@ @",
"@ @",
"@ @",
"@ @",
"@ @",
"@ @",
"@ @",
"@@@@@@@@@@@@@@@@",
NULL
};
static Fl_Pixmap broken_image(broken_xpm);
const char *Fl_Help_View::copy_menu_text = "Copy";
static Fl_Menu_Item rmb_menu[] = {
{ NULL, 0, NULL, (void*)1 }, { NULL }
};
struct fl_margins {
int depth_;
int margins_[100];
fl_margins() { clear(); }
int clear() {
depth_ = 0;
return margins_[0] = 4;
}
int current() { return margins_[depth_]; }
int pop() {
if (depth_ > 0) {
depth_ --;
return margins_[depth_];
} else return 4;
}
int push(int indent) {
int xx;
xx = margins_[depth_] + indent;
if (depth_ < 99) {
depth_ ++;
margins_[depth_] = xx;
}
return xx;
}
};
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_;
void Fl_Help_View::hv_draw(const char *t, int x, int y, int entity_extra_length)
{
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 = (int) current_pos_;
int l = (int) (f+strlen(t)); if (draw_mode_==1) {
selection_push_first_ = f;
selection_push_last_ = l;
} else {
selection_drag_first_ = f;
selection_drag_last_ = l + entity_extra_length;
}
}
}
}
}
#define DEBUG_EDIT_BUFFER 0
#if (DEBUG_EDIT_BUFFER > 1)
#define DEBUG_FUNCTION(L,F) \
printf("\n========\n [%d] --- %s\n========\n", L, F); \
fflush(stdout);
#else
#define DEBUG_FUNCTION(L,F)
#endif
class HV_Edit_Buffer : public Fl_String {
public:
void add(int ucs);
int cmp(const char *str) {
return !strcasecmp(c_str(), str);
}
int width() {
return (int)fl_width(c_str());
}
#if (DEBUG_EDIT_BUFFER)
void print(const char *text = "");
#endif
};
void HV_Edit_Buffer::add(int ucs) {
int len;
char cbuf[6];
len = fl_utf8encode((unsigned int)ucs, cbuf);
if (len < 1) len = 1;
append(cbuf, len);
}
#if (DEBUG_EDIT_BUFFER)
void HV_Edit_Buffer::print(const char *text) {
printf("HV_Edit_Buffer::print(%s), capacity=%d, size=%d\n",
text, capacity(), size());
printf(" \"%s\"\n", c_str() && size() ? c_str() : "");
fflush(stdout);
} #endif
Fl_Help_Block * Fl_Help_View::add_block(const char *s, int xx, int yy, int ww, int hh, unsigned char border) {
Fl_Help_Block *temp;
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);
}
void Fl_Help_View::add_link(const char *n, int xx, int yy, int ww, int hh) {
Fl_Help_Link *temp; char *target;
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_ ++;
}
void Fl_Help_View::add_target(const char *n, int yy) {
Fl_Help_Target *temp;
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_ ++;
}
int Fl_Help_View::compare_targets(const Fl_Help_Target *t0, const Fl_Help_Target *t1) {
return (strcasecmp(t0->name, t1->name));
}
int Fl_Help_View::do_align(Fl_Help_Block *block, int line, int xx, int a, int &l) {
int offset;
switch (a)
{
case RIGHT : offset = block->w - xx;
break;
case CENTER : offset = (block->w - xx) / 2;
break;
default : 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);
}
void
Fl_Help_View::draw()
{
int i; const Fl_Help_Block *block; const char *ptr, *attrs; HV_Edit_Buffer buf; char attr[1024]; int xx, yy, ww, hh; int line; Fl_Font font;
Fl_Fontsize fsize; Fl_Color fcolor; int head, pre, needspace; Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
int underline, xtra_ww;
DEBUG_FUNCTION(__LINE__,__FUNCTION__);
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();
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 ) { hscrollbar_.resize(x(), scorn_y, scorn_x - x(), scrollsize);
init_sizes();
}
draw_child(hscrollbar_);
hh -= scrollsize;
}
if ( ver_vis ) {
if ( scrollbar_.w() != scrollsize ) { scrollbar_.resize(scorn_x, y(), scrollsize, scorn_y - y());
init_sizes();
}
draw_child(scrollbar_);
ww -= scrollsize;
}
if ( hor_vis && ver_vis ) {
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;
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_);
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);
int entity_extra_length = 0;
for (ptr = block->start, buf.clear(); ptr < block->end;)
{
if ((*ptr == '<' || isspace((*ptr)&255)) && buf.size() > 0)
{
if (!head && !pre)
{
ww = buf.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;
}
hv_draw(buf.c_str(), xx + x() - leftline_, yy + y(), entity_extra_length);
buf.clear();
entity_extra_length = 0;
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_ = (int) (ptr-value_);
xx += ww;
if ((fsize + 2) > hh)
hh = fsize + 2;
needspace = 0;
}
else if (pre)
{
while (isspace((*ptr)&255))
{
if (*ptr == '\n')
{
hv_draw(buf.c_str(), xx + x() - leftline_, yy + y());
if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1,
xx + x() - leftline_ + buf.width());
buf.clear();
current_pos_ = (int) (ptr-value_);
if (line < 31)
line ++;
xx = block->line[line];
yy += hh;
hh = fsize + 2;
}
else if (*ptr == '\t')
{
buf += ' '; while (buf.size() & 7)
buf += ' ';
}
else {
buf += ' ';
}
if ((fsize + 2) > hh)
hh = fsize + 2;
ptr ++;
}
if (buf.size() > 0)
{
hv_draw(buf.c_str(), xx + x() - leftline_, yy + y());
ww = buf.width();
buf.clear();
if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1,
xx + x() - leftline_ + ww);
xx += ww;
current_pos_ = (int) (ptr-value_);
}
needspace = 0;
}
else
{
buf.clear();
while (isspace((*ptr)&255))
ptr ++;
current_pos_ = (int) (ptr-value_);
}
}
if (*ptr == '<')
{
ptr ++;
if (strncmp(ptr, "!--", 3) == 0)
{
ptr += 3;
if ((ptr = strstr(ptr, "-->")) != NULL)
{
ptr += 3;
continue;
}
else
break;
}
while (*ptr && *ptr != '>' && !isspace((*ptr)&255))
buf += *ptr++;
attrs = ptr;
while (*ptr && *ptr != '>')
ptr ++;
if (*ptr == '>')
ptr ++;
current_pos_ = (int) (ptr-value_);
if (buf.cmp("HEAD"))
head = 1;
else if (buf.cmp("BR"))
{
if (line < 31)
line ++;
xx = block->line[line];
yy += hh;
hh = 0;
}
else if (buf.cmp("HR"))
{
fl_line(block->x + x(), yy + y(), block->w + x(),
yy + y());
if (line < 31)
line ++;
xx = block->line[line];
yy += 2 * fsize; hh = 0;
}
else if (buf.cmp("CENTER") ||
buf.cmp("P") ||
buf.cmp("H1") ||
buf.cmp("H2") ||
buf.cmp("H3") ||
buf.cmp("H4") ||
buf.cmp("H5") ||
buf.cmp("H6") ||
buf.cmp("UL") ||
buf.cmp("OL") ||
buf.cmp("DL") ||
buf.cmp("LI") ||
buf.cmp("DD") ||
buf.cmp("DT") ||
buf.cmp("PRE"))
{
if (tolower(buf[0]) == 'h')
{
font = FL_HELVETICA_BOLD;
fsize = textsize_ + '7' - buf[1];
}
else if (buf.cmp("DT"))
{
font = textfont_ | FL_ITALIC;
fsize = textsize_;
}
else if (buf.cmp("PRE"))
{
font = FL_COURIER;
fsize = textsize_;
pre = 1;
}
if (buf.cmp("LI"))
{
if (block->ol) {
char buf[10];
snprintf(buf, sizeof(buf), "%d. ", block->ol_num);
hv_draw(buf, xx - (int)fl_width(buf) + x() - leftline_, yy + y());
}
else {
unsigned char bullet[4] = { 0xe2, 0x80, 0xa2, 0x00 };
hv_draw((char *)bullet, xx - fsize + x() - leftline_, yy + y());
}
}
pushfont(font, fsize);
buf.clear();
}
else if (buf.cmp("A") &&
get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
{
fl_color(linkcolor_);
underline = 1;
}
else if (buf.cmp("/A"))
{
fl_color(textcolor_);
underline = 0;
}
else if (buf.cmp("FONT"))
{
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)) {
fsize = (int)(textsize_ * pow(1.2, atof(attr) - 3.0));
} else {
fsize = (int)(fsize * pow(1.2, atof(attr) - 3.0));
}
}
pushfont(font, fsize);
}
else if (buf.cmp("/FONT"))
{
popfont(font, fsize, textcolor_);
}
else if (buf.cmp("U"))
underline = 1;
else if (buf.cmp("/U"))
underline = 0;
else if (buf.cmp("B") ||
buf.cmp("STRONG"))
pushfont(font |= FL_BOLD, fsize);
else if (buf.cmp("TD") ||
buf.cmp("TH"))
{
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 (buf.cmp("I") ||
buf.cmp("EM"))
pushfont(font |= FL_ITALIC, fsize);
else if (buf.cmp("CODE") ||
buf.cmp("TT"))
pushfont(font = FL_COURIER, fsize);
else if (buf.cmp("KBD"))
pushfont(font = FL_COURIER_BOLD, fsize);
else if (buf.cmp("VAR"))
pushfont(font = FL_COURIER_ITALIC, fsize);
else if (buf.cmp("/HEAD"))
head = 0;
else if (buf.cmp("/H1") ||
buf.cmp("/H2") ||
buf.cmp("/H3") ||
buf.cmp("/H4") ||
buf.cmp("/H5") ||
buf.cmp("/H6") ||
buf.cmp("/B") ||
buf.cmp("/STRONG") ||
buf.cmp("/I") ||
buf.cmp("/EM") ||
buf.cmp("/CODE") ||
buf.cmp("/TT") ||
buf.cmp("/KBD") ||
buf.cmp("/VAR"))
popfont(font, fsize, fcolor);
else if (buf.cmp("/PRE"))
{
popfont(font, fsize, fcolor);
pre = 0;
}
else if (buf.cmp("IMG"))
{
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;
}
buf.clear();
}
else if (*ptr == '\n' && pre)
{
hv_draw(buf.c_str(), xx + x() - leftline_, yy + y());
buf.clear();
if (line < 31)
line ++;
xx = block->line[line];
yy += hh;
hh = fsize + 2;
needspace = 0;
ptr ++;
current_pos_ = (int) (ptr-value_);
}
else if (isspace((*ptr)&255))
{
if (pre)
{
if (*ptr == ' ')
buf += ' ';
else
{
buf += ' '; while (buf.size() & 7)
buf += ' ';
}
}
ptr ++;
if (!pre) current_pos_ = (int) (ptr-value_);
needspace = 1;
}
else if (*ptr == '&') {
ptr ++;
int qch = quote_char(ptr);
if (qch < 0)
buf += '&';
else {
int utf8l = buf.size();
buf.add(qch);
utf8l = buf.size() - utf8l; const char *oldptr = ptr;
ptr = strchr(ptr, ';') + 1;
entity_extra_length += int(ptr - (oldptr-1)) - utf8l; }
if ((fsize + 2) > hh)
hh = fsize + 2;
}
else
{
buf += *ptr++;
if ((fsize + 2) > hh)
hh = fsize + 2;
}
}
if (buf.size() > 0 && !pre && !head)
{
ww = buf.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 (buf.size() > 0 && !head)
{
hv_draw(buf.c_str(), xx + x() - leftline_, yy + y());
if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1,
xx + x() - leftline_ + ww);
current_pos_ = (int) (ptr-value_);
}
}
fl_pop_clip();
}
static const char *vanilla(const char *p, const char *end) {
if (*p == '\0' || p >= end) return end;
for (;;) {
if (*p != '<') {
return p;
} else {
while (*p && p < end && *p != '>') p++;
}
p++;
if (*p == '\0' || p >= end) return end;
}
}
int Fl_Help_View::find(const char *s, int p) {
int i, c; Fl_Help_Block *b; const char *bp, *bs, *sp;
DEBUG_FUNCTION(__LINE__,__FUNCTION__);
if (!s || !value_) return -1;
if (p < 0 || p >= (int)strlen(value_)) p = 0;
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;
bp = vanilla(bp, b->end);
if (bp == b->end)
continue;
for (sp = s, bs = bp; *sp && *bp && bp < b->end; ) {
bool is_html_entity = false;
if (*bp == '&') {
if ((c = quote_char(bp + 1)) < 0) {
c = '&';
} else {
const char *entity_end = strchr(bp + 1, ';');
if (entity_end) {
is_html_entity = true; bp = entity_end;
} else {
c = '&';
}
}
} else {
c = *bp;
}
if (c == '\n') c = ' ';
int utf_len = 1;
if (c > 0x20 && c < 0x80 && tolower(*sp) == tolower(c)) {
sp++;
bp = vanilla(bp+1, b->end);
} else if (is_html_entity && fl_utf8decode(sp, NULL, &utf_len) == (unsigned int)c ) {
sp += utf_len;
bp = vanilla(bp+1, b->end);
} else if (*sp == c) {
sp++;
bp = vanilla(bp+1, b->end);
} else {
sp = s;
bp = bs = vanilla(bs+1, b->end);
}
}
if (!*sp) { topline(b->y - b->h);
return int(bs - value_);
}
}
return (-1);
}
void Fl_Help_View::format() {
int i; int done; Fl_Help_Block *block, *cell; int cells[MAX_COLUMNS],
row; const char *ptr, *start, *attrs; HV_Edit_Buffer buf; char attr[1024], wattr[1024], hattr[1024], linkdest[1024]; int xx, yy, ww, hh; int line; int links; Fl_Font font;
Fl_Fontsize fsize; Fl_Color fcolor; unsigned char border; int talign, newalign, head, pre, needspace; int table_width, table_offset; int column, columns[MAX_COLUMNS];
Fl_Color tc, rc; Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
fl_margins margins; Fl_Int_Vector OL_num;
OL_num.push_back(-1);
DEBUG_FUNCTION(__LINE__,__FUNCTION__);
int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
hsize_ = w() - scrollsize - Fl::box_dw(b);
done = 0;
while (!done)
{
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;
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;
for (ptr = value_, buf.clear(); *ptr;)
{
if ((*ptr == '<' || isspace((*ptr)&255)) && buf.size() > 0)
{
ww = buf.width();
if (!head && !pre)
{
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;
if ((fsize + 2) > hh)
hh = fsize + 2;
needspace = 0;
}
else if (pre)
{
if (linkdest[0])
add_link(linkdest, xx, yy - hh, ww, hh);
xx += ww;
if ((fsize + 2) > hh)
hh = fsize + 2;
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
{
while (isspace((*ptr)&255))
ptr ++;
}
buf.clear();
}
if (*ptr == '<')
{
start = ptr;
ptr ++;
if (strncmp(ptr, "!--", 3) == 0)
{
ptr += 3;
if ((ptr = strstr(ptr, "-->")) != NULL)
{
ptr += 3;
continue;
}
else
break;
}
while (*ptr && *ptr != '>' && !isspace((*ptr)&255))
buf += *ptr++;
attrs = ptr;
while (*ptr && *ptr != '>')
ptr ++;
if (*ptr == '>')
ptr ++;
if (buf.cmp("HEAD"))
head = 1;
else if (buf.cmp("/HEAD"))
head = 0;
else if (buf.cmp("TITLE"))
{
char *st;
for (st = title_;
*ptr != '<' && *ptr && st < (title_ + sizeof(title_) - 1);
*st++ = *ptr++) {}
*st = '\0';
buf.clear();
}
else if (buf.cmp("A"))
{
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 (buf.cmp("/A"))
linkdest[0] = '\0';
else if (buf.cmp("BODY"))
{
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 (buf.cmp("BR"))
{
line = do_align(block, line, xx, newalign, links);
xx = block->x;
block->h += hh;
yy += hh;
hh = 0;
}
else if (buf.cmp("CENTER") ||
buf.cmp("P") ||
buf.cmp("H1") ||
buf.cmp("H2") ||
buf.cmp("H3") ||
buf.cmp("H4") ||
buf.cmp("H5") ||
buf.cmp("H6") ||
buf.cmp("UL") ||
buf.cmp("OL") ||
buf.cmp("DL") ||
buf.cmp("LI") ||
buf.cmp("DD") ||
buf.cmp("DT") ||
buf.cmp("HR") ||
buf.cmp("PRE") ||
buf.cmp("TABLE"))
{
block->end = start;
line = do_align(block, line, xx, newalign, links);
newalign = buf.cmp("CENTER") ? CENTER : LEFT;
xx = block->x;
block->h += hh;
if (buf.cmp("OL")) {
int ol_num = 1;
if (get_attr(attrs, "START", attr, sizeof(attr)) != NULL) {
errno = 0;
char *endptr = 0;
ol_num = (int)strtol(attr, &endptr, 10);
if (errno || endptr == attr || ol_num < 0)
ol_num = 1;
}
OL_num.push_back(ol_num);
}
else if (buf.cmp("UL"))
OL_num.push_back(-1);
if (buf.cmp("UL") ||
buf.cmp("OL") ||
buf.cmp("DL"))
{
block->h += fsize + 2;
xx = margins.push(4 * fsize);
}
else if (buf.cmp("TABLE"))
{
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 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 (buf.cmp("DT"))
{
font = textfont_ | FL_ITALIC;
fsize = textsize_;
}
else if (buf.cmp("PRE"))
{
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])) ||
buf.cmp("DD") ||
buf.cmp("DT") ||
buf.cmp("P"))
yy += fsize + 2;
else if (buf.cmp("HR"))
{
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);
if (buf.cmp("LI")) {
block->ol = 0;
if (OL_num.size() && OL_num.back()>=0) {
block->ol = 1;
block->ol_num = (int)OL_num.back();
int nnum = OL_num.pop_back() + 1;
OL_num.push_back(nnum);
}
}
needspace = 0;
line = 0;
if (buf.cmp("CENTER"))
newalign = talign = CENTER;
else
newalign = get_align(attrs, talign);
}
else if (buf.cmp("/CENTER") ||
buf.cmp("/P") ||
buf.cmp("/H1") ||
buf.cmp("/H2") ||
buf.cmp("/H3") ||
buf.cmp("/H4") ||
buf.cmp("/H5") ||
buf.cmp("/H6") ||
buf.cmp("/PRE") ||
buf.cmp("/UL") ||
buf.cmp("/OL") ||
buf.cmp("/DL") ||
buf.cmp("/TABLE"))
{
line = do_align(block, line, xx, newalign, links);
xx = block->x;
block->end = ptr;
if (buf.cmp("/OL") ||
buf.cmp("/UL")) {
if (OL_num.size()) OL_num.pop_back();
}
if (buf.cmp("/UL") ||
buf.cmp("/OL") ||
buf.cmp("/DL"))
{
xx = margins.pop();
block->h += fsize + 2;
}
else if (buf.cmp("/TABLE"))
{
block->h += fsize + 2;
xx = margins.current();
}
else if (buf.cmp("/PRE"))
{
pre = 0;
hh = 0;
}
else if (buf.cmp("/CENTER"))
talign = LEFT;
popfont(font, fsize, fcolor);
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 (buf.cmp("TR"))
{
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 = (int) (block - blocks_);
needspace = 0;
column = 0;
line = 0;
rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc);
}
else if (buf.cmp("/TR") && 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 ;
block = add_block(start, xx, yy, hsize_, 0);
needspace = 0;
row = 0;
line = 0;
}
else if ((buf.cmp("TD") ||
buf.cmp("TH")) && row)
{
int colspan;
line = do_align(block, line, xx, newalign, links);
block->end = start;
block->h += hh;
if (buf.cmp("TH"))
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] = (int) (block - blocks_);
column += colspan;
block->bgcolor = get_color(get_attr(attrs, "BGCOLOR", attr,
sizeof(attr)), rc);
}
else if ((buf.cmp("/TD") ||
buf.cmp("/TH")) && row)
{
line = do_align(block, line, xx, newalign, links);
popfont(font, fsize, fcolor);
xx = margins.pop();
talign = LEFT;
}
else if (buf.cmp("FONT"))
{
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)) {
fsize = (int)(textsize_ * pow(1.2, atoi(attr) - 3.0));
} else {
fsize = (int)(fsize * pow(1.2, atoi(attr)));
}
}
pushfont(font, fsize);
}
else if (buf.cmp("/FONT"))
popfont(font, fsize, fcolor);
else if (buf.cmp("B") ||
buf.cmp("STRONG"))
pushfont(font |= FL_BOLD, fsize);
else if (buf.cmp("I") ||
buf.cmp("EM"))
pushfont(font |= FL_ITALIC, fsize);
else if (buf.cmp("CODE") ||
buf.cmp("TT"))
pushfont(font = FL_COURIER, fsize);
else if (buf.cmp("KBD"))
pushfont(font = FL_COURIER_BOLD, fsize);
else if (buf.cmp("VAR"))
pushfont(font = FL_COURIER_ITALIC, fsize);
else if (buf.cmp("/B") ||
buf.cmp("/STRONG") ||
buf.cmp("/I") ||
buf.cmp("/EM") ||
buf.cmp("/CODE") ||
buf.cmp("/TT") ||
buf.cmp("/KBD") ||
buf.cmp("/VAR"))
popfont(font, fsize, fcolor);
else if (buf.cmp("IMG"))
{
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-fsize, ww, height);
xx += ww;
if ((height + 2) > hh)
hh = height + 2;
needspace = 0;
}
buf.clear();
}
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 == '&')
{
ptr ++;
int qch = quote_char(ptr);
if (qch < 0)
buf += '&';
else {
buf.add(qch);
ptr = strchr(ptr, ';') + 1;
}
if ((fsize + 2) > hh)
hh = fsize + 2;
}
else
{
buf += *ptr++;
if ((fsize + 2) > hh)
hh = fsize + 2;
}
}
if (buf.size() > 0 && !head)
{
ww = buf.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 - fsize, ww, fsize);
xx += ww;
}
do_align(block, line, xx, newalign, links);
block->end = ptr;
size_ = yy + hh;
}
if (hh > block->h) block->h = hh;
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();
}
}
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);
}
void
Fl_Help_View::format_table(int *table_width, int *columns, const char *table) {
int column, num_columns, colspan, width, temp_width, max_width, incell, pre, needspace; HV_Edit_Buffer buf; char attr[1024], wattr[1024], hattr[1024]; const char *ptr, *attrs, *start; int minwidths[MAX_COLUMNS]; Fl_Font font;
Fl_Fontsize fsize; Fl_Color fcolor;
DEBUG_FUNCTION(__LINE__,__FUNCTION__);
*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);
for (ptr = table, column = -1, width = 0, incell = 0; *ptr;)
{
if ((*ptr == '<' || isspace((*ptr)&255)) && buf.size() > 0 && incell)
{
if (needspace)
{
buf += ' ';
needspace = 0;
}
temp_width = buf.width();
buf.clear();
if (temp_width > minwidths[column])
minwidths[column] = temp_width;
width += temp_width;
if (width > max_width)
max_width = width;
}
if (*ptr == '<')
{
start = ptr;
for (buf.clear(), ptr ++; *ptr && *ptr != '>' && !isspace((*ptr)&255);)
buf += *ptr++;
attrs = ptr;
while (*ptr && *ptr != '>')
ptr ++;
if (*ptr == '>')
ptr ++;
if (buf.cmp("BR") ||
buf.cmp("HR"))
{
width = 0;
needspace = 0;
}
else if (buf.cmp("TABLE") && start > table)
break;
else if (buf.cmp("CENTER") ||
buf.cmp("P") ||
buf.cmp("H1") ||
buf.cmp("H2") ||
buf.cmp("H3") ||
buf.cmp("H4") ||
buf.cmp("H5") ||
buf.cmp("H6") ||
buf.cmp("UL") ||
buf.cmp("OL") ||
buf.cmp("DL") ||
buf.cmp("LI") ||
buf.cmp("DD") ||
buf.cmp("DT") ||
buf.cmp("PRE"))
{
width = 0;
needspace = 0;
if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
{
font = FL_HELVETICA_BOLD;
fsize = textsize_ + '7' - buf[1];
}
else if (buf.cmp("DT"))
{
font = textfont_ | FL_ITALIC;
fsize = textsize_;
}
else if (buf.cmp("PRE"))
{
font = FL_COURIER;
fsize = textsize_;
pre = 1;
}
else if (buf.cmp("LI"))
{
width += 4 * fsize;
font = textfont_;
fsize = textsize_;
}
else
{
font = textfont_;
fsize = textsize_;
}
pushfont(font, fsize);
}
else if (buf.cmp("/CENTER") ||
buf.cmp("/P") ||
buf.cmp("/H1") ||
buf.cmp("/H2") ||
buf.cmp("/H3") ||
buf.cmp("/H4") ||
buf.cmp("/H5") ||
buf.cmp("/H6") ||
buf.cmp("/PRE") ||
buf.cmp("/UL") ||
buf.cmp("/OL") ||
buf.cmp("/DL"))
{
width = 0;
needspace = 0;
popfont(font, fsize, fcolor);
}
else if (buf.cmp("TR") || buf.cmp("/TR") ||
buf.cmp("/TABLE"))
{
if (column >= 0)
{
max_width /= colspan;
while (colspan > 0)
{
if (max_width > columns[column])
columns[column] = max_width;
column ++;
colspan --;
}
}
if (buf.cmp("/TABLE"))
break;
needspace = 0;
column = -1;
width = 0;
max_width = 0;
incell = 0;
}
else if (buf.cmp("TD") ||
buf.cmp("TH"))
{
if (column >= 0)
{
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;
if ((column + colspan) >= num_columns)
num_columns = column + colspan;
needspace = 0;
width = 0;
incell = 1;
if (buf.cmp("TH"))
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;
}
else if (buf.cmp("/TD") ||
buf.cmp("/TH"))
{
incell = 0;
popfont(font, fsize, fcolor);
}
else if (buf.cmp("B") ||
buf.cmp("STRONG"))
pushfont(font |= FL_BOLD, fsize);
else if (buf.cmp("I") ||
buf.cmp("EM"))
pushfont(font |= FL_ITALIC, fsize);
else if (buf.cmp("CODE") ||
buf.cmp("TT"))
pushfont(font = FL_COURIER, fsize);
else if (buf.cmp("KBD"))
pushfont(font = FL_COURIER_BOLD, fsize);
else if (buf.cmp("VAR"))
pushfont(font = FL_COURIER_ITALIC, fsize);
else if (buf.cmp("/B") ||
buf.cmp("/STRONG") ||
buf.cmp("/I") ||
buf.cmp("/EM") ||
buf.cmp("/CODE") ||
buf.cmp("/TT") ||
buf.cmp("/KBD") ||
buf.cmp("/VAR"))
popfont(font, fsize, fcolor);
else if (buf.cmp("IMG") && 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;
}
buf.clear();
}
else if (*ptr == '\n' && pre)
{
width = 0;
needspace = 0;
ptr ++;
}
else if (isspace((*ptr)&255))
{
needspace = 1;
ptr ++;
}
else if (*ptr == '&' )
{
ptr ++;
int qch = quote_char(ptr);
if (qch < 0)
buf += '&';
else {
buf.add(qch);
ptr = strchr(ptr, ';') + 1;
}
}
else
{
buf += *ptr++;
}
}
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
if (num_columns == 0)
return;
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
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
*table_width = 0;
scale_width = (scale_width - width) / num_columns;
#ifdef DEBUG
printf("adjusted scale_width = %d\n", scale_width);
#endif
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
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
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 }
void
Fl_Help_View::free_data() {
if (value_) {
const char *ptr, *attrs; HV_Edit_Buffer buf; char attr[1024], wattr[1024], hattr[1024];
DEBUG_FUNCTION(__LINE__,__FUNCTION__);
for (ptr = value_; *ptr;)
{
if (*ptr == '<')
{
ptr ++;
if (strncmp(ptr, "!--", 3) == 0)
{
ptr += 3;
if ((ptr = strstr(ptr, "-->")) != NULL)
{
ptr += 3;
continue;
}
else
break;
}
buf.clear();
while (*ptr && *ptr != '>' && !isspace((*ptr)&255))
buf += *ptr++;
attrs = ptr;
while (*ptr && *ptr != '>')
ptr ++;
if (*ptr == '>')
ptr ++;
if (buf.cmp("IMG"))
{
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))) {
img = get_image(attr, width, height);
if ((void*)img != &broken_image) {
img->release();
}
}
}
}
else
ptr ++;
}
free((void *)value_);
value_ = 0;
}
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;
}
}
int Fl_Help_View::get_align(const char *p, int a) {
char buf[255];
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);
}
const char * Fl_Help_View::get_attr(const char *p, const char *n, char *buf, int bufsize) {
char name[255], *ptr, 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);
}
Fl_Color Fl_Help_View::get_color(const char *n, Fl_Color c) {
int i; int rgb, r, g, b; static const struct { 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] == '#') {
rgb = (int)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;
}
}
Fl_Shared_Image *
Fl_Help_View::get_image(const char *name, int W, int H) {
const char *localname; char dir[FL_PATH_MAX]; char temp[3 * FL_PATH_MAX], *tempptr; Fl_Shared_Image *ip;
if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL) {
if (name[0] == '/') {
strlcpy(temp, directory_, sizeof(temp));
tempptr = skip_bytes(strchr(temp, ':'), 3);
if ((tempptr = strrchr(tempptr, '/')) != 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 { if ((ip = Fl_Shared_Image::find(localname, W, H)) == NULL) {
ip = (Fl_Shared_Image *)&broken_image;
} else {
ip->release();
}
}
return ip;
}
int
Fl_Help_View::get_length(const char *l) { int val;
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];
clear_selection();
strlcpy(target, linkp->name, sizeof(target));
set_changed();
if (strcmp(linkp->filename, filename_) != 0 && linkp->filename[0])
{
char dir[FL_PATH_MAX]; char temp[3 * FL_PATH_MAX], *tempptr;
if (strchr(directory_, ':') != NULL &&
strchr(linkp->filename, ':') == NULL)
{
if (linkp->filename[0] == '/')
{
strlcpy(temp, directory_, sizeof(temp));
tempptr = skip_bytes(strchr(temp, ':'), 3);
if ((tempptr = strrchr(tempptr, '/')) != NULL) {
strlcpy(tempptr, linkp->filename, sizeof(temp) - (tempptr - 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);
}
void Fl_Help_View::clear_selection()
{
if (current_view_==this)
clear_global_selection();
}
void Fl_Help_View::select_all()
{
clear_global_selection();
if (!value_) return;
current_view_ = this;
selection_drag_last_ = selection_last_ = (int) 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;
if (Fl::focus()!=this)
Fl::focus(this);
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_;
}
if (sf!=selection_first_ || sl!=selection_last_) {
return 1;
} else {
return 0;
}
}
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;
int p = 0;
char pre = 0;
int len = (int) strlen(value_);
char *txt = (char*)malloc(len+1), *d = txt;
const char *s = value_, *cmd, *src;
for (;;) {
int c = (*s++) & 0xff;
if (c==0) break;
if (c=='<') { cmd = s;
for (;;) {
c = (*s++) & 0xff;
if (c==0 || c=='>') break;
}
if (c==0) break;
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 = (int) (s-value_);
if (src && n>selection_first_ && n<=selection_last_) {
while (*src) {
*d++ = *src++;
}
c = src[-1] & 0xff;
p = isspace(c) ? ' ' : c;
}
continue;
}
const char *s2 = s;
if (c=='&') { int xx = quote_char(s);
if (xx >= 0) {
c = xx;
for (;;) {
char cc = *s++;
if (!cc || cc==';') break;
}
}
}
int n = (int) (s2-value_);
if (n>selection_first_ && n<=selection_last_) {
if (!pre && c < 256 && isspace(c)) c = ' ';
if (p != ' ' || c != ' ') {
if (s2 != s) { d += fl_utf8encode(c, d);
}
else *d++ = c;
}
p = c;
}
if (n>selection_last_) break; }
*d = 0;
Fl::copy(txt, (int) strlen(txt), clipboard);
free(txt);
}
int Fl_Help_View::text_selected() {
if (current_view_==this)
return selected_;
else
return 0;
}
int Fl_Help_View::copy(int clipboard) {
if (text_selected()) {
end_selection(clipboard);
return 1;
} else {
return 0;
}
}
int Fl_Help_View::handle(int event) {
static Fl_Help_Link *linkp;
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::event_button() == FL_RIGHT_MOUSE) {
rmb_menu[0].label(copy_menu_text);
if (text_selected())
rmb_menu[0].activate();
else
rmb_menu[0].deactivate();
fl_cursor(FL_CURSOR_DEFAULT);
const Fl_Menu_Item *mi = rmb_menu->popup(Fl::event_x(), Fl::event_y());
if (mi) switch (mi->argument()) {
case 1:
copy();
break;
}
}
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); }
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: {
int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT|FL_SHIFT);
if ( mods == FL_COMMAND) {
switch ( Fl::event_key() ) {
case 'a': select_all(); redraw(); return 1;
case 'c':
case 'x': end_selection(1); return 1;
}
}
break; }
}
return (Fl_Group::handle(event));
}
Fl_Help_View::Fl_Help_View(int xx, int yy, int ww, int hh, 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);
}
Fl_Help_View::~Fl_Help_View()
{
clear_selection();
free_data();
}
int Fl_Help_View::load(const char *f)
{
FILE *fp; long len; char *target; char *slash; const char *localname; char error[2 * FL_PATH_MAX]; char newname[FL_PATH_MAX];
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_));
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;
} else {
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 -1;
free_data();
strlcpy(filename_, newname, sizeof(filename_));
strlcpy(directory_, newname, sizeof(directory_));
if ((slash = strrchr(directory_, '/')) == NULL)
directory_[0] = '\0';
else if (slash > directory_ && slash[-1] != '/')
*slash = '\0';
if (strncmp(localname, "file:", 5) == 0)
localname += 5;
int ret = 0;
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) { }
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_ = fl_strdup(error);
ret = -1;
}
initial_load = 1;
format();
initial_load = 0;
if (target)
topline(target);
else
topline(0);
return ret;
}
void
Fl_Help_View::resize(int xx, int yy, int ww, int hh) {
Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
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();
}
void
Fl_Help_View::topline(const char *n) {
Fl_Help_Target key, *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);
}
void
Fl_Help_View::topline(int top) {
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(FL_REASON_DRAGGED);
redraw();
}
void
Fl_Help_View::leftline(int left) {
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();
}
void
Fl_Help_View::value(const char *val) {
clear_selection();
free_data();
set_changed();
if (!val)
return;
value_ = fl_strdup(val);
initial_load = 1;
format();
initial_load = 0;
topline(0);
leftline(0);
}
static int quote_char(const char *p) { int i; static const struct {
const char *name;
int namelen;
int code;
} *nameptr, names[] = { { "Aacute;", 7, 193 },
{ "aacute;", 7, 225 },
{ "Acirc;", 6, 194 },
{ "acirc;", 6, 226 },
{ "acute;", 6, 180 },
{ "AElig;", 6, 198 },
{ "aelig;", 6, 230 },
{ "Agrave;", 7, 192 },
{ "agrave;", 7, 224 },
{ "amp;", 4, '&' },
{ "Aring;", 6, 197 },
{ "aring;", 6, 229 },
{ "Atilde;", 7, 195 },
{ "atilde;", 7, 227 },
{ "Auml;", 5, 196 },
{ "auml;", 5, 228 },
{ "brvbar;", 7, 166 },
{ "bull;", 5, 0x2022 },
{ "Ccedil;", 7, 199 },
{ "ccedil;", 7, 231 },
{ "cedil;", 6, 184 },
{ "cent;", 5, 162 },
{ "copy;", 5, 169 },
{ "curren;", 7, 164 },
{ "dagger;", 7, 0x2020 },
{ "deg;", 4, 176 },
{ "divide;", 7, 247 },
{ "Eacute;", 7, 201 },
{ "eacute;", 7, 233 },
{ "Ecirc;", 6, 202 },
{ "ecirc;", 6, 234 },
{ "Egrave;", 7, 200 },
{ "egrave;", 7, 232 },
{ "ETH;", 4, 208 },
{ "eth;", 4, 240 },
{ "Euml;", 5, 203 },
{ "euml;", 5, 235 },
{ "euro;", 5, 0x20ac },
{ "frac12;", 7, 189 },
{ "frac14;", 7, 188 },
{ "frac34;", 7, 190 },
{ "gt;", 3, '>' },
{ "Iacute;", 7, 205 },
{ "iacute;", 7, 237 },
{ "Icirc;", 6, 206 },
{ "icirc;", 6, 238 },
{ "iexcl;", 6, 161 },
{ "Igrave;", 7, 204 },
{ "igrave;", 7, 236 },
{ "iquest;", 7, 191 },
{ "Iuml;", 5, 207 },
{ "iuml;", 5, 239 },
{ "laquo;", 6, 171 },
{ "lt;", 3, '<' },
{ "macr;", 5, 175 },
{ "micro;", 6, 181 },
{ "middot;", 7, 183 },
{ "nbsp;", 5, ' ' },
{ "ndash;", 6, 0x2013 },
{ "not;", 4, 172 },
{ "Ntilde;", 7, 209 },
{ "ntilde;", 7, 241 },
{ "Oacute;", 7, 211 },
{ "oacute;", 7, 243 },
{ "Ocirc;", 6, 212 },
{ "ocirc;", 6, 244 },
{ "Ograve;", 7, 210 },
{ "ograve;", 7, 242 },
{ "ordf;", 5, 170 },
{ "ordm;", 5, 186 },
{ "Oslash;", 7, 216 },
{ "oslash;", 7, 248 },
{ "Otilde;", 7, 213 },
{ "otilde;", 7, 245 },
{ "Ouml;", 5, 214 },
{ "ouml;", 5, 246 },
{ "para;", 5, 182 },
{ "permil;", 7, 0x2030 },
{ "plusmn;", 7, 177 },
{ "pound;", 6, 163 },
{ "quot;", 5, '\"' },
{ "raquo;", 6, 187 },
{ "reg;", 4, 174 },
{ "sect;", 5, 167 },
{ "shy;", 4, 173 },
{ "sup1;", 5, 185 },
{ "sup2;", 5, 178 },
{ "sup3;", 5, 179 },
{ "szlig;", 6, 223 },
{ "THORN;", 6, 222 },
{ "thorn;", 6, 254 },
{ "times;", 6, 215 },
{ "trade;", 6, 0x2122 },
{ "Uacute;", 7, 218 },
{ "uacute;", 7, 250 },
{ "Ucirc;", 6, 219 },
{ "ucirc;", 6, 251 },
{ "Ugrave;", 7, 217 },
{ "ugrave;", 7, 249 },
{ "uml;", 4, 168 },
{ "Uuml;", 5, 220 },
{ "uuml;", 5, 252 },
{ "Yacute;", 7, 221 },
{ "yacute;", 7, 253 },
{ "yen;", 4, 165 },
{ "Yuml;", 5, 0x0178 },
{ "yuml;", 5, 255 }
};
if (!strchr(p, ';')) return -1;
if (*p == '#') {
if (*(p+1) == 'x' || *(p+1) == 'X') return (int)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;
}
static void
scrollbar_callback(Fl_Widget *s, void *)
{
((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value()));
}
static void
hscrollbar_callback(Fl_Widget *s, void *)
{
((Fl_Help_View *)(s->parent()))->leftline(int(((Fl_Scrollbar*)s)->value()));
}