|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Help_View.cxx 8063 2010-12-19 21:20:10Z matt $" 00003 // 00004 // Fl_Help_View widget routines. 00005 // 00006 // Copyright 1997-2010 by Easy Software Products. 00007 // Image support by Matthias Melcher, Copyright 2000-2009. 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Library General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Library General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Library General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00022 // USA. 00023 // 00024 // Please report all bugs and problems on the following page: 00025 // 00026 // http://www.fltk.org/str.php 00027 // 00028 // Contents: 00029 // 00030 // Fl_Help_View::add_block() - Add a text block to the list. 00031 // Fl_Help_View::add_link() - Add a new link to the list. 00032 // Fl_Help_View::add_target() - Add a new target to the list. 00033 // Fl_Help_View::compare_targets() - Compare two targets. 00034 // Fl_Help_View::do_align() - Compute the alignment for a line in 00035 // a block. 00036 // Fl_Help_View::draw() - Draw the Fl_Help_View widget. 00037 // Fl_Help_View::format() - Format the help text. 00038 // Fl_Help_View::format_table() - Format a table... 00039 // Fl_Help_View::free_data() - Free memory used for the document. 00040 // Fl_Help_View::get_align() - Get an alignment attribute. 00041 // Fl_Help_View::get_attr() - Get an attribute value from the string. 00042 // Fl_Help_View::get_color() - Get an alignment attribute. 00043 // Fl_Help_View::handle() - Handle events in the widget. 00044 // Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget. 00045 // Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget. 00046 // Fl_Help_View::load() - Load the specified file. 00047 // Fl_Help_View::resize() - Resize the help widget. 00048 // Fl_Help_View::topline() - Set the top line to the named target. 00049 // Fl_Help_View::topline() - Set the top line by number. 00050 // Fl_Help_View::value() - Set the help text directly. 00051 // scrollbar_callback() - A callback for the scrollbar. 00052 // 00053 00054 // 00055 // Include necessary header files... 00056 // 00057 00058 #include <FL/Fl_Help_View.H> 00059 #include <FL/Fl_Window.H> 00060 #include <FL/Fl_Pixmap.H> 00061 #include <FL/x.H> 00062 #include <stdio.h> 00063 #include <stdlib.h> 00064 #include <FL/fl_utf8.h> 00065 #include <FL/filename.H> // fl_open_uri() 00066 #include "flstring.h" 00067 #include <ctype.h> 00068 #include <errno.h> 00069 #include <math.h> 00070 00071 #if defined(WIN32) && ! defined(__CYGWIN__) 00072 # include <io.h> 00073 # include <direct.h> 00074 #else 00075 # include <unistd.h> 00076 #endif // WIN32 00077 00078 #define MAX_COLUMNS 200 00079 00080 00081 // 00082 // Typedef the C API sort function type the only way I know how... 00083 // 00084 00085 extern "C" 00086 { 00087 typedef int (*compare_func_t)(const void *, const void *); 00088 } 00089 00090 00091 // 00092 // Local functions... 00093 // 00094 00095 static int quote_char(const char *); 00096 static void scrollbar_callback(Fl_Widget *s, void *); 00097 static void hscrollbar_callback(Fl_Widget *s, void *); 00098 00099 // 00100 // global flag for image loading (see get_image). 00101 // 00102 00103 static char initial_load = 0; 00104 00105 // 00106 // Broken image... 00107 // 00108 00109 static const char *broken_xpm[] = 00110 { 00111 "16 24 4 1", 00112 "@ c #000000", 00113 " c #ffffff", 00114 "+ c none", 00115 "x c #ff0000", 00116 // pixels 00117 "@@@@@@@+++++++++", 00118 "@ @++++++++++", 00119 "@ @+++++++++++", 00120 "@ @++@++++++++", 00121 "@ @@+++++++++", 00122 "@ @+++@+++++", 00123 "@ @++@@++++@", 00124 "@ xxx @@ @++@@", 00125 "@ xxx xx@@ @", 00126 "@ xxx xxx @", 00127 "@ xxxxxx @", 00128 "@ xxxx @", 00129 "@ xxxxxx @", 00130 "@ xxx xxx @", 00131 "@ xxx xxx @", 00132 "@ xxx xxx @", 00133 "@ @", 00134 "@ @", 00135 "@ @", 00136 "@ @", 00137 "@ @", 00138 "@ @", 00139 "@ @", 00140 "@@@@@@@@@@@@@@@@", 00141 NULL 00142 }; 00143 00144 static Fl_Pixmap broken_image(broken_xpm); 00145 00146 // 00147 // Simple margin stack for Fl_Help_View::format()... 00148 // 00149 00150 struct fl_margins { 00151 int depth_; 00152 int margins_[100]; 00153 00154 fl_margins() { clear(); } 00155 00156 int clear() { 00157 // puts("fl_margins::clear()"); 00158 00159 depth_ = 0; 00160 return margins_[0] = 4; 00161 } 00162 00163 int current() { return margins_[depth_]; } 00164 00165 int pop() { 00166 // printf("fl_margins::pop(): depth_=%d, xx=%d\n", depth_, 00167 // depth_ > 0 ? margins_[depth_ - 1] : 4); 00168 00169 if (depth_ > 0) { 00170 depth_ --; 00171 return margins_[depth_]; 00172 } else return 4; 00173 } 00174 00175 int push(int indent) { 00176 int xx; 00177 00178 xx = margins_[depth_] + indent; 00179 00180 // printf("fl_margins::push(indent=%d): depth_=%d, xx=%d\n", indent, 00181 // depth_ + 1, xx); 00182 00183 if (depth_ < 99) { 00184 depth_ ++; 00185 margins_[depth_] = xx; 00186 } 00187 00188 return xx; 00189 } 00190 }; 00191 00192 // 00193 // All the stuff needed to implement text selection in Fl_Help_View 00194 // 00195 00196 /* matt: 00197 * We are trying to keep binary compatibility with previous versions 00198 * of FLTK. This means that we are limited to adding static variables 00199 * only to not enlarge the Fl_Help_View class. Lucky for us, only one 00200 * text can be selected system wide, so we can remember the selection 00201 * in a single set of variables. 00202 * 00203 * Still to do: 00204 * - &word; style characters mess up our count inside a word boundary 00205 * - we can only select words, no individual characters 00206 * - no dragging of the selection into another widget 00207 * - selection must be cleared if another widget get focus! 00208 * - write a comment for every new function 00209 */ 00210 00211 /* 00212 The following functions are also used to draw stuff and should be replaced with 00213 local copies that are much faster when merely counting: 00214 00215 fl_color(Fl_Color); 00216 fl_rectf(int, int, int, int); 00217 fl_push_clip(int, int, int, int); 00218 fl_xyline(int, int, int); 00219 fl_rect() 00220 fl_line() 00221 img->draw() 00222 */ 00223 00224 // We don't put the offscreen buffer in the help view class because 00225 // we'd need to include x.H in the header... 00226 static Fl_Offscreen fl_help_view_buffer; 00227 int Fl_Help_View::selection_first = 0; 00228 int Fl_Help_View::selection_last = 0; 00229 int Fl_Help_View::selection_push_first = 0; 00230 int Fl_Help_View::selection_push_last = 0; 00231 int Fl_Help_View::selection_drag_first = 0; 00232 int Fl_Help_View::selection_drag_last = 0; 00233 int Fl_Help_View::selected = 0; 00234 int Fl_Help_View::draw_mode = 0; 00235 int Fl_Help_View::mouse_x = 0; 00236 int Fl_Help_View::mouse_y = 0; 00237 int Fl_Help_View::current_pos = 0; 00238 Fl_Help_View *Fl_Help_View::current_view = 0L; 00239 Fl_Color Fl_Help_View::hv_selection_color; 00240 Fl_Color Fl_Help_View::hv_selection_text_color; 00241 00242 /* 00243 * Limitation: if a word contains &code; notations, we will calculate a wrong length. 00244 * 00245 * This function must be optimized for speed! 00246 */ 00247 void Fl_Help_View::hv_draw(const char *t, int x, int y) 00248 { 00249 if (selected && current_view==this && current_pos<selection_last && current_pos>=selection_first) { 00250 Fl_Color c = fl_color(); 00251 fl_color(hv_selection_color); 00252 int w = (int)fl_width(t); 00253 if (current_pos+(int)strlen(t)<selection_last) 00254 w += (int)fl_width(' '); 00255 fl_rectf(x, y+fl_descent()-fl_height(), w, fl_height()); 00256 fl_color(hv_selection_text_color); 00257 fl_draw(t, x, y); 00258 fl_color(c); 00259 } else { 00260 fl_draw(t, x, y); 00261 } 00262 if (draw_mode) { 00263 int w = (int)fl_width(t); 00264 if (mouse_x>=x && mouse_x<x+w) { 00265 if (mouse_y>=y-fl_height()+fl_descent()&&mouse_y<=y+fl_descent()) { 00266 int f = current_pos; 00267 int l = f+strlen(t); // use 'quote_char' to calculate the true length of the HTML string 00268 if (draw_mode==1) { 00269 selection_push_first = f; 00270 selection_push_last = l; 00271 } else { 00272 selection_drag_first = f; 00273 selection_drag_last = l; 00274 } 00275 } 00276 } 00277 } 00278 } 00279 00280 00282 Fl_Help_Block * // O - Pointer to new block 00283 Fl_Help_View::add_block(const char *s, // I - Pointer to start of block text 00284 int xx, // I - X position of block 00285 int yy, // I - Y position of block 00286 int ww, // I - Right margin of block 00287 int hh, // I - Height of block 00288 unsigned char border) // I - Draw border? 00289 { 00290 Fl_Help_Block *temp; // New block 00291 00292 00293 // printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n", 00294 // s, xx, yy, ww, hh, border); 00295 00296 if (nblocks_ >= ablocks_) 00297 { 00298 ablocks_ += 16; 00299 00300 if (ablocks_ == 16) 00301 blocks_ = (Fl_Help_Block *)malloc(sizeof(Fl_Help_Block) * ablocks_); 00302 else 00303 blocks_ = (Fl_Help_Block *)realloc(blocks_, sizeof(Fl_Help_Block) * ablocks_); 00304 } 00305 00306 temp = blocks_ + nblocks_; 00307 memset(temp, 0, sizeof(Fl_Help_Block)); 00308 temp->start = s; 00309 temp->end = s; 00310 temp->x = xx; 00311 temp->y = yy; 00312 temp->w = ww; 00313 temp->h = hh; 00314 temp->border = border; 00315 temp->bgcolor = bgcolor_; 00316 nblocks_ ++; 00317 00318 return (temp); 00319 } 00320 00321 00323 void Fl_Help_View::add_link(const char *n, // I - Name of link 00324 int xx, // I - X position of link 00325 int yy, // I - Y position of link 00326 int ww, // I - Width of link text 00327 int hh) // I - Height of link text 00328 { 00329 Fl_Help_Link *temp; // New link 00330 char *target; // Pointer to target name 00331 00332 00333 if (nlinks_ >= alinks_) 00334 { 00335 alinks_ += 16; 00336 00337 if (alinks_ == 16) 00338 links_ = (Fl_Help_Link *)malloc(sizeof(Fl_Help_Link) * alinks_); 00339 else 00340 links_ = (Fl_Help_Link *)realloc(links_, sizeof(Fl_Help_Link) * alinks_); 00341 } 00342 00343 temp = links_ + nlinks_; 00344 00345 temp->x = xx; 00346 temp->y = yy; 00347 temp->w = xx + ww; 00348 temp->h = yy + hh; 00349 00350 strlcpy(temp->filename, n, sizeof(temp->filename)); 00351 00352 if ((target = strrchr(temp->filename, '#')) != NULL) 00353 { 00354 *target++ = '\0'; 00355 strlcpy(temp->name, target, sizeof(temp->name)); 00356 } 00357 else 00358 temp->name[0] = '\0'; 00359 00360 nlinks_ ++; 00361 } 00362 00363 00365 void Fl_Help_View::add_target(const char *n, // I - Name of target 00366 int yy) // I - Y position of target 00367 { 00368 Fl_Help_Target *temp; // New target 00369 00370 00371 if (ntargets_ >= atargets_) 00372 { 00373 atargets_ += 16; 00374 00375 if (atargets_ == 16) 00376 targets_ = (Fl_Help_Target *)malloc(sizeof(Fl_Help_Target) * atargets_); 00377 else 00378 targets_ = (Fl_Help_Target *)realloc(targets_, sizeof(Fl_Help_Target) * atargets_); 00379 } 00380 00381 temp = targets_ + ntargets_; 00382 00383 temp->y = yy; 00384 strlcpy(temp->name, n, sizeof(temp->name)); 00385 00386 ntargets_ ++; 00387 } 00388 00390 int // O - Result of comparison 00391 Fl_Help_View::compare_targets(const Fl_Help_Target *t0, // I - First target 00392 const Fl_Help_Target *t1) // I - Second target 00393 { 00394 return (strcasecmp(t0->name, t1->name)); 00395 } 00396 00398 int // O - New line 00399 Fl_Help_View::do_align(Fl_Help_Block *block, // I - Block to add to 00400 int line, // I - Current line 00401 int xx, // I - Current X position 00402 int a, // I - Current alignment 00403 int &l) // IO - Starting link 00404 { 00405 int offset; // Alignment offset 00406 00407 00408 switch (a) 00409 { 00410 case RIGHT : // Right align 00411 offset = block->w - xx; 00412 break; 00413 case CENTER : // Center 00414 offset = (block->w - xx) / 2; 00415 break; 00416 default : // Left align 00417 offset = 0; 00418 break; 00419 } 00420 00421 block->line[line] = block->x + offset; 00422 00423 if (line < 31) 00424 line ++; 00425 00426 while (l < nlinks_) 00427 { 00428 links_[l].x += offset; 00429 links_[l].w += offset; 00430 l ++; 00431 } 00432 00433 return (line); 00434 } 00435 00437 void 00438 Fl_Help_View::draw() 00439 { 00440 int i; // Looping var 00441 const Fl_Help_Block *block; // Pointer to current block 00442 const char *ptr, // Pointer to text in block 00443 *attrs; // Pointer to start of element attributes 00444 char *s, // Pointer into buffer 00445 buf[1024], // Text buffer 00446 attr[1024]; // Attribute buffer 00447 int xx, yy, ww, hh; // Current positions and sizes 00448 int line; // Current line 00449 Fl_Font font; 00450 Fl_Fontsize fsize; // Current font and size 00451 Fl_Color fcolor; // current font color 00452 int head, pre, // Flags for text 00453 needspace; // Do we need whitespace? 00454 Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; 00455 // Box to draw... 00456 int underline, // Underline text? 00457 xtra_ww; // Extra width for underlined space between words 00458 00459 // Draw the scrollbar(s) and box first... 00460 ww = w(); 00461 hh = h(); 00462 i = 0; 00463 00464 draw_box(b, x(), y(), ww, hh, bgcolor_); 00465 00466 if ( hscrollbar_.visible() || scrollbar_.visible() ) { 00467 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 00468 int hor_vis = hscrollbar_.visible(); 00469 int ver_vis = scrollbar_.visible(); 00470 // Scrollbar corner 00471 int scorn_x = x() + ww - (ver_vis?scrollsize:0) - Fl::box_dw(b) + Fl::box_dx(b); 00472 int scorn_y = y() + hh - (hor_vis?scrollsize:0) - Fl::box_dh(b) + Fl::box_dy(b); 00473 if ( hor_vis ) { 00474 if ( hscrollbar_.h() != scrollsize ) { // scrollsize changed? 00475 hscrollbar_.resize(x(), scorn_y, scorn_x - x(), scrollsize); 00476 init_sizes(); 00477 } 00478 draw_child(hscrollbar_); 00479 hh -= scrollsize; 00480 } 00481 if ( ver_vis ) { 00482 if ( scrollbar_.w() != scrollsize ) { // scrollsize changed? 00483 scrollbar_.resize(scorn_x, y(), scrollsize, scorn_y - y()); 00484 init_sizes(); 00485 } 00486 draw_child(scrollbar_); 00487 ww -= scrollsize; 00488 } 00489 if ( hor_vis && ver_vis ) { 00490 // Both scrollbars visible? Draw little gray box in corner 00491 fl_color(FL_GRAY); 00492 fl_rectf(scorn_x, scorn_y, scrollsize, scrollsize); 00493 } 00494 } 00495 00496 if (!value_) 00497 return; 00498 00499 if (current_view == this && selected) { 00500 hv_selection_color = FL_SELECTION_COLOR; 00501 hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR); 00502 } 00503 current_pos = 0; 00504 00505 // Clip the drawing to the inside of the box... 00506 fl_push_clip(x() + Fl::box_dx(b), y() + Fl::box_dy(b), 00507 ww - Fl::box_dw(b), hh - Fl::box_dh(b)); 00508 fl_color(textcolor_); 00509 00510 // Draw all visible blocks... 00511 for (i = 0, block = blocks_; i < nblocks_; i ++, block ++) 00512 if ((block->y + block->h) >= topline_ && block->y < (topline_ + h())) 00513 { 00514 line = 0; 00515 xx = block->line[line]; 00516 yy = block->y - topline_; 00517 hh = 0; 00518 pre = 0; 00519 head = 0; 00520 needspace = 0; 00521 underline = 0; 00522 00523 initfont(font, fsize, fcolor); 00524 00525 for (ptr = block->start, s = buf; ptr < block->end;) 00526 { 00527 if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf) 00528 { 00529 if (!head && !pre) 00530 { 00531 // Check width... 00532 *s = '\0'; 00533 s = buf; 00534 ww = (int)fl_width(buf); 00535 00536 if (needspace && xx > block->x) 00537 xx += (int)fl_width(' '); 00538 00539 if ((xx + ww) > block->w) 00540 { 00541 if (line < 31) 00542 line ++; 00543 xx = block->line[line]; 00544 yy += hh; 00545 hh = 0; 00546 } 00547 00548 hv_draw(buf, xx + x() - leftline_, yy + y()); 00549 if (underline) { 00550 xtra_ww = isspace((*ptr)&255)?(int)fl_width(' '):0; 00551 fl_xyline(xx + x() - leftline_, yy + y() + 1, 00552 xx + x() - leftline_ + ww + xtra_ww); 00553 } 00554 current_pos = ptr-value_; 00555 00556 xx += ww; 00557 if ((fsize + 2) > hh) 00558 hh = fsize + 2; 00559 00560 needspace = 0; 00561 } 00562 else if (pre) 00563 { 00564 while (isspace((*ptr)&255)) 00565 { 00566 if (*ptr == '\n') 00567 { 00568 *s = '\0'; 00569 s = buf; 00570 00571 hv_draw(buf, xx + x() - leftline_, yy + y()); 00572 if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, 00573 xx + x() - leftline_ + 00574 (int)fl_width(buf)); 00575 00576 current_pos = ptr-value_; 00577 if (line < 31) 00578 line ++; 00579 xx = block->line[line]; 00580 yy += hh; 00581 hh = fsize + 2; 00582 } 00583 else if (*ptr == '\t') 00584 { 00585 // Do tabs every 8 columns... 00586 while (((s - buf) & 7)) 00587 *s++ = ' '; 00588 } 00589 else 00590 *s++ = ' '; 00591 00592 if ((fsize + 2) > hh) 00593 hh = fsize + 2; 00594 00595 ptr ++; 00596 } 00597 00598 if (s > buf) 00599 { 00600 *s = '\0'; 00601 s = buf; 00602 00603 hv_draw(buf, xx + x() - leftline_, yy + y()); 00604 ww = (int)fl_width(buf); 00605 if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, 00606 xx + x() - leftline_ + ww); 00607 xx += ww; 00608 current_pos = ptr-value_; 00609 } 00610 00611 needspace = 0; 00612 } 00613 else 00614 { 00615 s = buf; 00616 00617 while (isspace((*ptr)&255)) 00618 ptr ++; 00619 current_pos = ptr-value_; 00620 } 00621 } 00622 00623 if (*ptr == '<') 00624 { 00625 ptr ++; 00626 00627 if (strncmp(ptr, "!--", 3) == 0) 00628 { 00629 // Comment... 00630 ptr += 3; 00631 if ((ptr = strstr(ptr, "-->")) != NULL) 00632 { 00633 ptr += 3; 00634 continue; 00635 } 00636 else 00637 break; 00638 } 00639 00640 while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) 00641 if (s < (buf + sizeof(buf) - 1)) 00642 *s++ = *ptr++; 00643 else 00644 ptr ++; 00645 00646 *s = '\0'; 00647 s = buf; 00648 00649 attrs = ptr; 00650 while (*ptr && *ptr != '>') 00651 ptr ++; 00652 00653 if (*ptr == '>') 00654 ptr ++; 00655 00656 // end of command reached, set the supposed start of printed eord here 00657 current_pos = ptr-value_; 00658 if (strcasecmp(buf, "HEAD") == 0) 00659 head = 1; 00660 else if (strcasecmp(buf, "BR") == 0) 00661 { 00662 if (line < 31) 00663 line ++; 00664 xx = block->line[line]; 00665 yy += hh; 00666 hh = 0; 00667 } 00668 else if (strcasecmp(buf, "HR") == 0) 00669 { 00670 fl_line(block->x + x(), yy + y(), block->w + x(), 00671 yy + y()); 00672 00673 if (line < 31) 00674 line ++; 00675 xx = block->line[line]; 00676 yy += 2 * hh; 00677 hh = 0; 00678 } 00679 else if (strcasecmp(buf, "CENTER") == 0 || 00680 strcasecmp(buf, "P") == 0 || 00681 strcasecmp(buf, "H1") == 0 || 00682 strcasecmp(buf, "H2") == 0 || 00683 strcasecmp(buf, "H3") == 0 || 00684 strcasecmp(buf, "H4") == 0 || 00685 strcasecmp(buf, "H5") == 0 || 00686 strcasecmp(buf, "H6") == 0 || 00687 strcasecmp(buf, "UL") == 0 || 00688 strcasecmp(buf, "OL") == 0 || 00689 strcasecmp(buf, "DL") == 0 || 00690 strcasecmp(buf, "LI") == 0 || 00691 strcasecmp(buf, "DD") == 0 || 00692 strcasecmp(buf, "DT") == 0 || 00693 strcasecmp(buf, "PRE") == 0) 00694 { 00695 if (tolower(buf[0]) == 'h') 00696 { 00697 font = FL_HELVETICA_BOLD; 00698 fsize = textsize_ + '7' - buf[1]; 00699 } 00700 else if (strcasecmp(buf, "DT") == 0) 00701 { 00702 font = textfont_ | FL_ITALIC; 00703 fsize = textsize_; 00704 } 00705 else if (strcasecmp(buf, "PRE") == 0) 00706 { 00707 font = FL_COURIER; 00708 fsize = textsize_; 00709 pre = 1; 00710 } 00711 00712 if (strcasecmp(buf, "LI") == 0) 00713 { 00714 // fl_font(FL_SYMBOL, fsize); // The default SYMBOL font on my XP box is not Unicode... 00715 char buf[8]; 00716 wchar_t b[] = {0x2022, 0x0}; 00717 // buf[fl_unicode2utf(b, 1, buf)] = 0; 00718 unsigned dstlen = fl_utf8fromwc(buf, 8, b, 1); 00719 buf[dstlen] = 0; 00720 hv_draw(buf, xx - fsize + x() - leftline_, yy + y()); 00721 } 00722 00723 pushfont(font, fsize); 00724 } 00725 else if (strcasecmp(buf, "A") == 0 && 00726 get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) 00727 { 00728 fl_color(linkcolor_); 00729 underline = 1; 00730 } 00731 else if (strcasecmp(buf, "/A") == 0) 00732 { 00733 fl_color(textcolor_); 00734 underline = 0; 00735 } 00736 else if (strcasecmp(buf, "FONT") == 0) 00737 { 00738 if (get_attr(attrs, "COLOR", attr, sizeof(attr)) != NULL) { 00739 textcolor_ = get_color(attr, textcolor_); 00740 } 00741 00742 if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) { 00743 if (!strncasecmp(attr, "helvetica", 9) || 00744 !strncasecmp(attr, "arial", 5) || 00745 !strncasecmp(attr, "sans", 4)) font = FL_HELVETICA; 00746 else if (!strncasecmp(attr, "times", 5) || 00747 !strncasecmp(attr, "serif", 5)) font = FL_TIMES; 00748 else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL; 00749 else font = FL_COURIER; 00750 } 00751 00752 if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) { 00753 if (isdigit(attr[0] & 255)) { 00754 // Absolute size 00755 fsize = (int)(textsize_ * pow(1.2, atof(attr) - 3.0)); 00756 } else { 00757 // Relative size 00758 fsize = (int)(fsize * pow(1.2, atof(attr) - 3.0)); 00759 } 00760 } 00761 00762 pushfont(font, fsize); 00763 } 00764 else if (strcasecmp(buf, "/FONT") == 0) 00765 { 00766 popfont(font, fsize, textcolor_); 00767 } 00768 else if (strcasecmp(buf, "U") == 0) 00769 underline = 1; 00770 else if (strcasecmp(buf, "/U") == 0) 00771 underline = 0; 00772 else if (strcasecmp(buf, "B") == 0 || 00773 strcasecmp(buf, "STRONG") == 0) 00774 pushfont(font |= FL_BOLD, fsize); 00775 else if (strcasecmp(buf, "TD") == 0 || 00776 strcasecmp(buf, "TH") == 0) 00777 { 00778 int tx, ty, tw, th; 00779 00780 if (tolower(buf[1]) == 'h') 00781 pushfont(font |= FL_BOLD, fsize); 00782 else 00783 pushfont(font = textfont_, fsize); 00784 00785 tx = block->x - 4 - leftline_; 00786 ty = block->y - topline_ - fsize - 3; 00787 tw = block->w - block->x + 7; 00788 th = block->h + fsize - 5; 00789 00790 if (tx < 0) 00791 { 00792 tw += tx; 00793 tx = 0; 00794 } 00795 00796 if (ty < 0) 00797 { 00798 th += ty; 00799 ty = 0; 00800 } 00801 00802 tx += x(); 00803 ty += y(); 00804 00805 if (block->bgcolor != bgcolor_) 00806 { 00807 fl_color(block->bgcolor); 00808 fl_rectf(tx, ty, tw, th); 00809 fl_color(textcolor_); 00810 } 00811 00812 if (block->border) 00813 fl_rect(tx, ty, tw, th); 00814 } 00815 else if (strcasecmp(buf, "I") == 0 || 00816 strcasecmp(buf, "EM") == 0) 00817 pushfont(font |= FL_ITALIC, fsize); 00818 else if (strcasecmp(buf, "CODE") == 0 || 00819 strcasecmp(buf, "TT") == 0) 00820 pushfont(font = FL_COURIER, fsize); 00821 else if (strcasecmp(buf, "KBD") == 0) 00822 pushfont(font = FL_COURIER_BOLD, fsize); 00823 else if (strcasecmp(buf, "VAR") == 0) 00824 pushfont(font = FL_COURIER_ITALIC, fsize); 00825 else if (strcasecmp(buf, "/HEAD") == 0) 00826 head = 0; 00827 else if (strcasecmp(buf, "/H1") == 0 || 00828 strcasecmp(buf, "/H2") == 0 || 00829 strcasecmp(buf, "/H3") == 0 || 00830 strcasecmp(buf, "/H4") == 0 || 00831 strcasecmp(buf, "/H5") == 0 || 00832 strcasecmp(buf, "/H6") == 0 || 00833 strcasecmp(buf, "/B") == 0 || 00834 strcasecmp(buf, "/STRONG") == 0 || 00835 strcasecmp(buf, "/I") == 0 || 00836 strcasecmp(buf, "/EM") == 0 || 00837 strcasecmp(buf, "/CODE") == 0 || 00838 strcasecmp(buf, "/TT") == 0 || 00839 strcasecmp(buf, "/KBD") == 0 || 00840 strcasecmp(buf, "/VAR") == 0) 00841 popfont(font, fsize, fcolor); 00842 else if (strcasecmp(buf, "/PRE") == 0) 00843 { 00844 popfont(font, fsize, fcolor); 00845 pre = 0; 00846 } 00847 else if (strcasecmp(buf, "IMG") == 0) 00848 { 00849 Fl_Shared_Image *img = 0; 00850 int width, height; 00851 char wattr[8], hattr[8]; 00852 00853 00854 get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); 00855 get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); 00856 width = get_length(wattr); 00857 height = get_length(hattr); 00858 00859 if (get_attr(attrs, "SRC", attr, sizeof(attr))) { 00860 img = get_image(attr, width, height); 00861 if (!width) width = img->w(); 00862 if (!height) height = img->h(); 00863 } 00864 00865 if (!width || !height) { 00866 if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL) { 00867 strcpy(attr, "IMG"); 00868 } 00869 } 00870 00871 ww = width; 00872 00873 if (needspace && xx > block->x) 00874 xx += (int)fl_width(' '); 00875 00876 if ((xx + ww) > block->w) 00877 { 00878 if (line < 31) 00879 line ++; 00880 00881 xx = block->line[line]; 00882 yy += hh; 00883 hh = 0; 00884 } 00885 00886 if (img) { 00887 img->draw(xx + x() - leftline_, 00888 yy + y() - fl_height() + fl_descent() + 2); 00889 } 00890 00891 xx += ww; 00892 if ((height + 2) > hh) 00893 hh = height + 2; 00894 00895 needspace = 0; 00896 } 00897 } 00898 else if (*ptr == '\n' && pre) 00899 { 00900 *s = '\0'; 00901 s = buf; 00902 00903 hv_draw(buf, xx + x() - leftline_, yy + y()); 00904 00905 if (line < 31) 00906 line ++; 00907 xx = block->line[line]; 00908 yy += hh; 00909 hh = fsize + 2; 00910 needspace = 0; 00911 00912 ptr ++; 00913 current_pos = ptr-value_; 00914 } 00915 else if (isspace((*ptr)&255)) 00916 { 00917 if (pre) 00918 { 00919 if (*ptr == ' ') 00920 *s++ = ' '; 00921 else 00922 { 00923 // Do tabs every 8 columns... 00924 while (((s - buf) & 7)) 00925 *s++ = ' '; 00926 } 00927 } 00928 00929 ptr ++; 00930 if (!pre) current_pos = ptr-value_; 00931 needspace = 1; 00932 } 00933 else if (*ptr == '&') 00934 { 00935 ptr ++; 00936 00937 int qch = quote_char(ptr); 00938 00939 if (qch < 0) 00940 *s++ = '&'; 00941 else { 00942 int l; 00943 l = fl_utf8encode((unsigned int) qch, s); 00944 if (l < 1) l = 1; 00945 s += l; 00946 ptr = strchr(ptr, ';') + 1; 00947 } 00948 00949 if ((fsize + 2) > hh) 00950 hh = fsize + 2; 00951 } 00952 else 00953 { 00954 *s++ = *ptr++; 00955 00956 if ((fsize + 2) > hh) 00957 hh = fsize + 2; 00958 } 00959 } 00960 00961 *s = '\0'; 00962 00963 if (s > buf && !pre && !head) 00964 { 00965 ww = (int)fl_width(buf); 00966 00967 if (needspace && xx > block->x) 00968 xx += (int)fl_width(' '); 00969 00970 if ((xx + ww) > block->w) 00971 { 00972 if (line < 31) 00973 line ++; 00974 xx = block->line[line]; 00975 yy += hh; 00976 hh = 0; 00977 } 00978 } 00979 00980 if (s > buf && !head) 00981 { 00982 hv_draw(buf, xx + x() - leftline_, yy + y()); 00983 if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, 00984 xx + x() - leftline_ + ww); 00985 current_pos = ptr-value_; 00986 } 00987 } 00988 00989 fl_pop_clip(); 00990 } 00991 00992 00993 00998 int // O - Matching position or -1 if not found 00999 Fl_Help_View::find(const char *s, // I - String to find 01000 int p) // I - Starting position 01001 { 01002 int i, // Looping var 01003 c; // Current character 01004 Fl_Help_Block *b; // Current block 01005 const char *bp, // Block matching pointer 01006 *bs, // Start of current comparison 01007 *sp; // Search string pointer 01008 01009 01010 // Range check input and value... 01011 if (!s || !value_) return -1; 01012 01013 if (p < 0 || p >= (int)strlen(value_)) p = 0; 01014 else if (p > 0) p ++; 01015 01016 // Look for the string... 01017 for (i = nblocks_, b = blocks_; i > 0; i --, b ++) { 01018 if (b->end < (value_ + p)) 01019 continue; 01020 01021 if (b->start < (value_ + p)) bp = value_ + p; 01022 else bp = b->start; 01023 01024 for (sp = s, bs = bp; *sp && *bp && bp < b->end; bp ++) { 01025 if (*bp == '<') { 01026 // skip to end of element... 01027 while (*bp && bp < b->end && *bp != '>') bp ++; 01028 continue; 01029 } else if (*bp == '&') { 01030 // decode HTML entity... 01031 if ((c = quote_char(bp + 1)) < 0) c = '&'; 01032 else bp = strchr(bp + 1, ';') + 1; 01033 } else c = *bp; 01034 01035 if (tolower(*sp) == tolower(c)) sp ++; 01036 else { 01037 // No match, so reset to start of search... 01038 sp = s; 01039 bs ++; 01040 bp = bs; 01041 } 01042 } 01043 01044 if (!*sp) { 01045 // Found a match! 01046 topline(b->y - b->h); 01047 return (b->end - value_); 01048 } 01049 } 01050 01051 // No match! 01052 return (-1); 01053 } 01054 01056 void Fl_Help_View::format() { 01057 int i; // Looping var 01058 int done; // Are we done yet? 01059 Fl_Help_Block *block, // Current block 01060 *cell; // Current table cell 01061 int cells[MAX_COLUMNS], 01062 // Cells in the current row... 01063 row; // Current table row (block number) 01064 const char *ptr, // Pointer into block 01065 *start, // Pointer to start of element 01066 *attrs; // Pointer to start of element attributes 01067 char *s, // Pointer into buffer 01068 buf[1024], // Text buffer 01069 attr[1024], // Attribute buffer 01070 wattr[1024], // Width attribute buffer 01071 hattr[1024], // Height attribute buffer 01072 linkdest[1024]; // Link destination 01073 int xx, yy, ww, hh; // Size of current text fragment 01074 int line; // Current line in block 01075 int links; // Links for current line 01076 Fl_Font font; 01077 Fl_Fontsize fsize; // Current font and size 01078 Fl_Color fcolor; // Current font color 01079 unsigned char border; // Draw border? 01080 int talign, // Current alignment 01081 newalign, // New alignment 01082 head, // In the <HEAD> section? 01083 pre, // <PRE> text? 01084 needspace; // Do we need whitespace? 01085 int table_width, // Width of table 01086 table_offset; // Offset of table 01087 int column, // Current table column number 01088 columns[MAX_COLUMNS]; 01089 // Column widths 01090 Fl_Color tc, rc; // Table/row background color 01091 Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; 01092 // Box to draw... 01093 fl_margins margins; // Left margin stack... 01094 01095 01096 // Reset document width... 01097 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 01098 hsize_ = w() - scrollsize - Fl::box_dw(b); 01099 01100 done = 0; 01101 while (!done) 01102 { 01103 // Reset state variables... 01104 done = 1; 01105 nblocks_ = 0; 01106 nlinks_ = 0; 01107 ntargets_ = 0; 01108 size_ = 0; 01109 bgcolor_ = color(); 01110 textcolor_ = textcolor(); 01111 linkcolor_ = fl_contrast(FL_BLUE, color()); 01112 01113 tc = rc = bgcolor_; 01114 01115 strcpy(title_, "Untitled"); 01116 01117 if (!value_) 01118 return; 01119 01120 // Setup for formatting... 01121 initfont(font, fsize, fcolor); 01122 01123 line = 0; 01124 links = 0; 01125 xx = margins.clear(); 01126 yy = fsize + 2; 01127 ww = 0; 01128 column = 0; 01129 border = 0; 01130 hh = 0; 01131 block = add_block(value_, xx, yy, hsize_, 0); 01132 row = 0; 01133 head = 0; 01134 pre = 0; 01135 talign = LEFT; 01136 newalign = LEFT; 01137 needspace = 0; 01138 linkdest[0] = '\0'; 01139 table_offset = 0; 01140 01141 // Html text character loop 01142 for (ptr = value_, s = buf; *ptr;) 01143 { 01144 // End of word? 01145 if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf) 01146 { 01147 // Get width of word parsed so far... 01148 *s = '\0'; 01149 ww = (int)fl_width(buf); 01150 01151 if (!head && !pre) 01152 { 01153 // Check width... 01154 if (ww > hsize_) { 01155 hsize_ = ww; 01156 done = 0; 01157 break; 01158 } 01159 01160 if (needspace && xx > block->x) 01161 ww += (int)fl_width(' '); 01162 01163 // printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n", 01164 // line, xx, ww, block->x, block->w); 01165 01166 if ((xx + ww) > block->w) 01167 { 01168 line = do_align(block, line, xx, newalign, links); 01169 xx = block->x; 01170 yy += hh; 01171 block->h += hh; 01172 hh = 0; 01173 } 01174 01175 if (linkdest[0]) 01176 add_link(linkdest, xx, yy - fsize, ww, fsize); 01177 01178 xx += ww; 01179 if ((fsize + 2) > hh) 01180 hh = fsize + 2; 01181 01182 needspace = 0; 01183 } 01184 else if (pre) 01185 { 01186 // Add a link as needed... 01187 if (linkdest[0]) 01188 add_link(linkdest, xx, yy - hh, ww, hh); 01189 01190 xx += ww; 01191 if ((fsize + 2) > hh) 01192 hh = fsize + 2; 01193 01194 // Handle preformatted text... 01195 while (isspace((*ptr)&255)) 01196 { 01197 if (*ptr == '\n') 01198 { 01199 if (xx > hsize_) break; 01200 01201 line = do_align(block, line, xx, newalign, links); 01202 xx = block->x; 01203 yy += hh; 01204 block->h += hh; 01205 hh = fsize + 2; 01206 } 01207 else 01208 xx += (int)fl_width(' '); 01209 01210 if ((fsize + 2) > hh) 01211 hh = fsize + 2; 01212 01213 ptr ++; 01214 } 01215 01216 if (xx > hsize_) { 01217 hsize_ = xx; 01218 done = 0; 01219 break; 01220 } 01221 01222 needspace = 0; 01223 } 01224 else 01225 { 01226 // Handle normal text or stuff in the <HEAD> section... 01227 while (isspace((*ptr)&255)) 01228 ptr ++; 01229 } 01230 01231 s = buf; 01232 } 01233 01234 if (*ptr == '<') 01235 { 01236 // Handle html tags.. 01237 start = ptr; 01238 ptr ++; 01239 01240 if (strncmp(ptr, "!--", 3) == 0) 01241 { 01242 // Comment... 01243 ptr += 3; 01244 if ((ptr = strstr(ptr, "-->")) != NULL) 01245 { 01246 ptr += 3; 01247 continue; 01248 } 01249 else 01250 break; 01251 } 01252 01253 while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) 01254 if (s < (buf + sizeof(buf) - 1)) 01255 *s++ = *ptr++; 01256 else 01257 ptr ++; 01258 01259 *s = '\0'; 01260 s = buf; 01261 01262 // puts(buf); 01263 01264 attrs = ptr; 01265 while (*ptr && *ptr != '>') 01266 ptr ++; 01267 01268 if (*ptr == '>') 01269 ptr ++; 01270 01271 if (strcasecmp(buf, "HEAD") == 0) 01272 head = 1; 01273 else if (strcasecmp(buf, "/HEAD") == 0) 01274 head = 0; 01275 else if (strcasecmp(buf, "TITLE") == 0) 01276 { 01277 // Copy the title in the document... 01278 for (s = title_; 01279 *ptr != '<' && *ptr && s < (title_ + sizeof(title_) - 1); 01280 *s++ = *ptr++); 01281 01282 *s = '\0'; 01283 s = buf; 01284 } 01285 else if (strcasecmp(buf, "A") == 0) 01286 { 01287 if (get_attr(attrs, "NAME", attr, sizeof(attr)) != NULL) 01288 add_target(attr, yy - fsize - 2); 01289 01290 if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) 01291 strlcpy(linkdest, attr, sizeof(linkdest)); 01292 } 01293 else if (strcasecmp(buf, "/A") == 0) 01294 linkdest[0] = '\0'; 01295 else if (strcasecmp(buf, "BODY") == 0) 01296 { 01297 bgcolor_ = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), 01298 color()); 01299 textcolor_ = get_color(get_attr(attrs, "TEXT", attr, sizeof(attr)), 01300 textcolor()); 01301 linkcolor_ = get_color(get_attr(attrs, "LINK", attr, sizeof(attr)), 01302 fl_contrast(FL_BLUE, color())); 01303 } 01304 else if (strcasecmp(buf, "BR") == 0) 01305 { 01306 line = do_align(block, line, xx, newalign, links); 01307 xx = block->x; 01308 block->h += hh; 01309 yy += hh; 01310 hh = 0; 01311 } 01312 else if (strcasecmp(buf, "CENTER") == 0 || 01313 strcasecmp(buf, "P") == 0 || 01314 strcasecmp(buf, "H1") == 0 || 01315 strcasecmp(buf, "H2") == 0 || 01316 strcasecmp(buf, "H3") == 0 || 01317 strcasecmp(buf, "H4") == 0 || 01318 strcasecmp(buf, "H5") == 0 || 01319 strcasecmp(buf, "H6") == 0 || 01320 strcasecmp(buf, "UL") == 0 || 01321 strcasecmp(buf, "OL") == 0 || 01322 strcasecmp(buf, "DL") == 0 || 01323 strcasecmp(buf, "LI") == 0 || 01324 strcasecmp(buf, "DD") == 0 || 01325 strcasecmp(buf, "DT") == 0 || 01326 strcasecmp(buf, "HR") == 0 || 01327 strcasecmp(buf, "PRE") == 0 || 01328 strcasecmp(buf, "TABLE") == 0) 01329 { 01330 block->end = start; 01331 line = do_align(block, line, xx, newalign, links); 01332 newalign = strcasecmp(buf, "CENTER") ? LEFT : CENTER; 01333 xx = block->x; 01334 block->h += hh; 01335 01336 if (strcasecmp(buf, "UL") == 0 || 01337 strcasecmp(buf, "OL") == 0 || 01338 strcasecmp(buf, "DL") == 0) 01339 { 01340 block->h += fsize + 2; 01341 xx = margins.push(4 * fsize); 01342 } 01343 else if (strcasecmp(buf, "TABLE") == 0) 01344 { 01345 if (get_attr(attrs, "BORDER", attr, sizeof(attr))) 01346 border = (uchar)atoi(attr); 01347 else 01348 border = 0; 01349 01350 tc = rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_); 01351 01352 block->h += fsize + 2; 01353 01354 format_table(&table_width, columns, start); 01355 01356 if ((xx + table_width) > hsize_) { 01357 #ifdef DEBUG 01358 printf("xx=%d, table_width=%d, hsize_=%d\n", xx, table_width, 01359 hsize_); 01360 #endif // DEBUG 01361 hsize_ = xx + table_width; 01362 done = 0; 01363 break; 01364 } 01365 01366 switch (get_align(attrs, talign)) 01367 { 01368 default : 01369 table_offset = 0; 01370 break; 01371 01372 case CENTER : 01373 table_offset = (hsize_ - table_width) / 2 - textsize_; 01374 break; 01375 01376 case RIGHT : 01377 table_offset = hsize_ - table_width - textsize_; 01378 break; 01379 } 01380 01381 column = 0; 01382 } 01383 01384 if (tolower(buf[0]) == 'h' && isdigit(buf[1])) 01385 { 01386 font = FL_HELVETICA_BOLD; 01387 fsize = textsize_ + '7' - buf[1]; 01388 } 01389 else if (strcasecmp(buf, "DT") == 0) 01390 { 01391 font = textfont_ | FL_ITALIC; 01392 fsize = textsize_; 01393 } 01394 else if (strcasecmp(buf, "PRE") == 0) 01395 { 01396 font = FL_COURIER; 01397 fsize = textsize_; 01398 pre = 1; 01399 } 01400 else 01401 { 01402 font = textfont_; 01403 fsize = textsize_; 01404 } 01405 01406 pushfont(font, fsize); 01407 01408 yy = block->y + block->h; 01409 hh = 0; 01410 01411 if ((tolower(buf[0]) == 'h' && isdigit(buf[1])) || 01412 strcasecmp(buf, "DD") == 0 || 01413 strcasecmp(buf, "DT") == 0 || 01414 strcasecmp(buf, "P") == 0) 01415 yy += fsize + 2; 01416 else if (strcasecmp(buf, "HR") == 0) 01417 { 01418 hh += 2 * fsize; 01419 yy += fsize; 01420 } 01421 01422 if (row) 01423 block = add_block(start, xx, yy, block->w, 0); 01424 else 01425 block = add_block(start, xx, yy, hsize_, 0); 01426 01427 needspace = 0; 01428 line = 0; 01429 01430 if (strcasecmp(buf, "CENTER") == 0) 01431 newalign = talign = CENTER; 01432 else 01433 newalign = get_align(attrs, talign); 01434 } 01435 else if (strcasecmp(buf, "/CENTER") == 0 || 01436 strcasecmp(buf, "/P") == 0 || 01437 strcasecmp(buf, "/H1") == 0 || 01438 strcasecmp(buf, "/H2") == 0 || 01439 strcasecmp(buf, "/H3") == 0 || 01440 strcasecmp(buf, "/H4") == 0 || 01441 strcasecmp(buf, "/H5") == 0 || 01442 strcasecmp(buf, "/H6") == 0 || 01443 strcasecmp(buf, "/PRE") == 0 || 01444 strcasecmp(buf, "/UL") == 0 || 01445 strcasecmp(buf, "/OL") == 0 || 01446 strcasecmp(buf, "/DL") == 0 || 01447 strcasecmp(buf, "/TABLE") == 0) 01448 { 01449 line = do_align(block, line, xx, newalign, links); 01450 xx = block->x; 01451 block->end = ptr; 01452 01453 if (strcasecmp(buf, "/UL") == 0 || 01454 strcasecmp(buf, "/OL") == 0 || 01455 strcasecmp(buf, "/DL") == 0) 01456 { 01457 xx = margins.pop(); 01458 block->h += fsize + 2; 01459 } 01460 else if (strcasecmp(buf, "/TABLE") == 0) 01461 { 01462 block->h += fsize + 2; 01463 xx = margins.current(); 01464 } 01465 else if (strcasecmp(buf, "/PRE") == 0) 01466 { 01467 pre = 0; 01468 hh = 0; 01469 } 01470 else if (strcasecmp(buf, "/CENTER") == 0) 01471 talign = LEFT; 01472 01473 popfont(font, fsize, fcolor); 01474 01475 //#if defined(__GNUC__) 01476 //#warning FIXME this isspace & 255 test will probably not work on a utf8 stream... And we use it everywhere! 01477 //#endif /*__GNUC__*/ 01478 while (isspace((*ptr)&255)) 01479 ptr ++; 01480 01481 block->h += hh; 01482 yy += hh; 01483 01484 if (tolower(buf[2]) == 'l') 01485 yy += fsize + 2; 01486 01487 if (row) 01488 block = add_block(ptr, xx, yy, block->w, 0); 01489 else 01490 block = add_block(ptr, xx, yy, hsize_, 0); 01491 01492 needspace = 0; 01493 hh = 0; 01494 line = 0; 01495 newalign = talign; 01496 } 01497 else if (strcasecmp(buf, "TR") == 0) 01498 { 01499 block->end = start; 01500 line = do_align(block, line, xx, newalign, links); 01501 xx = block->x; 01502 block->h += hh; 01503 01504 if (row) 01505 { 01506 yy = blocks_[row].y + blocks_[row].h; 01507 01508 for (cell = blocks_ + row + 1; cell <= block; cell ++) 01509 if ((cell->y + cell->h) > yy) 01510 yy = cell->y + cell->h; 01511 01512 block = blocks_ + row; 01513 01514 block->h = yy - block->y + 2; 01515 01516 for (i = 0; i < column; i ++) 01517 if (cells[i]) 01518 { 01519 cell = blocks_ + cells[i]; 01520 cell->h = block->h; 01521 } 01522 } 01523 01524 memset(cells, 0, sizeof(cells)); 01525 01526 yy = block->y + block->h - 4; 01527 hh = 0; 01528 block = add_block(start, xx, yy, hsize_, 0); 01529 row = block - blocks_; 01530 needspace = 0; 01531 column = 0; 01532 line = 0; 01533 01534 rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc); 01535 } 01536 else if (strcasecmp(buf, "/TR") == 0 && row) 01537 { 01538 line = do_align(block, line, xx, newalign, links); 01539 block->end = start; 01540 block->h += hh; 01541 talign = LEFT; 01542 01543 xx = blocks_[row].x; 01544 yy = blocks_[row].y + blocks_[row].h; 01545 01546 for (cell = blocks_ + row + 1; cell <= block; cell ++) 01547 if ((cell->y + cell->h) > yy) 01548 yy = cell->y + cell->h; 01549 01550 block = blocks_ + row; 01551 01552 block->h = yy - block->y + 2; 01553 01554 for (i = 0; i < column; i ++) 01555 if (cells[i]) 01556 { 01557 cell = blocks_ + cells[i]; 01558 cell->h = block->h; 01559 } 01560 01561 yy = block->y + block->h /*- 4*/; 01562 block = add_block(start, xx, yy, hsize_, 0); 01563 needspace = 0; 01564 row = 0; 01565 line = 0; 01566 } 01567 else if ((strcasecmp(buf, "TD") == 0 || 01568 strcasecmp(buf, "TH") == 0) && row) 01569 { 01570 int colspan; // COLSPAN attribute 01571 01572 01573 line = do_align(block, line, xx, newalign, links); 01574 block->end = start; 01575 block->h += hh; 01576 01577 if (strcasecmp(buf, "TH") == 0) 01578 font = textfont_ | FL_BOLD; 01579 else 01580 font = textfont_; 01581 01582 fsize = textsize_; 01583 01584 xx = blocks_[row].x + fsize + 3 + table_offset; 01585 for (i = 0; i < column; i ++) 01586 xx += columns[i] + 6; 01587 01588 margins.push(xx - margins.current()); 01589 01590 if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL) 01591 colspan = atoi(attr); 01592 else 01593 colspan = 1; 01594 01595 for (i = 0, ww = -6; i < colspan; i ++) 01596 ww += columns[column + i] + 6; 01597 01598 if (block->end == block->start && nblocks_ > 1) 01599 { 01600 nblocks_ --; 01601 block --; 01602 } 01603 01604 pushfont(font, fsize); 01605 01606 yy = blocks_[row].y; 01607 hh = 0; 01608 block = add_block(start, xx, yy, xx + ww, 0, border); 01609 needspace = 0; 01610 line = 0; 01611 newalign = get_align(attrs, tolower(buf[1]) == 'h' ? CENTER : LEFT); 01612 talign = newalign; 01613 01614 cells[column] = block - blocks_; 01615 01616 column += colspan; 01617 01618 block->bgcolor = get_color(get_attr(attrs, "BGCOLOR", attr, 01619 sizeof(attr)), rc); 01620 } 01621 else if ((strcasecmp(buf, "/TD") == 0 || 01622 strcasecmp(buf, "/TH") == 0) && row) 01623 { 01624 line = do_align(block, line, xx, newalign, links); 01625 popfont(font, fsize, fcolor); 01626 xx = margins.pop(); 01627 talign = LEFT; 01628 } 01629 else if (strcasecmp(buf, "FONT") == 0) 01630 { 01631 if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) { 01632 if (!strncasecmp(attr, "helvetica", 9) || 01633 !strncasecmp(attr, "arial", 5) || 01634 !strncasecmp(attr, "sans", 4)) font = FL_HELVETICA; 01635 else if (!strncasecmp(attr, "times", 5) || 01636 !strncasecmp(attr, "serif", 5)) font = FL_TIMES; 01637 else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL; 01638 else font = FL_COURIER; 01639 } 01640 01641 if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) { 01642 if (isdigit(attr[0] & 255)) { 01643 // Absolute size 01644 fsize = (int)(textsize_ * pow(1.2, atoi(attr) - 3.0)); 01645 } else { 01646 // Relative size 01647 fsize = (int)(fsize * pow(1.2, atoi(attr))); 01648 } 01649 } 01650 01651 pushfont(font, fsize); 01652 } 01653 else if (strcasecmp(buf, "/FONT") == 0) 01654 popfont(font, fsize, fcolor); 01655 else if (strcasecmp(buf, "B") == 0 || 01656 strcasecmp(buf, "STRONG") == 0) 01657 pushfont(font |= FL_BOLD, fsize); 01658 else if (strcasecmp(buf, "I") == 0 || 01659 strcasecmp(buf, "EM") == 0) 01660 pushfont(font |= FL_ITALIC, fsize); 01661 else if (strcasecmp(buf, "CODE") == 0 || 01662 strcasecmp(buf, "TT") == 0) 01663 pushfont(font = FL_COURIER, fsize); 01664 else if (strcasecmp(buf, "KBD") == 0) 01665 pushfont(font = FL_COURIER_BOLD, fsize); 01666 else if (strcasecmp(buf, "VAR") == 0) 01667 pushfont(font = FL_COURIER_ITALIC, fsize); 01668 else if (strcasecmp(buf, "/B") == 0 || 01669 strcasecmp(buf, "/STRONG") == 0 || 01670 strcasecmp(buf, "/I") == 0 || 01671 strcasecmp(buf, "/EM") == 0 || 01672 strcasecmp(buf, "/CODE") == 0 || 01673 strcasecmp(buf, "/TT") == 0 || 01674 strcasecmp(buf, "/KBD") == 0 || 01675 strcasecmp(buf, "/VAR") == 0) 01676 popfont(font, fsize, fcolor); 01677 else if (strcasecmp(buf, "IMG") == 0) 01678 { 01679 Fl_Shared_Image *img = 0; 01680 int width; 01681 int height; 01682 01683 01684 get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); 01685 get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); 01686 width = get_length(wattr); 01687 height = get_length(hattr); 01688 01689 if (get_attr(attrs, "SRC", attr, sizeof(attr))) { 01690 img = get_image(attr, width, height); 01691 width = img->w(); 01692 height = img->h(); 01693 } 01694 01695 ww = width; 01696 01697 if (ww > hsize_) { 01698 hsize_ = ww; 01699 done = 0; 01700 break; 01701 } 01702 01703 if (needspace && xx > block->x) 01704 ww += (int)fl_width(' '); 01705 01706 if ((xx + ww) > block->w) 01707 { 01708 line = do_align(block, line, xx, newalign, links); 01709 xx = block->x; 01710 yy += hh; 01711 block->h += hh; 01712 hh = 0; 01713 } 01714 01715 if (linkdest[0]) 01716 add_link(linkdest, xx, yy - height, ww, height); 01717 01718 xx += ww; 01719 if ((height + 2) > hh) 01720 hh = height + 2; 01721 01722 needspace = 0; 01723 } 01724 } 01725 else if (*ptr == '\n' && pre) 01726 { 01727 if (linkdest[0]) 01728 add_link(linkdest, xx, yy - hh, ww, hh); 01729 01730 if (xx > hsize_) { 01731 hsize_ = xx; 01732 done = 0; 01733 break; 01734 } 01735 01736 line = do_align(block, line, xx, newalign, links); 01737 xx = block->x; 01738 yy += hh; 01739 block->h += hh; 01740 needspace = 0; 01741 ptr ++; 01742 } 01743 else if (isspace((*ptr)&255)) 01744 { 01745 needspace = 1; 01746 if ( pre ) { 01747 xx += (int)fl_width(' '); 01748 } 01749 ptr ++; 01750 } 01751 else if (*ptr == '&' && s < (buf + sizeof(buf) - 1)) 01752 { 01753 // Handle html '&' codes, eg. "&" 01754 ptr ++; 01755 01756 int qch = quote_char(ptr); 01757 01758 if (qch < 0) 01759 *s++ = '&'; 01760 else { 01761 int l; 01762 l = fl_utf8encode((unsigned int) qch, s); 01763 if (l < 1) l = 1; 01764 s += l; 01765 ptr = strchr(ptr, ';') + 1; 01766 } 01767 01768 if ((fsize + 2) > hh) 01769 hh = fsize + 2; 01770 } 01771 else 01772 { 01773 if (s < (buf + sizeof(buf) - 1)) 01774 *s++ = *ptr++; 01775 else 01776 ptr ++; 01777 01778 if ((fsize + 2) > hh) 01779 hh = fsize + 2; 01780 } 01781 } 01782 01783 if (s > buf && !head) 01784 { 01785 *s = '\0'; 01786 ww = (int)fl_width(buf); 01787 01788 // printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n", 01789 // line, xx, ww, block->x, block->w); 01790 01791 if (ww > hsize_) { 01792 hsize_ = ww; 01793 done = 0; 01794 break; 01795 } 01796 01797 if (needspace && xx > block->x) 01798 ww += (int)fl_width(' '); 01799 01800 if ((xx + ww) > block->w) 01801 { 01802 line = do_align(block, line, xx, newalign, links); 01803 xx = block->x; 01804 yy += hh; 01805 block->h += hh; 01806 hh = 0; 01807 } 01808 01809 if (linkdest[0]) 01810 add_link(linkdest, xx, yy - fsize, ww, fsize); 01811 01812 xx += ww; 01813 } 01814 01815 do_align(block, line, xx, newalign, links); 01816 01817 block->end = ptr; 01818 size_ = yy + hh; 01819 } 01820 01821 // printf("margins.depth_=%d\n", margins.depth_); 01822 01823 if (ntargets_ > 1) 01824 qsort(targets_, ntargets_, sizeof(Fl_Help_Target), 01825 (compare_func_t)compare_targets); 01826 01827 int dx = Fl::box_dw(b) - Fl::box_dx(b); 01828 int dy = Fl::box_dh(b) - Fl::box_dy(b); 01829 int ss = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 01830 int dw = Fl::box_dw(b) + ss; 01831 int dh = Fl::box_dh(b); 01832 01833 if (hsize_ > (w() - dw)) { 01834 hscrollbar_.show(); 01835 01836 dh += ss; 01837 01838 if (size_ < (h() - dh)) { 01839 scrollbar_.hide(); 01840 hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy, 01841 w() - Fl::box_dw(b), ss); 01842 } else { 01843 scrollbar_.show(); 01844 scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b), 01845 ss, h() - ss - Fl::box_dh(b)); 01846 hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy, 01847 w() - ss - Fl::box_dw(b), ss); 01848 } 01849 } else { 01850 hscrollbar_.hide(); 01851 01852 if (size_ < (h() - dh)) scrollbar_.hide(); 01853 else { 01854 scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b), 01855 ss, h() - Fl::box_dh(b)); 01856 scrollbar_.show(); 01857 } 01858 } 01859 01860 // Reset scrolling if it needs to be... 01861 if (scrollbar_.visible()) { 01862 int temph = h() - Fl::box_dh(b); 01863 if (hscrollbar_.visible()) temph -= ss; 01864 if ((topline_ + temph) > size_) topline(size_ - temph); 01865 else topline(topline_); 01866 } else topline(0); 01867 01868 if (hscrollbar_.visible()) { 01869 int tempw = w() - ss - Fl::box_dw(b); 01870 if ((leftline_ + tempw) > hsize_) leftline(hsize_ - tempw); 01871 else leftline(leftline_); 01872 } else leftline(0); 01873 } 01874 01875 01877 void 01878 Fl_Help_View::format_table(int *table_width, // O - Total table width 01879 int *columns, // O - Column widths 01880 const char *table) // I - Pointer to start of table 01881 { 01882 int column, // Current column 01883 num_columns, // Number of columns 01884 colspan, // COLSPAN attribute 01885 width, // Current width 01886 temp_width, // Temporary width 01887 max_width, // Maximum width 01888 incell, // In a table cell? 01889 pre, // <PRE> text? 01890 needspace; // Need whitespace? 01891 char *s, // Pointer into buffer 01892 buf[1024], // Text buffer 01893 attr[1024], // Other attribute 01894 wattr[1024], // WIDTH attribute 01895 hattr[1024]; // HEIGHT attribute 01896 const char *ptr, // Pointer into table 01897 *attrs, // Pointer to attributes 01898 *start; // Start of element 01899 int minwidths[MAX_COLUMNS]; // Minimum widths for each column 01900 Fl_Font font; 01901 Fl_Fontsize fsize; // Current font and size 01902 Fl_Color fcolor; // Currrent font color 01903 01904 // Clear widths... 01905 *table_width = 0; 01906 for (column = 0; column < MAX_COLUMNS; column ++) 01907 { 01908 columns[column] = 0; 01909 minwidths[column] = 0; 01910 } 01911 01912 num_columns = 0; 01913 colspan = 0; 01914 max_width = 0; 01915 pre = 0; 01916 needspace = 0; 01917 fstack_.top(font, fsize, fcolor); 01918 01919 // Scan the table... 01920 for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;) 01921 { 01922 if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf && incell) 01923 { 01924 // Check width... 01925 if (needspace) 01926 { 01927 *s++ = ' '; 01928 needspace = 0; 01929 } 01930 01931 *s = '\0'; 01932 temp_width = (int)fl_width(buf); 01933 s = buf; 01934 01935 if (temp_width > minwidths[column]) 01936 minwidths[column] = temp_width; 01937 01938 width += temp_width; 01939 01940 if (width > max_width) 01941 max_width = width; 01942 } 01943 01944 if (*ptr == '<') 01945 { 01946 start = ptr; 01947 01948 for (s = buf, ptr ++; *ptr && *ptr != '>' && !isspace((*ptr)&255);) 01949 if (s < (buf + sizeof(buf) - 1)) 01950 *s++ = *ptr++; 01951 else 01952 ptr ++; 01953 01954 *s = '\0'; 01955 s = buf; 01956 01957 attrs = ptr; 01958 while (*ptr && *ptr != '>') 01959 ptr ++; 01960 01961 if (*ptr == '>') 01962 ptr ++; 01963 01964 if (strcasecmp(buf, "BR") == 0 || 01965 strcasecmp(buf, "HR") == 0) 01966 { 01967 width = 0; 01968 needspace = 0; 01969 } 01970 else if (strcasecmp(buf, "TABLE") == 0 && start > table) 01971 break; 01972 else if (strcasecmp(buf, "CENTER") == 0 || 01973 strcasecmp(buf, "P") == 0 || 01974 strcasecmp(buf, "H1") == 0 || 01975 strcasecmp(buf, "H2") == 0 || 01976 strcasecmp(buf, "H3") == 0 || 01977 strcasecmp(buf, "H4") == 0 || 01978 strcasecmp(buf, "H5") == 0 || 01979 strcasecmp(buf, "H6") == 0 || 01980 strcasecmp(buf, "UL") == 0 || 01981 strcasecmp(buf, "OL") == 0 || 01982 strcasecmp(buf, "DL") == 0 || 01983 strcasecmp(buf, "LI") == 0 || 01984 strcasecmp(buf, "DD") == 0 || 01985 strcasecmp(buf, "DT") == 0 || 01986 strcasecmp(buf, "PRE") == 0) 01987 { 01988 width = 0; 01989 needspace = 0; 01990 01991 if (tolower(buf[0]) == 'h' && isdigit(buf[1])) 01992 { 01993 font = FL_HELVETICA_BOLD; 01994 fsize = textsize_ + '7' - buf[1]; 01995 } 01996 else if (strcasecmp(buf, "DT") == 0) 01997 { 01998 font = textfont_ | FL_ITALIC; 01999 fsize = textsize_; 02000 } 02001 else if (strcasecmp(buf, "PRE") == 0) 02002 { 02003 font = FL_COURIER; 02004 fsize = textsize_; 02005 pre = 1; 02006 } 02007 else if (strcasecmp(buf, "LI") == 0) 02008 { 02009 width += 4 * fsize; 02010 font = textfont_; 02011 fsize = textsize_; 02012 } 02013 else 02014 { 02015 font = textfont_; 02016 fsize = textsize_; 02017 } 02018 02019 pushfont(font, fsize); 02020 } 02021 else if (strcasecmp(buf, "/CENTER") == 0 || 02022 strcasecmp(buf, "/P") == 0 || 02023 strcasecmp(buf, "/H1") == 0 || 02024 strcasecmp(buf, "/H2") == 0 || 02025 strcasecmp(buf, "/H3") == 0 || 02026 strcasecmp(buf, "/H4") == 0 || 02027 strcasecmp(buf, "/H5") == 0 || 02028 strcasecmp(buf, "/H6") == 0 || 02029 strcasecmp(buf, "/PRE") == 0 || 02030 strcasecmp(buf, "/UL") == 0 || 02031 strcasecmp(buf, "/OL") == 0 || 02032 strcasecmp(buf, "/DL") == 0) 02033 { 02034 width = 0; 02035 needspace = 0; 02036 02037 popfont(font, fsize, fcolor); 02038 } 02039 else if (strcasecmp(buf, "TR") == 0 || strcasecmp(buf, "/TR") == 0 || 02040 strcasecmp(buf, "/TABLE") == 0) 02041 { 02042 // printf("%s column = %d, colspan = %d, num_columns = %d\n", 02043 // buf, column, colspan, num_columns); 02044 02045 if (column >= 0) 02046 { 02047 // This is a hack to support COLSPAN... 02048 max_width /= colspan; 02049 02050 while (colspan > 0) 02051 { 02052 if (max_width > columns[column]) 02053 columns[column] = max_width; 02054 02055 column ++; 02056 colspan --; 02057 } 02058 } 02059 02060 if (strcasecmp(buf, "/TABLE") == 0) 02061 break; 02062 02063 needspace = 0; 02064 column = -1; 02065 width = 0; 02066 max_width = 0; 02067 incell = 0; 02068 } 02069 else if (strcasecmp(buf, "TD") == 0 || 02070 strcasecmp(buf, "TH") == 0) 02071 { 02072 // printf("BEFORE column = %d, colspan = %d, num_columns = %d\n", 02073 // column, colspan, num_columns); 02074 02075 if (column >= 0) 02076 { 02077 // This is a hack to support COLSPAN... 02078 max_width /= colspan; 02079 02080 while (colspan > 0) 02081 { 02082 if (max_width > columns[column]) 02083 columns[column] = max_width; 02084 02085 column ++; 02086 colspan --; 02087 } 02088 } 02089 else 02090 column ++; 02091 02092 if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL) 02093 colspan = atoi(attr); 02094 else 02095 colspan = 1; 02096 02097 // printf("AFTER column = %d, colspan = %d, num_columns = %d\n", 02098 // column, colspan, num_columns); 02099 02100 if ((column + colspan) >= num_columns) 02101 num_columns = column + colspan; 02102 02103 needspace = 0; 02104 width = 0; 02105 incell = 1; 02106 02107 if (strcasecmp(buf, "TH") == 0) 02108 font = textfont_ | FL_BOLD; 02109 else 02110 font = textfont_; 02111 02112 fsize = textsize_; 02113 02114 pushfont(font, fsize); 02115 02116 if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL) 02117 max_width = get_length(attr); 02118 else 02119 max_width = 0; 02120 02121 // printf("max_width = %d\n", max_width); 02122 } 02123 else if (strcasecmp(buf, "/TD") == 0 || 02124 strcasecmp(buf, "/TH") == 0) 02125 { 02126 incell = 0; 02127 popfont(font, fsize, fcolor); 02128 } 02129 else if (strcasecmp(buf, "B") == 0 || 02130 strcasecmp(buf, "STRONG") == 0) 02131 pushfont(font |= FL_BOLD, fsize); 02132 else if (strcasecmp(buf, "I") == 0 || 02133 strcasecmp(buf, "EM") == 0) 02134 pushfont(font |= FL_ITALIC, fsize); 02135 else if (strcasecmp(buf, "CODE") == 0 || 02136 strcasecmp(buf, "TT") == 0) 02137 pushfont(font = FL_COURIER, fsize); 02138 else if (strcasecmp(buf, "KBD") == 0) 02139 pushfont(font = FL_COURIER_BOLD, fsize); 02140 else if (strcasecmp(buf, "VAR") == 0) 02141 pushfont(font = FL_COURIER_ITALIC, fsize); 02142 else if (strcasecmp(buf, "/B") == 0 || 02143 strcasecmp(buf, "/STRONG") == 0 || 02144 strcasecmp(buf, "/I") == 0 || 02145 strcasecmp(buf, "/EM") == 0 || 02146 strcasecmp(buf, "/CODE") == 0 || 02147 strcasecmp(buf, "/TT") == 0 || 02148 strcasecmp(buf, "/KBD") == 0 || 02149 strcasecmp(buf, "/VAR") == 0) 02150 popfont(font, fsize, fcolor); 02151 else if (strcasecmp(buf, "IMG") == 0 && incell) 02152 { 02153 Fl_Shared_Image *img = 0; 02154 int iwidth, iheight; 02155 02156 02157 get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); 02158 get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); 02159 iwidth = get_length(wattr); 02160 iheight = get_length(hattr); 02161 02162 if (get_attr(attrs, "SRC", attr, sizeof(attr))) { 02163 img = get_image(attr, iwidth, iheight); 02164 iwidth = img->w(); 02165 iheight = img->h(); 02166 } 02167 02168 if (iwidth > minwidths[column]) 02169 minwidths[column] = iwidth; 02170 02171 width += iwidth; 02172 if (needspace) 02173 width += (int)fl_width(' '); 02174 02175 if (width > max_width) 02176 max_width = width; 02177 02178 needspace = 0; 02179 } 02180 } 02181 else if (*ptr == '\n' && pre) 02182 { 02183 width = 0; 02184 needspace = 0; 02185 ptr ++; 02186 } 02187 else if (isspace((*ptr)&255)) 02188 { 02189 needspace = 1; 02190 02191 ptr ++; 02192 } 02193 else if (*ptr == '&' && s < (buf + sizeof(buf) - 1)) 02194 { 02195 ptr ++; 02196 02197 int qch = quote_char(ptr); 02198 02199 if (qch < 0) 02200 *s++ = '&'; 02201 else { 02202 // int l; 02203 // l = fl_utf8encode((unsigned int) qch, s); 02204 // if (l < 1) l = 1; 02205 // s += l; 02206 *s++ = qch; 02207 ptr = strchr(ptr, ';') + 1; 02208 } 02209 } 02210 else 02211 { 02212 if (s < (buf + sizeof(buf) - 1)) 02213 *s++ = *ptr++; 02214 else 02215 ptr ++; 02216 } 02217 } 02218 02219 // Now that we have scanned the entire table, adjust the table and 02220 // cell widths to fit on the screen... 02221 if (get_attr(table + 6, "WIDTH", attr, sizeof(attr))) 02222 *table_width = get_length(attr); 02223 else 02224 *table_width = 0; 02225 02226 #ifdef DEBUG 02227 printf("num_columns = %d, table_width = %d\n", num_columns, *table_width); 02228 #endif // DEBUG 02229 02230 if (num_columns == 0) 02231 return; 02232 02233 // Add up the widths... 02234 for (column = 0, width = 0; column < num_columns; column ++) 02235 width += columns[column]; 02236 02237 #ifdef DEBUG 02238 printf("width = %d, w() = %d\n", width, w()); 02239 for (column = 0; column < num_columns; column ++) 02240 printf(" columns[%d] = %d, minwidths[%d] = %d\n", column, columns[column], 02241 column, minwidths[column]); 02242 #endif // DEBUG 02243 02244 // Adjust the width if needed... 02245 int scale_width = *table_width; 02246 02247 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 02248 if (scale_width == 0) { 02249 if (width > (hsize_ - scrollsize)) scale_width = hsize_ - scrollsize; 02250 else scale_width = width; 02251 } 02252 02253 if (width < scale_width) { 02254 #ifdef DEBUG 02255 printf("Scaling table up to %d from %d...\n", scale_width, width); 02256 #endif // DEBUG 02257 02258 *table_width = 0; 02259 02260 scale_width = (scale_width - width) / num_columns; 02261 02262 #ifdef DEBUG 02263 printf("adjusted scale_width = %d\n", scale_width); 02264 #endif // DEBUG 02265 02266 for (column = 0; column < num_columns; column ++) { 02267 columns[column] += scale_width; 02268 02269 (*table_width) += columns[column]; 02270 } 02271 } 02272 else if (width > scale_width) { 02273 #ifdef DEBUG 02274 printf("Scaling table down to %d from %d...\n", scale_width, width); 02275 #endif // DEBUG 02276 02277 for (column = 0; column < num_columns; column ++) { 02278 width -= minwidths[column]; 02279 scale_width -= minwidths[column]; 02280 } 02281 02282 #ifdef DEBUG 02283 printf("adjusted width = %d, scale_width = %d\n", width, scale_width); 02284 #endif // DEBUG 02285 02286 if (width > 0) { 02287 for (column = 0; column < num_columns; column ++) { 02288 columns[column] -= minwidths[column]; 02289 columns[column] = scale_width * columns[column] / width; 02290 columns[column] += minwidths[column]; 02291 } 02292 } 02293 02294 *table_width = 0; 02295 for (column = 0; column < num_columns; column ++) { 02296 (*table_width) += columns[column]; 02297 } 02298 } 02299 else if (*table_width == 0) 02300 *table_width = width; 02301 02302 #ifdef DEBUG 02303 printf("FINAL table_width = %d\n", *table_width); 02304 for (column = 0; column < num_columns; column ++) 02305 printf(" columns[%d] = %d\n", column, columns[column]); 02306 #endif // DEBUG 02307 } 02308 02309 02311 void 02312 Fl_Help_View::free_data() { 02313 // Release all images... 02314 if (value_) { 02315 const char *ptr, // Pointer into block 02316 *attrs; // Pointer to start of element attributes 02317 char *s, // Pointer into buffer 02318 buf[1024], // Text buffer 02319 attr[1024], // Attribute buffer 02320 wattr[1024], // Width attribute buffer 02321 hattr[1024]; // Height attribute buffer 02322 02323 for (ptr = value_; *ptr;) 02324 { 02325 if (*ptr == '<') 02326 { 02327 ptr ++; 02328 02329 if (strncmp(ptr, "!--", 3) == 0) 02330 { 02331 // Comment... 02332 ptr += 3; 02333 if ((ptr = strstr(ptr, "-->")) != NULL) 02334 { 02335 ptr += 3; 02336 continue; 02337 } 02338 else 02339 break; 02340 } 02341 02342 s = buf; 02343 02344 while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) 02345 if (s < (buf + sizeof(buf) - 1)) 02346 *s++ = *ptr++; 02347 else 02348 ptr ++; 02349 02350 *s = '\0'; 02351 02352 attrs = ptr; 02353 while (*ptr && *ptr != '>') 02354 ptr ++; 02355 02356 if (*ptr == '>') 02357 ptr ++; 02358 02359 if (strcasecmp(buf, "IMG") == 0) 02360 { 02361 Fl_Shared_Image *img; 02362 int width; 02363 int height; 02364 02365 get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); 02366 get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); 02367 width = get_length(wattr); 02368 height = get_length(hattr); 02369 02370 if (get_attr(attrs, "SRC", attr, sizeof(attr))) { 02371 // Get and release the image to free it from memory... 02372 img = get_image(attr, width, height); 02373 if ((void*)img != &broken_image) { 02374 img->release(); 02375 } 02376 } 02377 } 02378 } 02379 else 02380 ptr ++; 02381 } 02382 02383 free((void *)value_); 02384 value_ = 0; 02385 } 02386 02387 // Free all of the arrays... 02388 if (nblocks_) { 02389 free(blocks_); 02390 02391 ablocks_ = 0; 02392 nblocks_ = 0; 02393 blocks_ = 0; 02394 } 02395 02396 if (nlinks_) { 02397 free(links_); 02398 02399 alinks_ = 0; 02400 nlinks_ = 0; 02401 links_ = 0; 02402 } 02403 02404 if (ntargets_) { 02405 free(targets_); 02406 02407 atargets_ = 0; 02408 ntargets_ = 0; 02409 targets_ = 0; 02410 } 02411 } 02412 02414 int // O - Alignment 02415 Fl_Help_View::get_align(const char *p, // I - Pointer to start of attrs 02416 int a) // I - Default alignment 02417 { 02418 char buf[255]; // Alignment value 02419 02420 02421 if (get_attr(p, "ALIGN", buf, sizeof(buf)) == NULL) 02422 return (a); 02423 02424 if (strcasecmp(buf, "CENTER") == 0) 02425 return (CENTER); 02426 else if (strcasecmp(buf, "RIGHT") == 0) 02427 return (RIGHT); 02428 else 02429 return (LEFT); 02430 } 02431 02432 02434 const char * // O - Pointer to buf or NULL 02435 Fl_Help_View::get_attr(const char *p, // I - Pointer to start of attributes 02436 const char *n, // I - Name of attribute 02437 char *buf, // O - Buffer for attribute value 02438 int bufsize) // I - Size of buffer 02439 { 02440 char name[255], // Name from string 02441 *ptr, // Pointer into name or value 02442 quote; // Quote 02443 02444 02445 buf[0] = '\0'; 02446 02447 while (*p && *p != '>') 02448 { 02449 while (isspace((*p)&255)) 02450 p ++; 02451 02452 if (*p == '>' || !*p) 02453 return (NULL); 02454 02455 for (ptr = name; *p && !isspace((*p)&255) && *p != '=' && *p != '>';) 02456 if (ptr < (name + sizeof(name) - 1)) 02457 *ptr++ = *p++; 02458 else 02459 p ++; 02460 02461 *ptr = '\0'; 02462 02463 if (isspace((*p)&255) || !*p || *p == '>') 02464 buf[0] = '\0'; 02465 else 02466 { 02467 if (*p == '=') 02468 p ++; 02469 02470 for (ptr = buf; *p && !isspace((*p)&255) && *p != '>';) 02471 if (*p == '\'' || *p == '\"') 02472 { 02473 quote = *p++; 02474 02475 while (*p && *p != quote) 02476 if ((ptr - buf + 1) < bufsize) 02477 *ptr++ = *p++; 02478 else 02479 p ++; 02480 02481 if (*p == quote) 02482 p ++; 02483 } 02484 else if ((ptr - buf + 1) < bufsize) 02485 *ptr++ = *p++; 02486 else 02487 p ++; 02488 02489 *ptr = '\0'; 02490 } 02491 02492 if (strcasecmp(n, name) == 0) 02493 return (buf); 02494 else 02495 buf[0] = '\0'; 02496 02497 if (*p == '>') 02498 return (NULL); 02499 } 02500 02501 return (NULL); 02502 } 02503 02504 02506 Fl_Color // O - Color value 02507 Fl_Help_View::get_color(const char *n, // I - Color name 02508 Fl_Color c) // I - Default color value 02509 { 02510 int i; // Looping var 02511 int rgb, r, g, b; // RGB values 02512 static const struct { // Color name table 02513 const char *name; 02514 int r, g, b; 02515 } colors[] = { 02516 { "black", 0x00, 0x00, 0x00 }, 02517 { "red", 0xff, 0x00, 0x00 }, 02518 { "green", 0x00, 0x80, 0x00 }, 02519 { "yellow", 0xff, 0xff, 0x00 }, 02520 { "blue", 0x00, 0x00, 0xff }, 02521 { "magenta", 0xff, 0x00, 0xff }, 02522 { "fuchsia", 0xff, 0x00, 0xff }, 02523 { "cyan", 0x00, 0xff, 0xff }, 02524 { "aqua", 0x00, 0xff, 0xff }, 02525 { "white", 0xff, 0xff, 0xff }, 02526 { "gray", 0x80, 0x80, 0x80 }, 02527 { "grey", 0x80, 0x80, 0x80 }, 02528 { "lime", 0x00, 0xff, 0x00 }, 02529 { "maroon", 0x80, 0x00, 0x00 }, 02530 { "navy", 0x00, 0x00, 0x80 }, 02531 { "olive", 0x80, 0x80, 0x00 }, 02532 { "purple", 0x80, 0x00, 0x80 }, 02533 { "silver", 0xc0, 0xc0, 0xc0 }, 02534 { "teal", 0x00, 0x80, 0x80 } 02535 }; 02536 02537 02538 if (!n || !n[0]) return c; 02539 02540 if (n[0] == '#') { 02541 // Do hex color lookup 02542 rgb = strtol(n + 1, NULL, 16); 02543 02544 if (strlen(n) > 4) { 02545 r = rgb >> 16; 02546 g = (rgb >> 8) & 255; 02547 b = rgb & 255; 02548 } else { 02549 r = (rgb >> 8) * 17; 02550 g = ((rgb >> 4) & 15) * 17; 02551 b = (rgb & 15) * 17; 02552 } 02553 return (fl_rgb_color((uchar)r, (uchar)g, (uchar)b)); 02554 } else { 02555 for (i = 0; i < (int)(sizeof(colors) / sizeof(colors[0])); i ++) 02556 if (!strcasecmp(n, colors[i].name)) { 02557 return fl_rgb_color(colors[i].r, colors[i].g, colors[i].b); 02558 } 02559 return c; 02560 } 02561 } 02562 02563 02577 /* Implementation note: (A.S. Apr 05, 2009) 02578 02579 Fl_Help_View::get_image() uses a static global flag (initial_load) 02580 to determine, if it is called from the initial loading of a document 02581 (load() or value()), or from resize() or draw(). 02582 02583 A better solution would be to manage all loaded images in an own 02584 structure like Fl_Help_Target (Fl_Help_Image ?) to avoid using this 02585 global flag, but this would break the ABI ! 02586 02587 This should be fixed in FLTK 1.3 ! 02588 02589 02590 If initial_load is true, then Fl_Shared_Image::get() is called to 02591 load the image, and the reference count of the shared image is 02592 increased by one. 02593 02594 If initial_load is false, then Fl_Shared_Image::find() is called to 02595 load the image, and the image is released immediately. This avoids 02596 increasing the reference count when calling get_image() from draw() 02597 or resize(). 02598 02599 Calling Fl_Shared_Image::find() instead of Fl_Shared_Image::get() avoids 02600 doing unnecessary i/o for "broken images" within each resize/redraw. 02601 02602 Each image must be released exactly once in the destructor or before 02603 a new document is loaded: see free_data(). 02604 */ 02605 02606 Fl_Shared_Image * 02607 Fl_Help_View::get_image(const char *name, int W, int H) { 02608 const char *localname; // Local filename 02609 char dir[FL_PATH_MAX]; // Current directory 02610 char temp[FL_PATH_MAX], // Temporary filename 02611 *tempptr; // Pointer into temporary name 02612 Fl_Shared_Image *ip; // Image pointer... 02613 02614 // See if the image can be found... 02615 if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL) { 02616 if (name[0] == '/') { 02617 strlcpy(temp, directory_, sizeof(temp)); 02618 02619 if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) { 02620 strlcpy(tempptr, name, sizeof(temp) - (tempptr - temp)); 02621 } else { 02622 strlcat(temp, name, sizeof(temp)); 02623 } 02624 } else { 02625 snprintf(temp, sizeof(temp), "%s/%s", directory_, name); 02626 } 02627 02628 if (link_) localname = (*link_)(this, temp); 02629 else localname = temp; 02630 } else if (name[0] != '/' && strchr(name, ':') == NULL) { 02631 if (directory_[0]) snprintf(temp, sizeof(temp), "%s/%s", directory_, name); 02632 else { 02633 fl_getcwd(dir, sizeof(dir)); 02634 snprintf(temp, sizeof(temp), "file:%s/%s", dir, name); 02635 } 02636 02637 if (link_) localname = (*link_)(this, temp); 02638 else localname = temp; 02639 } else if (link_) localname = (*link_)(this, name); 02640 else localname = name; 02641 02642 if (!localname) return 0; 02643 02644 if (strncmp(localname, "file:", 5) == 0) localname += 5; 02645 02646 if (initial_load) { 02647 if ((ip = Fl_Shared_Image::get(localname, W, H)) == NULL) { 02648 ip = (Fl_Shared_Image *)&broken_image; 02649 } 02650 } else { // draw or resize 02651 if ((ip = Fl_Shared_Image::find(localname, W, H)) == NULL) { 02652 ip = (Fl_Shared_Image *)&broken_image; 02653 } else { 02654 ip->release(); 02655 } 02656 } 02657 02658 return ip; 02659 } 02660 02661 02663 int 02664 Fl_Help_View::get_length(const char *l) { // I - Value 02665 int val; // Integer value 02666 02667 if (!l[0]) return 0; 02668 02669 val = atoi(l); 02670 if (l[strlen(l) - 1] == '%') { 02671 if (val > 100) val = 100; 02672 else if (val < 0) val = 0; 02673 02674 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 02675 val = val * (hsize_ - scrollsize) / 100; 02676 } 02677 02678 return val; 02679 } 02680 02681 02682 Fl_Help_Link *Fl_Help_View::find_link(int xx, int yy) 02683 { 02684 int i; 02685 Fl_Help_Link *linkp; 02686 for (i = nlinks_, linkp = links_; i > 0; i --, linkp ++) { 02687 if (xx >= linkp->x && xx < linkp->w && 02688 yy >= linkp->y && yy < linkp->h) 02689 break; 02690 } 02691 return i ? linkp : 0L; 02692 } 02693 02694 void Fl_Help_View::follow_link(Fl_Help_Link *linkp) 02695 { 02696 char target[32]; // Current target 02697 02698 clear_selection(); 02699 02700 strlcpy(target, linkp->name, sizeof(target)); 02701 02702 set_changed(); 02703 02704 if (strcmp(linkp->filename, filename_) != 0 && linkp->filename[0]) 02705 { 02706 char dir[FL_PATH_MAX]; // Current directory 02707 char temp[FL_PATH_MAX], // Temporary filename 02708 *tempptr; // Pointer into temporary filename 02709 02710 02711 if (strchr(directory_, ':') != NULL && 02712 strchr(linkp->filename, ':') == NULL) 02713 { 02714 if (linkp->filename[0] == '/') 02715 { 02716 strlcpy(temp, directory_, sizeof(temp)); 02717 if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) 02718 strlcpy(tempptr, linkp->filename, sizeof(temp)); 02719 else 02720 strlcat(temp, linkp->filename, sizeof(temp)); 02721 } 02722 else 02723 snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename); 02724 } 02725 else if (linkp->filename[0] != '/' && strchr(linkp->filename, ':') == NULL) 02726 { 02727 if (directory_[0]) 02728 snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename); 02729 else 02730 { 02731 fl_getcwd(dir, sizeof(dir)); 02732 snprintf(temp, sizeof(temp), "file:%s/%s", dir, linkp->filename); 02733 } 02734 } 02735 else 02736 strlcpy(temp, linkp->filename, sizeof(temp)); 02737 02738 if (linkp->name[0]) 02739 snprintf(temp + strlen(temp), sizeof(temp) - strlen(temp), "#%s", 02740 linkp->name); 02741 02742 load(temp); 02743 } 02744 else if (target[0]) 02745 topline(target); 02746 else 02747 topline(0); 02748 02749 leftline(0); 02750 } 02751 02753 void Fl_Help_View::clear_selection() 02754 { 02755 if (current_view==this) 02756 clear_global_selection(); 02757 } 02759 void Fl_Help_View::select_all() 02760 { 02761 clear_global_selection(); 02762 if (!value_) return; 02763 current_view = this; 02764 selection_drag_last = selection_last = strlen(value_); 02765 selected = 1; 02766 } 02767 02768 void Fl_Help_View::clear_global_selection() 02769 { 02770 if (selected) redraw(); 02771 selection_push_first = selection_push_last = 0; 02772 selection_drag_first = selection_drag_last = 0; 02773 selection_first = selection_last = 0; 02774 selected = 0; 02775 } 02776 02777 char Fl_Help_View::begin_selection() 02778 { 02779 clear_global_selection(); 02780 02781 if (!fl_help_view_buffer) fl_help_view_buffer = fl_create_offscreen(1, 1); 02782 02783 mouse_x = Fl::event_x(); 02784 mouse_y = Fl::event_y(); 02785 draw_mode = 1; 02786 02787 current_view = this; 02788 fl_begin_offscreen(fl_help_view_buffer); 02789 draw(); 02790 fl_end_offscreen(); 02791 02792 draw_mode = 0; 02793 02794 if (selection_push_last) return 1; 02795 else return 0; 02796 } 02797 02798 char Fl_Help_View::extend_selection() 02799 { 02800 if (Fl::event_is_click()) 02801 return 0; 02802 02803 // printf("old selection_first=%d, selection_last=%d\n", 02804 // selection_first, selection_last); 02805 02806 int sf = selection_first, sl = selection_last; 02807 02808 selected = 1; 02809 mouse_x = Fl::event_x(); 02810 mouse_y = Fl::event_y(); 02811 draw_mode = 2; 02812 02813 fl_begin_offscreen(fl_help_view_buffer); 02814 draw(); 02815 fl_end_offscreen(); 02816 02817 draw_mode = 0; 02818 02819 if (selection_push_first < selection_drag_first) { 02820 selection_first = selection_push_first; 02821 } else { 02822 selection_first = selection_drag_first; 02823 } 02824 02825 if (selection_push_last > selection_drag_last) { 02826 selection_last = selection_push_last; 02827 } else { 02828 selection_last = selection_drag_last; 02829 } 02830 02831 // printf("new selection_first=%d, selection_last=%d\n", 02832 // selection_first, selection_last); 02833 02834 if (sf!=selection_first || sl!=selection_last) { 02835 // puts("REDRAW!!!\n"); 02836 return 1; 02837 } else { 02838 // puts(""); 02839 return 0; 02840 } 02841 } 02842 02843 // convert a command with up to four letters into an unsigned int 02844 static unsigned int command(const char *cmd) 02845 { 02846 unsigned int ret = (tolower(cmd[0])<<24); 02847 char c = cmd[1]; 02848 if (c=='>' || c==' ' || c==0) return ret; 02849 ret |= (tolower(c)<<16); 02850 c = cmd[2]; 02851 if (c=='>' || c==' ' || c==0) return ret; 02852 ret |= (tolower(c)<<8); 02853 c = cmd[3]; 02854 if (c=='>' || c==' ' || c==0) return ret; 02855 ret |= tolower(c); 02856 c = cmd[4]; 02857 if (c=='>' || c==' ' || c==0) return ret; 02858 return 0; 02859 } 02860 02861 #define CMD(a, b, c, d) ((a<<24)|(b<<16)|(c<<8)|d) 02862 02863 void Fl_Help_View::end_selection(int clipboard) 02864 { 02865 if (!selected || current_view!=this) 02866 return; 02867 // convert the select part of our html text into some kind of somewhat readable ASCII 02868 // and store it in the selection buffer 02869 char p = 0, pre = 0;; 02870 int len = strlen(value_); 02871 char *txt = (char*)malloc(len+1), *d = txt; 02872 const char *s = value_, *cmd, *src; 02873 for (;;) { 02874 char c = *s++; 02875 if (c==0) break; 02876 if (c=='<') { // begin of some html command. Skip until we find a '>' 02877 cmd = s; 02878 for (;;) { 02879 c = *s++; 02880 if (c==0 || c=='>') break; 02881 } 02882 if (c==0) break; 02883 // do something with this command... . 02884 // the replacement string must not be longer that the command itself plus '<' and '>' 02885 src = 0; 02886 switch (command(cmd)) { 02887 case CMD('p','r','e', 0 ): pre = 1; break; 02888 case CMD('/','p','r','e'): pre = 0; break; 02889 case CMD('t','d', 0 , 0 ): 02890 case CMD('p', 0 , 0 , 0 ): 02891 case CMD('/','p', 0 , 0 ): 02892 case CMD('b','r', 0 , 0 ): src = "\n"; break; 02893 case CMD('l','i', 0 , 0 ): src = "\n * "; break; 02894 case CMD('/','h','1', 0 ): 02895 case CMD('/','h','2', 0 ): 02896 case CMD('/','h','3', 0 ): 02897 case CMD('/','h','4', 0 ): 02898 case CMD('/','h','5', 0 ): 02899 case CMD('/','h','6', 0 ): src = "\n\n"; break; 02900 case CMD('t','r', 0 , 0 ): 02901 case CMD('h','1', 0 , 0 ): 02902 case CMD('h','2', 0 , 0 ): 02903 case CMD('h','3', 0 , 0 ): 02904 case CMD('h','4', 0 , 0 ): 02905 case CMD('h','5', 0 , 0 ): 02906 case CMD('h','6', 0 , 0 ): src = "\n\n"; break; 02907 case CMD('d','t', 0 , 0 ): src = "\n "; break; 02908 case CMD('d','d', 0 , 0 ): src = "\n - "; break; 02909 } 02910 int n = s-value_; 02911 if (src && n>selection_first && n<=selection_last) { 02912 while (*src) { 02913 *d++ = *src++; 02914 } 02915 c = src[-1]; 02916 p = isspace(c&255) ? ' ' : c; 02917 } 02918 continue; 02919 } 02920 if (c=='&') { // special characters 02921 int xx = quote_char(s); 02922 if (xx>=0) { 02923 c = (char)xx; 02924 for (;;) { 02925 char cc = *s++; 02926 if (!cc || cc==';') break; 02927 } 02928 } 02929 } 02930 int n = s-value_; 02931 if (n>selection_first && n<=selection_last) { 02932 if (!pre && isspace(c&255)) c = ' '; 02933 if (p!=' '||c!=' ') 02934 *d++ = c; 02935 p = c; 02936 } 02937 } 02938 *d = 0; 02939 Fl::copy(txt, strlen(txt), clipboard); 02940 free(txt); 02941 } 02942 02943 #define ctrl(x) ((x)&0x1f) 02944 02946 int // O - 1 if we handled it, 0 otherwise 02947 Fl_Help_View::handle(int event) // I - Event to handle 02948 { 02949 static Fl_Help_Link *linkp; // currently clicked link 02950 02951 int xx = Fl::event_x() - x() + leftline_; 02952 int yy = Fl::event_y() - y() + topline_; 02953 02954 switch (event) 02955 { 02956 case FL_FOCUS: 02957 redraw(); 02958 return 1; 02959 case FL_UNFOCUS: 02960 clear_selection(); 02961 redraw(); 02962 return 1; 02963 case FL_ENTER : 02964 Fl_Group::handle(event); 02965 return 1; 02966 case FL_LEAVE : 02967 fl_cursor(FL_CURSOR_DEFAULT); 02968 break; 02969 case FL_MOVE: 02970 if (find_link(xx, yy)) fl_cursor(FL_CURSOR_HAND); 02971 else fl_cursor(FL_CURSOR_DEFAULT); 02972 return 1; 02973 case FL_PUSH: 02974 if (Fl_Group::handle(event)) return 1; 02975 linkp = find_link(xx, yy); 02976 if (linkp) { 02977 fl_cursor(FL_CURSOR_HAND); 02978 return 1; 02979 } 02980 if (begin_selection()) { 02981 fl_cursor(FL_CURSOR_INSERT); 02982 return 1; 02983 } 02984 fl_cursor(FL_CURSOR_DEFAULT); 02985 return 1; 02986 case FL_DRAG: 02987 if (linkp) { 02988 if (Fl::event_is_click()) { 02989 fl_cursor(FL_CURSOR_HAND); 02990 } else { 02991 fl_cursor(FL_CURSOR_DEFAULT); // should be "FL_CURSOR_CANCEL" if we had it 02992 } 02993 return 1; 02994 } 02995 if (current_view==this && selection_push_last) { 02996 if (extend_selection()) redraw(); 02997 fl_cursor(FL_CURSOR_INSERT); 02998 return 1; 02999 } 03000 fl_cursor(FL_CURSOR_DEFAULT); 03001 return 1; 03002 case FL_RELEASE: 03003 if (linkp) { 03004 if (Fl::event_is_click()) { 03005 follow_link(linkp); 03006 } 03007 fl_cursor(FL_CURSOR_DEFAULT); 03008 linkp = 0; 03009 return 1; 03010 } 03011 if (current_view==this && selection_push_last) { 03012 end_selection(); 03013 return 1; 03014 } 03015 return 1; 03016 case FL_SHORTCUT: { 03017 char ascii = Fl::event_text()[0]; 03018 switch (ascii) { 03019 case ctrl('A'): select_all(); redraw(); return 1; 03020 case ctrl('C'): 03021 case ctrl('X'): end_selection(1); return 1; 03022 } 03023 break; } 03024 } 03025 return (Fl_Group::handle(event)); 03026 } 03027 03032 Fl_Help_View::Fl_Help_View(int xx, // I - Left position 03033 int yy, // I - Top position 03034 int ww, // I - Width in pixels 03035 int hh, // I - Height in pixels 03036 const char *l) 03037 : Fl_Group(xx, yy, ww, hh, l), 03038 scrollbar_(xx + ww - Fl::scrollbar_size(), yy, 03039 Fl::scrollbar_size(), hh - Fl::scrollbar_size()), 03040 hscrollbar_(xx, yy + hh - Fl::scrollbar_size(), 03041 ww - Fl::scrollbar_size(), Fl::scrollbar_size()) 03042 { 03043 color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); 03044 03045 title_[0] = '\0'; 03046 defcolor_ = FL_FOREGROUND_COLOR; 03047 bgcolor_ = FL_BACKGROUND_COLOR; 03048 textcolor_ = FL_FOREGROUND_COLOR; 03049 linkcolor_ = FL_SELECTION_COLOR; 03050 textfont_ = FL_TIMES; 03051 textsize_ = 12; 03052 value_ = NULL; 03053 03054 ablocks_ = 0; 03055 nblocks_ = 0; 03056 blocks_ = (Fl_Help_Block *)0; 03057 03058 link_ = (Fl_Help_Func *)0; 03059 03060 alinks_ = 0; 03061 nlinks_ = 0; 03062 links_ = (Fl_Help_Link *)0; 03063 03064 atargets_ = 0; 03065 ntargets_ = 0; 03066 targets_ = (Fl_Help_Target *)0; 03067 03068 directory_[0] = '\0'; 03069 filename_[0] = '\0'; 03070 03071 topline_ = 0; 03072 leftline_ = 0; 03073 size_ = 0; 03074 hsize_ = 0; 03075 scrollbar_size_ = 0; 03076 03077 scrollbar_.value(0, hh, 0, 1); 03078 scrollbar_.step(8.0); 03079 scrollbar_.show(); 03080 scrollbar_.callback(scrollbar_callback); 03081 03082 hscrollbar_.value(0, ww, 0, 1); 03083 hscrollbar_.step(8.0); 03084 hscrollbar_.show(); 03085 hscrollbar_.callback(hscrollbar_callback); 03086 hscrollbar_.type(FL_HORIZONTAL); 03087 end(); 03088 03089 resize(xx, yy, ww, hh); 03090 } 03091 03092 03098 Fl_Help_View::~Fl_Help_View() 03099 { 03100 clear_selection(); 03101 free_data(); 03102 } 03103 03104 03109 int // O - 0 on success, -1 on error 03110 Fl_Help_View::load(const char *f)// I - Filename to load (may also have target) 03111 { 03112 FILE *fp; // File to read from 03113 long len; // Length of file 03114 char *target; // Target in file 03115 char *slash; // Directory separator 03116 const char *localname; // Local filename 03117 char error[1024]; // Error buffer 03118 char newname[FL_PATH_MAX]; // New filename buffer 03119 03120 // printf("load(%s)\n",f); fflush(stdout); 03121 03122 if (strncmp(f, "ftp:", 4) == 0 || 03123 strncmp(f, "http:", 5) == 0 || 03124 strncmp(f, "https:", 6) == 0 || 03125 strncmp(f, "ipp:", 4) == 0 || 03126 strncmp(f, "mailto:", 7) == 0 || 03127 strncmp(f, "news:", 5) == 0) { 03128 char urimsg[FL_PATH_MAX]; 03129 if ( fl_open_uri(f, urimsg, sizeof(urimsg)) == 0 ) { 03130 clear_selection(); 03131 03132 strlcpy(newname, f, sizeof(newname)); 03133 if ((target = strrchr(newname, '#')) != NULL) 03134 *target++ = '\0'; 03135 03136 if (link_) 03137 localname = (*link_)(this, newname); 03138 else 03139 localname = filename_; 03140 03141 if (!localname) 03142 return (0); 03143 03144 free_data(); 03145 03146 strlcpy(filename_, newname, sizeof(filename_)); 03147 strlcpy(directory_, newname, sizeof(directory_)); 03148 03149 // Note: We do not support Windows backslashes, since they are illegal 03150 // in URLs... 03151 if ((slash = strrchr(directory_, '/')) == NULL) 03152 directory_[0] = '\0'; 03153 else if (slash > directory_ && slash[-1] != '/') 03154 *slash = '\0'; 03155 03156 snprintf(error, sizeof(error), 03157 "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" 03158 "<BODY><H1>Error</H1>" 03159 "<P>Unable to follow the link \"%s\" - " 03160 "%s.</P></BODY>", 03161 f, urimsg); 03162 value(error); 03163 //return(-1); 03164 } 03165 return(0); 03166 } 03167 03168 clear_selection(); 03169 03170 strlcpy(newname, f, sizeof(newname)); 03171 if ((target = strrchr(newname, '#')) != NULL) 03172 *target++ = '\0'; 03173 03174 if (link_) 03175 localname = (*link_)(this, newname); 03176 else 03177 localname = filename_; 03178 03179 if (!localname) 03180 return (0); 03181 03182 free_data(); 03183 03184 strlcpy(filename_, newname, sizeof(filename_)); 03185 strlcpy(directory_, newname, sizeof(directory_)); 03186 03187 // Note: We do not support Windows backslashes, since they are illegal 03188 // in URLs... 03189 if ((slash = strrchr(directory_, '/')) == NULL) 03190 directory_[0] = '\0'; 03191 else if (slash > directory_ && slash[-1] != '/') 03192 *slash = '\0'; 03193 03194 if (strncmp(localname, "file:", 5) == 0) 03195 localname += 5; // Adjust for local filename... 03196 03197 if ((fp = fl_fopen(localname, "rb")) != NULL) 03198 { 03199 fseek(fp, 0, SEEK_END); 03200 len = ftell(fp); 03201 rewind(fp); 03202 03203 value_ = (const char *)calloc(len + 1, 1); 03204 if (fread((void *)value_, 1, len, fp)==0) { /* use default 0 */ } 03205 fclose(fp); 03206 } 03207 else 03208 { 03209 snprintf(error, sizeof(error), 03210 "<HTML><HEAD><TITLE>Error</TITLE></HEAD>" 03211 "<BODY><H1>Error</H1>" 03212 "<P>Unable to follow the link \"%s\" - " 03213 "%s.</P></BODY>", 03214 localname, strerror(errno)); 03215 value_ = strdup(error); 03216 } 03217 03218 initial_load = 1; 03219 format(); 03220 initial_load = 0; 03221 03222 if (target) 03223 topline(target); 03224 else 03225 topline(0); 03226 03227 return (0); 03228 } 03229 03230 03233 void 03234 Fl_Help_View::resize(int xx, // I - New left position 03235 int yy, // I - New top position 03236 int ww, // I - New width 03237 int hh) // I - New height 03238 { 03239 Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; 03240 // Box to draw... 03241 03242 03243 Fl_Widget::resize(xx, yy, ww, hh); 03244 03245 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 03246 scrollbar_.resize(x() + w() - scrollsize - Fl::box_dw(b) + Fl::box_dx(b), 03247 y() + Fl::box_dy(b), scrollsize, h() - scrollsize - Fl::box_dh(b)); 03248 hscrollbar_.resize(x() + Fl::box_dx(b), 03249 y() + h() - scrollsize - Fl::box_dh(b) + Fl::box_dy(b), 03250 w() - scrollsize - Fl::box_dw(b), scrollsize); 03251 03252 format(); 03253 } 03254 03255 03260 void 03261 Fl_Help_View::topline(const char *n) // I - Target name 03262 { 03263 Fl_Help_Target key, // Target name key 03264 *target; // Pointer to matching target 03265 03266 03267 if (ntargets_ == 0) 03268 return; 03269 03270 strlcpy(key.name, n, sizeof(key.name)); 03271 03272 target = (Fl_Help_Target *)bsearch(&key, targets_, ntargets_, sizeof(Fl_Help_Target), 03273 (compare_func_t)compare_targets); 03274 03275 if (target != NULL) 03276 topline(target->y); 03277 } 03278 03279 03287 void 03288 Fl_Help_View::topline(int top) // I - Top line number 03289 { 03290 if (!value_) 03291 return; 03292 03293 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 03294 if (size_ < (h() - scrollsize) || top < 0) 03295 top = 0; 03296 else if (top > size_) 03297 top = size_; 03298 03299 topline_ = top; 03300 03301 scrollbar_.value(topline_, h() - scrollsize, 0, size_); 03302 03303 do_callback(); 03304 03305 redraw(); 03306 } 03307 03308 03316 void 03317 Fl_Help_View::leftline(int left) // I - Left position 03318 { 03319 if (!value_) 03320 return; 03321 03322 int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 03323 if (hsize_ < (w() - scrollsize) || left < 0) 03324 left = 0; 03325 else if (left > hsize_) 03326 left = hsize_; 03327 03328 leftline_ = left; 03329 03330 hscrollbar_.value(leftline_, w() - scrollsize, 0, hsize_); 03331 03332 redraw(); 03333 } 03334 03335 03343 void 03344 Fl_Help_View::value(const char *val) // I - Text to view 03345 { 03346 clear_selection(); 03347 free_data(); 03348 set_changed(); 03349 03350 if (!val) 03351 return; 03352 03353 value_ = strdup(val); 03354 03355 initial_load = 1; 03356 format(); 03357 initial_load = 0; 03358 03359 topline(0); 03360 leftline(0); 03361 } 03362 03363 03364 #ifdef ENC 03365 # undef ENC 03366 #endif 03367 // part b in the table seems to be mac_roman - beku 03368 # define ENC(a, b) a 03369 03370 03372 static int // O - Code or -1 on error 03373 quote_char(const char *p) { // I - Quoted string 03374 int i; // Looping var 03375 static struct { 03376 const char *name; 03377 int namelen; 03378 int code; 03379 } *nameptr, // Pointer into name array 03380 names[] = { // Quoting names 03381 { "Aacute;", 7, ENC(193,231) }, 03382 { "aacute;", 7, ENC(225,135) }, 03383 { "Acirc;", 6, ENC(194,229) }, 03384 { "acirc;", 6, ENC(226,137) }, 03385 { "acute;", 6, ENC(180,171) }, 03386 { "AElig;", 6, ENC(198,174) }, 03387 { "aelig;", 6, ENC(230,190) }, 03388 { "Agrave;", 7, ENC(192,203) }, 03389 { "agrave;", 7, ENC(224,136) }, 03390 { "amp;", 4, ENC('&','&') }, 03391 { "Aring;", 6, ENC(197,129) }, 03392 { "aring;", 6, ENC(229,140) }, 03393 { "Atilde;", 7, ENC(195,204) }, 03394 { "atilde;", 7, ENC(227,139) }, 03395 { "Auml;", 5, ENC(196,128) }, 03396 { "auml;", 5, ENC(228,138) }, 03397 { "brvbar;", 7, ENC(166, -1) }, 03398 { "bull;", 5, ENC(149,165) }, 03399 { "Ccedil;", 7, ENC(199,199) }, 03400 { "ccedil;", 7, ENC(231,141) }, 03401 { "cedil;", 6, ENC(184,252) }, 03402 { "cent;", 5, ENC(162,162) }, 03403 { "copy;", 5, ENC(169,169) }, 03404 { "curren;", 7, ENC(164, -1) }, 03405 { "deg;", 4, ENC(176,161) }, 03406 { "divide;", 7, ENC(247,214) }, 03407 { "Eacute;", 7, ENC(201,131) }, 03408 { "eacute;", 7, ENC(233,142) }, 03409 { "Ecirc;", 6, ENC(202,230) }, 03410 { "ecirc;", 6, ENC(234,144) }, 03411 { "Egrave;", 7, ENC(200,233) }, 03412 { "egrave;", 7, ENC(232,143) }, 03413 { "ETH;", 4, ENC(208, -1) }, 03414 { "eth;", 4, ENC(240, -1) }, 03415 { "Euml;", 5, ENC(203,232) }, 03416 { "euml;", 5, ENC(235,145) }, 03417 { "euro;", 5, ENC(128,219) }, 03418 { "frac12;", 7, ENC(189, -1) }, 03419 { "frac14;", 7, ENC(188, -1) }, 03420 { "frac34;", 7, ENC(190, -1) }, 03421 { "gt;", 3, ENC('>','>') }, 03422 { "Iacute;", 7, ENC(205,234) }, 03423 { "iacute;", 7, ENC(237,146) }, 03424 { "Icirc;", 6, ENC(206,235) }, 03425 { "icirc;", 6, ENC(238,148) }, 03426 { "iexcl;", 6, ENC(161,193) }, 03427 { "Igrave;", 7, ENC(204,237) }, 03428 { "igrave;", 7, ENC(236,147) }, 03429 { "iquest;", 7, ENC(191,192) }, 03430 { "Iuml;", 5, ENC(207,236) }, 03431 { "iuml;", 5, ENC(239,149) }, 03432 { "laquo;", 6, ENC(171,199) }, 03433 { "lt;", 3, ENC('<','<') }, 03434 { "macr;", 5, ENC(175,248) }, 03435 { "micro;", 6, ENC(181,181) }, 03436 { "middot;", 7, ENC(183,225) }, 03437 { "nbsp;", 5, ENC(' ',' ') }, 03438 { "not;", 4, ENC(172,194) }, 03439 { "Ntilde;", 7, ENC(209,132) }, 03440 { "ntilde;", 7, ENC(241,150) }, 03441 { "Oacute;", 7, ENC(211,238) }, 03442 { "oacute;", 7, ENC(243,151) }, 03443 { "Ocirc;", 6, ENC(212,239) }, 03444 { "ocirc;", 6, ENC(244,153) }, 03445 { "Ograve;", 7, ENC(210,241) }, 03446 { "ograve;", 7, ENC(242,152) }, 03447 { "ordf;", 5, ENC(170,187) }, 03448 { "ordm;", 5, ENC(186,188) }, 03449 { "Oslash;", 7, ENC(216,175) }, 03450 { "oslash;", 7, ENC(248,191) }, 03451 { "Otilde;", 7, ENC(213,205) }, 03452 { "otilde;", 7, ENC(245,155) }, 03453 { "Ouml;", 5, ENC(214,133) }, 03454 { "ouml;", 5, ENC(246,154) }, 03455 { "para;", 5, ENC(182,166) }, 03456 { "premil;", 7, ENC(137,228) }, 03457 { "plusmn;", 7, ENC(177,177) }, 03458 { "pound;", 6, ENC(163,163) }, 03459 { "quot;", 5, ENC('\"','\"') }, 03460 { "raquo;", 6, ENC(187,200) }, 03461 { "reg;", 4, ENC(174,168) }, 03462 { "sect;", 5, ENC(167,164) }, 03463 { "shy;", 4, ENC(173,'-') }, 03464 { "sup1;", 5, ENC(185, -1) }, 03465 { "sup2;", 5, ENC(178, -1) }, 03466 { "sup3;", 5, ENC(179, -1) }, 03467 { "szlig;", 6, ENC(223,167) }, 03468 { "THORN;", 6, ENC(222, -1) }, 03469 { "thorn;", 6, ENC(254, -1) }, 03470 { "times;", 6, ENC(215,'x') }, 03471 { "trade;", 6, ENC(153,170) }, 03472 { "Uacute;", 7, ENC(218,242) }, 03473 { "uacute;", 7, ENC(250,156) }, 03474 { "Ucirc;", 6, ENC(219,243) }, 03475 { "ucirc;", 6, ENC(251,158) }, 03476 { "Ugrave;", 7, ENC(217,244) }, 03477 { "ugrave;", 7, ENC(249,157) }, 03478 { "uml;", 4, ENC(168,172) }, 03479 { "Uuml;", 5, ENC(220,134) }, 03480 { "uuml;", 5, ENC(252,159) }, 03481 { "Yacute;", 7, ENC(221, -1) }, 03482 { "yacute;", 7, ENC(253, -1) }, 03483 { "yen;", 4, ENC(165,180) }, 03484 { "Yuml;", 5, ENC(159,217) }, 03485 { "yuml;", 5, ENC(255,216) } 03486 }; 03487 03488 if (!strchr(p, ';')) return -1; 03489 if (*p == '#') { 03490 if (*(p+1) == 'x' || *(p+1) == 'X') return strtol(p+2, NULL, 16); 03491 else return atoi(p+1); 03492 } 03493 for (i = (int)(sizeof(names) / sizeof(names[0])), nameptr = names; i > 0; i --, nameptr ++) 03494 if (strncmp(p, nameptr->name, nameptr->namelen) == 0) 03495 return nameptr->code; 03496 03497 return -1; 03498 } 03499 03500 03502 static void 03503 scrollbar_callback(Fl_Widget *s, void *) 03504 { 03505 ((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value())); 03506 } 03507 03508 03510 static void 03511 hscrollbar_callback(Fl_Widget *s, void *) 03512 { 03513 ((Fl_Help_View *)(s->parent()))->leftline(int(((Fl_Scrollbar*)s)->value())); 03514 } 03515 03516 03517 // 03518 // End of "$Id: Fl_Help_View.cxx 8063 2010-12-19 21:20:10Z matt $". 03519 //