2 // "$Id: Fl_Help_View.cxx 8063 2010-12-19 21:20:10Z matt $"
4 // Fl_Help_View widget routines.
6 // Copyright 1997-2010 by Easy Software Products.
7 // Image support by Matthias Melcher, Copyright 2000-2009.
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Library General Public License for more details.
19 // You should have received a copy of the GNU Library General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 // Please report all bugs and problems on the following page:
26 // http://www.fltk.org/str.php
30 // Fl_Help_View::add_block() - Add a text block to the list.
31 // Fl_Help_View::add_link() - Add a new link to the list.
32 // Fl_Help_View::add_target() - Add a new target to the list.
33 // Fl_Help_View::compare_targets() - Compare two targets.
34 // Fl_Help_View::do_align() - Compute the alignment for a line in
36 // Fl_Help_View::draw() - Draw the Fl_Help_View widget.
37 // Fl_Help_View::format() - Format the help text.
38 // Fl_Help_View::format_table() - Format a table...
39 // Fl_Help_View::free_data() - Free memory used for the document.
40 // Fl_Help_View::get_align() - Get an alignment attribute.
41 // Fl_Help_View::get_attr() - Get an attribute value from the string.
42 // Fl_Help_View::get_color() - Get an alignment attribute.
43 // Fl_Help_View::handle() - Handle events in the widget.
44 // Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget.
45 // Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget.
46 // Fl_Help_View::load() - Load the specified file.
47 // Fl_Help_View::resize() - Resize the help widget.
48 // Fl_Help_View::topline() - Set the top line to the named target.
49 // Fl_Help_View::topline() - Set the top line by number.
50 // Fl_Help_View::value() - Set the help text directly.
51 // scrollbar_callback() - A callback for the scrollbar.
55 // Include necessary header files...
58 #include <FL/Fl_Help_View.H>
59 #include <FL/Fl_Window.H>
60 #include <FL/Fl_Pixmap.H>
64 #include <FL/fl_utf8.h>
65 #include <FL/filename.H> // fl_open_uri()
71 #if defined(WIN32) && ! defined(__CYGWIN__)
78 #define MAX_COLUMNS 200
82 // Typedef the C API sort function type the only way I know how...
87 typedef int (*compare_func_t
)(const void *, const void *);
95 static int quote_char(const char *);
96 static void scrollbar_callback(Fl_Widget
*s
, void *);
97 static void hscrollbar_callback(Fl_Widget
*s
, void *);
100 // global flag for image loading (see get_image).
103 static char initial_load
= 0;
109 static const char *broken_xpm
[] =
144 static Fl_Pixmap
broken_image(broken_xpm
);
147 // Simple margin stack for Fl_Help_View::format()...
154 fl_margins() { clear(); }
157 // puts("fl_margins::clear()");
160 return margins_
[0] = 4;
163 int current() { return margins_
[depth_
]; }
166 // printf("fl_margins::pop(): depth_=%d, xx=%d\n", depth_,
167 // depth_ > 0 ? margins_[depth_ - 1] : 4);
171 return margins_
[depth_
];
175 int push(int indent
) {
178 xx
= margins_
[depth_
] + indent
;
180 // printf("fl_margins::push(indent=%d): depth_=%d, xx=%d\n", indent,
185 margins_
[depth_
] = xx
;
193 // All the stuff needed to implement text selection in Fl_Help_View
197 * We are trying to keep binary compatibility with previous versions
198 * of FLTK. This means that we are limited to adding static variables
199 * only to not enlarge the Fl_Help_View class. Lucky for us, only one
200 * text can be selected system wide, so we can remember the selection
201 * in a single set of variables.
204 * - &word; style characters mess up our count inside a word boundary
205 * - we can only select words, no individual characters
206 * - no dragging of the selection into another widget
207 * - selection must be cleared if another widget get focus!
208 * - write a comment for every new function
212 The following functions are also used to draw stuff and should be replaced with
213 local copies that are much faster when merely counting:
216 fl_rectf(int, int, int, int);
217 fl_push_clip(int, int, int, int);
218 fl_xyline(int, int, int);
224 // We don't put the offscreen buffer in the help view class because
225 // we'd need to include x.H in the header...
226 static Fl_Offscreen fl_help_view_buffer
;
227 int Fl_Help_View::selection_first
= 0;
228 int Fl_Help_View::selection_last
= 0;
229 int Fl_Help_View::selection_push_first
= 0;
230 int Fl_Help_View::selection_push_last
= 0;
231 int Fl_Help_View::selection_drag_first
= 0;
232 int Fl_Help_View::selection_drag_last
= 0;
233 int Fl_Help_View::selected
= 0;
234 int Fl_Help_View::draw_mode
= 0;
235 int Fl_Help_View::mouse_x
= 0;
236 int Fl_Help_View::mouse_y
= 0;
237 int Fl_Help_View::current_pos
= 0;
238 Fl_Help_View
*Fl_Help_View::current_view
= 0L;
239 Fl_Color
Fl_Help_View::hv_selection_color
;
240 Fl_Color
Fl_Help_View::hv_selection_text_color
;
243 * Limitation: if a word contains &code; notations, we will calculate a wrong length.
245 * This function must be optimized for speed!
247 void Fl_Help_View::hv_draw(const char *t
, int x
, int y
)
249 if (selected
&& current_view
==this && current_pos
<selection_last
&& current_pos
>=selection_first
) {
250 Fl_Color c
= fl_color();
251 fl_color(hv_selection_color
);
252 int w
= (int)fl_width(t
);
253 if (current_pos
+(int)strlen(t
)<selection_last
)
254 w
+= (int)fl_width(' ');
255 fl_rectf(x
, y
+fl_descent()-fl_height(), w
, fl_height());
256 fl_color(hv_selection_text_color
);
263 int w
= (int)fl_width(t
);
264 if (mouse_x
>=x
&& mouse_x
<x
+w
) {
265 if (mouse_y
>=y
-fl_height()+fl_descent()&&mouse_y
<=y
+fl_descent()) {
267 int l
= f
+strlen(t
); // use 'quote_char' to calculate the true length of the HTML string
269 selection_push_first
= f
;
270 selection_push_last
= l
;
272 selection_drag_first
= f
;
273 selection_drag_last
= l
;
281 /** Adds a text block to the list. */
282 Fl_Help_Block
* // O - Pointer to new block
283 Fl_Help_View::add_block(const char *s
, // I - Pointer to start of block text
284 int xx
, // I - X position of block
285 int yy
, // I - Y position of block
286 int ww
, // I - Right margin of block
287 int hh
, // I - Height of block
288 unsigned char border
) // I - Draw border?
290 Fl_Help_Block
*temp
; // New block
293 // printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n",
294 // s, xx, yy, ww, hh, border);
296 if (nblocks_
>= ablocks_
)
301 blocks_
= (Fl_Help_Block
*)malloc(sizeof(Fl_Help_Block
) * ablocks_
);
303 blocks_
= (Fl_Help_Block
*)realloc(blocks_
, sizeof(Fl_Help_Block
) * ablocks_
);
306 temp
= blocks_
+ nblocks_
;
307 memset(temp
, 0, sizeof(Fl_Help_Block
));
314 temp
->border
= border
;
315 temp
->bgcolor
= bgcolor_
;
322 /** Adds a new link to the list. */
323 void Fl_Help_View::add_link(const char *n
, // I - Name of link
324 int xx
, // I - X position of link
325 int yy
, // I - Y position of link
326 int ww
, // I - Width of link text
327 int hh
) // I - Height of link text
329 Fl_Help_Link
*temp
; // New link
330 char *target
; // Pointer to target name
333 if (nlinks_
>= alinks_
)
338 links_
= (Fl_Help_Link
*)malloc(sizeof(Fl_Help_Link
) * alinks_
);
340 links_
= (Fl_Help_Link
*)realloc(links_
, sizeof(Fl_Help_Link
) * alinks_
);
343 temp
= links_
+ nlinks_
;
350 strlcpy(temp
->filename
, n
, sizeof(temp
->filename
));
352 if ((target
= strrchr(temp
->filename
, '#')) != NULL
)
355 strlcpy(temp
->name
, target
, sizeof(temp
->name
));
358 temp
->name
[0] = '\0';
364 /** Adds a new target to the list. */
365 void Fl_Help_View::add_target(const char *n
, // I - Name of target
366 int yy
) // I - Y position of target
368 Fl_Help_Target
*temp
; // New target
371 if (ntargets_
>= atargets_
)
376 targets_
= (Fl_Help_Target
*)malloc(sizeof(Fl_Help_Target
) * atargets_
);
378 targets_
= (Fl_Help_Target
*)realloc(targets_
, sizeof(Fl_Help_Target
) * atargets_
);
381 temp
= targets_
+ ntargets_
;
384 strlcpy(temp
->name
, n
, sizeof(temp
->name
));
389 /** Compares two targets.*/
390 int // O - Result of comparison
391 Fl_Help_View::compare_targets(const Fl_Help_Target
*t0
, // I - First target
392 const Fl_Help_Target
*t1
) // I - Second target
394 return (strcasecmp(t0
->name
, t1
->name
));
397 /** Computes the alignment for a line in a block.*/
399 Fl_Help_View::do_align(Fl_Help_Block
*block
, // I - Block to add to
400 int line
, // I - Current line
401 int xx
, // I - Current X position
402 int a
, // I - Current alignment
403 int &l
) // IO - Starting link
405 int offset
; // Alignment offset
410 case RIGHT
: // Right align
411 offset
= block
->w
- xx
;
413 case CENTER
: // Center
414 offset
= (block
->w
- xx
) / 2;
416 default : // Left align
421 block
->line
[line
] = block
->x
+ offset
;
428 links_
[l
].x
+= offset
;
429 links_
[l
].w
+= offset
;
436 /** Draws the Fl_Help_View widget. */
440 int i
; // Looping var
441 const Fl_Help_Block
*block
; // Pointer to current block
442 const char *ptr
, // Pointer to text in block
443 *attrs
; // Pointer to start of element attributes
444 char *s
, // Pointer into buffer
445 buf
[1024], // Text buffer
446 attr
[1024]; // Attribute buffer
447 int xx
, yy
, ww
, hh
; // Current positions and sizes
448 int line
; // Current line
450 Fl_Fontsize fsize
; // Current font and size
451 Fl_Color fcolor
; // current font color
452 int head
, pre
, // Flags for text
453 needspace
; // Do we need whitespace?
454 Fl_Boxtype b
= box() ? box() : FL_DOWN_BOX
;
456 int underline
, // Underline text?
457 xtra_ww
; // Extra width for underlined space between words
459 // Draw the scrollbar(s) and box first...
464 draw_box(b
, x(), y(), ww
, hh
, bgcolor_
);
466 if ( hscrollbar_
.visible() || scrollbar_
.visible() ) {
467 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
468 int hor_vis
= hscrollbar_
.visible();
469 int ver_vis
= scrollbar_
.visible();
471 int scorn_x
= x() + ww
- (ver_vis
?scrollsize
:0) - Fl::box_dw(b
) + Fl::box_dx(b
);
472 int scorn_y
= y() + hh
- (hor_vis
?scrollsize
:0) - Fl::box_dh(b
) + Fl::box_dy(b
);
474 if ( hscrollbar_
.h() != scrollsize
) { // scrollsize changed?
475 hscrollbar_
.resize(x(), scorn_y
, scorn_x
- x(), scrollsize
);
478 draw_child(hscrollbar_
);
482 if ( scrollbar_
.w() != scrollsize
) { // scrollsize changed?
483 scrollbar_
.resize(scorn_x
, y(), scrollsize
, scorn_y
- y());
486 draw_child(scrollbar_
);
489 if ( hor_vis
&& ver_vis
) {
490 // Both scrollbars visible? Draw little gray box in corner
492 fl_rectf(scorn_x
, scorn_y
, scrollsize
, scrollsize
);
499 if (current_view
== this && selected
) {
500 hv_selection_color
= FL_SELECTION_COLOR
;
501 hv_selection_text_color
= fl_contrast(textcolor_
, FL_SELECTION_COLOR
);
505 // Clip the drawing to the inside of the box...
506 fl_push_clip(x() + Fl::box_dx(b
), y() + Fl::box_dy(b
),
507 ww
- Fl::box_dw(b
), hh
- Fl::box_dh(b
));
508 fl_color(textcolor_
);
510 // Draw all visible blocks...
511 for (i
= 0, block
= blocks_
; i
< nblocks_
; i
++, block
++)
512 if ((block
->y
+ block
->h
) >= topline_
&& block
->y
< (topline_
+ h()))
515 xx
= block
->line
[line
];
516 yy
= block
->y
- topline_
;
523 initfont(font
, fsize
, fcolor
);
525 for (ptr
= block
->start
, s
= buf
; ptr
< block
->end
;)
527 if ((*ptr
== '<' || isspace((*ptr
)&255)) && s
> buf
)
534 ww
= (int)fl_width(buf
);
536 if (needspace
&& xx
> block
->x
)
537 xx
+= (int)fl_width(' ');
539 if ((xx
+ ww
) > block
->w
)
543 xx
= block
->line
[line
];
548 hv_draw(buf
, xx
+ x() - leftline_
, yy
+ y());
550 xtra_ww
= isspace((*ptr
)&255)?(int)fl_width(' '):0;
551 fl_xyline(xx
+ x() - leftline_
, yy
+ y() + 1,
552 xx
+ x() - leftline_
+ ww
+ xtra_ww
);
554 current_pos
= ptr
-value_
;
557 if ((fsize
+ 2) > hh
)
564 while (isspace((*ptr
)&255))
571 hv_draw(buf
, xx
+ x() - leftline_
, yy
+ y());
572 if (underline
) fl_xyline(xx
+ x() - leftline_
, yy
+ y() + 1,
573 xx
+ x() - leftline_
+
576 current_pos
= ptr
-value_
;
579 xx
= block
->line
[line
];
583 else if (*ptr
== '\t')
585 // Do tabs every 8 columns...
586 while (((s
- buf
) & 7))
592 if ((fsize
+ 2) > hh
)
603 hv_draw(buf
, xx
+ x() - leftline_
, yy
+ y());
604 ww
= (int)fl_width(buf
);
605 if (underline
) fl_xyline(xx
+ x() - leftline_
, yy
+ y() + 1,
606 xx
+ x() - leftline_
+ ww
);
608 current_pos
= ptr
-value_
;
617 while (isspace((*ptr
)&255))
619 current_pos
= ptr
-value_
;
627 if (strncmp(ptr
, "!--", 3) == 0)
631 if ((ptr
= strstr(ptr
, "-->")) != NULL
)
640 while (*ptr
&& *ptr
!= '>' && !isspace((*ptr
)&255))
641 if (s
< (buf
+ sizeof(buf
) - 1))
650 while (*ptr
&& *ptr
!= '>')
656 // end of command reached, set the supposed start of printed eord here
657 current_pos
= ptr
-value_
;
658 if (strcasecmp(buf
, "HEAD") == 0)
660 else if (strcasecmp(buf
, "BR") == 0)
664 xx
= block
->line
[line
];
668 else if (strcasecmp(buf
, "HR") == 0)
670 fl_line(block
->x
+ x(), yy
+ y(), block
->w
+ x(),
675 xx
= block
->line
[line
];
679 else if (strcasecmp(buf
, "CENTER") == 0 ||
680 strcasecmp(buf
, "P") == 0 ||
681 strcasecmp(buf
, "H1") == 0 ||
682 strcasecmp(buf
, "H2") == 0 ||
683 strcasecmp(buf
, "H3") == 0 ||
684 strcasecmp(buf
, "H4") == 0 ||
685 strcasecmp(buf
, "H5") == 0 ||
686 strcasecmp(buf
, "H6") == 0 ||
687 strcasecmp(buf
, "UL") == 0 ||
688 strcasecmp(buf
, "OL") == 0 ||
689 strcasecmp(buf
, "DL") == 0 ||
690 strcasecmp(buf
, "LI") == 0 ||
691 strcasecmp(buf
, "DD") == 0 ||
692 strcasecmp(buf
, "DT") == 0 ||
693 strcasecmp(buf
, "PRE") == 0)
695 if (tolower(buf
[0]) == 'h')
697 font
= FL_HELVETICA_BOLD
;
698 fsize
= textsize_
+ '7' - buf
[1];
700 else if (strcasecmp(buf
, "DT") == 0)
702 font
= textfont_
| FL_ITALIC
;
705 else if (strcasecmp(buf
, "PRE") == 0)
712 if (strcasecmp(buf
, "LI") == 0)
714 // fl_font(FL_SYMBOL, fsize); // The default SYMBOL font on my XP box is not Unicode...
716 wchar_t b
[] = {0x2022, 0x0};
717 // buf[fl_unicode2utf(b, 1, buf)] = 0;
718 unsigned dstlen
= fl_utf8fromwc(buf
, 8, b
, 1);
720 hv_draw(buf
, xx
- fsize
+ x() - leftline_
, yy
+ y());
723 pushfont(font
, fsize
);
725 else if (strcasecmp(buf
, "A") == 0 &&
726 get_attr(attrs
, "HREF", attr
, sizeof(attr
)) != NULL
)
728 fl_color(linkcolor_
);
731 else if (strcasecmp(buf
, "/A") == 0)
733 fl_color(textcolor_
);
736 else if (strcasecmp(buf
, "FONT") == 0)
738 if (get_attr(attrs
, "COLOR", attr
, sizeof(attr
)) != NULL
) {
739 textcolor_
= get_color(attr
, textcolor_
);
742 if (get_attr(attrs
, "FACE", attr
, sizeof(attr
)) != NULL
) {
743 if (!strncasecmp(attr
, "helvetica", 9) ||
744 !strncasecmp(attr
, "arial", 5) ||
745 !strncasecmp(attr
, "sans", 4)) font
= FL_HELVETICA
;
746 else if (!strncasecmp(attr
, "times", 5) ||
747 !strncasecmp(attr
, "serif", 5)) font
= FL_TIMES
;
748 else if (!strncasecmp(attr
, "symbol", 6)) font
= FL_SYMBOL
;
749 else font
= FL_COURIER
;
752 if (get_attr(attrs
, "SIZE", attr
, sizeof(attr
)) != NULL
) {
753 if (isdigit(attr
[0] & 255)) {
755 fsize
= (int)(textsize_
* pow(1.2, atof(attr
) - 3.0));
758 fsize
= (int)(fsize
* pow(1.2, atof(attr
) - 3.0));
762 pushfont(font
, fsize
);
764 else if (strcasecmp(buf
, "/FONT") == 0)
766 popfont(font
, fsize
, textcolor_
);
768 else if (strcasecmp(buf
, "U") == 0)
770 else if (strcasecmp(buf
, "/U") == 0)
772 else if (strcasecmp(buf
, "B") == 0 ||
773 strcasecmp(buf
, "STRONG") == 0)
774 pushfont(font
|= FL_BOLD
, fsize
);
775 else if (strcasecmp(buf
, "TD") == 0 ||
776 strcasecmp(buf
, "TH") == 0)
780 if (tolower(buf
[1]) == 'h')
781 pushfont(font
|= FL_BOLD
, fsize
);
783 pushfont(font
= textfont_
, fsize
);
785 tx
= block
->x
- 4 - leftline_
;
786 ty
= block
->y
- topline_
- fsize
- 3;
787 tw
= block
->w
- block
->x
+ 7;
788 th
= block
->h
+ fsize
- 5;
805 if (block
->bgcolor
!= bgcolor_
)
807 fl_color(block
->bgcolor
);
808 fl_rectf(tx
, ty
, tw
, th
);
809 fl_color(textcolor_
);
813 fl_rect(tx
, ty
, tw
, th
);
815 else if (strcasecmp(buf
, "I") == 0 ||
816 strcasecmp(buf
, "EM") == 0)
817 pushfont(font
|= FL_ITALIC
, fsize
);
818 else if (strcasecmp(buf
, "CODE") == 0 ||
819 strcasecmp(buf
, "TT") == 0)
820 pushfont(font
= FL_COURIER
, fsize
);
821 else if (strcasecmp(buf
, "KBD") == 0)
822 pushfont(font
= FL_COURIER_BOLD
, fsize
);
823 else if (strcasecmp(buf
, "VAR") == 0)
824 pushfont(font
= FL_COURIER_ITALIC
, fsize
);
825 else if (strcasecmp(buf
, "/HEAD") == 0)
827 else if (strcasecmp(buf
, "/H1") == 0 ||
828 strcasecmp(buf
, "/H2") == 0 ||
829 strcasecmp(buf
, "/H3") == 0 ||
830 strcasecmp(buf
, "/H4") == 0 ||
831 strcasecmp(buf
, "/H5") == 0 ||
832 strcasecmp(buf
, "/H6") == 0 ||
833 strcasecmp(buf
, "/B") == 0 ||
834 strcasecmp(buf
, "/STRONG") == 0 ||
835 strcasecmp(buf
, "/I") == 0 ||
836 strcasecmp(buf
, "/EM") == 0 ||
837 strcasecmp(buf
, "/CODE") == 0 ||
838 strcasecmp(buf
, "/TT") == 0 ||
839 strcasecmp(buf
, "/KBD") == 0 ||
840 strcasecmp(buf
, "/VAR") == 0)
841 popfont(font
, fsize
, fcolor
);
842 else if (strcasecmp(buf
, "/PRE") == 0)
844 popfont(font
, fsize
, fcolor
);
847 else if (strcasecmp(buf
, "IMG") == 0)
849 Fl_Shared_Image
*img
= 0;
851 char wattr
[8], hattr
[8];
854 get_attr(attrs
, "WIDTH", wattr
, sizeof(wattr
));
855 get_attr(attrs
, "HEIGHT", hattr
, sizeof(hattr
));
856 width
= get_length(wattr
);
857 height
= get_length(hattr
);
859 if (get_attr(attrs
, "SRC", attr
, sizeof(attr
))) {
860 img
= get_image(attr
, width
, height
);
861 if (!width
) width
= img
->w();
862 if (!height
) height
= img
->h();
865 if (!width
|| !height
) {
866 if (get_attr(attrs
, "ALT", attr
, sizeof(attr
)) == NULL
) {
873 if (needspace
&& xx
> block
->x
)
874 xx
+= (int)fl_width(' ');
876 if ((xx
+ ww
) > block
->w
)
881 xx
= block
->line
[line
];
887 img
->draw(xx
+ x() - leftline_
,
888 yy
+ y() - fl_height() + fl_descent() + 2);
892 if ((height
+ 2) > hh
)
898 else if (*ptr
== '\n' && pre
)
903 hv_draw(buf
, xx
+ x() - leftline_
, yy
+ y());
907 xx
= block
->line
[line
];
913 current_pos
= ptr
-value_
;
915 else if (isspace((*ptr
)&255))
923 // Do tabs every 8 columns...
924 while (((s
- buf
) & 7))
930 if (!pre
) current_pos
= ptr
-value_
;
933 else if (*ptr
== '&')
937 int qch
= quote_char(ptr
);
943 l
= fl_utf8encode((unsigned int) qch
, s
);
946 ptr
= strchr(ptr
, ';') + 1;
949 if ((fsize
+ 2) > hh
)
956 if ((fsize
+ 2) > hh
)
963 if (s
> buf
&& !pre
&& !head
)
965 ww
= (int)fl_width(buf
);
967 if (needspace
&& xx
> block
->x
)
968 xx
+= (int)fl_width(' ');
970 if ((xx
+ ww
) > block
->w
)
974 xx
= block
->line
[line
];
980 if (s
> buf
&& !head
)
982 hv_draw(buf
, xx
+ x() - leftline_
, yy
+ y());
983 if (underline
) fl_xyline(xx
+ x() - leftline_
, yy
+ y() + 1,
984 xx
+ x() - leftline_
+ ww
);
985 current_pos
= ptr
-value_
;
994 /** Finds the specified string \p s at starting position \p p.
996 \return the matching position or -1 if not found
998 int // O - Matching position or -1 if not found
999 Fl_Help_View::find(const char *s
, // I - String to find
1000 int p
) // I - Starting position
1002 int i
, // Looping var
1003 c
; // Current character
1004 Fl_Help_Block
*b
; // Current block
1005 const char *bp
, // Block matching pointer
1006 *bs
, // Start of current comparison
1007 *sp
; // Search string pointer
1010 // Range check input and value...
1011 if (!s
|| !value_
) return -1;
1013 if (p
< 0 || p
>= (int)strlen(value_
)) p
= 0;
1014 else if (p
> 0) p
++;
1016 // Look for the string...
1017 for (i
= nblocks_
, b
= blocks_
; i
> 0; i
--, b
++) {
1018 if (b
->end
< (value_
+ p
))
1021 if (b
->start
< (value_
+ p
)) bp
= value_
+ p
;
1024 for (sp
= s
, bs
= bp
; *sp
&& *bp
&& bp
< b
->end
; bp
++) {
1026 // skip to end of element...
1027 while (*bp
&& bp
< b
->end
&& *bp
!= '>') bp
++;
1029 } else if (*bp
== '&') {
1030 // decode HTML entity...
1031 if ((c
= quote_char(bp
+ 1)) < 0) c
= '&';
1032 else bp
= strchr(bp
+ 1, ';') + 1;
1035 if (tolower(*sp
) == tolower(c
)) sp
++;
1037 // No match, so reset to start of search...
1046 topline(b
->y
- b
->h
);
1047 return (b
->end
- value_
);
1055 /** Formats the help text. */
1056 void Fl_Help_View::format() {
1057 int i
; // Looping var
1058 int done
; // Are we done yet?
1059 Fl_Help_Block
*block
, // Current block
1060 *cell
; // Current table cell
1061 int cells
[MAX_COLUMNS
],
1062 // Cells in the current row...
1063 row
; // Current table row (block number)
1064 const char *ptr
, // Pointer into block
1065 *start
, // Pointer to start of element
1066 *attrs
; // Pointer to start of element attributes
1067 char *s
, // Pointer into buffer
1068 buf
[1024], // Text buffer
1069 attr
[1024], // Attribute buffer
1070 wattr
[1024], // Width attribute buffer
1071 hattr
[1024], // Height attribute buffer
1072 linkdest
[1024]; // Link destination
1073 int xx
, yy
, ww
, hh
; // Size of current text fragment
1074 int line
; // Current line in block
1075 int links
; // Links for current line
1077 Fl_Fontsize fsize
; // Current font and size
1078 Fl_Color fcolor
; // Current font color
1079 unsigned char border
; // Draw border?
1080 int talign
, // Current alignment
1081 newalign
, // New alignment
1082 head
, // In the <HEAD> section?
1084 needspace
; // Do we need whitespace?
1085 int table_width
, // Width of table
1086 table_offset
; // Offset of table
1087 int column
, // Current table column number
1088 columns
[MAX_COLUMNS
];
1090 Fl_Color tc
, rc
; // Table/row background color
1091 Fl_Boxtype b
= box() ? box() : FL_DOWN_BOX
;
1093 fl_margins margins
; // Left margin stack...
1096 // Reset document width...
1097 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
1098 hsize_
= w() - scrollsize
- Fl::box_dw(b
);
1103 // Reset state variables...
1110 textcolor_
= textcolor();
1111 linkcolor_
= fl_contrast(FL_BLUE
, color());
1115 strcpy(title_
, "Untitled");
1120 // Setup for formatting...
1121 initfont(font
, fsize
, fcolor
);
1125 xx
= margins
.clear();
1131 block
= add_block(value_
, xx
, yy
, hsize_
, 0);
1141 // Html text character loop
1142 for (ptr
= value_
, s
= buf
; *ptr
;)
1145 if ((*ptr
== '<' || isspace((*ptr
)&255)) && s
> buf
)
1147 // Get width of word parsed so far...
1149 ww
= (int)fl_width(buf
);
1160 if (needspace
&& xx
> block
->x
)
1161 ww
+= (int)fl_width(' ');
1163 // printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
1164 // line, xx, ww, block->x, block->w);
1166 if ((xx
+ ww
) > block
->w
)
1168 line
= do_align(block
, line
, xx
, newalign
, links
);
1176 add_link(linkdest
, xx
, yy
- fsize
, ww
, fsize
);
1179 if ((fsize
+ 2) > hh
)
1186 // Add a link as needed...
1188 add_link(linkdest
, xx
, yy
- hh
, ww
, hh
);
1191 if ((fsize
+ 2) > hh
)
1194 // Handle preformatted text...
1195 while (isspace((*ptr
)&255))
1199 if (xx
> hsize_
) break;
1201 line
= do_align(block
, line
, xx
, newalign
, links
);
1208 xx
+= (int)fl_width(' ');
1210 if ((fsize
+ 2) > hh
)
1226 // Handle normal text or stuff in the <HEAD> section...
1227 while (isspace((*ptr
)&255))
1236 // Handle html tags..
1240 if (strncmp(ptr
, "!--", 3) == 0)
1244 if ((ptr
= strstr(ptr
, "-->")) != NULL
)
1253 while (*ptr
&& *ptr
!= '>' && !isspace((*ptr
)&255))
1254 if (s
< (buf
+ sizeof(buf
) - 1))
1265 while (*ptr
&& *ptr
!= '>')
1271 if (strcasecmp(buf
, "HEAD") == 0)
1273 else if (strcasecmp(buf
, "/HEAD") == 0)
1275 else if (strcasecmp(buf
, "TITLE") == 0)
1277 // Copy the title in the document...
1279 *ptr
!= '<' && *ptr
&& s
< (title_
+ sizeof(title_
) - 1);
1285 else if (strcasecmp(buf
, "A") == 0)
1287 if (get_attr(attrs
, "NAME", attr
, sizeof(attr
)) != NULL
)
1288 add_target(attr
, yy
- fsize
- 2);
1290 if (get_attr(attrs
, "HREF", attr
, sizeof(attr
)) != NULL
)
1291 strlcpy(linkdest
, attr
, sizeof(linkdest
));
1293 else if (strcasecmp(buf
, "/A") == 0)
1295 else if (strcasecmp(buf
, "BODY") == 0)
1297 bgcolor_
= get_color(get_attr(attrs
, "BGCOLOR", attr
, sizeof(attr
)),
1299 textcolor_
= get_color(get_attr(attrs
, "TEXT", attr
, sizeof(attr
)),
1301 linkcolor_
= get_color(get_attr(attrs
, "LINK", attr
, sizeof(attr
)),
1302 fl_contrast(FL_BLUE
, color()));
1304 else if (strcasecmp(buf
, "BR") == 0)
1306 line
= do_align(block
, line
, xx
, newalign
, links
);
1312 else if (strcasecmp(buf
, "CENTER") == 0 ||
1313 strcasecmp(buf
, "P") == 0 ||
1314 strcasecmp(buf
, "H1") == 0 ||
1315 strcasecmp(buf
, "H2") == 0 ||
1316 strcasecmp(buf
, "H3") == 0 ||
1317 strcasecmp(buf
, "H4") == 0 ||
1318 strcasecmp(buf
, "H5") == 0 ||
1319 strcasecmp(buf
, "H6") == 0 ||
1320 strcasecmp(buf
, "UL") == 0 ||
1321 strcasecmp(buf
, "OL") == 0 ||
1322 strcasecmp(buf
, "DL") == 0 ||
1323 strcasecmp(buf
, "LI") == 0 ||
1324 strcasecmp(buf
, "DD") == 0 ||
1325 strcasecmp(buf
, "DT") == 0 ||
1326 strcasecmp(buf
, "HR") == 0 ||
1327 strcasecmp(buf
, "PRE") == 0 ||
1328 strcasecmp(buf
, "TABLE") == 0)
1331 line
= do_align(block
, line
, xx
, newalign
, links
);
1332 newalign
= strcasecmp(buf
, "CENTER") ? LEFT
: CENTER
;
1336 if (strcasecmp(buf
, "UL") == 0 ||
1337 strcasecmp(buf
, "OL") == 0 ||
1338 strcasecmp(buf
, "DL") == 0)
1340 block
->h
+= fsize
+ 2;
1341 xx
= margins
.push(4 * fsize
);
1343 else if (strcasecmp(buf
, "TABLE") == 0)
1345 if (get_attr(attrs
, "BORDER", attr
, sizeof(attr
)))
1346 border
= (uchar
)atoi(attr
);
1350 tc
= rc
= get_color(get_attr(attrs
, "BGCOLOR", attr
, sizeof(attr
)), bgcolor_
);
1352 block
->h
+= fsize
+ 2;
1354 format_table(&table_width
, columns
, start
);
1356 if ((xx
+ table_width
) > hsize_
) {
1358 printf("xx=%d, table_width=%d, hsize_=%d\n", xx
, table_width
,
1361 hsize_
= xx
+ table_width
;
1366 switch (get_align(attrs
, talign
))
1373 table_offset
= (hsize_
- table_width
) / 2 - textsize_
;
1377 table_offset
= hsize_
- table_width
- textsize_
;
1384 if (tolower(buf
[0]) == 'h' && isdigit(buf
[1]))
1386 font
= FL_HELVETICA_BOLD
;
1387 fsize
= textsize_
+ '7' - buf
[1];
1389 else if (strcasecmp(buf
, "DT") == 0)
1391 font
= textfont_
| FL_ITALIC
;
1394 else if (strcasecmp(buf
, "PRE") == 0)
1406 pushfont(font
, fsize
);
1408 yy
= block
->y
+ block
->h
;
1411 if ((tolower(buf
[0]) == 'h' && isdigit(buf
[1])) ||
1412 strcasecmp(buf
, "DD") == 0 ||
1413 strcasecmp(buf
, "DT") == 0 ||
1414 strcasecmp(buf
, "P") == 0)
1416 else if (strcasecmp(buf
, "HR") == 0)
1423 block
= add_block(start
, xx
, yy
, block
->w
, 0);
1425 block
= add_block(start
, xx
, yy
, hsize_
, 0);
1430 if (strcasecmp(buf
, "CENTER") == 0)
1431 newalign
= talign
= CENTER
;
1433 newalign
= get_align(attrs
, talign
);
1435 else if (strcasecmp(buf
, "/CENTER") == 0 ||
1436 strcasecmp(buf
, "/P") == 0 ||
1437 strcasecmp(buf
, "/H1") == 0 ||
1438 strcasecmp(buf
, "/H2") == 0 ||
1439 strcasecmp(buf
, "/H3") == 0 ||
1440 strcasecmp(buf
, "/H4") == 0 ||
1441 strcasecmp(buf
, "/H5") == 0 ||
1442 strcasecmp(buf
, "/H6") == 0 ||
1443 strcasecmp(buf
, "/PRE") == 0 ||
1444 strcasecmp(buf
, "/UL") == 0 ||
1445 strcasecmp(buf
, "/OL") == 0 ||
1446 strcasecmp(buf
, "/DL") == 0 ||
1447 strcasecmp(buf
, "/TABLE") == 0)
1449 line
= do_align(block
, line
, xx
, newalign
, links
);
1453 if (strcasecmp(buf
, "/UL") == 0 ||
1454 strcasecmp(buf
, "/OL") == 0 ||
1455 strcasecmp(buf
, "/DL") == 0)
1458 block
->h
+= fsize
+ 2;
1460 else if (strcasecmp(buf
, "/TABLE") == 0)
1462 block
->h
+= fsize
+ 2;
1463 xx
= margins
.current();
1465 else if (strcasecmp(buf
, "/PRE") == 0)
1470 else if (strcasecmp(buf
, "/CENTER") == 0)
1473 popfont(font
, fsize
, fcolor
);
1475 //#if defined(__GNUC__)
1476 //#warning FIXME this isspace & 255 test will probably not work on a utf8 stream... And we use it everywhere!
1477 //#endif /*__GNUC__*/
1478 while (isspace((*ptr
)&255))
1484 if (tolower(buf
[2]) == 'l')
1488 block
= add_block(ptr
, xx
, yy
, block
->w
, 0);
1490 block
= add_block(ptr
, xx
, yy
, hsize_
, 0);
1497 else if (strcasecmp(buf
, "TR") == 0)
1500 line
= do_align(block
, line
, xx
, newalign
, links
);
1506 yy
= blocks_
[row
].y
+ blocks_
[row
].h
;
1508 for (cell
= blocks_
+ row
+ 1; cell
<= block
; cell
++)
1509 if ((cell
->y
+ cell
->h
) > yy
)
1510 yy
= cell
->y
+ cell
->h
;
1512 block
= blocks_
+ row
;
1514 block
->h
= yy
- block
->y
+ 2;
1516 for (i
= 0; i
< column
; i
++)
1519 cell
= blocks_
+ cells
[i
];
1524 memset(cells
, 0, sizeof(cells
));
1526 yy
= block
->y
+ block
->h
- 4;
1528 block
= add_block(start
, xx
, yy
, hsize_
, 0);
1529 row
= block
- blocks_
;
1534 rc
= get_color(get_attr(attrs
, "BGCOLOR", attr
, sizeof(attr
)), tc
);
1536 else if (strcasecmp(buf
, "/TR") == 0 && row
)
1538 line
= do_align(block
, line
, xx
, newalign
, links
);
1543 xx
= blocks_
[row
].x
;
1544 yy
= blocks_
[row
].y
+ blocks_
[row
].h
;
1546 for (cell
= blocks_
+ row
+ 1; cell
<= block
; cell
++)
1547 if ((cell
->y
+ cell
->h
) > yy
)
1548 yy
= cell
->y
+ cell
->h
;
1550 block
= blocks_
+ row
;
1552 block
->h
= yy
- block
->y
+ 2;
1554 for (i
= 0; i
< column
; i
++)
1557 cell
= blocks_
+ cells
[i
];
1561 yy
= block
->y
+ block
->h
/*- 4*/;
1562 block
= add_block(start
, xx
, yy
, hsize_
, 0);
1567 else if ((strcasecmp(buf
, "TD") == 0 ||
1568 strcasecmp(buf
, "TH") == 0) && row
)
1570 int colspan
; // COLSPAN attribute
1573 line
= do_align(block
, line
, xx
, newalign
, links
);
1577 if (strcasecmp(buf
, "TH") == 0)
1578 font
= textfont_
| FL_BOLD
;
1584 xx
= blocks_
[row
].x
+ fsize
+ 3 + table_offset
;
1585 for (i
= 0; i
< column
; i
++)
1586 xx
+= columns
[i
] + 6;
1588 margins
.push(xx
- margins
.current());
1590 if (get_attr(attrs
, "COLSPAN", attr
, sizeof(attr
)) != NULL
)
1591 colspan
= atoi(attr
);
1595 for (i
= 0, ww
= -6; i
< colspan
; i
++)
1596 ww
+= columns
[column
+ i
] + 6;
1598 if (block
->end
== block
->start
&& nblocks_
> 1)
1604 pushfont(font
, fsize
);
1606 yy
= blocks_
[row
].y
;
1608 block
= add_block(start
, xx
, yy
, xx
+ ww
, 0, border
);
1611 newalign
= get_align(attrs
, tolower(buf
[1]) == 'h' ? CENTER
: LEFT
);
1614 cells
[column
] = block
- blocks_
;
1618 block
->bgcolor
= get_color(get_attr(attrs
, "BGCOLOR", attr
,
1621 else if ((strcasecmp(buf
, "/TD") == 0 ||
1622 strcasecmp(buf
, "/TH") == 0) && row
)
1624 line
= do_align(block
, line
, xx
, newalign
, links
);
1625 popfont(font
, fsize
, fcolor
);
1629 else if (strcasecmp(buf
, "FONT") == 0)
1631 if (get_attr(attrs
, "FACE", attr
, sizeof(attr
)) != NULL
) {
1632 if (!strncasecmp(attr
, "helvetica", 9) ||
1633 !strncasecmp(attr
, "arial", 5) ||
1634 !strncasecmp(attr
, "sans", 4)) font
= FL_HELVETICA
;
1635 else if (!strncasecmp(attr
, "times", 5) ||
1636 !strncasecmp(attr
, "serif", 5)) font
= FL_TIMES
;
1637 else if (!strncasecmp(attr
, "symbol", 6)) font
= FL_SYMBOL
;
1638 else font
= FL_COURIER
;
1641 if (get_attr(attrs
, "SIZE", attr
, sizeof(attr
)) != NULL
) {
1642 if (isdigit(attr
[0] & 255)) {
1644 fsize
= (int)(textsize_
* pow(1.2, atoi(attr
) - 3.0));
1647 fsize
= (int)(fsize
* pow(1.2, atoi(attr
)));
1651 pushfont(font
, fsize
);
1653 else if (strcasecmp(buf
, "/FONT") == 0)
1654 popfont(font
, fsize
, fcolor
);
1655 else if (strcasecmp(buf
, "B") == 0 ||
1656 strcasecmp(buf
, "STRONG") == 0)
1657 pushfont(font
|= FL_BOLD
, fsize
);
1658 else if (strcasecmp(buf
, "I") == 0 ||
1659 strcasecmp(buf
, "EM") == 0)
1660 pushfont(font
|= FL_ITALIC
, fsize
);
1661 else if (strcasecmp(buf
, "CODE") == 0 ||
1662 strcasecmp(buf
, "TT") == 0)
1663 pushfont(font
= FL_COURIER
, fsize
);
1664 else if (strcasecmp(buf
, "KBD") == 0)
1665 pushfont(font
= FL_COURIER_BOLD
, fsize
);
1666 else if (strcasecmp(buf
, "VAR") == 0)
1667 pushfont(font
= FL_COURIER_ITALIC
, fsize
);
1668 else if (strcasecmp(buf
, "/B") == 0 ||
1669 strcasecmp(buf
, "/STRONG") == 0 ||
1670 strcasecmp(buf
, "/I") == 0 ||
1671 strcasecmp(buf
, "/EM") == 0 ||
1672 strcasecmp(buf
, "/CODE") == 0 ||
1673 strcasecmp(buf
, "/TT") == 0 ||
1674 strcasecmp(buf
, "/KBD") == 0 ||
1675 strcasecmp(buf
, "/VAR") == 0)
1676 popfont(font
, fsize
, fcolor
);
1677 else if (strcasecmp(buf
, "IMG") == 0)
1679 Fl_Shared_Image
*img
= 0;
1684 get_attr(attrs
, "WIDTH", wattr
, sizeof(wattr
));
1685 get_attr(attrs
, "HEIGHT", hattr
, sizeof(hattr
));
1686 width
= get_length(wattr
);
1687 height
= get_length(hattr
);
1689 if (get_attr(attrs
, "SRC", attr
, sizeof(attr
))) {
1690 img
= get_image(attr
, width
, height
);
1703 if (needspace
&& xx
> block
->x
)
1704 ww
+= (int)fl_width(' ');
1706 if ((xx
+ ww
) > block
->w
)
1708 line
= do_align(block
, line
, xx
, newalign
, links
);
1716 add_link(linkdest
, xx
, yy
- height
, ww
, height
);
1719 if ((height
+ 2) > hh
)
1725 else if (*ptr
== '\n' && pre
)
1728 add_link(linkdest
, xx
, yy
- hh
, ww
, hh
);
1736 line
= do_align(block
, line
, xx
, newalign
, links
);
1743 else if (isspace((*ptr
)&255))
1747 xx
+= (int)fl_width(' ');
1751 else if (*ptr
== '&' && s
< (buf
+ sizeof(buf
) - 1))
1753 // Handle html '&' codes, eg. "&"
1756 int qch
= quote_char(ptr
);
1762 l
= fl_utf8encode((unsigned int) qch
, s
);
1765 ptr
= strchr(ptr
, ';') + 1;
1768 if ((fsize
+ 2) > hh
)
1773 if (s
< (buf
+ sizeof(buf
) - 1))
1778 if ((fsize
+ 2) > hh
)
1783 if (s
> buf
&& !head
)
1786 ww
= (int)fl_width(buf
);
1788 // printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
1789 // line, xx, ww, block->x, block->w);
1797 if (needspace
&& xx
> block
->x
)
1798 ww
+= (int)fl_width(' ');
1800 if ((xx
+ ww
) > block
->w
)
1802 line
= do_align(block
, line
, xx
, newalign
, links
);
1810 add_link(linkdest
, xx
, yy
- fsize
, ww
, fsize
);
1815 do_align(block
, line
, xx
, newalign
, links
);
1821 // printf("margins.depth_=%d\n", margins.depth_);
1824 qsort(targets_
, ntargets_
, sizeof(Fl_Help_Target
),
1825 (compare_func_t
)compare_targets
);
1827 int dx
= Fl::box_dw(b
) - Fl::box_dx(b
);
1828 int dy
= Fl::box_dh(b
) - Fl::box_dy(b
);
1829 int ss
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
1830 int dw
= Fl::box_dw(b
) + ss
;
1831 int dh
= Fl::box_dh(b
);
1833 if (hsize_
> (w() - dw
)) {
1838 if (size_
< (h() - dh
)) {
1840 hscrollbar_
.resize(x() + Fl::box_dx(b
), y() + h() - ss
- dy
,
1841 w() - Fl::box_dw(b
), ss
);
1844 scrollbar_
.resize(x() + w() - ss
- dx
, y() + Fl::box_dy(b
),
1845 ss
, h() - ss
- Fl::box_dh(b
));
1846 hscrollbar_
.resize(x() + Fl::box_dx(b
), y() + h() - ss
- dy
,
1847 w() - ss
- Fl::box_dw(b
), ss
);
1852 if (size_
< (h() - dh
)) scrollbar_
.hide();
1854 scrollbar_
.resize(x() + w() - ss
- dx
, y() + Fl::box_dy(b
),
1855 ss
, h() - Fl::box_dh(b
));
1860 // Reset scrolling if it needs to be...
1861 if (scrollbar_
.visible()) {
1862 int temph
= h() - Fl::box_dh(b
);
1863 if (hscrollbar_
.visible()) temph
-= ss
;
1864 if ((topline_
+ temph
) > size_
) topline(size_
- temph
);
1865 else topline(topline_
);
1868 if (hscrollbar_
.visible()) {
1869 int tempw
= w() - ss
- Fl::box_dw(b
);
1870 if ((leftline_
+ tempw
) > hsize_
) leftline(hsize_
- tempw
);
1871 else leftline(leftline_
);
1876 /** Formats a table */
1878 Fl_Help_View::format_table(int *table_width
, // O - Total table width
1879 int *columns
, // O - Column widths
1880 const char *table
) // I - Pointer to start of table
1882 int column
, // Current column
1883 num_columns
, // Number of columns
1884 colspan
, // COLSPAN attribute
1885 width
, // Current width
1886 temp_width
, // Temporary width
1887 max_width
, // Maximum width
1888 incell
, // In a table cell?
1890 needspace
; // Need whitespace?
1891 char *s
, // Pointer into buffer
1892 buf
[1024], // Text buffer
1893 attr
[1024], // Other attribute
1894 wattr
[1024], // WIDTH attribute
1895 hattr
[1024]; // HEIGHT attribute
1896 const char *ptr
, // Pointer into table
1897 *attrs
, // Pointer to attributes
1898 *start
; // Start of element
1899 int minwidths
[MAX_COLUMNS
]; // Minimum widths for each column
1901 Fl_Fontsize fsize
; // Current font and size
1902 Fl_Color fcolor
; // Currrent font color
1906 for (column
= 0; column
< MAX_COLUMNS
; column
++)
1908 columns
[column
] = 0;
1909 minwidths
[column
] = 0;
1917 fstack_
.top(font
, fsize
, fcolor
);
1919 // Scan the table...
1920 for (ptr
= table
, column
= -1, width
= 0, s
= buf
, incell
= 0; *ptr
;)
1922 if ((*ptr
== '<' || isspace((*ptr
)&255)) && s
> buf
&& incell
)
1932 temp_width
= (int)fl_width(buf
);
1935 if (temp_width
> minwidths
[column
])
1936 minwidths
[column
] = temp_width
;
1938 width
+= temp_width
;
1940 if (width
> max_width
)
1948 for (s
= buf
, ptr
++; *ptr
&& *ptr
!= '>' && !isspace((*ptr
)&255);)
1949 if (s
< (buf
+ sizeof(buf
) - 1))
1958 while (*ptr
&& *ptr
!= '>')
1964 if (strcasecmp(buf
, "BR") == 0 ||
1965 strcasecmp(buf
, "HR") == 0)
1970 else if (strcasecmp(buf
, "TABLE") == 0 && start
> table
)
1972 else if (strcasecmp(buf
, "CENTER") == 0 ||
1973 strcasecmp(buf
, "P") == 0 ||
1974 strcasecmp(buf
, "H1") == 0 ||
1975 strcasecmp(buf
, "H2") == 0 ||
1976 strcasecmp(buf
, "H3") == 0 ||
1977 strcasecmp(buf
, "H4") == 0 ||
1978 strcasecmp(buf
, "H5") == 0 ||
1979 strcasecmp(buf
, "H6") == 0 ||
1980 strcasecmp(buf
, "UL") == 0 ||
1981 strcasecmp(buf
, "OL") == 0 ||
1982 strcasecmp(buf
, "DL") == 0 ||
1983 strcasecmp(buf
, "LI") == 0 ||
1984 strcasecmp(buf
, "DD") == 0 ||
1985 strcasecmp(buf
, "DT") == 0 ||
1986 strcasecmp(buf
, "PRE") == 0)
1991 if (tolower(buf
[0]) == 'h' && isdigit(buf
[1]))
1993 font
= FL_HELVETICA_BOLD
;
1994 fsize
= textsize_
+ '7' - buf
[1];
1996 else if (strcasecmp(buf
, "DT") == 0)
1998 font
= textfont_
| FL_ITALIC
;
2001 else if (strcasecmp(buf
, "PRE") == 0)
2007 else if (strcasecmp(buf
, "LI") == 0)
2019 pushfont(font
, fsize
);
2021 else if (strcasecmp(buf
, "/CENTER") == 0 ||
2022 strcasecmp(buf
, "/P") == 0 ||
2023 strcasecmp(buf
, "/H1") == 0 ||
2024 strcasecmp(buf
, "/H2") == 0 ||
2025 strcasecmp(buf
, "/H3") == 0 ||
2026 strcasecmp(buf
, "/H4") == 0 ||
2027 strcasecmp(buf
, "/H5") == 0 ||
2028 strcasecmp(buf
, "/H6") == 0 ||
2029 strcasecmp(buf
, "/PRE") == 0 ||
2030 strcasecmp(buf
, "/UL") == 0 ||
2031 strcasecmp(buf
, "/OL") == 0 ||
2032 strcasecmp(buf
, "/DL") == 0)
2037 popfont(font
, fsize
, fcolor
);
2039 else if (strcasecmp(buf
, "TR") == 0 || strcasecmp(buf
, "/TR") == 0 ||
2040 strcasecmp(buf
, "/TABLE") == 0)
2042 // printf("%s column = %d, colspan = %d, num_columns = %d\n",
2043 // buf, column, colspan, num_columns);
2047 // This is a hack to support COLSPAN...
2048 max_width
/= colspan
;
2052 if (max_width
> columns
[column
])
2053 columns
[column
] = max_width
;
2060 if (strcasecmp(buf
, "/TABLE") == 0)
2069 else if (strcasecmp(buf
, "TD") == 0 ||
2070 strcasecmp(buf
, "TH") == 0)
2072 // printf("BEFORE column = %d, colspan = %d, num_columns = %d\n",
2073 // column, colspan, num_columns);
2077 // This is a hack to support COLSPAN...
2078 max_width
/= colspan
;
2082 if (max_width
> columns
[column
])
2083 columns
[column
] = max_width
;
2092 if (get_attr(attrs
, "COLSPAN", attr
, sizeof(attr
)) != NULL
)
2093 colspan
= atoi(attr
);
2097 // printf("AFTER column = %d, colspan = %d, num_columns = %d\n",
2098 // column, colspan, num_columns);
2100 if ((column
+ colspan
) >= num_columns
)
2101 num_columns
= column
+ colspan
;
2107 if (strcasecmp(buf
, "TH") == 0)
2108 font
= textfont_
| FL_BOLD
;
2114 pushfont(font
, fsize
);
2116 if (get_attr(attrs
, "WIDTH", attr
, sizeof(attr
)) != NULL
)
2117 max_width
= get_length(attr
);
2121 // printf("max_width = %d\n", max_width);
2123 else if (strcasecmp(buf
, "/TD") == 0 ||
2124 strcasecmp(buf
, "/TH") == 0)
2127 popfont(font
, fsize
, fcolor
);
2129 else if (strcasecmp(buf
, "B") == 0 ||
2130 strcasecmp(buf
, "STRONG") == 0)
2131 pushfont(font
|= FL_BOLD
, fsize
);
2132 else if (strcasecmp(buf
, "I") == 0 ||
2133 strcasecmp(buf
, "EM") == 0)
2134 pushfont(font
|= FL_ITALIC
, fsize
);
2135 else if (strcasecmp(buf
, "CODE") == 0 ||
2136 strcasecmp(buf
, "TT") == 0)
2137 pushfont(font
= FL_COURIER
, fsize
);
2138 else if (strcasecmp(buf
, "KBD") == 0)
2139 pushfont(font
= FL_COURIER_BOLD
, fsize
);
2140 else if (strcasecmp(buf
, "VAR") == 0)
2141 pushfont(font
= FL_COURIER_ITALIC
, fsize
);
2142 else if (strcasecmp(buf
, "/B") == 0 ||
2143 strcasecmp(buf
, "/STRONG") == 0 ||
2144 strcasecmp(buf
, "/I") == 0 ||
2145 strcasecmp(buf
, "/EM") == 0 ||
2146 strcasecmp(buf
, "/CODE") == 0 ||
2147 strcasecmp(buf
, "/TT") == 0 ||
2148 strcasecmp(buf
, "/KBD") == 0 ||
2149 strcasecmp(buf
, "/VAR") == 0)
2150 popfont(font
, fsize
, fcolor
);
2151 else if (strcasecmp(buf
, "IMG") == 0 && incell
)
2153 Fl_Shared_Image
*img
= 0;
2154 int iwidth
, iheight
;
2157 get_attr(attrs
, "WIDTH", wattr
, sizeof(wattr
));
2158 get_attr(attrs
, "HEIGHT", hattr
, sizeof(hattr
));
2159 iwidth
= get_length(wattr
);
2160 iheight
= get_length(hattr
);
2162 if (get_attr(attrs
, "SRC", attr
, sizeof(attr
))) {
2163 img
= get_image(attr
, iwidth
, iheight
);
2168 if (iwidth
> minwidths
[column
])
2169 minwidths
[column
] = iwidth
;
2173 width
+= (int)fl_width(' ');
2175 if (width
> max_width
)
2181 else if (*ptr
== '\n' && pre
)
2187 else if (isspace((*ptr
)&255))
2193 else if (*ptr
== '&' && s
< (buf
+ sizeof(buf
) - 1))
2197 int qch
= quote_char(ptr
);
2203 // l = fl_utf8encode((unsigned int) qch, s);
2204 // if (l < 1) l = 1;
2207 ptr
= strchr(ptr
, ';') + 1;
2212 if (s
< (buf
+ sizeof(buf
) - 1))
2219 // Now that we have scanned the entire table, adjust the table and
2220 // cell widths to fit on the screen...
2221 if (get_attr(table
+ 6, "WIDTH", attr
, sizeof(attr
)))
2222 *table_width
= get_length(attr
);
2227 printf("num_columns = %d, table_width = %d\n", num_columns
, *table_width
);
2230 if (num_columns
== 0)
2233 // Add up the widths...
2234 for (column
= 0, width
= 0; column
< num_columns
; column
++)
2235 width
+= columns
[column
];
2238 printf("width = %d, w() = %d\n", width
, w());
2239 for (column
= 0; column
< num_columns
; column
++)
2240 printf(" columns[%d] = %d, minwidths[%d] = %d\n", column
, columns
[column
],
2241 column
, minwidths
[column
]);
2244 // Adjust the width if needed...
2245 int scale_width
= *table_width
;
2247 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
2248 if (scale_width
== 0) {
2249 if (width
> (hsize_
- scrollsize
)) scale_width
= hsize_
- scrollsize
;
2250 else scale_width
= width
;
2253 if (width
< scale_width
) {
2255 printf("Scaling table up to %d from %d...\n", scale_width
, width
);
2260 scale_width
= (scale_width
- width
) / num_columns
;
2263 printf("adjusted scale_width = %d\n", scale_width
);
2266 for (column
= 0; column
< num_columns
; column
++) {
2267 columns
[column
] += scale_width
;
2269 (*table_width
) += columns
[column
];
2272 else if (width
> scale_width
) {
2274 printf("Scaling table down to %d from %d...\n", scale_width
, width
);
2277 for (column
= 0; column
< num_columns
; column
++) {
2278 width
-= minwidths
[column
];
2279 scale_width
-= minwidths
[column
];
2283 printf("adjusted width = %d, scale_width = %d\n", width
, scale_width
);
2287 for (column
= 0; column
< num_columns
; column
++) {
2288 columns
[column
] -= minwidths
[column
];
2289 columns
[column
] = scale_width
* columns
[column
] / width
;
2290 columns
[column
] += minwidths
[column
];
2295 for (column
= 0; column
< num_columns
; column
++) {
2296 (*table_width
) += columns
[column
];
2299 else if (*table_width
== 0)
2300 *table_width
= width
;
2303 printf("FINAL table_width = %d\n", *table_width
);
2304 for (column
= 0; column
< num_columns
; column
++)
2305 printf(" columns[%d] = %d\n", column
, columns
[column
]);
2310 /** Frees memory used for the document. */
2312 Fl_Help_View::free_data() {
2313 // Release all images...
2315 const char *ptr
, // Pointer into block
2316 *attrs
; // Pointer to start of element attributes
2317 char *s
, // Pointer into buffer
2318 buf
[1024], // Text buffer
2319 attr
[1024], // Attribute buffer
2320 wattr
[1024], // Width attribute buffer
2321 hattr
[1024]; // Height attribute buffer
2323 for (ptr
= value_
; *ptr
;)
2329 if (strncmp(ptr
, "!--", 3) == 0)
2333 if ((ptr
= strstr(ptr
, "-->")) != NULL
)
2344 while (*ptr
&& *ptr
!= '>' && !isspace((*ptr
)&255))
2345 if (s
< (buf
+ sizeof(buf
) - 1))
2353 while (*ptr
&& *ptr
!= '>')
2359 if (strcasecmp(buf
, "IMG") == 0)
2361 Fl_Shared_Image
*img
;
2365 get_attr(attrs
, "WIDTH", wattr
, sizeof(wattr
));
2366 get_attr(attrs
, "HEIGHT", hattr
, sizeof(hattr
));
2367 width
= get_length(wattr
);
2368 height
= get_length(hattr
);
2370 if (get_attr(attrs
, "SRC", attr
, sizeof(attr
))) {
2371 // Get and release the image to free it from memory...
2372 img
= get_image(attr
, width
, height
);
2373 if ((void*)img
!= &broken_image
) {
2383 free((void *)value_
);
2387 // Free all of the arrays...
2413 /** Gets an alignment attribute. */
2414 int // O - Alignment
2415 Fl_Help_View::get_align(const char *p
, // I - Pointer to start of attrs
2416 int a
) // I - Default alignment
2418 char buf
[255]; // Alignment value
2421 if (get_attr(p
, "ALIGN", buf
, sizeof(buf
)) == NULL
)
2424 if (strcasecmp(buf
, "CENTER") == 0)
2426 else if (strcasecmp(buf
, "RIGHT") == 0)
2433 /** Gets an attribute value from the string. */
2434 const char * // O - Pointer to buf or NULL
2435 Fl_Help_View::get_attr(const char *p
, // I - Pointer to start of attributes
2436 const char *n
, // I - Name of attribute
2437 char *buf
, // O - Buffer for attribute value
2438 int bufsize
) // I - Size of buffer
2440 char name
[255], // Name from string
2441 *ptr
, // Pointer into name or value
2447 while (*p
&& *p
!= '>')
2449 while (isspace((*p
)&255))
2452 if (*p
== '>' || !*p
)
2455 for (ptr
= name
; *p
&& !isspace((*p
)&255) && *p
!= '=' && *p
!= '>';)
2456 if (ptr
< (name
+ sizeof(name
) - 1))
2463 if (isspace((*p
)&255) || !*p
|| *p
== '>')
2470 for (ptr
= buf
; *p
&& !isspace((*p
)&255) && *p
!= '>';)
2471 if (*p
== '\'' || *p
== '\"')
2475 while (*p
&& *p
!= quote
)
2476 if ((ptr
- buf
+ 1) < bufsize
)
2484 else if ((ptr
- buf
+ 1) < bufsize
)
2492 if (strcasecmp(n
, name
) == 0)
2505 /** Gets a color attribute. */
2506 Fl_Color
// O - Color value
2507 Fl_Help_View::get_color(const char *n
, // I - Color name
2508 Fl_Color c
) // I - Default color value
2510 int i
; // Looping var
2511 int rgb
, r
, g
, b
; // RGB values
2512 static const struct { // Color name table
2516 { "black", 0x00, 0x00, 0x00 },
2517 { "red", 0xff, 0x00, 0x00 },
2518 { "green", 0x00, 0x80, 0x00 },
2519 { "yellow", 0xff, 0xff, 0x00 },
2520 { "blue", 0x00, 0x00, 0xff },
2521 { "magenta", 0xff, 0x00, 0xff },
2522 { "fuchsia", 0xff, 0x00, 0xff },
2523 { "cyan", 0x00, 0xff, 0xff },
2524 { "aqua", 0x00, 0xff, 0xff },
2525 { "white", 0xff, 0xff, 0xff },
2526 { "gray", 0x80, 0x80, 0x80 },
2527 { "grey", 0x80, 0x80, 0x80 },
2528 { "lime", 0x00, 0xff, 0x00 },
2529 { "maroon", 0x80, 0x00, 0x00 },
2530 { "navy", 0x00, 0x00, 0x80 },
2531 { "olive", 0x80, 0x80, 0x00 },
2532 { "purple", 0x80, 0x00, 0x80 },
2533 { "silver", 0xc0, 0xc0, 0xc0 },
2534 { "teal", 0x00, 0x80, 0x80 }
2538 if (!n
|| !n
[0]) return c
;
2541 // Do hex color lookup
2542 rgb
= strtol(n
+ 1, NULL
, 16);
2544 if (strlen(n
) > 4) {
2546 g
= (rgb
>> 8) & 255;
2549 r
= (rgb
>> 8) * 17;
2550 g
= ((rgb
>> 4) & 15) * 17;
2551 b
= (rgb
& 15) * 17;
2553 return (fl_rgb_color((uchar
)r
, (uchar
)g
, (uchar
)b
));
2555 for (i
= 0; i
< (int)(sizeof(colors
) / sizeof(colors
[0])); i
++)
2556 if (!strcasecmp(n
, colors
[i
].name
)) {
2557 return fl_rgb_color(colors
[i
].r
, colors
[i
].g
, colors
[i
].b
);
2564 /** Gets an inline image.
2566 The image reference count is maintained accordingly, such that
2567 the image can be released exactly once when the document is closed.
2569 \return a pointer to a cached Fl_Shared_Image, if the image can be loaded,
2570 otherwise a pointer to an internal Fl_Pixmap (broken_image).
2572 \todo Fl_Help_View::get_image() returns a pointer to the internal
2573 Fl_Pixmap broken_image, but this is _not_ compatible with the
2574 return type Fl_Shared_Image (release() must not be called).
2577 /* Implementation note: (A.S. Apr 05, 2009)
2579 Fl_Help_View::get_image() uses a static global flag (initial_load)
2580 to determine, if it is called from the initial loading of a document
2581 (load() or value()), or from resize() or draw().
2583 A better solution would be to manage all loaded images in an own
2584 structure like Fl_Help_Target (Fl_Help_Image ?) to avoid using this
2585 global flag, but this would break the ABI !
2587 This should be fixed in FLTK 1.3 !
2590 If initial_load is true, then Fl_Shared_Image::get() is called to
2591 load the image, and the reference count of the shared image is
2594 If initial_load is false, then Fl_Shared_Image::find() is called to
2595 load the image, and the image is released immediately. This avoids
2596 increasing the reference count when calling get_image() from draw()
2599 Calling Fl_Shared_Image::find() instead of Fl_Shared_Image::get() avoids
2600 doing unnecessary i/o for "broken images" within each resize/redraw.
2602 Each image must be released exactly once in the destructor or before
2603 a new document is loaded: see free_data().
2607 Fl_Help_View::get_image(const char *name
, int W
, int H
) {
2608 const char *localname
; // Local filename
2609 char dir
[FL_PATH_MAX
]; // Current directory
2610 char temp
[FL_PATH_MAX
], // Temporary filename
2611 *tempptr
; // Pointer into temporary name
2612 Fl_Shared_Image
*ip
; // Image pointer...
2614 // See if the image can be found...
2615 if (strchr(directory_
, ':') != NULL
&& strchr(name
, ':') == NULL
) {
2616 if (name
[0] == '/') {
2617 strlcpy(temp
, directory_
, sizeof(temp
));
2619 if ((tempptr
= strrchr(strchr(directory_
, ':') + 3, '/')) != NULL
) {
2620 strlcpy(tempptr
, name
, sizeof(temp
) - (tempptr
- temp
));
2622 strlcat(temp
, name
, sizeof(temp
));
2625 snprintf(temp
, sizeof(temp
), "%s/%s", directory_
, name
);
2628 if (link_
) localname
= (*link_
)(this, temp
);
2629 else localname
= temp
;
2630 } else if (name
[0] != '/' && strchr(name
, ':') == NULL
) {
2631 if (directory_
[0]) snprintf(temp
, sizeof(temp
), "%s/%s", directory_
, name
);
2633 fl_getcwd(dir
, sizeof(dir
));
2634 snprintf(temp
, sizeof(temp
), "file:%s/%s", dir
, name
);
2637 if (link_
) localname
= (*link_
)(this, temp
);
2638 else localname
= temp
;
2639 } else if (link_
) localname
= (*link_
)(this, name
);
2640 else localname
= name
;
2642 if (!localname
) return 0;
2644 if (strncmp(localname
, "file:", 5) == 0) localname
+= 5;
2647 if ((ip
= Fl_Shared_Image::get(localname
, W
, H
)) == NULL
) {
2648 ip
= (Fl_Shared_Image
*)&broken_image
;
2650 } else { // draw or resize
2651 if ((ip
= Fl_Shared_Image::find(localname
, W
, H
)) == NULL
) {
2652 ip
= (Fl_Shared_Image
*)&broken_image
;
2662 /** Gets a length value, either absolute or %. */
2664 Fl_Help_View::get_length(const char *l
) { // I - Value
2665 int val
; // Integer value
2667 if (!l
[0]) return 0;
2670 if (l
[strlen(l
) - 1] == '%') {
2671 if (val
> 100) val
= 100;
2672 else if (val
< 0) val
= 0;
2674 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
2675 val
= val
* (hsize_
- scrollsize
) / 100;
2682 Fl_Help_Link
*Fl_Help_View::find_link(int xx
, int yy
)
2685 Fl_Help_Link
*linkp
;
2686 for (i
= nlinks_
, linkp
= links_
; i
> 0; i
--, linkp
++) {
2687 if (xx
>= linkp
->x
&& xx
< linkp
->w
&&
2688 yy
>= linkp
->y
&& yy
< linkp
->h
)
2691 return i
? linkp
: 0L;
2694 void Fl_Help_View::follow_link(Fl_Help_Link
*linkp
)
2696 char target
[32]; // Current target
2700 strlcpy(target
, linkp
->name
, sizeof(target
));
2704 if (strcmp(linkp
->filename
, filename_
) != 0 && linkp
->filename
[0])
2706 char dir
[FL_PATH_MAX
]; // Current directory
2707 char temp
[FL_PATH_MAX
], // Temporary filename
2708 *tempptr
; // Pointer into temporary filename
2711 if (strchr(directory_
, ':') != NULL
&&
2712 strchr(linkp
->filename
, ':') == NULL
)
2714 if (linkp
->filename
[0] == '/')
2716 strlcpy(temp
, directory_
, sizeof(temp
));
2717 if ((tempptr
= strrchr(strchr(directory_
, ':') + 3, '/')) != NULL
)
2718 strlcpy(tempptr
, linkp
->filename
, sizeof(temp
));
2720 strlcat(temp
, linkp
->filename
, sizeof(temp
));
2723 snprintf(temp
, sizeof(temp
), "%s/%s", directory_
, linkp
->filename
);
2725 else if (linkp
->filename
[0] != '/' && strchr(linkp
->filename
, ':') == NULL
)
2728 snprintf(temp
, sizeof(temp
), "%s/%s", directory_
, linkp
->filename
);
2731 fl_getcwd(dir
, sizeof(dir
));
2732 snprintf(temp
, sizeof(temp
), "file:%s/%s", dir
, linkp
->filename
);
2736 strlcpy(temp
, linkp
->filename
, sizeof(temp
));
2739 snprintf(temp
+ strlen(temp
), sizeof(temp
) - strlen(temp
), "#%s",
2752 /** Removes the current text selection. */
2753 void Fl_Help_View::clear_selection()
2755 if (current_view
==this)
2756 clear_global_selection();
2758 /** Selects all the text in the view. */
2759 void Fl_Help_View::select_all()
2761 clear_global_selection();
2762 if (!value_
) return;
2763 current_view
= this;
2764 selection_drag_last
= selection_last
= strlen(value_
);
2768 void Fl_Help_View::clear_global_selection()
2770 if (selected
) redraw();
2771 selection_push_first
= selection_push_last
= 0;
2772 selection_drag_first
= selection_drag_last
= 0;
2773 selection_first
= selection_last
= 0;
2777 char Fl_Help_View::begin_selection()
2779 clear_global_selection();
2781 if (!fl_help_view_buffer
) fl_help_view_buffer
= fl_create_offscreen(1, 1);
2783 mouse_x
= Fl::event_x();
2784 mouse_y
= Fl::event_y();
2787 current_view
= this;
2788 fl_begin_offscreen(fl_help_view_buffer
);
2794 if (selection_push_last
) return 1;
2798 char Fl_Help_View::extend_selection()
2800 if (Fl::event_is_click())
2803 // printf("old selection_first=%d, selection_last=%d\n",
2804 // selection_first, selection_last);
2806 int sf
= selection_first
, sl
= selection_last
;
2809 mouse_x
= Fl::event_x();
2810 mouse_y
= Fl::event_y();
2813 fl_begin_offscreen(fl_help_view_buffer
);
2819 if (selection_push_first
< selection_drag_first
) {
2820 selection_first
= selection_push_first
;
2822 selection_first
= selection_drag_first
;
2825 if (selection_push_last
> selection_drag_last
) {
2826 selection_last
= selection_push_last
;
2828 selection_last
= selection_drag_last
;
2831 // printf("new selection_first=%d, selection_last=%d\n",
2832 // selection_first, selection_last);
2834 if (sf
!=selection_first
|| sl
!=selection_last
) {
2835 // puts("REDRAW!!!\n");
2843 // convert a command with up to four letters into an unsigned int
2844 static unsigned int command(const char *cmd
)
2846 unsigned int ret
= (tolower(cmd
[0])<<24);
2848 if (c
=='>' || c
==' ' || c
==0) return ret
;
2849 ret
|= (tolower(c
)<<16);
2851 if (c
=='>' || c
==' ' || c
==0) return ret
;
2852 ret
|= (tolower(c
)<<8);
2854 if (c
=='>' || c
==' ' || c
==0) return ret
;
2857 if (c
=='>' || c
==' ' || c
==0) return ret
;
2861 #define CMD(a, b, c, d) ((a<<24)|(b<<16)|(c<<8)|d)
2863 void Fl_Help_View::end_selection(int clipboard
)
2865 if (!selected
|| current_view
!=this)
2867 // convert the select part of our html text into some kind of somewhat readable ASCII
2868 // and store it in the selection buffer
2869 char p
= 0, pre
= 0;;
2870 int len
= strlen(value_
);
2871 char *txt
= (char*)malloc(len
+1), *d
= txt
;
2872 const char *s
= value_
, *cmd
, *src
;
2876 if (c
=='<') { // begin of some html command. Skip until we find a '>'
2880 if (c
==0 || c
=='>') break;
2883 // do something with this command... .
2884 // the replacement string must not be longer that the command itself plus '<' and '>'
2886 switch (command(cmd
)) {
2887 case CMD('p','r','e', 0 ): pre
= 1; break;
2888 case CMD('/','p','r','e'): pre
= 0; break;
2889 case CMD('t','d', 0 , 0 ):
2890 case CMD('p', 0 , 0 , 0 ):
2891 case CMD('/','p', 0 , 0 ):
2892 case CMD('b','r', 0 , 0 ): src
= "\n"; break;
2893 case CMD('l','i', 0 , 0 ): src
= "\n * "; break;
2894 case CMD('/','h','1', 0 ):
2895 case CMD('/','h','2', 0 ):
2896 case CMD('/','h','3', 0 ):
2897 case CMD('/','h','4', 0 ):
2898 case CMD('/','h','5', 0 ):
2899 case CMD('/','h','6', 0 ): src
= "\n\n"; break;
2900 case CMD('t','r', 0 , 0 ):
2901 case CMD('h','1', 0 , 0 ):
2902 case CMD('h','2', 0 , 0 ):
2903 case CMD('h','3', 0 , 0 ):
2904 case CMD('h','4', 0 , 0 ):
2905 case CMD('h','5', 0 , 0 ):
2906 case CMD('h','6', 0 , 0 ): src
= "\n\n"; break;
2907 case CMD('d','t', 0 , 0 ): src
= "\n "; break;
2908 case CMD('d','d', 0 , 0 ): src
= "\n - "; break;
2911 if (src
&& n
>selection_first
&& n
<=selection_last
) {
2916 p
= isspace(c
&255) ? ' ' : c
;
2920 if (c
=='&') { // special characters
2921 int xx
= quote_char(s
);
2926 if (!cc
|| cc
==';') break;
2931 if (n
>selection_first
&& n
<=selection_last
) {
2932 if (!pre
&& isspace(c
&255)) c
= ' ';
2939 Fl::copy(txt
, strlen(txt
), clipboard
);
2943 #define ctrl(x) ((x)&0x1f)
2945 /** Handles events in the widget. */
2946 int // O - 1 if we handled it, 0 otherwise
2947 Fl_Help_View::handle(int event
) // I - Event to handle
2949 static Fl_Help_Link
*linkp
; // currently clicked link
2951 int xx
= Fl::event_x() - x() + leftline_
;
2952 int yy
= Fl::event_y() - y() + topline_
;
2964 Fl_Group::handle(event
);
2967 fl_cursor(FL_CURSOR_DEFAULT
);
2970 if (find_link(xx
, yy
)) fl_cursor(FL_CURSOR_HAND
);
2971 else fl_cursor(FL_CURSOR_DEFAULT
);
2974 if (Fl_Group::handle(event
)) return 1;
2975 linkp
= find_link(xx
, yy
);
2977 fl_cursor(FL_CURSOR_HAND
);
2980 if (begin_selection()) {
2981 fl_cursor(FL_CURSOR_INSERT
);
2984 fl_cursor(FL_CURSOR_DEFAULT
);
2988 if (Fl::event_is_click()) {
2989 fl_cursor(FL_CURSOR_HAND
);
2991 fl_cursor(FL_CURSOR_DEFAULT
); // should be "FL_CURSOR_CANCEL" if we had it
2995 if (current_view
==this && selection_push_last
) {
2996 if (extend_selection()) redraw();
2997 fl_cursor(FL_CURSOR_INSERT
);
3000 fl_cursor(FL_CURSOR_DEFAULT
);
3004 if (Fl::event_is_click()) {
3007 fl_cursor(FL_CURSOR_DEFAULT
);
3011 if (current_view
==this && selection_push_last
) {
3017 char ascii
= Fl::event_text()[0];
3019 case ctrl('A'): select_all(); redraw(); return 1;
3021 case ctrl('X'): end_selection(1); return 1;
3025 return (Fl_Group::handle(event
));
3029 The constructor creates the Fl_Help_View widget at the specified
3032 Fl_Help_View::Fl_Help_View(int xx
, // I - Left position
3033 int yy
, // I - Top position
3034 int ww
, // I - Width in pixels
3035 int hh
, // I - Height in pixels
3037 : Fl_Group(xx
, yy
, ww
, hh
, l
),
3038 scrollbar_(xx
+ ww
- Fl::scrollbar_size(), yy
,
3039 Fl::scrollbar_size(), hh
- Fl::scrollbar_size()),
3040 hscrollbar_(xx
, yy
+ hh
- Fl::scrollbar_size(),
3041 ww
- Fl::scrollbar_size(), Fl::scrollbar_size())
3043 color(FL_BACKGROUND2_COLOR
, FL_SELECTION_COLOR
);
3046 defcolor_
= FL_FOREGROUND_COLOR
;
3047 bgcolor_
= FL_BACKGROUND_COLOR
;
3048 textcolor_
= FL_FOREGROUND_COLOR
;
3049 linkcolor_
= FL_SELECTION_COLOR
;
3050 textfont_
= FL_TIMES
;
3056 blocks_
= (Fl_Help_Block
*)0;
3058 link_
= (Fl_Help_Func
*)0;
3062 links_
= (Fl_Help_Link
*)0;
3066 targets_
= (Fl_Help_Target
*)0;
3068 directory_
[0] = '\0';
3069 filename_
[0] = '\0';
3075 scrollbar_size_
= 0;
3077 scrollbar_
.value(0, hh
, 0, 1);
3078 scrollbar_
.step(8.0);
3080 scrollbar_
.callback(scrollbar_callback
);
3082 hscrollbar_
.value(0, ww
, 0, 1);
3083 hscrollbar_
.step(8.0);
3085 hscrollbar_
.callback(hscrollbar_callback
);
3086 hscrollbar_
.type(FL_HORIZONTAL
);
3089 resize(xx
, yy
, ww
, hh
);
3093 /** Destroys the Fl_Help_View widget.
3095 The destructor destroys the widget and frees all memory that has been
3096 allocated for the current document.
3098 Fl_Help_View::~Fl_Help_View()
3105 /** Loads the specified file.
3107 This method loads the specified file or URL.
3109 int // O - 0 on success, -1 on error
3110 Fl_Help_View::load(const char *f
)// I - Filename to load (may also have target)
3112 FILE *fp
; // File to read from
3113 long len
; // Length of file
3114 char *target
; // Target in file
3115 char *slash
; // Directory separator
3116 const char *localname
; // Local filename
3117 char error
[1024]; // Error buffer
3118 char newname
[FL_PATH_MAX
]; // New filename buffer
3120 // printf("load(%s)\n",f); fflush(stdout);
3122 if (strncmp(f
, "ftp:", 4) == 0 ||
3123 strncmp(f
, "http:", 5) == 0 ||
3124 strncmp(f
, "https:", 6) == 0 ||
3125 strncmp(f
, "ipp:", 4) == 0 ||
3126 strncmp(f
, "mailto:", 7) == 0 ||
3127 strncmp(f
, "news:", 5) == 0) {
3128 char urimsg
[FL_PATH_MAX
];
3129 if ( fl_open_uri(f
, urimsg
, sizeof(urimsg
)) == 0 ) {
3132 strlcpy(newname
, f
, sizeof(newname
));
3133 if ((target
= strrchr(newname
, '#')) != NULL
)
3137 localname
= (*link_
)(this, newname
);
3139 localname
= filename_
;
3146 strlcpy(filename_
, newname
, sizeof(filename_
));
3147 strlcpy(directory_
, newname
, sizeof(directory_
));
3149 // Note: We do not support Windows backslashes, since they are illegal
3151 if ((slash
= strrchr(directory_
, '/')) == NULL
)
3152 directory_
[0] = '\0';
3153 else if (slash
> directory_
&& slash
[-1] != '/')
3156 snprintf(error
, sizeof(error
),
3157 "<HTML><HEAD><TITLE>Error</TITLE></HEAD>"
3158 "<BODY><H1>Error</H1>"
3159 "<P>Unable to follow the link \"%s\" - "
3170 strlcpy(newname
, f
, sizeof(newname
));
3171 if ((target
= strrchr(newname
, '#')) != NULL
)
3175 localname
= (*link_
)(this, newname
);
3177 localname
= filename_
;
3184 strlcpy(filename_
, newname
, sizeof(filename_
));
3185 strlcpy(directory_
, newname
, sizeof(directory_
));
3187 // Note: We do not support Windows backslashes, since they are illegal
3189 if ((slash
= strrchr(directory_
, '/')) == NULL
)
3190 directory_
[0] = '\0';
3191 else if (slash
> directory_
&& slash
[-1] != '/')
3194 if (strncmp(localname
, "file:", 5) == 0)
3195 localname
+= 5; // Adjust for local filename...
3197 if ((fp
= fl_fopen(localname
, "rb")) != NULL
)
3199 fseek(fp
, 0, SEEK_END
);
3203 value_
= (const char *)calloc(len
+ 1, 1);
3204 if (fread((void *)value_
, 1, len
, fp
)==0) { /* use default 0 */ }
3209 snprintf(error
, sizeof(error
),
3210 "<HTML><HEAD><TITLE>Error</TITLE></HEAD>"
3211 "<BODY><H1>Error</H1>"
3212 "<P>Unable to follow the link \"%s\" - "
3214 localname
, strerror(errno
));
3215 value_
= strdup(error
);
3231 /** Resizes the help widget. */
3234 Fl_Help_View::resize(int xx
, // I - New left position
3235 int yy
, // I - New top position
3236 int ww
, // I - New width
3237 int hh
) // I - New height
3239 Fl_Boxtype b
= box() ? box() : FL_DOWN_BOX
;
3243 Fl_Widget::resize(xx
, yy
, ww
, hh
);
3245 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
3246 scrollbar_
.resize(x() + w() - scrollsize
- Fl::box_dw(b
) + Fl::box_dx(b
),
3247 y() + Fl::box_dy(b
), scrollsize
, h() - scrollsize
- Fl::box_dh(b
));
3248 hscrollbar_
.resize(x() + Fl::box_dx(b
),
3249 y() + h() - scrollsize
- Fl::box_dh(b
) + Fl::box_dy(b
),
3250 w() - scrollsize
- Fl::box_dw(b
), scrollsize
);
3256 /** Scrolls the text to the indicated position, given a named destination.
3258 \param[in] n target name
3261 Fl_Help_View::topline(const char *n
) // I - Target name
3263 Fl_Help_Target key
, // Target name key
3264 *target
; // Pointer to matching target
3270 strlcpy(key
.name
, n
, sizeof(key
.name
));
3272 target
= (Fl_Help_Target
*)bsearch(&key
, targets_
, ntargets_
, sizeof(Fl_Help_Target
),
3273 (compare_func_t
)compare_targets
);
3280 /** Scrolls the text to the indicated position, given a pixel line.
3282 If the given pixel value \p top is out of range, then the text is
3283 scrolled to the top or bottom of the document, resp.
3285 \param[in] top top line number in pixels (0 = start of document)
3288 Fl_Help_View::topline(int top
) // I - Top line number
3293 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
3294 if (size_
< (h() - scrollsize
) || top
< 0)
3296 else if (top
> size_
)
3301 scrollbar_
.value(topline_
, h() - scrollsize
, 0, size_
);
3309 /** Scrolls the text to the indicated position, given a pixel column.
3311 If the given pixel value \p left is out of range, then the text is
3312 scrolled to the left or right side of the document, resp.
3314 \param[in] left left column number in pixels (0 = left side)
3317 Fl_Help_View::leftline(int left
) // I - Left position
3322 int scrollsize
= scrollbar_size_
? scrollbar_size_
: Fl::scrollbar_size();
3323 if (hsize_
< (w() - scrollsize
) || left
< 0)
3325 else if (left
> hsize_
)
3330 hscrollbar_
.value(leftline_
, w() - scrollsize
, 0, hsize_
);
3336 /** Sets the current help text buffer to the string provided and reformats the text.
3338 The provided character string \p val is copied internally and will be
3339 freed when value() is called again, or when the widget is destroyed.
3341 If \p val is NULL, then the widget is cleared.
3344 Fl_Help_View::value(const char *val
) // I - Text to view
3353 value_
= strdup(val
);
3367 // part b in the table seems to be mac_roman - beku
3368 # define ENC(a, b) a
3371 /** Returns the character code associated with a quoted char. */
3372 static int // O - Code or -1 on error
3373 quote_char(const char *p
) { // I - Quoted string
3374 int i
; // Looping var
3379 } *nameptr
, // Pointer into name array
3380 names
[] = { // Quoting names
3381 { "Aacute;", 7, ENC(193,231) },
3382 { "aacute;", 7, ENC(225,135) },
3383 { "Acirc;", 6, ENC(194,229) },
3384 { "acirc;", 6, ENC(226,137) },
3385 { "acute;", 6, ENC(180,171) },
3386 { "AElig;", 6, ENC(198,174) },
3387 { "aelig;", 6, ENC(230,190) },
3388 { "Agrave;", 7, ENC(192,203) },
3389 { "agrave;", 7, ENC(224,136) },
3390 { "amp;", 4, ENC('&','&') },
3391 { "Aring;", 6, ENC(197,129) },
3392 { "aring;", 6, ENC(229,140) },
3393 { "Atilde;", 7, ENC(195,204) },
3394 { "atilde;", 7, ENC(227,139) },
3395 { "Auml;", 5, ENC(196,128) },
3396 { "auml;", 5, ENC(228,138) },
3397 { "brvbar;", 7, ENC(166, -1) },
3398 { "bull;", 5, ENC(149,165) },
3399 { "Ccedil;", 7, ENC(199,199) },
3400 { "ccedil;", 7, ENC(231,141) },
3401 { "cedil;", 6, ENC(184,252) },
3402 { "cent;", 5, ENC(162,162) },
3403 { "copy;", 5, ENC(169,169) },
3404 { "curren;", 7, ENC(164, -1) },
3405 { "deg;", 4, ENC(176,161) },
3406 { "divide;", 7, ENC(247,214) },
3407 { "Eacute;", 7, ENC(201,131) },
3408 { "eacute;", 7, ENC(233,142) },
3409 { "Ecirc;", 6, ENC(202,230) },
3410 { "ecirc;", 6, ENC(234,144) },
3411 { "Egrave;", 7, ENC(200,233) },
3412 { "egrave;", 7, ENC(232,143) },
3413 { "ETH;", 4, ENC(208, -1) },
3414 { "eth;", 4, ENC(240, -1) },
3415 { "Euml;", 5, ENC(203,232) },
3416 { "euml;", 5, ENC(235,145) },
3417 { "euro;", 5, ENC(128,219) },
3418 { "frac12;", 7, ENC(189, -1) },
3419 { "frac14;", 7, ENC(188, -1) },
3420 { "frac34;", 7, ENC(190, -1) },
3421 { "gt;", 3, ENC('>','>') },
3422 { "Iacute;", 7, ENC(205,234) },
3423 { "iacute;", 7, ENC(237,146) },
3424 { "Icirc;", 6, ENC(206,235) },
3425 { "icirc;", 6, ENC(238,148) },
3426 { "iexcl;", 6, ENC(161,193) },
3427 { "Igrave;", 7, ENC(204,237) },
3428 { "igrave;", 7, ENC(236,147) },
3429 { "iquest;", 7, ENC(191,192) },
3430 { "Iuml;", 5, ENC(207,236) },
3431 { "iuml;", 5, ENC(239,149) },
3432 { "laquo;", 6, ENC(171,199) },
3433 { "lt;", 3, ENC('<','<') },
3434 { "macr;", 5, ENC(175,248) },
3435 { "micro;", 6, ENC(181,181) },
3436 { "middot;", 7, ENC(183,225) },
3437 { "nbsp;", 5, ENC(' ',' ') },
3438 { "not;", 4, ENC(172,194) },
3439 { "Ntilde;", 7, ENC(209,132) },
3440 { "ntilde;", 7, ENC(241,150) },
3441 { "Oacute;", 7, ENC(211,238) },
3442 { "oacute;", 7, ENC(243,151) },
3443 { "Ocirc;", 6, ENC(212,239) },
3444 { "ocirc;", 6, ENC(244,153) },
3445 { "Ograve;", 7, ENC(210,241) },
3446 { "ograve;", 7, ENC(242,152) },
3447 { "ordf;", 5, ENC(170,187) },
3448 { "ordm;", 5, ENC(186,188) },
3449 { "Oslash;", 7, ENC(216,175) },
3450 { "oslash;", 7, ENC(248,191) },
3451 { "Otilde;", 7, ENC(213,205) },
3452 { "otilde;", 7, ENC(245,155) },
3453 { "Ouml;", 5, ENC(214,133) },
3454 { "ouml;", 5, ENC(246,154) },
3455 { "para;", 5, ENC(182,166) },
3456 { "premil;", 7, ENC(137,228) },
3457 { "plusmn;", 7, ENC(177,177) },
3458 { "pound;", 6, ENC(163,163) },
3459 { "quot;", 5, ENC('\"','\"') },
3460 { "raquo;", 6, ENC(187,200) },
3461 { "reg;", 4, ENC(174,168) },
3462 { "sect;", 5, ENC(167,164) },
3463 { "shy;", 4, ENC(173,'-') },
3464 { "sup1;", 5, ENC(185, -1) },
3465 { "sup2;", 5, ENC(178, -1) },
3466 { "sup3;", 5, ENC(179, -1) },
3467 { "szlig;", 6, ENC(223,167) },
3468 { "THORN;", 6, ENC(222, -1) },
3469 { "thorn;", 6, ENC(254, -1) },
3470 { "times;", 6, ENC(215,'x') },
3471 { "trade;", 6, ENC(153,170) },
3472 { "Uacute;", 7, ENC(218,242) },
3473 { "uacute;", 7, ENC(250,156) },
3474 { "Ucirc;", 6, ENC(219,243) },
3475 { "ucirc;", 6, ENC(251,158) },
3476 { "Ugrave;", 7, ENC(217,244) },
3477 { "ugrave;", 7, ENC(249,157) },
3478 { "uml;", 4, ENC(168,172) },
3479 { "Uuml;", 5, ENC(220,134) },
3480 { "uuml;", 5, ENC(252,159) },
3481 { "Yacute;", 7, ENC(221, -1) },
3482 { "yacute;", 7, ENC(253, -1) },
3483 { "yen;", 4, ENC(165,180) },
3484 { "Yuml;", 5, ENC(159,217) },
3485 { "yuml;", 5, ENC(255,216) }
3488 if (!strchr(p
, ';')) return -1;
3490 if (*(p
+1) == 'x' || *(p
+1) == 'X') return strtol(p
+2, NULL
, 16);
3491 else return atoi(p
+1);
3493 for (i
= (int)(sizeof(names
) / sizeof(names
[0])), nameptr
= names
; i
> 0; i
--, nameptr
++)
3494 if (strncmp(p
, nameptr
->name
, nameptr
->namelen
) == 0)
3495 return nameptr
->code
;
3501 /** The vertical scrollbar callback. */
3503 scrollbar_callback(Fl_Widget
*s
, void *)
3505 ((Fl_Help_View
*)(s
->parent()))->topline(int(((Fl_Scrollbar
*)s
)->value()));
3509 /** The horizontal scrollbar callback. */
3511 hscrollbar_callback(Fl_Widget
*s
, void *)
3513 ((Fl_Help_View
*)(s
->parent()))->leftline(int(((Fl_Scrollbar
*)s
)->value()));
3518 // End of "$Id: Fl_Help_View.cxx 8063 2010-12-19 21:20:10Z matt $".