Subversion Repositories Kolibri OS

Rev

Rev 9898 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9896 akron1 1
(*
9898 akron1 2
    Copyright 2016-2023 Anton Krotov
9896 akron1 3
 
4
    This file is part of fb2read.
5
 
6
    fb2read is free software: you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation, either version 3 of the License, or
9
    (at your option) any later version.
10
 
11
    fb2read is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with fb2read. If not, see .
18
*)
19
 
20
MODULE DOM;
21
 
22
IMPORT XML, SU := SysUtils, S := Strings, Font, Window, G := Graph, LibImg,
9898 akron1 23
       RF := ReadFile, File, Ini, K := KOSAPI, sys := SYSTEM,
9896 akron1 24
       V := Vector, Cursor, box_lib, tables, Search;
25
 
26
 
27
CONST
28
 
29
  BACK_COLOR*       = 0;
30
  TEXT_COLOR*       = 1;
31
  ITALIC_COLOR*     = 2;
32
  LINK_COLOR*       = 3;
33
  VISITED_COLOR*    = 4;
34
  CLICKED_COLOR*    = 5;
35
 
36
  CellPadding       = 5;
37
 
38
 
39
TYPE
40
 
41
  TSettings* = RECORD
42
 
43
    Colors*   : ARRAY 6 OF INTEGER;
44
    FontSize* : INTEGER;
45
    TwoCol*   : BOOLEAN;
46
    b_pict*   : BOOLEAN;
47
 
48
    PADDING*   : RECORD Left, Right, Top*, Bottom, ColInter, LRpc*, CInt*: INTEGER END;
49
 
50
    PARAGRAPH*,
51
    EPIGRAPH*,
52
    LEVEL,
53
    SUB,
54
    SUP,
55
    InterLin*,
56
    Picture*,
9898 akron1 57
    picture_fsize*,
9896 akron1 58
    SpaceW: INTEGER
59
 
60
  END;
61
 
62
  StackItem = POINTER TO TStackItem;
63
 
64
  TStackItem = RECORD (XML.DESC_ELEMENT)
65
 
66
    body : XML.TAG;
67
    Ycur : INTEGER;
68
    d    : REAL
69
 
70
  END;
71
 
72
 
73
VAR
74
 
75
  Settings* : TSettings;
76
  Canvas_X, Canvas_Y: INTEGER;
9898 akron1 77
  ColLeft, ColRight: Window.tRect;
9896 akron1 78
 
79
  Ymin, Ymax, Ycur : INTEGER;
80
 
81
  X, Y, W, LineH, W1, W2: INTEGER;
82
 
83
  epigraph  : INTEGER;
84
  sup, sub  : INTEGER;
85
  ref_depth : INTEGER;
86
  align     : INTEGER;
87
  code      : INTEGER;
88
  strong    : INTEGER;
89
  italic    : INTEGER;
90
  strike    : INTEGER;
91
  refer     : INTEGER;
92
 
93
  Text      : ARRAY 100000 OF XML.TEXT;
94
  TextCount : INTEGER;
95
 
96
  Lines: INTEGER;
97
 
98
  description, contents, mainbody, body, ref, cover, clickRef, hoverRef: XML.TAG;
99
 
100
  MainBody: BOOLEAN;
101
 
102
  f_stk, b_stk, vis_ref: XML.LIST;
103
 
104
  FilePath, FileName: S.STRING;
105
 
106
  done, last, resized, loaded*, mouseDown: BOOLEAN;
107
 
108
  Stack*: ARRAY 1000000 OF CHAR;
109
 
110
  Ycont: INTEGER;
111
 
112
  history: File.FS;
113
 
114
  references: V.VECTOR;
115
  cursor: INTEGER;
116
 
117
  fsize2, chksum: INTEGER;
118
 
119
  sb: box_lib.scrollbar;
120
  urlstr* : S.STRING;
121
  DrawStatus, DrawToolbar: PROCEDURE;
9912 akron1 122
  win_size_x, win_size_y: INTEGER;
9896 akron1 123
 
124
 
125
PROCEDURE PushRef(ref: XML.TAG);
126
VAR item: StackItem;
127
BEGIN
128
  NEW(item);
129
  item.body := ref;
130
  XML.AddItem(vis_ref, item);
131
END PushRef;
132
 
133
 
134
PROCEDURE Push(VAR stk: XML.LIST);
135
VAR item: StackItem;
136
BEGIN
137
  NEW(item);
138
  item.body := body;
139
  item.Ycur := Ycur;
140
  XML.AddItem(stk, item);
141
  IF body = contents THEN
142
    Ycont := Ycur
143
  END
144
END Push;
145
 
146
 
147
PROCEDURE Pop(VAR stk: XML.LIST);
148
VAR item : StackItem;
149
BEGIN
150
  item := stk.last(StackItem);
151
  IF item # NIL THEN
152
    body := item.body;
153
    Ymin := body.Ymin;
154
    Ymax := body.Ymax;
155
    Ycur := item.Ycur;
156
    XML.DelLastItem(stk)
157
  END
158
END Pop;
159
 
160
 
161
PROCEDURE Clear(VAR stk: XML.LIST);
162
BEGIN
163
  REPEAT
164
    XML.DelLastItem(stk)
165
  UNTIL stk.last = NIL
166
END Clear;
167
 
168
 
169
PROCEDURE AddToLine(text: XML.TEXT);
170
BEGIN
171
  Text[TextCount] := text;
172
  INC(TextCount)
173
END AddToLine;
174
 
175
 
176
PROCEDURE Epigraph(): INTEGER;
177
  RETURN ORD(epigraph > 0) * Settings.EPIGRAPH
178
END Epigraph;
179
 
180
 
181
PROCEDURE SpaceWidth(): INTEGER;
182
VAR Result: INTEGER;
183
BEGIN
184
  IF code > 0 THEN
185
    Result := Font.MonoWidth()
186
  ELSE
187
    Result := Settings.SpaceW
188
  END
189
  RETURN Result
190
END SpaceWidth;
191
 
192
 
193
PROCEDURE Trim;
194
VAR n: INTEGER;
195
BEGIN
196
  IF TextCount > 0 THEN
197
    n := TextCount - 1;
198
    WHILE (n >= 0) & (Text[n] IS XML.SPACE) DO
199
      Text[n].width := -1;
200
      DEC(n)
201
    END;
202
    TextCount := n + 1
203
  END
204
END Trim;
205
 
206
 
207
PROCEDURE Align;
208
VAR
209
  i, n, sp, d, quo, rem, x: INTEGER;
210
  text: XML.TEXT;
211
BEGIN
212
  IF (TextCount > 0) & (code = 0) & (align # 3) THEN
213
    sp := 0;
214
    Trim;
215
    n := TextCount - 1;
216
    IF n >= 0 THEN
217
      d := W - Text[n].X - Text[n].width
218
    END;
219
    IF align = 1 THEN
220
      x := (d + Text[0].X) DIV 2
221
    ELSIF align = 2 THEN
222
      x := d + Text[0].X
223
    ELSIF align = 0 THEN
224
      x := Text[0].X;
225
      FOR i := 0 TO n DO
226
        IF Text[i] IS XML.SPACE THEN
227
          INC(sp)
228
        END
229
      END;
230
      IF sp > 0 THEN
231
        quo := d DIV sp;
232
        rem := d MOD sp;
233
        FOR i := 0 TO n DO
234
          IF Text[i] IS XML.SPACE THEN
235
            text := Text[i];
236
            text.width := text.width + quo + ORD(rem > 0);
237
            DEC(rem)
238
          END
239
        END
240
      END
241
    END;
242
    FOR i := 0 TO n DO
243
      text := Text[i];
244
      text.X := x;
245
      INC(x, text.width)
246
    END
247
  END
248
END Align;
249
 
250
 
251
PROCEDURE NewLine;
252
BEGIN
253
  IF align # 0 THEN
254
    Align
255
  END;
256
  X := Epigraph();
257
  INC(Y, LineH);
258
  TextCount := 0
259
END NewLine;
260
 
261
 
262
PROCEDURE Sup(open: BOOLEAN);
263
BEGIN
264
  IF open THEN
265
    IF sup = 0 THEN
266
      DEC(Y, Settings.SUP)
267
    END;
268
    INC(sup)
269
  ELSE
270
    DEC(sup);
271
    IF sup = 0 THEN
272
      INC(Y, Settings.SUP)
273
    END
274
  END
275
END Sup;
276
 
277
 
278
PROCEDURE Sub(open: BOOLEAN);
279
BEGIN
280
  IF open THEN
281
    IF sub = 0 THEN
282
      INC(Y, Settings.SUB)
283
    END;
284
    INC(sub)
285
  ELSE
286
    DEC(sub);
287
    IF sub = 0 THEN
288
      DEC(Y, Settings.SUB)
289
    END
290
  END
291
END Sub;
292
 
293
 
294
PROCEDURE Split(word: XML.WORD);
295
VAR
296
  i, n, max, len: INTEGER;
297
  c: CHAR;
298
  rem: XML.WORD;
299
BEGIN
300
  WHILE Font.TextWidth(word.value, max) <= W DO
301
    INC(max)
302
  END;
303
  DEC(max);
304
  IF max = 0 THEN
305
    max := 1
306
  END;
307
  i := 0;
308
  n := 0;
309
  len := word.value.last - word.value.first + 1;
310
  WHILE (n <= max) & (i < len) DO
311
    c := S.GetChar(word.value, i);
312
    INC(n);
313
    IF (80X <= c) & (c <= 0BFX) THEN
314
      DEC(n)
315
    END;
316
    INC(i)
317
  END;
318
  IF n > max THEN
319
    DEC(i);
320
    rem := XML.CreateWord();
321
    rem^ := word^;
322
    rem.value.first := word.value.first + i;
323
    word.next := rem;
324
    word.value.last := rem.value.first - 1;
325
    word.length := S.Utf8Length(word.value);
326
    word.width := Font.TextWidth(word.value, word.length)
327
  END
328
END Split;
329
 
330
 
331
PROCEDURE Depth(tag: XML.ELEMENT): INTEGER;
332
VAR n: INTEGER;
333
BEGIN
334
  n := 0;
335
  WHILE tag # NIL DO
336
    IF tag(XML.TAG).value = XML.tag_section THEN
337
      INC(n)
338
    END;
339
    tag := tag.parent
340
  END
341
  RETURN n
342
END Depth;
343
 
344
 
345
PROCEDURE shift(tag: XML.TAG; shx, shy: INTEGER);
346
VAR cur: XML.ELEMENT; t: XML.TAG;
347
BEGIN
348
  cur := tag.child.first;
349
  WHILE cur # NIL DO
350
    IF cur IS XML.TAG THEN
351
      t := cur(XML.TAG);
352
      INC(t.X, shx);
353
      INC(t.Ymin, shy);
354
      INC(t.Ymax, shy);
355
      shift(t, shx, shy)
356
    ELSIF cur IS XML.TEXT THEN
357
      INC(cur(XML.TEXT).X, shx);
358
      INC(cur(XML.TEXT).Y, shy)
359
    END;
360
    cur := cur.next
361
  END
362
END shift;
363
 
364
 
365
PROCEDURE getspan(td: XML.TAG; span: S.STRING): INTEGER;
366
VAR res: INTEGER;
367
    attr_value: S.CHARS;
368
    err: BOOLEAN;
369
BEGIN
370
  IF XML.GetAttr(td, span, attr_value) THEN
371
    res := S.CharsToInt(attr_value, err);
372
    IF err OR (res <= 0) THEN
373
      res := 1
374
    END
375
  ELSE
376
    res := 1
377
  END
378
  RETURN res
379
END getspan;
380
 
381
 
382
PROCEDURE td(t: tables.Table; tag: XML.TAG);
383
BEGIN
384
  tag.cell := t.cells.count;
385
  tables.td(t, getspan(tag, "colspan"), getspan(tag, "rowspan"))
386
END td;
387
 
388
 
389
PROCEDURE tr(t: tables.Table; tag: XML.TAG);
390
VAR
391
  cur       : XML.ELEMENT;
392
  cell      : XML.TAG;
393
BEGIN
394
  tables.tr(t);
395
  cur := tag.child.first;
396
  WHILE cur # NIL DO
397
    IF cur IS XML.TAG THEN
398
      cell := cur(XML.TAG);
399
      IF (cell.value = XML.tag_td) OR (cell.value = XML.tag_th) THEN
400
        cell.table := t;
401
        td(t, cell)
402
      END
403
    END;
404
    cur := cur.next
405
  END
406
END tr;
407
 
408
 
409
PROCEDURE table(t: tables.Table; tag: XML.TAG; open: BOOLEAN);
410
VAR
411
  cur       : XML.ELEMENT;
412
  row       : XML.TAG;
413
BEGIN
414
  IF open THEN
415
    tables.table(t, W, TRUE);
416
    cur := tag.child.first;
417
    WHILE cur # NIL DO
418
      IF cur IS XML.TAG THEN
419
        row := cur(XML.TAG);
420
        IF row.value = XML.tag_tr THEN
421
          row.table := t;
422
          tr(t, row)
423
        END
424
      END;
425
      cur := cur.next
426
    END;
427
    tables.table(t, W, FALSE)
428
  END
429
END table;
430
 
431
 
9898 akron1 432
PROCEDURE Image (VAR tag: XML.TAG; destroy: BOOLEAN);
433
VAR
434
	note  : BOOLEAN;
435
	img   : XML.TAG;
436
	URL   : INTEGER;
437
	chars : S.CHARS;
438
	sizeY : INTEGER;
439
	FName : S.STRING;
440
	path  : S.STRING;
441
BEGIN
442
	LibImg.Destroy(tag.img);
443
	img := XML.GetRef(tag, note, URL);
444
	IF img # NIL THEN
445
		IF img.child.first IS XML.WORD THEN
446
			chars := img.child.first(XML.WORD).value;
447
			tag.img := LibImg.GetImg(chars.first, chars.last - chars.first + 1, W, sizeY)
448
		END
449
	ELSIF URL # 0 THEN
450
		S.PtrToString(URL, FName);
451
		tag.img := LibImg.LoadFromFile(FName, W, sizeY);
452
		IF tag.img = 0 THEN
453
			path := FilePath;
454
			IF FName[0] # "/" THEN
455
				S.Append(path, "/")
456
			END;
457
			S.Append(path, FName);
458
			tag.img := LibImg.LoadFromFile(path, W, sizeY)
459
		END
460
	END;
461
	IF (tag.img # 0) & destroy THEN
462
		INC(Y, (sizeY DIV LineH) * LineH);
463
		NewLine;
464
		tag.Ymax := Y - Y MOD LineH;
465
		LibImg.Destroy(tag.img)
466
	END
467
END Image;
468
 
469
 
9896 akron1 470
PROCEDURE layout(body: XML.ELEMENT);
471
VAR
472
  cur       : XML.ELEMENT;
473
  tag       : XML.TAG;
474
  word      : XML.WORD;
475
  text      : XML.TEXT;
476
  tag_value : INTEGER;
477
  _align    : INTEGER;
478
  title     : XML.ELEMENT;
479
  width     : INTEGER;
480
  height1   : INTEGER;
481
  height2   : INTEGER;
482
 
483
BEGIN
484
  cur := body;
485
  WHILE cur # NIL DO
486
    IF cur IS XML.TAG THEN
487
      tag := cur(XML.TAG);
488
      tag_value := tag.value;
489
      CASE tag_value OF
490
      |XML.tag_p, XML.tag_v:
491
        Trim;
492
        IF TextCount > 0 THEN
493
          NewLine
494
        END;
495
        X := Settings.PARAGRAPH + Epigraph()
496
      |XML.tag_epigraph:
497
        NewLine;
498
        INC(epigraph)
499
      |XML.tag_contents_item:
500
        INC(ref_depth);
501
        Settings.EPIGRAPH := Settings.LEVEL * Depth(tag);
502
        _align := align;
503
        align := 3
504
      |XML.tag_title:
505
        INC(strong);
506
        Font.Bold(TRUE);
507
        _align := align;
508
        align := 1;
509
        IF MainBody THEN
510
          tag.value := XML.tag_contents_item;
511
          title := XML.Copy(tag);
512
          XML.AddChild(contents, title);
513
          title.parent := tag.parent;
514
          tag.value := XML.tag_title
515
        END
516
      |XML.tag_subtitle:
517
        NewLine;
518
        _align := align;
519
        align := 1
520
      |XML.tag_text_author, XML.tag_date:
521
        _align := align;
522
        align := 2
523
      |XML.tag_section, XML.tag_body, XML.tag_empty_line, XML.tag_poem, XML.tag_stanza, XML.tag_annotation, XML.tag_cite:
524
        NewLine
525
      |XML.tag_a:
526
        INC(ref_depth);
527
        IF XML.IsNote(tag) THEN
528
          Sup(TRUE)
529
        END
530
      |XML.tag_sup:
531
        Sup(TRUE)
532
      |XML.tag_sub:
533
        Sub(TRUE)
534
      |XML.tag_code:
535
        Font.sysfont(TRUE);
536
        INC(code)
537
      |XML.tag_image:
538
        tag.X := 0;
539
        NewLine;
540
        NewLine
541
      |XML.tag_coverpage:
542
        cover := tag
543
 
544
      |XML.tag_table:
545
        NewLine;
546
        tables.destroy(tag.table);
547
        NEW(tag.table);
548
        table(tag.table, tag, TRUE)
549
      |XML.tag_td, XML.tag_th:
550
        IF tag_value = XML.tag_th THEN
551
          INC(strong);
552
          Font.Bold(TRUE);
553
        END;
554
        SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_tr, 21);
555
        NewLine; DEC(Y, LineH);
556
        tag.Width := tables.get_width(tag.table, tag.cell);
557
        tag.X := tables.get_x(tag.table, tag.cell);
558
        width := W;
559
        W := tag.Width - 2 * CellPadding;
560
        IF W <= 0 THEN
561
          W := 1
562
        END
563
      |XML.tag_tr:
564
        SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_table, 20)
565
 
566
      |XML.tag_strong:
567
        INC(strong);
568
        Font.Bold(TRUE)
569
      ELSE
570
      END;
571
 
572
      tag.Ymin := Y - Y MOD LineH;
573
      layout(tag.child.first);
574
      tag.Ymax := Y - Y MOD LineH;
575
 
576
      CASE tag_value OF
577
      |XML.tag_epigraph:
578
        NewLine;
579
        DEC(epigraph)
580
      |XML.tag_subtitle:
581
        NewLine;
582
        NewLine;
583
        align := _align
584
      |XML.tag_title, XML.tag_text_author, XML.tag_date:
585
        DEC(strong);
586
        Font.Bold(strong > 0);
587
        NewLine;
588
        align := _align
589
      |XML.tag_contents_item:
590
        DEC(ref_depth);
591
        align := _align;
592
      |XML.tag_section, XML.tag_poem, XML.tag_v, XML.tag_p, XML.tag_annotation, XML.tag_cite:
593
        NewLine
594
      |XML.tag_a:
595
        DEC(ref_depth);
596
        IF XML.IsNote(tag) THEN
597
          Sup(FALSE)
598
        END
599
      |XML.tag_sup:
600
        Sup(FALSE)
601
      |XML.tag_sub:
602
        Sub(FALSE)
603
      |XML.tag_code:
604
        DEC(code);
605
        Font.sysfont(code > 0)
606
      |XML.tag_image:
9898 akron1 607
        Image(tag, TRUE)
9896 akron1 608
      |XML.tag_table:
609
        Y := tag.Ymin + tables.get_table_height(tag.table);
610
        tag.Ymax := Y - Y MOD LineH;
611
        NewLine;
612
      |XML.tag_td, XML.tag_th:
613
        IF tag_value = XML.tag_th THEN
614
          DEC(strong);
615
          Font.Bold(strong > 0)
616
        END;
617
        W := width;
618
        NewLine;
619
        Y := tag.Ymin + Settings.SUP; //!!!
620
        height1 := tables.get_height(tag.table, tag.cell);
621
        height2 := tag.Ymax - tag.Ymin + LineH;
622
        IF height2 > height1 THEN
623
          tables.set_height(tag.table, tag.cell, height2)
624
        END;
625
        INC(tag.Ymin, tables.get_y(tag.table, tag.cell));
626
        INC(tag.Ymax, tables.get_height(tag.table, tag.cell));
627
        shift(tag, tag.X + CellPadding, tables.get_y(tag.table, tag.cell));
628
 
629
      |XML.tag_strong:
630
        DEC(strong);
631
        Font.Bold(strong > 0)
632
      ELSE
633
      END
634
    ELSIF cur IS XML.WORD THEN
635
      word := cur(XML.WORD);
636
      word.length := S.Utf8Length(word.value);
637
      word.width := Font.TextWidth(word.value, word.length);
638
      IF W - X < word.width THEN
639
        Align;
640
        NewLine
641
      END;
642
      IF W < word.width THEN
643
        Split(word)
644
      END
645
    ELSIF cur IS XML.SPACE THEN
646
      IF W - X < SpaceWidth() THEN
647
          cur(XML.SPACE).width := 0
648
      ELSE
649
          cur(XML.SPACE).width := SpaceWidth()
650
      END
651
    END;
652
    IF cur IS XML.TEXT THEN
653
      IF ref_depth > 0 THEN
654
        V.push(references, cur)
655
      END;
656
      text := cur(XML.TEXT);
657
      text.X := X;
658
      text.Y := Y;
659
      INC(X, text.width);
660
      AddToLine(text)
661
    END;
662
    cur := cur.next
663
  END
664
END layout;
665
 
666
 
667
PROCEDURE layout2(body: XML.ELEMENT);
668
VAR
669
  color : INTEGER;
670
  cur   : XML.ELEMENT;
671
  text  : XML.TEXT;
672
  tag   : XML.TAG;
673
  y, y0 : INTEGER;
674
  value : INTEGER;
675
 
9898 akron1 676
  PROCEDURE DrawText(Col: Window.tRect; min, max, y0, y: INTEGER; right: BOOLEAN; VAR text: XML.TEXT);
9896 akron1 677
  VAR word: XML.WORD;
678
  BEGIN
679
    IF (min <= y0) & (y0 <= max) THEN
680
      Font.sysfont(code > 0);
681
      IF text IS XML.WORD THEN
682
        word := text(XML.WORD);
9898 akron1 683
        Font.Text(Col, word.X, y - Col.height * ORD(right), word.value.first, word.length);
9896 akron1 684
      END;
9898 akron1 685
      Font.StrikeText(Col, text.X, y - Col.height * ORD(right), text.width)
9896 akron1 686
    END
687
  END DrawText;
688
 
9898 akron1 689
  PROCEDURE DrawImage(VAR tag: XML.TAG);
9896 akron1 690
  VAR sizeX, sizeY, img, y: INTEGER;
691
  BEGIN
692
    IF tag.img # 0 THEN
693
      y := Ycur;
694
      LibImg.GetInf(tag.img, sizeX, sizeY, img);
9898 akron1 695
      IF (y <= tag.Ymax) & (tag.Ymin <= y + ColLeft.height) THEN
696
        G.Image(ColLeft.left + tag.X, tag.Ymin - y + ColLeft.top, sizeX, sizeY, img, ColLeft.top, ColLeft.top + ColLeft.height - 1)
9896 akron1 697
      END;
698
      IF Settings.TwoCol THEN
9898 akron1 699
        y := Ycur + ColLeft.height;
700
        IF (y <= tag.Ymax) & (tag.Ymin <= y + ColRight.height) THEN
701
          G.Image(ColRight.left + tag.X, tag.Ymin - y + ColLeft.top, sizeX, sizeY, img, ColRight.top, ColRight.top + ColRight.height - 1)
9896 akron1 702
        END
703
      END
704
    END
9898 akron1 705
  END DrawImage;
9896 akron1 706
 
707
  PROCEDURE td(VAR tag: XML.TAG);
708
  VAR x1, y1, x2, y2, cl: INTEGER;
709
  BEGIN
9898 akron1 710
    x1 := tag.X + ColLeft.left;
711
    y1 := tag.Ymin - Ycur + ColLeft.top;
9896 akron1 712
    x2 := x1 + tag.Width;
713
    y2 := y1 + tables.get_height(tag.table, tag.cell);
714
    cl := G.GetColor();
715
    G.SetColor(Settings.Colors[TEXT_COLOR]);
716
    G.Rect(x1, y1, x2, y2);
717
    IF Settings.TwoCol THEN
9898 akron1 718
      x1 := x1 - ColLeft.left + ColRight.left;
719
      x2 := x2 - ColLeft.left + ColRight.left;
720
      y1 := y1 - ColLeft.height;
721
      y2 := y2 - ColLeft.height;
9896 akron1 722
      G.Rect(x1, y1, x2, y2)
723
    END;
724
    G.SetColor(cl)
725
  END td;
726
 
727
BEGIN
728
  cur := body;
729
  WHILE cur # NIL DO
730
    IF cur IS XML.TAG THEN
731
      tag := cur(XML.TAG);
732
      IF (tag.value = XML.tag_td) OR (tag.value = XML.tag_th) THEN
733
         tag.Ymax := tag.Ymin + tables.get_height(tag.table, tag.cell)
734
      END;
735
 
736
      IF (tag.Ymin < Ycur + LineH * Lines * (ORD(Settings.TwoCol) + 1)) & (tag.Ymax >= Ycur) OR (tag.value = XML.tag_tr) THEN
737
 
738
      value := tag.value;
739
      CASE value OF
740
      |XML.tag_a:
741
      	INC(refer);
742
        color := Font.Font.color;
743
        IF tag.Clicked THEN
744
          Font.SetFontColor(Settings.Colors[CLICKED_COLOR])
745
        ELSE
746
          IF tag.Visited THEN
747
            Font.SetFontColor(Settings.Colors[VISITED_COLOR])
748
          ELSE
749
            Font.SetFontColor(Settings.Colors[LINK_COLOR])
750
          END
751
        END
752
      |XML.tag_contents_item:
753
		IF tag.Clicked THEN
754
			INC(refer);
755
			color := Font.Font.color;
756
			Font.SetFontColor(Settings.Colors[CLICKED_COLOR])
757
		ELSIF tag.Visited THEN
758
			INC(refer);
759
			color := Font.Font.color;
760
			Font.SetFontColor(Settings.Colors[VISITED_COLOR])
761
		END
762
      |XML.tag_title, XML.tag_strong, XML.tag_th:
763
        INC(strong);
764
        Font.Bold(TRUE)
765
      |XML.tag_strikethrough:
766
        INC(strike);
767
        Font.Strike(TRUE)
768
      |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis:
769
        INC(italic);
770
        Font.Italic(TRUE, refer = 0)
771
      |XML.tag_image:
9898 akron1 772
      	Image(tag, FALSE);
773
        DrawImage(tag);
774
        LibImg.Destroy(tag.img)
9896 akron1 775
      |XML.tag_code:
776
        INC(code)
777
      ELSE
778
      END;
779
      layout2(tag.child.first);
780
      CASE value OF
781
      |XML.tag_a:
782
      	DEC(refer);
783
        Font.SetFontColor(color)
784
      |XML.tag_contents_item:
785
		IF tag.Clicked OR tag.Visited THEN
786
			DEC(refer);
787
			Font.SetFontColor(color)
788
		END
789
      |XML.tag_title, XML.tag_strong:
790
        DEC(strong);
791
        Font.Bold(strong > 0)
792
      |XML.tag_strikethrough:
793
        DEC(strike);
794
        Font.Strike(strike > 0)
795
      |XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis:
796
        DEC(italic);
797
        Font.Italic(italic > 0, refer = 0)
798
      |XML.tag_td:
799
        td(tag)
800
      |XML.tag_th:
801
        DEC(strong);
802
        Font.Bold(strong > 0);
803
        td(tag)
804
      |XML.tag_code:
805
        DEC(code)
806
      ELSE
807
      END
808
 
809
      END
810
    ELSIF cur IS XML.TEXT THEN
811
      text := cur(XML.TEXT);
812
      y  := text.Y - Ycur;
813
      y0 := y - y MOD LineH;
9898 akron1 814
      DrawText(ColLeft, 0, ColLeft.height - LineH, y0, y, FALSE, text);
9896 akron1 815
      IF Settings.TwoCol THEN
9898 akron1 816
        DrawText(ColRight, ColLeft.height, ColLeft.height + ColRight.height - LineH, y0, y, TRUE, text)
9896 akron1 817
      END
818
    END;
819
    cur := cur.next
820
  END
821
END layout2;
822
 
823
 
9898 akron1 824
PROCEDURE DrawFrame (color: INTEGER);
9896 akron1 825
VAR max_X, max_Y: INTEGER;
826
BEGIN
827
  max_X := G.Buffer.Width - 1;
828
  max_Y := G.Buffer.Height - 1;
9898 akron1 829
  G.SetColor(color);
9896 akron1 830
  G.HLine(0, max_X, 0);
831
  G.HLine(0, max_X, max_Y);
832
  G.VLine(0, 0, max_Y);
833
  sb.max_area := (Ymax - Ymin) DIV LineH + 50;
834
  sb.cur_area := 50;
835
  sb.position := (Ycur - Ymin) DIV LineH;
836
  box_lib.scrollbar_v_draw(sb)
9898 akron1 837
END DrawFrame;
9896 akron1 838
 
839
 
840
PROCEDURE Draw*;
9898 akron1 841
(*VAR max_Y: INTEGER;*)
9896 akron1 842
BEGIN
9898 akron1 843
  (*max_Y := G.Buffer.Height - 1;*)
844
  IF Settings.b_pict & (Settings.Picture # 0) THEN
845
      G.Copy(G.BackImg, G.Buffer, 0, G.Buffer.Height, 0)
846
  ELSE
847
      G.Fill(G.Buffer, Settings.Colors[BACK_COLOR])
848
  END;
9896 akron1 849
  Font.SetFontColor(Settings.Colors[TEXT_COLOR]);
850
  IF ((body = description) OR (body = contents)) & Settings.TwoCol THEN
851
    Settings.TwoCol := FALSE;
852
    layout2(body.child.first);
853
    Settings.TwoCol := TRUE;
854
    Search.draw(body, ColLeft, ColRight, Ycur, LineH, FALSE)
855
  ELSE
856
    layout2(body.child.first);
857
    Search.draw(body, ColLeft, ColRight, Ycur, LineH, Settings.TwoCol)
858
  END;
9898 akron1 859
  (*G.Copy(G.BackImg, G.Buffer, 0, ColLeft.top + 1, 0);
860
  G.Copy(G.BackImg, G.Buffer, max_Y - ColLeft.top, ColLeft.top + 1, max_Y - ColLeft.top);*)
861
  DrawFrame(0);
9896 akron1 862
  G.Draw(Canvas_X, Canvas_Y);
863
  DrawToolbar;
864
  DrawStatus
865
END Draw;
866
 
867
 
868
PROCEDURE BackEnabled* (): BOOLEAN;
869
	RETURN b_stk.first # NIL
870
END BackEnabled;
871
 
872
 
873
PROCEDURE FrwEnabled* (): BOOLEAN;
874
	RETURN f_stk.first # NIL
875
END FrwEnabled;
876
 
877
 
878
PROCEDURE ContentsEnabled* (): BOOLEAN;
879
	RETURN (contents # NIL) (*& (body # contents)*)
880
END ContentsEnabled;
881
 
882
 
883
PROCEDURE DescrEnabled* (): BOOLEAN;
884
	RETURN (description # NIL) (*& (body # description)*)
885
END DescrEnabled;
886
 
887
 
888
PROCEDURE Back*;
889
BEGIN
890
  IF b_stk.first # NIL THEN
891
    Push(f_stk);
892
    Pop(b_stk)
893
  END
894
END Back;
895
 
896
 
897
PROCEDURE Forward*;
898
BEGIN
899
  IF f_stk.first # NIL THEN
900
    Push(b_stk);
901
    Pop(f_stk)
902
  END
903
END Forward;
904
 
905
 
906
PROCEDURE Contents*;
907
BEGIN
908
  IF (contents # NIL) & (body # contents) THEN
909
    Push(b_stk);
910
    Clear(f_stk);
911
    body := contents;
912
    Ycur := Ycont;
913
    Ymin := 0;
914
    Ymax := body.Ymax
915
  END
916
END Contents;
917
 
918
 
919
PROCEDURE Descr*;
920
BEGIN
921
  IF (description # NIL) & (body # description) THEN
922
    Push(b_stk);
923
    Clear(f_stk);
924
    body := description;
925
    Ycur := 0;
926
    Ymin := 0;
927
    Ymax := body.Ymax
928
  END
929
END Descr;
930
 
931
 
9898 akron1 932
PROCEDURE Scroll* (n: INTEGER);
9896 akron1 933
BEGIN
9898 akron1 934
	INC(Ycur, LineH*n);
935
	SU.MinMax(Ycur, Ymin, Ymax)
936
END Scroll;
9896 akron1 937
 
938
 
939
PROCEDURE PageUp*;
940
BEGIN
9898 akron1 941
    Scroll(-Lines * (ORD(Settings.TwoCol) + 1))
9896 akron1 942
END PageUp;
943
 
944
 
945
PROCEDURE PageDown*;
946
BEGIN
9898 akron1 947
    Scroll(Lines * (ORD(Settings.TwoCol) + 1))
9896 akron1 948
END PageDown;
949
 
950
 
951
PROCEDURE Home*;
952
BEGIN
953
  IF Ycur # Ymin THEN
954
    Push(b_stk);
955
    Clear(f_stk);
956
    Ycur := Ymin
957
  END
958
END Home;
959
 
960
 
961
PROCEDURE End*;
962
BEGIN
963
  IF Ycur # Ymax THEN
964
    Push(b_stk);
965
    Clear(f_stk);
966
    Ycur := Ymax
967
  END
968
END End;
969
 
970
 
971
PROCEDURE ScrollBar*;
972
BEGIN
973
  Ycur := sb.position * LineH + Ymin
974
END ScrollBar;
975
 
976
 
977
PROCEDURE GetBody(tag: XML.TAG): XML.TAG;
978
BEGIN
979
  WHILE (tag # NIL) & (tag.value # XML.tag_body) DO
980
    tag := tag.parent(XML.TAG)
981
  END
982
  RETURN tag
983
END GetBody;
984
 
985
 
986
PROCEDURE layout3(Body: XML.ELEMENT; X, Y: INTEGER);
987
VAR
988
  ptr   : V.ANYPTR;
989
  text  : XML.TEXT;
990
  sect  : XML.TAG;
991
  y     : INTEGER;
992
  i     : INTEGER;
993
BEGIN
994
  i := 0;
995
  WHILE i < references.count DO
996
    ptr := V.get(references, i);
997
    text := ptr(XML.TEXT);
998
    y  := text.Y - Ycur;
999
    IF (y <= Y) & (Y <= y + Font.FontH()) & (text.X <= X) & (X <= text.X + text.width) THEN
1000
      sect := text.parent(XML.TAG);
1001
      IF Body = contents THEN
1002
        WHILE (sect # NIL) & (sect.value # XML.tag_contents_item) DO
1003
          sect := sect.parent(XML.TAG)
1004
        END
1005
      ELSE
1006
        WHILE (sect # NIL) & (sect # Body) DO
1007
          IF sect.value = XML.tag_contents_item THEN
1008
            sect := NIL
1009
          ELSE
1010
            sect := sect.parent(XML.TAG)
1011
          END
1012
        END
1013
      END;
1014
 
1015
      IF sect # NIL THEN
1016
        sect := text.parent(XML.TAG);
1017
        WHILE sect # NIL DO
1018
          IF (sect.value = XML.tag_contents_item) & (Body = contents) OR (sect.value = XML.tag_a) THEN
1019
            ref := sect;
1020
            sect := NIL;
1021
            i := references.count
1022
          ELSE
1023
            sect := sect.parent(XML.TAG)
1024
          END
1025
        END
1026
      END
1027
    END;
1028
    INC(i)
1029
  END
1030
END layout3;
1031
 
1032
 
9898 akron1 1033
PROCEDURE getRefProp (VAR ref, body: XML.TAG; VAR URL: INTEGER; VAR note: BOOLEAN; VAR Y: INTEGER);
1034
BEGIN
1035
	note := FALSE;
1036
	URL := 0;
1037
	Y := 0;
1038
	IF ref.value = XML.tag_a THEN
1039
		ref := XML.GetRef(ref, note, URL)
1040
	ELSE
1041
		ref := ref.parent(XML.TAG)
1042
	END;
1043
	IF ref # NIL THEN
1044
		Y := ref.Ymin;
1045
	END;
1046
	IF note THEN
1047
	  	body := ref
1048
	ELSE
1049
	  	body := GetBody(ref)
1050
	END
1051
END getRefProp;
1052
 
1053
 
1054
PROCEDURE zstreq (s1, s2: INTEGER): BOOLEAN;
1055
VAR
1056
    c1, c2: CHAR;
1057
BEGIN
1058
    REPEAT
1059
        sys.GET(s1, c1); INC(s1);
1060
        sys.GET(s2, c2); INC(s2);
1061
    UNTIL (c1 = 0X) OR (c2 = 0X)
1062
 
1063
    RETURN c1 = c2
1064
END zstreq;
1065
 
1066
 
1067
PROCEDURE refeq (ref1, ref2: XML.TAG): BOOLEAN;
1068
VAR
1069
	body1, body2: XML.TAG;
1070
	URL1, URL2: INTEGER;
1071
	note1, note2: BOOLEAN;
1072
	Y1, Y2: INTEGER;
1073
BEGIN
1074
	getRefProp(ref1, body1, URL1, note1, Y1);
1075
	getRefProp(ref2, body2, URL2, note2, Y2);
1076
	RETURN (ref1 = ref2) & (body1 = body2) & (URL1 = 0) & (URL2 = 0) & (note1 = note2) & (Y1 = Y2) OR
1077
			(URL1 # 0) & (URL2 # 0) & zstreq(URL1, URL2)
1078
END refeq;
1079
 
1080
 
1081
PROCEDURE setVisited (ref: XML.TAG);
1082
VAR
1083
	i: INTEGER;
1084
	cur: V.ANYPTR;
1085
BEGIN
1086
	FOR i := 0 TO references.count - 1 DO
1087
		cur := V.get(references, i);
1088
		IF cur IS XML.TEXT THEN
1089
			cur := cur(XML.TEXT).parent;
1090
			IF refeq(cur(XML.TAG), ref) THEN
1091
				cur(XML.TAG).Visited := TRUE
1092
			END
1093
		END
1094
	END
1095
END setVisited;
1096
 
1097
 
9896 akron1 1098
PROCEDURE MouseDown;
1099
BEGIN
1100
	IF ~mouseDown THEN
1101
		mouseDown := TRUE;
1102
		clickRef := ref;
9898 akron1 1103
		IF ref # NIL THEN
1104
			ref.Clicked := TRUE
1105
		END;
9896 akron1 1106
		Draw
1107
	END
1108
END MouseDown;
1109
 
1110
 
1111
PROCEDURE MouseUp;
1112
VAR
1113
	note : BOOLEAN;
1114
	URL  : INTEGER;
1115
	redraw: BOOLEAN;
1116
BEGIN
1117
	redraw := FALSE;
1118
	mouseDown := FALSE;
1119
	IF (ref # NIL) & (clickRef = ref) & ref.Clicked THEN
1120
		redraw := TRUE;
1121
        ref.Clicked := FALSE;
1122
		note := FALSE;
1123
		URL := 0;
1124
		IF ref.value = XML.tag_a THEN
1125
			ref := XML.GetRef(ref, note, URL)
1126
		ELSE
1127
			ref := ref.parent(XML.TAG)
1128
		END;
1129
		IF ref # NIL THEN
1130
			Push(b_stk);
1131
			Clear(f_stk);
1132
			Ycur := ref.Ymin;
1133
			IF note THEN
1134
			  	body := ref
1135
			ELSE
1136
			  	body := GetBody(ref)
1137
			END;
1138
			Ymax := body.Ymax;
1139
			Ymin := body.Ymin;
1140
 
1141
			IF ~clickRef.Visited THEN
9898 akron1 1142
				setVisited(clickRef);
9896 akron1 1143
				clickRef.Visited := TRUE;
1144
				PushRef(clickRef)
1145
			END
1146
		ELSIF URL # 0 THEN
1147
			SU.Run(Ini.Browser, URL);
1148
			IF ~clickRef.Visited THEN
9898 akron1 1149
				setVisited(clickRef);
9896 akron1 1150
				clickRef.Visited := TRUE;
1151
				PushRef(clickRef)
1152
			END
9898 akron1 1153
		END
9896 akron1 1154
	END;
1155
	IF clickRef # NIL THEN
1156
		clickRef.Clicked := FALSE;
1157
		clickRef := NIL;
1158
		redraw := TRUE
1159
	END;
1160
	IF hoverRef # NIL THEN
1161
		hoverRef.Clicked := FALSE;
1162
		hoverRef := NIL;
1163
		redraw := TRUE
1164
	END;
1165
	IF redraw THEN
1166
		Draw
1167
	END
1168
END MouseUp;
1169
 
1170
 
1171
PROCEDURE Click*(X, Y: INTEGER; clicked: BOOLEAN);
1172
VAR
1173
  note : BOOLEAN;
1174
  URL  : INTEGER;
1175
  urlchars: S.CHARS;
1176
  urlstr1 : S.STRING;
1177
BEGIN
1178
  DEC(Y, Settings.PADDING.Top);
1179
  DEC(X, Settings.PADDING.Left);
1180
  IF (0 <= Y) & (Y <= Lines * LineH) THEN
1181
    ref := NIL;
1182
    layout3(body, X, Y);
1183
    IF (ref = NIL) & Settings.TwoCol THEN
9898 akron1 1184
      layout3(body, X - ColLeft.width - Settings.PADDING.ColInter, Y + Lines * LineH);
9896 akron1 1185
    END;
1186
    hoverRef := ref;
1187
	IF clicked THEN
1188
		MouseDown
1189
	ELSE
1190
		MouseUp
1191
	END;
1192
    IF ref # NIL THEN
1193
      SU.SetCursor(cursor);
1194
      note := FALSE;
1195
      URL := 0;
1196
      IF ref.value = XML.tag_a THEN
1197
        ref := XML.GetRef(ref, note, URL)
1198
      END;
1199
      IF URL # 0 THEN
1200
        S.PtrToString(URL, urlstr1);
1201
        S.StrToChars(urlstr1, urlchars)
1202
      END
1203
    ELSE
1204
      SU.SetCursor(0);
1205
      urlstr1 := ""
1206
    END;
1207
    IF urlstr1 # urlstr THEN
1208
      urlstr := urlstr1;
1209
      DrawStatus
1210
    END
1211
  ELSE
1212
      SU.SetCursor(0);
1213
      urlstr := "";
1214
      ref := NIL;
1215
      DrawStatus
1216
  END
1217
END Click;
1218
 
1219
 
1220
PROCEDURE main(fb: XML.ELEMENT; Contents: BOOLEAN);
1221
VAR
1222
  cur: XML.ELEMENT;
1223
  tag: XML.TAG;
1224
  par, epi: INTEGER;
1225
 
1226
 
1227
  PROCEDURE lout(body: XML.ELEMENT);
1228
  BEGIN
1229
    TextCount := 0;
1230
    X := 0;
1231
    Y := Settings.SUP;
1232
    layout(body(XML.TAG).child.first);
1233
    body(XML.TAG).Ymax := Y - Settings.SUP
1234
  END lout;
1235
 
1236
  PROCEDURE lout_one_col(body: XML.ELEMENT);
1237
  BEGIN
1238
    IF body # NIL THEN
1239
      IF Settings.TwoCol THEN
1240
        W := W2;
1241
        Settings.TwoCol := FALSE;
1242
        lout(body);
1243
        Settings.TwoCol := TRUE;
1244
        W := W1
1245
      ELSE
1246
        lout(body)
1247
      END
1248
    END
1249
  END lout_one_col;
1250
 
1251
BEGIN
1252
  TextCount := 0;
1253
  sup := 0;
1254
  sub := 0;
1255
  epigraph := 0;
1256
  align := 0;
1257
  code := 0;
1258
  strong := 0;
1259
  italic := 0;
1260
  strike := 0;
1261
  refer := 0;
1262
  SU.ErrorIf(fb = NIL, 11);
1263
  MainBody := FALSE;
1264
  description := NIL;
1265
  mainbody := NIL;
1266
  cover := NIL;
1267
  cur := fb;
1268
  cur := cur(XML.TAG).child.first;
1269
  WHILE (cur # NIL) & (mainbody = NIL) DO
1270
    IF cur IS XML.TAG THEN
1271
      tag := cur(XML.TAG);
1272
      IF tag.value = XML.tag_description THEN
1273
        description := tag
1274
      ELSIF tag.value = XML.tag_body THEN
1275
        mainbody := tag
1276
      END
1277
    END;
1278
    cur := cur.next
1279
  END;
1280
  SU.ErrorIf(mainbody = NIL, 12);
1281
 
1282
  WHILE cur # NIL DO
1283
    IF (cur IS XML.TAG) & (cur(XML.TAG).value = XML.tag_body) THEN
1284
      lout(cur)
1285
    END;
1286
    cur := cur.next
1287
  END;
1288
 
1289
  IF Contents THEN
1290
    contents := XML.CreateTag();
1291
    MainBody := TRUE;
1292
  END;
1293
  lout(mainbody);
1294
  IF Contents & (contents.child.first = NIL) THEN
1295
    DISPOSE(contents)
1296
  END;
1297
  MainBody := FALSE;
1298
  epigraph := 1;
1299
  par := Settings.PARAGRAPH;
1300
  epi := Settings.EPIGRAPH;
1301
  Settings.PARAGRAPH := 0;
1302
  Settings.EPIGRAPH := 0;
1303
  lout_one_col(contents);
1304
  Settings.EPIGRAPH := epi;
1305
  Settings.PARAGRAPH := par;
1306
  epigraph := 0;
1307
  lout_one_col(description);
1308
  body := mainbody;
1309
  Ymax := body.Ymax;
1310
  Ycur := 0;
1311
  Ymin := 0;
1312
  Ycont := 0
1313
END main;
1314
 
1315
 
1316
PROCEDURE Find* (d: INTEGER);
1317
VAR
1318
    y, min, max: INTEGER;
1319
 
1320
BEGIN
1321
    Search.fnext(body, y, d);
1322
    IF y >= 0 THEN
1323
        DEC(y, y MOD LineH);
1324
        min := Ycur;
9898 akron1 1325
        max := min + ColLeft.height - LineH;
9896 akron1 1326
        IF Settings.TwoCol THEN
9898 akron1 1327
            INC(max, ColRight.height)
9896 akron1 1328
        END;
1329
 
1330
        IF (y < min) OR (y > max) THEN
9898 akron1 1331
            Ycur := MAX(y - ColLeft.height DIV 2, 0)
9896 akron1 1332
        END;
1333
 
1334
        DEC(Ycur, Ycur MOD LineH)
1335
    END
1336
END Find;
1337
 
1338
 
1339
PROCEDURE OpenSearch*;
1340
BEGIN
1341
    Search.open(Find)
1342
END OpenSearch;
1343
 
1344
 
1345
PROCEDURE CloseSearch*;
1346
BEGIN
1347
    Search.close
1348
END CloseSearch;
1349
 
1350
 
1351
PROCEDURE found* (): BOOLEAN;
1352
    RETURN Search.found(body)
1353
END found;
1354
 
1355
 
1356
PROCEDURE FontSizeChange(fs: INTEGER);
1357
BEGIN
1358
  Settings.SUP               :=  fs DIV 4;
1359
  Settings.SUB               :=  fs DIV 4;
1360
  Settings.SpaceW            :=  fs DIV 2;
1361
  Settings.LEVEL             :=  Settings.PARAGRAPH;
1362
  Settings.PADDING.Bottom    :=  Settings.PADDING.Top;
1363
  Settings.PADDING.Left      :=  G.Buffer.Width * Settings.PADDING.LRpc DIV 100;
1364
  IF Settings.PADDING.Left = 0 THEN
1365
    Settings.PADDING.Left := 1
1366
  END;
1367
  Settings.PADDING.Right     :=  Settings.PADDING.Left;
1368
  Settings.PADDING.ColInter  :=  G.Buffer.Width * Settings.PADDING.CInt DIV 100;
1369
 
1370
  LineH := Font.FontH() + Settings.SUP + Settings.SUB + Settings.InterLin;
9898 akron1 1371
  Window.initRect(
9896 akron1 1372
    ColLeft, Settings.PADDING.Left, Settings.PADDING.Top,
1373
    G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right,
1374
    G.Buffer.Height - Settings.PADDING.Top - Settings.PADDING.Bottom);
1375
  IF Settings.TwoCol THEN
9898 akron1 1376
    ColLeft.width := (ColLeft.width - Settings.PADDING.ColInter) DIV 2;
9896 akron1 1377
    ColRight := ColLeft;
9898 akron1 1378
    ColRight.left := ColLeft.left + ColLeft.width + Settings.PADDING.ColInter
9896 akron1 1379
  END;
9898 akron1 1380
  W := ColLeft.width;
1381
  Lines := ColLeft.height DIV LineH;
1382
  ColLeft.height  := Lines * LineH;
1383
  ColRight.height := ColLeft.height;
9896 akron1 1384
END FontSizeChange;
1385
 
1386
 
1387
PROCEDURE Resize*(Width, Height: INTEGER);
9898 akron1 1388
VAR d: REAL; resize: BOOLEAN; sizeX, sizeY, data, back_picture: INTEGER;
9896 akron1 1389
 
1390
  PROCEDURE stk1(stk: XML.LIST);
1391
  VAR cur: StackItem;
1392
  BEGIN
1393
    cur := stk.first(StackItem);
1394
    WHILE cur # NIL DO
1395
      cur.d := FLT(cur.Ycur - cur.body.Ymin) / FLT(cur.body.Ymax - cur.body.Ymin);
1396
      cur := cur.next(StackItem)
1397
    END
1398
  END stk1;
1399
 
1400
  PROCEDURE stk2(stk: XML.LIST);
1401
  VAR cur: StackItem;
1402
  BEGIN
1403
    cur := stk.first(StackItem);
1404
    WHILE cur # NIL DO
1405
      cur.Ycur := FLOOR(FLT(cur.body.Ymax - cur.body.Ymin) * cur.d) + cur.body.Ymin;
1406
      cur.Ycur := cur.Ycur - cur.Ycur MOD LineH;
1407
      SU.MinMax(cur.Ycur, cur.body.Ymin, cur.body.Ymax);
1408
      cur := cur.next(StackItem)
1409
    END
1410
  END stk2;
1411
 
1412
BEGIN
1413
  resize := (Width # G.Buffer.Width) OR resized;
1414
  G.Resize(Width, Height);
1415
  IF (Settings.Picture # 0) & Settings.b_pict THEN
9898 akron1 1416
  	back_picture := LibImg.GetImg(Settings.Picture, Settings.picture_fsize, 1000000, sizeY);
1417
  	IF back_picture # 0 THEN
1418
	    LibImg.GetInf(back_picture, sizeX, sizeY, data);
1419
    	G.CreateBackImg;
1420
	    G.BackImage(sizeX, sizeY, data);
1421
    	LibImg.Destroy(back_picture)
1422
    END
9896 akron1 1423
  ELSE
9898 akron1 1424
    G.DestroyBackImg;
1425
    G.Fill(G.Buffer, Settings.Colors[BACK_COLOR]);
1426
    //G.Fill(G.BackImg, Settings.Colors[BACK_COLOR])
9896 akron1 1427
  END;
1428
 
1429
  IF Font.FontH() # 0 THEN
1430
    FontSizeChange(Font.FontH());
1431
  ELSE
1432
    FontSizeChange(Settings.FontSize);
1433
  END;
1434
 
9898 akron1 1435
  ColLeft.width  := G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right;
9896 akron1 1436
  IF Settings.TwoCol THEN
9898 akron1 1437
    ColLeft.width  := (ColLeft.width - Settings.PADDING.ColInter) DIV 2;
1438
    ColRight.width := ColLeft.width;
1439
    ColRight.left  := ColLeft.left + ColLeft.width + Settings.PADDING.ColInter
9896 akron1 1440
  END;
9898 akron1 1441
  ColLeft.height  := G.Buffer.Height - Settings.PADDING.Top  - Settings.PADDING.Bottom;
1442
  Lines           := ColLeft.height DIV LineH;
1443
  ColLeft.height  := Lines * LineH;
1444
  ColRight.height := ColLeft.height;
9896 akron1 1445
 
1446
  IF done & resize THEN
1447
    resized := FALSE;
1448
    Push(b_stk);
1449
    stk1(b_stk);
1450
    stk1(f_stk);
1451
    IF contents # NIL THEN
1452
      d := FLT(Ycont) / FLT(contents.Ymax)
1453
    END;
9898 akron1 1454
    W := ColLeft.width;
1455
    W2 := ColLeft.width + ColRight.width + Settings.PADDING.ColInter;
9896 akron1 1456
    W1 := W;
1457
    main(XML.FB, FALSE);
1458
    Search.resize;
1459
    stk2(b_stk);
1460
    stk2(f_stk);
1461
    IF contents # NIL THEN
1462
      Ycont := FLOOR(FLT(contents.Ymax) * d);
1463
      Ycont := Ycont - Ycont MOD LineH;
1464
      SU.MinMax(Ycont, 0, contents.Ymax)
1465
    END;
1466
    Pop(b_stk);
1467
  END
1468
END Resize;
1469
 
1470
 
1471
PROCEDURE SetColors*;
1472
BEGIN
1473
  Settings.Colors[BACK_COLOR]     := Ini.GetColor("back",    Settings.Colors[BACK_COLOR]);
1474
  Settings.Colors[TEXT_COLOR]     := Ini.GetColor("text",    Settings.Colors[TEXT_COLOR]);
1475
  Settings.Colors[ITALIC_COLOR]   := Ini.GetColor("italic",  Settings.Colors[ITALIC_COLOR]);
1476
  Settings.Colors[LINK_COLOR]     := Ini.GetColor("link",    Settings.Colors[LINK_COLOR]);
1477
  Settings.Colors[VISITED_COLOR]  := Ini.GetColor("visited", Settings.Colors[LINK_COLOR]);
1478
END SetColors;
1479
 
1480
 
1481
PROCEDURE Resized(set1, set2: TSettings): BOOLEAN;
1482
  RETURN (set1.FontSize # set2.FontSize) OR (set1.TwoCol # set2.TwoCol) OR
1483
         (set1.PARAGRAPH # set2.PARAGRAPH) OR (set1.EPIGRAPH # set2.EPIGRAPH) OR
1484
         (set1.PADDING.LRpc # set2.PADDING.LRpc) OR (set1.PADDING.CInt # set2.PADDING.CInt)
1485
         OR (set1.InterLin # set2.InterLin)
1486
END Resized;
1487
 
1488
 
1489
PROCEDURE SetSettings*(NewSet: TSettings);
1490
BEGIN
1491
  resized := Resized(Settings, NewSet) OR resized;
1492
  Settings := NewSet;
1493
  Font.Init(Settings.Colors[ITALIC_COLOR], Settings.Colors[TEXT_COLOR], Settings.FontSize);
1494
  Resize(G.Buffer.Width, G.Buffer.Height)
1495
END SetSettings;
1496
 
1497
 
1498
PROCEDURE Init*(Left, Top, Width, Height: INTEGER);
1499
BEGIN
1500
  G.Resize(Width, Height);
1501
  Canvas_X := Left;
1502
  Canvas_Y := Top
1503
END Init;
1504
 
1505
 
1506
PROCEDURE Start;
1507
BEGIN
1508
  XML.Open(FileName);
1509
  main(XML.FB, TRUE);
1510
  done := TRUE;
1511
  SU.Halt
1512
END Start;
1513
 
1514
 
1515
PROCEDURE CleanHistory*(fname: S.STRING);
1516
VAR F: File.FS; pos, pos2, fsize, size, buf, buf2: INTEGER; c: CHAR;
1517
BEGIN
1518
  F := File.Open(fname);
1519
  IF F # NIL THEN
1520
    fsize := File.Seek(F, 0, 2);
1521
    pos := File.Seek(F, 0, 0);
1522
    buf := K.malloc(fsize + 1024);
1523
    buf2 := K.malloc(fsize + 1024);
1524
    pos := File.Read(F, buf, fsize);
1525
    File.Close(F);
1526
    pos := 0;
1527
    pos2 := 0;
1528
    WHILE pos < fsize DO
1529
      sys.GET(buf + pos, size);
1530
      sys.GET(buf + pos + 4, c);
1531
      IF c = 0X THEN
1532
        sys.MOVE(buf + pos, buf2 + pos2, size);
1533
        pos2 := pos2 + size
1534
      END;
1535
      pos := pos + size
1536
    END;
1537
    F := File.Create(fname);
1538
    pos := File.Write(F, buf2, pos2);
1539
    File.Close(F);
1540
    buf := K.free(buf);
1541
    buf2 := K.free(buf2)
1542
  END
1543
END CleanHistory;
1544
 
1545
 
1546
PROCEDURE Save;
9912 akron1 1547
VAR history: File.FS; size, pos: INTEGER;
9896 akron1 1548
 
1549
  PROCEDURE WriteInt(history: File.FS; x: INTEGER);
1550
  BEGIN
9898 akron1 1551
    IF File.WriteInt(history, x) THEN END
9896 akron1 1552
  END WriteInt;
1553
 
1554
  PROCEDURE WriteStk(history: File.FS; VAR stk: XML.LIST; links: BOOLEAN);
1555
  VAR
1556
      cur: StackItem;
1557
  BEGIN
1558
    WriteInt(history, XML.ListCount(stk));
1559
    cur := stk.first(StackItem);
1560
    WHILE cur # NIL DO
1561
      WriteInt(history, cur.body.num);
1562
      IF ~links THEN
1563
      	WriteInt(history, cur.Ycur)
1564
      END;
1565
      cur := cur.next(StackItem)
1566
    END
1567
  END WriteStk;
1568
 
1569
BEGIN
1570
  Ini.Save(Settings.Colors, Settings.b_pict);
1571
  history := File.Open(Ini.History);
1572
  IF history = NIL THEN
1573
    history := File.Create(Ini.History)
1574
  ELSE
1575
    pos := File.Seek(history, 0 , 2)
1576
  END;
1577
  size := 1 + 18*4 + 1 + 8*(XML.ListCount(b_stk) + XML.ListCount(f_stk)) + 4*XML.ListCount(vis_ref) + 12;
1578
  WriteInt(history, size);
9898 akron1 1579
  IF File.WriteChar(history, 0X) THEN END;
9896 akron1 1580
  WriteInt(history, fsize2);
1581
  WriteInt(history, chksum);
1582
  WriteInt(history, win_size_x);
1583
  WriteInt(history, win_size_y);
1584
  WriteInt(history, Settings.PADDING.LRpc);
1585
  WriteInt(history, Settings.PADDING.Top);
1586
  WriteInt(history, Settings.PADDING.CInt);
1587
  WriteInt(history, Settings.PARAGRAPH);
1588
  WriteInt(history, Settings.EPIGRAPH);
1589
  WriteInt(history, Settings.InterLin);
1590
 
9898 akron1 1591
  IF File.WriteBool(history, Settings.TwoCol) THEN END;
9896 akron1 1592
 
1593
  WriteInt(history, Settings.FontSize);
1594
  WriteInt(history, body.num);
1595
  WriteInt(history, Ymin);
1596
  WriteInt(history, Ymax);
1597
  WriteInt(history, Ycur);
1598
  WriteInt(history, Ycont);
1599
 
1600
  WriteStk(history, b_stk, FALSE);
1601
  WriteStk(history, f_stk, FALSE);
1602
  WriteStk(history, vis_ref, TRUE);
1603
 
1604
  WriteInt(history, size);
1605
 
1606
  File.Close(history);
1607
  CleanHistory(Ini.History)
1608
END Save;
1609
 
1610
 
1611
PROCEDURE ReadInt(VAR x: INTEGER);
1612
BEGIN
9898 akron1 1613
  IF File.ReadInt(history, x) THEN END
9896 akron1 1614
END ReadInt;
1615
 
1616
 
1617
PROCEDURE Load;
1618
VAR body_num, ycur, size, pos: INTEGER;
1619
 
1620
  PROCEDURE ReadStk(VAR stk: XML.LIST);
1621
  VAR n, num: INTEGER;
1622
  BEGIN
1623
    ReadInt(n);
1624
    WHILE n > 0 DO
1625
      ReadInt(num);
1626
      body := XML.GetTagByNum(num);
1627
      ReadInt(Ycur);
1628
      Push(stk);
1629
      DEC(n)
1630
    END
1631
  END ReadStk;
1632
 
1633
	PROCEDURE ReadRef;
1634
	VAR
1635
		n, num: INTEGER;
1636
		ref: XML.TAG;
1637
	BEGIN
1638
		ReadInt(n);
1639
		WHILE n > 0 DO
1640
			ReadInt(num);
1641
			ref := XML.GetTagByNum(num);
1642
			IF ref # NIL THEN
9898 akron1 1643
				setVisited(ref);
1644
				ref.Visited := TRUE;
1645
				PushRef(ref)
9896 akron1 1646
			END;
1647
			DEC(n)
1648
		END
1649
	END ReadRef;
1650
 
1651
BEGIN
1652
  ReadInt(Settings.PADDING.LRpc);
1653
  ReadInt(Settings.PADDING.Top);
1654
  ReadInt(Settings.PADDING.CInt);
1655
  ReadInt(Settings.PARAGRAPH);
1656
  ReadInt(Settings.EPIGRAPH);
1657
  ReadInt(Settings.InterLin);
9898 akron1 1658
  IF File.ReadBool(history, Settings.TwoCol) THEN END;
9896 akron1 1659
  ReadInt(Settings.FontSize);
1660
 
1661
  SetSettings(Settings);
1662
 
1663
  ReadInt(body_num);
1664
  ReadInt(Ymin);
1665
  ReadInt(Ymax);
1666
  ReadInt(ycur);
1667
  ReadInt(Ycont);
1668
 
1669
  ReadStk(b_stk);
1670
  ReadStk(f_stk);
1671
  ReadRef;
1672
 
1673
  ReadInt(size);
1674
  pos := File.Seek(history, -size, 1);
1675
  pos := File.Seek(history, 4, 1);
9898 akron1 1676
  IF File.WriteChar(history, 1X) THEN END;
9896 akron1 1677
 
1678
  Ycur := ycur;
1679
  body := XML.GetTagByNum(body_num);
1680
  File.Close(history)
1681
END Load;
1682
 
1683
 
1684
PROCEDURE GetWinSize*(hist_fn: S.STRING; VAR win_size_x, win_size_y: INTEGER);
1685
VAR c: CHAR; size, pos, x, y, fsize, _chksum: INTEGER; found: BOOLEAN;
1686
BEGIN
1687
  fsize2 := RF.FileSize(hist_fn);
1688
  chksum := RF.ChkSum(hist_fn);
1689
  found := FALSE;
1690
  history := File.Open(Ini.History);
1691
  pos := File.Seek(history, -4, 2);
1692
  last := FALSE;
1693
  WHILE pos >= 0 DO
9898 akron1 1694
    IF File.ReadInt(history, size) THEN
9896 akron1 1695
      pos := File.Seek(history, -size + 4, 1);
1696
    END;
9898 akron1 1697
    IF File.ReadChar(history, c) THEN END;
9896 akron1 1698
    ReadInt(fsize);
1699
    ReadInt(_chksum);
1700
    IF (c = 0X) & (fsize = fsize2) & (_chksum = chksum) THEN
1701
      found := TRUE;
9898 akron1 1702
      IF File.ReadInt(history, x) & File.ReadInt(history, y) THEN
9896 akron1 1703
        win_size_x := x;
1704
        win_size_y := y;
1705
      ELSE
1706
        found := FALSE
1707
      END;
1708
      pos := -1
1709
    ELSE
1710
      IF ~last THEN
1711
        last := TRUE;
1712
        ReadInt(x);
1713
        ReadInt(y);
1714
        ReadInt(Settings.PADDING.LRpc);
1715
        ReadInt(Settings.PADDING.Top);
1716
        ReadInt(Settings.PADDING.CInt);
1717
        ReadInt(Settings.PARAGRAPH);
1718
        ReadInt(Settings.EPIGRAPH);
1719
        ReadInt(Settings.InterLin);
9898 akron1 1720
        IF File.ReadBool(history, Settings.TwoCol) THEN END;
9896 akron1 1721
        ReadInt(Settings.FontSize);
1722
      END;
1723
      pos := File.Seek(history, pos - 8, 0)
1724
    END
1725
  END;
1726
  IF ~found THEN
1727
    File.Close(history)
1728
  END
1729
END GetWinSize;
1730
 
1731
 
1732
PROCEDURE Open*(FName: S.STRING; DrawWindow, _DrawStatus, _DrawToolbar: SU.ENTRY);
1733
VAR PID, event: INTEGER;
1734
BEGIN
1735
  DrawStatus := _DrawStatus;
1736
  DrawToolbar := _DrawToolbar;
1737
  cursor := SU.LoadCursor(Cursor.GetCursor());
1738
  references := V.create(1024);
1739
  ref_depth := 0;
1740
  done := FALSE;
1741
  loaded := FALSE;
1742
  FilePath := FName;
1743
  FileName := FName;
1744
  S.GetPath(FilePath);
9898 akron1 1745
  W  := ColLeft.width;
9896 akron1 1746
  W1 := W;
9898 akron1 1747
  W2 := ColLeft.width + ColRight.width + Settings.PADDING.ColInter;
1748
  Lines := ColLeft.height DIV LineH;
1749
  ColLeft.height := Lines * LineH;
9896 akron1 1750
  PID := SU.NewThread(Start, Stack);
1751
  WHILE ~SU.IsTerminated(PID) DO
1752
    event := SU.CheckEvent();
1753
    IF event = 3 THEN
1754
      SU.TerminateThreadId(PID);
1755
      SU.Halt
1756
    END;
1757
    G.Progress(RF.Progress());
1758
    G.Draw(Canvas_X, Canvas_Y);
1759
    DrawWindow;
1760
    SU.Pause(30)
1761
  END;
1762
  IF ~done THEN
1763
    SU.Halt
1764
  END;
1765
  loaded := TRUE;
1766
  resized := TRUE;
1767
  IF history # NIL THEN
1768
    Load
1769
  ELSE
1770
    SetSettings(Settings)
1771
  END
1772
END Open;
1773
 
1774
 
1775
PROCEDURE Close*;
1776
BEGIN
1777
  SU.DelCursor(cursor);
1778
  Save;
1779
  SU.Halt
1780
END Close;
1781
 
1782
 
1783
PROCEDURE SetScrollBar*(_sb: box_lib.scrollbar);
1784
BEGIN
1785
  sb := _sb
1786
END SetScrollBar;
1787
 
1788
 
1789
PROCEDURE Set_b_pict*(b_pict: BOOLEAN);
1790
BEGIN
1791
  Settings.b_pict := b_pict
1792
END Set_b_pict;
1793
 
1794
 
9912 akron1 1795
PROCEDURE SetWinSize* (x, y: INTEGER);
9896 akron1 1796
BEGIN
9912 akron1 1797
	win_size_x := x;
1798
	win_size_y := y
1799
END SetWinSize;
1800
 
1801
 
1802
BEGIN
9896 akron1 1803
	clickRef := NIL;
1804
	hoverRef := NIL;
1805
	mouseDown := FALSE
1806
END DOM.