-
Notifications
You must be signed in to change notification settings - Fork 0
/
htmldisp.h
3094 lines (2607 loc) · 107 KB
/
htmldisp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* $Header: d:/cvsroot/tads/html/htmldisp.h,v 1.3 1999/07/11 00:46:40 MJRoberts Exp $ */
/*
* Copyright (c) 1997 by Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
htmldisp.h - HTML formatter display objects
Function
The display objects are the objects that the HTML formatter
prepares from the parse tree. Display objects map directly onto
the visual display, so it's easy to take a list of display objects
and draw the document into a window.
Display objects are organized into a simple linear list. Each
object has a rectangular boundary in the drawing coordinate system.
Notes
Modified
09/08/97 MJRoberts - Creation
*/
#ifndef HTMLDISP_H
#define HTMLDISP_H
#include <limits.h>
#ifndef TADSHTML_H
#include "tadshtml.h"
#endif
#ifndef HTMLATTR_H
#include "htmlattr.h"
#endif
#ifndef HTMLURL_H
#include "htmlurl.h"
#endif
#ifndef HTMLSYS_H
#include "htmlsys.h"
#endif
/* ------------------------------------------------------------------------ */
/*
* Memory heap source ID. For each memory block we allocate in
* CHtmlDisp::operator new, we keep track of whether the memory came
* from the formatter heap or from the system heap.
*/
enum htmldisp_heapid_t
{
HTMLDISP_HEAPID_SYS = 0, /* system heap */
HTMLDISP_HEAPID_FMT = 1 /* formatter heap */
};
/* ------------------------------------------------------------------------ */
/*
* Whitespace search object. This lets us search a series of display
* items to find and remove trailing whitespace.
*/
class CHtmlDisp_wsinfo
{
public:
CHtmlDisp_wsinfo()
{
/* we haven't found any whitespace yet */
last_ws_disp_ = 0;
}
/*
* Scan for and remove trailing whitespace. We'll start with the
* given display item and scan ahead to (but not including) 'nxt', or
* the end of the list if 'nxt' is null. We'll trim off any
* contiguous run of whitespace we find at the end of the display
* list.
*/
void remove_trailing_whitespace(class CHtmlSysWin *win,
class CHtmlDisp *disp,
class CHtmlDisp *nxt);
/*
* Hide trailing whitespace. This doesn't actually remove any
* trailing whitespace, but merely suppresses the display of trailing
* whitespace on a line.
*/
void hide_trailing_whitespace(class CHtmlSysWin *win,
class CHtmlDisp *disp,
class CHtmlDisp *nxt);
/*
* For the display item's use: remember a position in the current
* display item as the start of the trailing whitespace in this
* item. If we find that this is the last item with text, we'll
* come back here to remove trailing whitespace later.
*/
void set_ws_pos(class CHtmlDisp *disp, void *pos)
{
/* if we don't have a previous position already, set this one */
if (last_ws_disp_ == 0)
{
last_ws_disp_ = disp;
last_ws_pos_ = pos;
}
}
/*
* For the display item's use: clear the trailing whitespace
* position. If we find that the current display item doesn't have
* any whitespace, but it has something that negates the "trailing"
* status of any previous whitespace (such as more non-whitespace
* text), we need to forget about the previous whitespace, since
* it's not trailing after all.
*/
void clear_ws_pos()
{
last_ws_disp_ = 0;
}
private:
/* last display item containing whitespace */
class CHtmlDisp *last_ws_disp_;
/*
* position of whitespace in last display item; this context
* information is meaningful only to the display item
*/
void *last_ws_pos_;
};
/* ------------------------------------------------------------------------ */
/*
* Display site implementation. This class can be multiply inherited into
* a CHtmlDisp subclass to implement a CHtmlSysImageDisplaySite interface
* on the display object.
*
* To use this mix-in with a CHtmlDisp subclass, the subclass must do the
* following:
*
* 1. Add this class to its base class list
*
* 2. Explicitly call our constructor from the subclass constructor,
* passing us the window object, the address of the 'pos_' record from the
* subclass, and the image object.
*
* 3. On a call to the subclass's virtual unset_win() method, explicitly
* call our unset_win() method.
*
* 4. On a call to the subclass's virtual cancel_playback() method,
* explicitly call our cancel_playback() method.
*/
class CHtmlDispDisplaySite: public CHtmlSysImageDisplaySite
{
public:
/* create */
CHtmlDispDisplaySite(class CHtmlSysWin *win, const CHtmlRect *pos,
class CHtmlResCacheObject *image);
/* destroy */
virtual ~CHtmlDispDisplaySite();
/* unset our window reference */
void unset_win();
/* cancel playback - if our image is animated, we'll halt it */
void cancel_playback();
/* get/set the current image being displayed in the site */
class CHtmlResCacheObject *get_site_image() const { return site_image_; }
void set_site_image(class CHtmlResCacheObject *image);
/* -------------------------------------------------------------------- */
/*
* CHtmlSysImageDisplaySite interface implementation
*/
/* invalidate an area of the display site */
virtual void dispsite_inval(unsigned int x, unsigned int y,
unsigned int width, unsigned int height);
/* set a timer event */
virtual void dispsite_set_timer(unsigned long delay_ms,
class CHtmlSysImageAnimated *image);
/* cancel timer events */
virtual void dispsite_cancel_timer(class CHtmlSysImageAnimated *image);
protected:
/* timer callback */
static void img_timer_cb(void *ctx);
/* the position record from the CHtmlDisp object */
const CHtmlRect *posp_;
/* the window we're associated with */
class CHtmlSysWin *win_;
/*
* our timer - this is used if the object being displayed requests
* timer operations from its display site (i.e., us)
*/
class CHtmlSysTimer *timer_;
/* the image we're displaying */
class CHtmlResCacheObject *site_image_;
};
/* ------------------------------------------------------------------------ */
/*
* Basic display object
*/
class CHtmlDisp
{
public:
CHtmlDisp() { nxt_ = 0; line_id_bit_ = 0; }
virtual ~CHtmlDisp() { }
/*
* Unset the window - receive notification that the window is about to
* be deleted. Most display items don't keep a reference to their
* window, so this does nothing by default. This can be overridden in
* subclasses that keep a reference to the containing window, so they
* know the reference is not usable after this point.
*/
virtual void unset_win() { }
/*
* Cancel playback. This should stop playback of any active media in
* the display item; for example, animations should be halted.
*/
virtual void cancel_playback() { }
/* memory allocator - use the formatter for memory management */
static void *operator new(size_t siz, class CHtmlFormatter *formatter);
static void operator delete(void *ptr);
/*
* Get/set the line ID. The formatter needs to be able to tell when
* two adjacent items in the display list are in different lines.
* To accomplish this, it tags each item with a line ID; upon
* starting a new line, it increments the ID. If the line ID's of
* two adjacent items are the same, the items are on the same line,
* otherwise they're on different lines. Note that since we only
* need to distinguish adjacent items, we don't need a lot of
* precision in the line ID; we keep more than one bit, though, to
* allow for line ID's to be updated in the formatter *too often*
* (more than once per line), since it's often difficult to
* increment the line ID exactly once per line.
*/
int get_line_id() const { return line_id_bit_; }
void set_line_id(int id) { line_id_bit_ = id; }
/*
* Draw the object in a window. If the selection range intersects
* the item, the appropriate portion should be drawn selected, if it
* has a special selected appearance. If 'clicked' is true, it
* means the mouse button is being held down with the mouse over the
* item, so the item should be drawn with any appropriate feedback.
*/
virtual void draw(class CHtmlSysWin *win,
unsigned long sel_start, unsigned long sel_end,
int clicked) = 0;
/*
* Get the cursor type that should be used when the cursor is over
* this item. Returns the standard arrow cursor by default.
*/
virtual Html_csrtype_t
get_cursor_type(class CHtmlSysWin *, class CHtmlFormatter *,
int /*x*/, int /*y*/, int /*more_mode*/) const
{ return HTML_CSRTYPE_ARROW; }
/* delete this item and all following items in its list */
static void delete_list(CHtmlDisp *head);
/*
* Measure the native width of this display object. This is the
* amount of space that the object would take up without any
* external constraints. For text, this is the width of the text in
* the current font; for a picture, it's the width of the graphic or
* the declared size.
*/
virtual int measure_width(class CHtmlSysWin *win) = 0;
/*
* Get the amount of space this item needs above the text baseline
* for displaying text. Generally, items that don't display text
* should return zero, since they don't contribute to the text area.
*/
virtual int get_text_height(class CHtmlSysWin *) { return 0; }
/*
* Get the overall vertical space needs for the item. text_height
* is the vertical space above the text baseline used by the tallest
* text item. *above_base is the amount of space this item needs
* above the text baseline, and *total is the amount of vertical
* space this item needs overall.
*/
virtual void get_vertical_space(class CHtmlSysWin *win, int text_height,
int *above_base, int *below_base,
int *total) = 0;
/*
* Set my position, given the top of the area for the current line,
* the total height of the line, the offset of the text baseline from
* the top of the line area, and the maximum height of the text in the
* line. The default implementation simply sets this item aligned at
* the top of the line.
*/
virtual void set_line_pos(class CHtmlSysWin *, int left, int top,
int /*total_height*/, int /*text_base_offset*/,
int /*max_text_height*/)
{
pos_.offset(left - pos_.left, top - pos_.top);
}
/*
* Receive notification that the item has been moved from the deferred
* list to the normal display list. Only certain types of display
* items are deferred, so this default implementation does nothing and
* must be overridden for deferrable items.
*
* line_spacing is the vertical whitespace above the current line; the
* item should generally be vertically offset by this amount.
*/
virtual void format_deferred(class CHtmlSysWin *,
class CHtmlFormatter *,
long /*line_spacing*/) { }
/* get next object in display list */
CHtmlDisp *get_next_disp() const { return nxt_; }
/*
* Find the line break position, given the amount of space
* remaining in the current line. If the current display object can
* be broken into two pieces such that the first piece fits into the
* availble space but adding the second piece would not, we will
* break it into two pieces, creating a new display object for the
* second piece and linking the new object into the list, and return
* the new object. If the current object fits in its entirety,
* we'll see if we can break within the next object. prev_char is
* the last character of text from the previous display object, or
* zero if the previous object did not contain text; if two text
* objects are adjacent, they'll use this in determining if a line
* break can be inserted between them. If prv and prv_pos are
* non-null, and we find that this object won't fit and we can't
* break before it, we'll call the previous object's
* find_line_break_prv method to tell it that it should break at the
* previous break position it found.
*/
virtual CHtmlDisp *find_line_break(class CHtmlFormatter *formatter,
class CHtmlSysWin *win,
long space_avail,
class CHtmlLineBreak *break_pos);
/*
* Do a break at a position we previously found. 'break_pos' is the
* break position information that we previously set up.
*/
virtual CHtmlDisp *do_line_break(class CHtmlFormatter *formatter,
class CHtmlSysWin *win,
class CHtmlLineBreak *break_pos);
/*
* Do a break to the right of a position we previously found, skipping
* leading spaces on the new line. This is called when the break
* position was in a preceding item, but it found that it had only
* whitespace after the break position; we should simply break at the
* start of this item, or wherever the next non-whitespace can be
* found.
*/
virtual CHtmlDisp *do_line_break_skipsp(class CHtmlFormatter *formatter,
class CHtmlSysWin *win);
/*
* Find the location of trailing whitespace in the display item. If
* the item doesn't have any trailing whitespace, but it does have
* text or something else that would prevent any previous whitespace
* from being the trailing whitespace, this should clear the
* whitespace position in the search state. If we have trailing
* whitespace, this should set the position in the search state
* object so that we can come back and remove this whitespace. By
* default, this routine does nothing, since default display items
* don't affect the text stream.
*/
virtual void find_trailing_whitespace(class CHtmlDisp_wsinfo *) { }
/*
* Remove trailing whitespace that we previously found with a call to
* find_trailing_whitespace().
*
* 'pos' is the position of the whitespace that this object set on the
* previous call to find_trailing_whitespace(). If 'pos' is null, it
* means that the start of the run of whitespace was in an earlier
* item in the list, in which case this item must be all whitespace
* and can be made completely invisible.
*/
virtual void remove_trailing_whitespace(class CHtmlSysWin *,
void * /*pos*/) { }
/*
* hide trailing whitespace - this doesn't actually delete the
* whitespace, but merely prevents it from being displayed visually
*/
virtual void hide_trailing_whitespace(class CHtmlSysWin *,
void * /*pos*/) { }
/*
* Measure the width of the trailing whitespace, if any.
*/
virtual long measure_trailing_ws_width(class CHtmlSysWin *) const
{ return 0; }
/*
* Measure the metrics of this item for use in a table cell.
* Measures this item's contribution to the minimum and maximum
* width of items in the cell.
*/
virtual void measure_for_table(class CHtmlSysWin *win,
class CHtmlTableMetrics *metrics);
/*
* Measure the metrics of this item for use in a banner. Measurs
* the item's contribution to the minimum and maximum width of the
* items within the banner, so that we can determine the proper
* horizontal extent of a vertical banner. This does almost exactly
* the same thing as measure_for_table, and in most cases simply
* calls that method to carry out the work. However, in a few
* cases, we want to do something different; in particular, for tags
* that can be based on a percentage of the window size, we don't
* make a contribution to the banner sizes at all, since we won't
* know the window size until we know the banner size, hence we
* can't guess about our contribution.
*/
virtual void measure_for_banner(class CHtmlSysWin *win,
class CHtmlTableMetrics *metrics)
{
/* for most cases, simply do the same thing as we'd do in a table */
measure_for_table(win, metrics);
}
/* get/set the position of this display object */
CHtmlRect get_pos() const { return pos_; }
void set_pos(CHtmlRect *pos) { pos_ = *pos; }
void set_pos(int left, int top, int right, int bottom)
{ pos_.set(left, top, right, bottom); }
/*
* Insert me after another display object in a list. This can only
* be used to add a single item.
*/
void add_after(CHtmlDisp *prv)
{ nxt_ = prv->nxt_; prv->nxt_ = this; }
/*
* Insert a list after another display object in a list. This adds
* me and any other items following me in my list.
*/
void add_list_after(CHtmlDisp *prv);
/* make me the end of my chain by forgetting my next item */
void clear_next_disp() { nxt_ = 0; }
/* invalidate my area on the display */
void inval(class CHtmlSysWin *win);
/*
* Invalidate my area on the display, limiting the invalidation to
* the given selection range. By default, we'll just invalidate our
* area. Some subclasses (text, in particular) should override this
* to limit the invalidation to the selected range.
*/
virtual void inval_range(class CHtmlSysWin *win,
unsigned long start_ofs, unsigned long end_ofs)
{
/* by default, invalidate our entire area */
inval(win);
}
/*
* Invalidate my area on the display only if I'm a link. By
* default, I won't do anything, since default dispaly items aren't
* linked.
*/
virtual void inval_link(class CHtmlSysWin *) { }
/* invalidate if appropriate for a change in the link 'clicked' status */
virtual void on_click_change(class CHtmlSysWin *win)
{ inval(win); }
/*
* Get my offset in the linear array containing the text stream.
* If this item doesn't contain text, return the text offset of the
* next item in the display list. By default, items don't contain
* any text.
*/
virtual unsigned long get_text_ofs() const
{
return (nxt_ == 0 ? ULONG_MAX : nxt_->get_text_ofs());
}
/*
* Determine if the item contains a given text offset. By default,
* we'll simply return false, since non-text items don't contain any
* text offsets.
*/
virtual int contains_text_ofs(unsigned long /*ofs*/) const
{
return FALSE;
}
/* determine if I intersect the given text offset range */
virtual int overlaps_text_range(unsigned long l, unsigned long r) const
{
return get_text_ofs() >= l && get_text_ofs() <= r;
}
/*
* Determine if the item is past a given text offset. If there's no
* next item, considers this item part of the range (hence returns
* false).
*
* If there's a next item, we return true if the next item's offset is
* greater than the given offset. If the next item's offset is less
* than the given offset, we're obviously not beyond the offset because
* the next item is still within the range, hence we must return false.
* If the next item's offset is equal to the given offset, we haven't
* yet reached that offset, so we want to return false in this case as
* well.
*/
virtual int is_past_text_ofs(unsigned long ofs) const
{
return nxt_ == 0 ? FALSE : (nxt_->get_text_ofs() > ofs);
}
/*
* Get the position of a character within this item. txtofs is the
* offset within the linear text array for the text stream of the
* character we're interested in. By default, we don't have any
* text, so we'll just return our own position.
*/
virtual CHtmlPoint get_text_pos(class CHtmlSysWin *,
unsigned long /*txtofs*/)
{
return CHtmlPoint(pos_.left, pos_.top);
}
/*
* Get the text offset of a character, given its position. Since
* basic objects don't contain text, this will simply return the
* object's text offset by default.
*/
virtual unsigned long find_textofs_by_pos(class CHtmlSysWin *,
CHtmlPoint) const
{ return get_text_ofs(); }
/*
* Append my text to a string buffer. By default, this does
* nothing, since default objects have no text.
*/
virtual void add_text_to_buf(CStringBuf *) const { }
/*
* add my text to a buffer, clipping the text to the given starting
* and ending offsets
*/
virtual void add_text_to_buf_clip(CStringBuf *buf,
unsigned long startofs,
unsigned long endofs) const { }
/*
* Get the hyperlink object associated with the item. Returns null if
* this item isn't hyperlinked. If the item is associated with a
* hypertext link, this returns the link object.
*
* The base display item isn't linkable itself, but it can inherit a
* division link from an enclosing DIV. So, by default, we just look
* for an inherited DIV link.
*/
virtual class CHtmlDispLink *get_link(class CHtmlFormatter *formatter,
int /*x*/, int /*y*/) const;
/*
* Get the link I inherit from my enclosing DIV, if any. This looks
* for the innermost enclosing DIV that has an associated link.
*/
class CHtmlDispLinkDIV *find_div_link(class CHtmlFormatter *formatter)
const;
/*
* Get the container link. If this item is part of a group of items
* linked to a containing <A> tag, this returns the containing <A>
* link. This ignores any image map or other internal structure.
*/
virtual class CHtmlDispLink *get_container_link() const
{ return 0; }
/*
* Determine if this item can qualify as an inexact hit when seeking
* the item nearest a mouse location. Since inexact hits are used
* to determine text selection ranges, we only allow inexact matches
* of text items.
*/
virtual int allow_inexact_hit() const { return FALSE; }
/*
* Determine if this item is in the background as far as mouse
* clicks are concerned. If this returns true, we'll ignore this
* object for the purposes of locating a mouse click, and instead
* look further in the list for an overlaid object that contains the
* click. Table cells use this, for example, so that mouse clicks
* go to the cell contents rather than to the cell object itself.
*/
virtual int is_in_background() const { return FALSE; }
/*
* Get my ALT text, if I have any. Some object types, such as
* IMG's, have an alternative textual representation that they can
* display when a textual description is needed.
*/
virtual const textchar_t *get_alt_text() const { return 0; }
protected:
/*
* Basic deferred formatting implementation for floating margin items.
* The subclass must calculate the height and provide the margin
* alignment, and we'll set things up in the formatter accordingly.
*/
void basic_format_deferred(class CHtmlSysWin *win,
class CHtmlFormatter *formatter,
long line_spacing,
HTML_Attrib_id_t align, long height);
/* position */
CHtmlRect pos_;
private:
/* next object in the list */
CHtmlDisp *nxt_;
/* line ID bit */
int line_id_bit_ : 8;
};
/* ------------------------------------------------------------------------ */
/*
* A display item representing a DIV (division) tag. This doesn't display
* anything; it's an internal placeholder to keep track of the contents of
* the division.
*/
class CHtmlDispDIV: public CHtmlDisp
{
public:
CHtmlDispDIV(unsigned long startofs, unsigned long endofs)
{
/* remember the text range */
startofs_ = startofs;
endofs_ = endofs;
/* we don't know our parent DIV yet */
parent_div_ = 0;
/* we don't have a DIV-level hyperlink */
div_link_ = 0;
/* we don't know the last display item in the DIV yet */
div_tail_ = 0;
}
/* get our associated hyperlink object */
virtual class CHtmlDispLink *get_link(class CHtmlFormatter *formatter,
int x, int y) const;
/* get our start/end offset */
unsigned long get_start_ofs() const { return startofs_; }
unsigned long get_end_ofs() const { return endofs_; }
/* we have no visual presence, so there's nothing to draw */
virtual void draw(class CHtmlSysWin *, unsigned long, unsigned long,
int clicked)
{ }
/* we don't take up any space */
virtual int measure_width(class CHtmlSysWin *) { return 0; }
virtual void get_vertical_space(class CHtmlSysWin *, int,
int *above_base, int *below_base,
int *total)
{ *above_base = *below_base = *total = 0; }
/* get/set the parent DIV */
CHtmlDispDIV *get_parent_div() const { return parent_div_; }
void set_parent_div(CHtmlDispDIV *par) { parent_div_ = par; }
/* get/set the DIV-level hyperlink object */
class CHtmlDispLinkDIV *get_div_link() const { return div_link_; }
void set_div_link(class CHtmlDispLinkDIV *link) { div_link_ = link; }
/*
* Get/set the last display item in the DIV. The formatter gives us
* this information when building the display list; the DIV covers
* everything from the next item after the DIV to this last item.
*/
CHtmlDisp *get_div_tail() const { return div_tail_; }
void set_div_tail(CHtmlDisp *tail) { div_tail_ = tail; }
private:
/* the range of text offsets this division covers */
unsigned long startofs_;
unsigned long endofs_;
/* the last display item in the DIV */
CHtmlDisp *div_tail_;
/* the parent DIV display item */
CHtmlDispDIV *parent_div_;
/* our DIV-level hyperlink object */
class CHtmlDispLinkDIV *div_link_;
};
/* ------------------------------------------------------------------------ */
/*
* <NOBR> flag. This doesn't actually display anything; it's just a flag
* that we can insert into the display stream to tell us that word-wrapping
* is being enabled or disabled. This lets us take the wrapping mode into
* effect when calculating widths.
*/
class CHtmlDispNOBR: public CHtmlDisp
{
public:
CHtmlDispNOBR(int nobr) { nobr_ = nobr; }
/*
* Measure for a table or banner. We don't take up any space, but we
* do need to set the current wrapping status in the metrics.
*/
void measure_for_table(class CHtmlSysWin *win,
class CHtmlTableMetrics *metrics);
/* we don't have any on-screen appearance */
void draw(class CHtmlSysWin *, unsigned long, unsigned long, int) { }
/* we don't take up any space */
int measure_width(class CHtmlSysWin *) { return 0; }
void get_vertical_space(class CHtmlSysWin *, int,
int *above_base, int *below_base, int *total)
{ *above_base = *below_base = *total = 0; }
private:
/* are we in a <NOBR> section? */
int nobr_;
};
/* ------------------------------------------------------------------------ */
/*
* Link object. This item doesn't actually have any display presence,
* but is used to store the link information used by all of the linkable
* objects within a <A> ... </A> group. Each linkable object refers
* back to this object for their link information.
*
* The link object keeps track of the first and last display items
* belonging to the group, so that group-wide operations (for example,
* highlighting all of the items in the group) can be done.
*
* Although this object doesn't have a display presence, it's
* implemented as a display item to simplify memory management - it goes
* in the display list along with all of the other display items, so it
* will be deleted along with them.
*/
/* clicked states */
const int CHtmlDispLink_none = 0x00; /* not clicked/hovering */
const int CHtmlDispLink_clicked = 0x01; /* mouse is being clicked */
const int CHtmlDispLink_hover = 0x02; /* mouse is hovering */
const int CHtmlDispLink_divhover = 0x04; /* mouse is hovering over DIV */
const int CHtmlDispLink_clickedoff = 0x08; /* mouse is clicked but off link */
class CHtmlDispLink: public CHtmlDisp
{
public:
CHtmlDispLink(int style, int append, int noenter, CHtmlUrl *href,
const textchar_t *title, size_t titlelen)
{
/* remember our style */
style_ = style;
append_ = append;
noenter_ = noenter;
/* remember our link information */
if (href != 0)
{
href_.set_url(href);
nohref_ = FALSE;
}
else
nohref_ = TRUE;
title_.set(title, titlelen);
/* contained items will be added later */
first_ = last_ = 0;
/* not yet clicked */
clicked_ = FALSE;
/* presume we're not using special hover settings */
use_hover_fg_ = use_hover_bg_ = hover_underline_ = FALSE;
}
/*
* Is this a "clickable" link? A clickable link is one with an active
* UI presence, where clicking on the link activates the hyperlink. If
* a link isn't clickable, the UI should treat a click on the link as
* though it were a click on an ordinary, unlinked item.
*/
virtual int is_clickable_link() const { return TRUE; }
/* set hover foreground color */
void set_hover_fg(HTML_color_t color)
{
hover_fg_ = color;
use_hover_fg_ = TRUE;
}
/* set hover background color */
void set_hover_bg(HTML_color_t color)
{
hover_bg_ = color;
use_hover_bg_ = TRUE;
}
/* set HOVER=UNDERLINE */
void set_hover_underline() { hover_underline_ = TRUE; }
/*
* get the hover foreground/background color - returns true if the
* color is set, false if not
*/
int get_hover_fg(HTML_color_t *cp) const
{
*cp = hover_fg_;
return use_hover_fg_;
}
int get_hover_bg(HTML_color_t *cp) const
{
*cp = hover_bg_;
return use_hover_bg_;
}
/* add an underline while hovering? */
int hover_underline() const { return hover_underline_; }
/* links have no effect on line breaking, since they're invisible */
CHtmlDisp *find_line_break(class CHtmlFormatter *, class CHtmlSysWin *,
long, class CHtmlLineBreak *)
{ return 0; }
/* add an item linked to this item */
void add_link_item(CHtmlDisp *item)
{
/* if we don't yet have a first item, remember it as the first */
if (first_ == 0)
first_ = item;
/* it's the last one we've heard about so far */
last_ = item;
}
/* get the first and last item in our list */
class CHtmlDisp *get_first_link_item() const { return first_; }
class CHtmlDisp *get_last_link_item() const { return last_; }
/* get the link style (LINK_STYLE_xxx) */
int get_style() const { return style_; }
/*
* Check if the link's contents are to be rendered in plain style
* (i.e., not using any special link rendering style). The link is
* drawn plain if its style is PLAIN, or its style is HIDDEN and the
* mouse isn't currently over or clicking on the link.
*/
int is_plain() const
{
return (style_ == LINK_STYLE_PLAIN
|| (style_ == LINK_STYLE_HIDDEN
&& !(clicked_
& (CHtmlDispLink_hover | CHtmlDispLink_clicked))));
}
/* check if the link is shown even when links are globally hidden */
int is_forced() const { return style_ == LINK_STYLE_FORCED; }
/* get current clicked state */
int get_clicked() const { return clicked_; }
/*
* Set clicked state, and invalidate all items linked to me.
* clicked is a combination of the CHtmlDispLink_xxx states (see
* above).
*/
virtual void set_clicked(class CHtmlSysWin *win, int clicked);
/*
* Set the clicked state for my sub-items only. This doesn't notify
* our DIV.
*/
void set_clicked_sub(class CHtmlSysWin *win, int clicked);
/*
* CHtmlDisp Overrides - mostly these are trivial implementations,
* since we don't do much as a display item
*/
/* no display presence, so drawing is trivial */
void draw(class CHtmlSysWin *, unsigned long, unsigned long, int) { }
/* no display area */
int measure_width(class CHtmlSysWin *) { return 0; }
void measure_for_table(CHtmlSysWin *, CHtmlTableMetrics *) { }
int get_text_height(class CHtmlSysWin *) { return 0; }
void get_vertical_space(class CHtmlSysWin *, int, int *above_base,
int *below_base, int *total)
{
*above_base = 0;
*below_base = 0;
*total = 0;
}
/* invalidate if I'm a link - I am, so invalidate me */
void inval_link(class CHtmlSysWin *win) { inval(win); }
/* get my command-entering attributes */
int get_append() const { return append_; }
int get_noenter() const { return noenter_; }
public:
/*
* Link information. If nohref_ is set, it means that the link has
* no HREF - this is appropriate for AREA tags with the NOHREF
* attribute.
*/
CHtmlUrl href_;
int nohref_ : 1;
CStringBuf title_;
protected:
/* first and last display items linked to this item */
CHtmlDisp *first_;
CHtmlDisp *last_;
/* hover colors, foreground and background */
HTML_color_t hover_fg_;
HTML_color_t hover_bg_;
/*
* flag indicating that I'm in the clicked state - i.e., the mouse
* button was clicked down over this item, the mouse is still over
* this item, and the mouse button is still being held down
*/
int clicked_;
/* link style (LINK_STYLE_xxx) */
unsigned int style_ : 2;
/*
* NOENTER - true means that we don't automatically enter the
* command, but allow the player to continue editing after adding
* our HREF
*/
int noenter_ : 1;
/*
* APPEND - true means that we append our HREF to the command line
* under construction, rather than clearing any existing command
*/
int append_ : 1;
/* use the hover foreground/background colors */
int use_hover_fg_ : 1;
int use_hover_bg_ : 1;
/*
* HOVER=UNDERLINE - true means that we add an underline when the mouse
* is hovering on this link; false means that we leave the underlining
* status as it is while hovering.
*/
int hover_underline_ : 1;
};
/*
* A special hyperlink object for a DIV tag. A DIV link isn't a real link;
* it's just a proxy for the links within the DIV group.
*/
class CHtmlDispLinkDIV: public CHtmlDispLink
{
public:
/*