21c201190a
git-svn-id: svn://kolibrios.org@9912 a494cfbc-eb01-0410-851d-a64ba20cac60
1807 lines
42 KiB
Plaintext
1807 lines
42 KiB
Plaintext
(*
|
|
Copyright 2016-2023 Anton Krotov
|
|
|
|
This file is part of fb2read.
|
|
|
|
fb2read is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
fb2read is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with fb2read. If not, see <http://www.gnu.org/licenses/>.
|
|
*)
|
|
|
|
MODULE DOM;
|
|
|
|
IMPORT XML, SU := SysUtils, S := Strings, Font, Window, G := Graph, LibImg,
|
|
RF := ReadFile, File, Ini, K := KOSAPI, sys := SYSTEM,
|
|
V := Vector, Cursor, box_lib, tables, Search;
|
|
|
|
|
|
CONST
|
|
|
|
BACK_COLOR* = 0;
|
|
TEXT_COLOR* = 1;
|
|
ITALIC_COLOR* = 2;
|
|
LINK_COLOR* = 3;
|
|
VISITED_COLOR* = 4;
|
|
CLICKED_COLOR* = 5;
|
|
|
|
CellPadding = 5;
|
|
|
|
|
|
TYPE
|
|
|
|
TSettings* = RECORD
|
|
|
|
Colors* : ARRAY 6 OF INTEGER;
|
|
FontSize* : INTEGER;
|
|
TwoCol* : BOOLEAN;
|
|
b_pict* : BOOLEAN;
|
|
|
|
PADDING* : RECORD Left, Right, Top*, Bottom, ColInter, LRpc*, CInt*: INTEGER END;
|
|
|
|
PARAGRAPH*,
|
|
EPIGRAPH*,
|
|
LEVEL,
|
|
SUB,
|
|
SUP,
|
|
InterLin*,
|
|
Picture*,
|
|
picture_fsize*,
|
|
SpaceW: INTEGER
|
|
|
|
END;
|
|
|
|
StackItem = POINTER TO TStackItem;
|
|
|
|
TStackItem = RECORD (XML.DESC_ELEMENT)
|
|
|
|
body : XML.TAG;
|
|
Ycur : INTEGER;
|
|
d : REAL
|
|
|
|
END;
|
|
|
|
|
|
VAR
|
|
|
|
Settings* : TSettings;
|
|
Canvas_X, Canvas_Y: INTEGER;
|
|
ColLeft, ColRight: Window.tRect;
|
|
|
|
Ymin, Ymax, Ycur : INTEGER;
|
|
|
|
X, Y, W, LineH, W1, W2: INTEGER;
|
|
|
|
epigraph : INTEGER;
|
|
sup, sub : INTEGER;
|
|
ref_depth : INTEGER;
|
|
align : INTEGER;
|
|
code : INTEGER;
|
|
strong : INTEGER;
|
|
italic : INTEGER;
|
|
strike : INTEGER;
|
|
refer : INTEGER;
|
|
|
|
Text : ARRAY 100000 OF XML.TEXT;
|
|
TextCount : INTEGER;
|
|
|
|
Lines: INTEGER;
|
|
|
|
description, contents, mainbody, body, ref, cover, clickRef, hoverRef: XML.TAG;
|
|
|
|
MainBody: BOOLEAN;
|
|
|
|
f_stk, b_stk, vis_ref: XML.LIST;
|
|
|
|
FilePath, FileName: S.STRING;
|
|
|
|
done, last, resized, loaded*, mouseDown: BOOLEAN;
|
|
|
|
Stack*: ARRAY 1000000 OF CHAR;
|
|
|
|
Ycont: INTEGER;
|
|
|
|
history: File.FS;
|
|
|
|
references: V.VECTOR;
|
|
cursor: INTEGER;
|
|
|
|
fsize2, chksum: INTEGER;
|
|
|
|
sb: box_lib.scrollbar;
|
|
urlstr* : S.STRING;
|
|
DrawStatus, DrawToolbar: PROCEDURE;
|
|
win_size_x, win_size_y: INTEGER;
|
|
|
|
|
|
PROCEDURE PushRef(ref: XML.TAG);
|
|
VAR item: StackItem;
|
|
BEGIN
|
|
NEW(item);
|
|
item.body := ref;
|
|
XML.AddItem(vis_ref, item);
|
|
END PushRef;
|
|
|
|
|
|
PROCEDURE Push(VAR stk: XML.LIST);
|
|
VAR item: StackItem;
|
|
BEGIN
|
|
NEW(item);
|
|
item.body := body;
|
|
item.Ycur := Ycur;
|
|
XML.AddItem(stk, item);
|
|
IF body = contents THEN
|
|
Ycont := Ycur
|
|
END
|
|
END Push;
|
|
|
|
|
|
PROCEDURE Pop(VAR stk: XML.LIST);
|
|
VAR item : StackItem;
|
|
BEGIN
|
|
item := stk.last(StackItem);
|
|
IF item # NIL THEN
|
|
body := item.body;
|
|
Ymin := body.Ymin;
|
|
Ymax := body.Ymax;
|
|
Ycur := item.Ycur;
|
|
XML.DelLastItem(stk)
|
|
END
|
|
END Pop;
|
|
|
|
|
|
PROCEDURE Clear(VAR stk: XML.LIST);
|
|
BEGIN
|
|
REPEAT
|
|
XML.DelLastItem(stk)
|
|
UNTIL stk.last = NIL
|
|
END Clear;
|
|
|
|
|
|
PROCEDURE AddToLine(text: XML.TEXT);
|
|
BEGIN
|
|
Text[TextCount] := text;
|
|
INC(TextCount)
|
|
END AddToLine;
|
|
|
|
|
|
PROCEDURE Epigraph(): INTEGER;
|
|
RETURN ORD(epigraph > 0) * Settings.EPIGRAPH
|
|
END Epigraph;
|
|
|
|
|
|
PROCEDURE SpaceWidth(): INTEGER;
|
|
VAR Result: INTEGER;
|
|
BEGIN
|
|
IF code > 0 THEN
|
|
Result := Font.MonoWidth()
|
|
ELSE
|
|
Result := Settings.SpaceW
|
|
END
|
|
RETURN Result
|
|
END SpaceWidth;
|
|
|
|
|
|
PROCEDURE Trim;
|
|
VAR n: INTEGER;
|
|
BEGIN
|
|
IF TextCount > 0 THEN
|
|
n := TextCount - 1;
|
|
WHILE (n >= 0) & (Text[n] IS XML.SPACE) DO
|
|
Text[n].width := -1;
|
|
DEC(n)
|
|
END;
|
|
TextCount := n + 1
|
|
END
|
|
END Trim;
|
|
|
|
|
|
PROCEDURE Align;
|
|
VAR
|
|
i, n, sp, d, quo, rem, x: INTEGER;
|
|
text: XML.TEXT;
|
|
BEGIN
|
|
IF (TextCount > 0) & (code = 0) & (align # 3) THEN
|
|
sp := 0;
|
|
Trim;
|
|
n := TextCount - 1;
|
|
IF n >= 0 THEN
|
|
d := W - Text[n].X - Text[n].width
|
|
END;
|
|
IF align = 1 THEN
|
|
x := (d + Text[0].X) DIV 2
|
|
ELSIF align = 2 THEN
|
|
x := d + Text[0].X
|
|
ELSIF align = 0 THEN
|
|
x := Text[0].X;
|
|
FOR i := 0 TO n DO
|
|
IF Text[i] IS XML.SPACE THEN
|
|
INC(sp)
|
|
END
|
|
END;
|
|
IF sp > 0 THEN
|
|
quo := d DIV sp;
|
|
rem := d MOD sp;
|
|
FOR i := 0 TO n DO
|
|
IF Text[i] IS XML.SPACE THEN
|
|
text := Text[i];
|
|
text.width := text.width + quo + ORD(rem > 0);
|
|
DEC(rem)
|
|
END
|
|
END
|
|
END
|
|
END;
|
|
FOR i := 0 TO n DO
|
|
text := Text[i];
|
|
text.X := x;
|
|
INC(x, text.width)
|
|
END
|
|
END
|
|
END Align;
|
|
|
|
|
|
PROCEDURE NewLine;
|
|
BEGIN
|
|
IF align # 0 THEN
|
|
Align
|
|
END;
|
|
X := Epigraph();
|
|
INC(Y, LineH);
|
|
TextCount := 0
|
|
END NewLine;
|
|
|
|
|
|
PROCEDURE Sup(open: BOOLEAN);
|
|
BEGIN
|
|
IF open THEN
|
|
IF sup = 0 THEN
|
|
DEC(Y, Settings.SUP)
|
|
END;
|
|
INC(sup)
|
|
ELSE
|
|
DEC(sup);
|
|
IF sup = 0 THEN
|
|
INC(Y, Settings.SUP)
|
|
END
|
|
END
|
|
END Sup;
|
|
|
|
|
|
PROCEDURE Sub(open: BOOLEAN);
|
|
BEGIN
|
|
IF open THEN
|
|
IF sub = 0 THEN
|
|
INC(Y, Settings.SUB)
|
|
END;
|
|
INC(sub)
|
|
ELSE
|
|
DEC(sub);
|
|
IF sub = 0 THEN
|
|
DEC(Y, Settings.SUB)
|
|
END
|
|
END
|
|
END Sub;
|
|
|
|
|
|
PROCEDURE Split(word: XML.WORD);
|
|
VAR
|
|
i, n, max, len: INTEGER;
|
|
c: CHAR;
|
|
rem: XML.WORD;
|
|
BEGIN
|
|
WHILE Font.TextWidth(word.value, max) <= W DO
|
|
INC(max)
|
|
END;
|
|
DEC(max);
|
|
IF max = 0 THEN
|
|
max := 1
|
|
END;
|
|
i := 0;
|
|
n := 0;
|
|
len := word.value.last - word.value.first + 1;
|
|
WHILE (n <= max) & (i < len) DO
|
|
c := S.GetChar(word.value, i);
|
|
INC(n);
|
|
IF (80X <= c) & (c <= 0BFX) THEN
|
|
DEC(n)
|
|
END;
|
|
INC(i)
|
|
END;
|
|
IF n > max THEN
|
|
DEC(i);
|
|
rem := XML.CreateWord();
|
|
rem^ := word^;
|
|
rem.value.first := word.value.first + i;
|
|
word.next := rem;
|
|
word.value.last := rem.value.first - 1;
|
|
word.length := S.Utf8Length(word.value);
|
|
word.width := Font.TextWidth(word.value, word.length)
|
|
END
|
|
END Split;
|
|
|
|
|
|
PROCEDURE Depth(tag: XML.ELEMENT): INTEGER;
|
|
VAR n: INTEGER;
|
|
BEGIN
|
|
n := 0;
|
|
WHILE tag # NIL DO
|
|
IF tag(XML.TAG).value = XML.tag_section THEN
|
|
INC(n)
|
|
END;
|
|
tag := tag.parent
|
|
END
|
|
RETURN n
|
|
END Depth;
|
|
|
|
|
|
PROCEDURE shift(tag: XML.TAG; shx, shy: INTEGER);
|
|
VAR cur: XML.ELEMENT; t: XML.TAG;
|
|
BEGIN
|
|
cur := tag.child.first;
|
|
WHILE cur # NIL DO
|
|
IF cur IS XML.TAG THEN
|
|
t := cur(XML.TAG);
|
|
INC(t.X, shx);
|
|
INC(t.Ymin, shy);
|
|
INC(t.Ymax, shy);
|
|
shift(t, shx, shy)
|
|
ELSIF cur IS XML.TEXT THEN
|
|
INC(cur(XML.TEXT).X, shx);
|
|
INC(cur(XML.TEXT).Y, shy)
|
|
END;
|
|
cur := cur.next
|
|
END
|
|
END shift;
|
|
|
|
|
|
PROCEDURE getspan(td: XML.TAG; span: S.STRING): INTEGER;
|
|
VAR res: INTEGER;
|
|
attr_value: S.CHARS;
|
|
err: BOOLEAN;
|
|
BEGIN
|
|
IF XML.GetAttr(td, span, attr_value) THEN
|
|
res := S.CharsToInt(attr_value, err);
|
|
IF err OR (res <= 0) THEN
|
|
res := 1
|
|
END
|
|
ELSE
|
|
res := 1
|
|
END
|
|
RETURN res
|
|
END getspan;
|
|
|
|
|
|
PROCEDURE td(t: tables.Table; tag: XML.TAG);
|
|
BEGIN
|
|
tag.cell := t.cells.count;
|
|
tables.td(t, getspan(tag, "colspan"), getspan(tag, "rowspan"))
|
|
END td;
|
|
|
|
|
|
PROCEDURE tr(t: tables.Table; tag: XML.TAG);
|
|
VAR
|
|
cur : XML.ELEMENT;
|
|
cell : XML.TAG;
|
|
BEGIN
|
|
tables.tr(t);
|
|
cur := tag.child.first;
|
|
WHILE cur # NIL DO
|
|
IF cur IS XML.TAG THEN
|
|
cell := cur(XML.TAG);
|
|
IF (cell.value = XML.tag_td) OR (cell.value = XML.tag_th) THEN
|
|
cell.table := t;
|
|
td(t, cell)
|
|
END
|
|
END;
|
|
cur := cur.next
|
|
END
|
|
END tr;
|
|
|
|
|
|
PROCEDURE table(t: tables.Table; tag: XML.TAG; open: BOOLEAN);
|
|
VAR
|
|
cur : XML.ELEMENT;
|
|
row : XML.TAG;
|
|
BEGIN
|
|
IF open THEN
|
|
tables.table(t, W, TRUE);
|
|
cur := tag.child.first;
|
|
WHILE cur # NIL DO
|
|
IF cur IS XML.TAG THEN
|
|
row := cur(XML.TAG);
|
|
IF row.value = XML.tag_tr THEN
|
|
row.table := t;
|
|
tr(t, row)
|
|
END
|
|
END;
|
|
cur := cur.next
|
|
END;
|
|
tables.table(t, W, FALSE)
|
|
END
|
|
END table;
|
|
|
|
|
|
PROCEDURE Image (VAR tag: XML.TAG; destroy: BOOLEAN);
|
|
VAR
|
|
note : BOOLEAN;
|
|
img : XML.TAG;
|
|
URL : INTEGER;
|
|
chars : S.CHARS;
|
|
sizeY : INTEGER;
|
|
FName : S.STRING;
|
|
path : S.STRING;
|
|
BEGIN
|
|
LibImg.Destroy(tag.img);
|
|
img := XML.GetRef(tag, note, URL);
|
|
IF img # NIL THEN
|
|
IF img.child.first IS XML.WORD THEN
|
|
chars := img.child.first(XML.WORD).value;
|
|
tag.img := LibImg.GetImg(chars.first, chars.last - chars.first + 1, W, sizeY)
|
|
END
|
|
ELSIF URL # 0 THEN
|
|
S.PtrToString(URL, FName);
|
|
tag.img := LibImg.LoadFromFile(FName, W, sizeY);
|
|
IF tag.img = 0 THEN
|
|
path := FilePath;
|
|
IF FName[0] # "/" THEN
|
|
S.Append(path, "/")
|
|
END;
|
|
S.Append(path, FName);
|
|
tag.img := LibImg.LoadFromFile(path, W, sizeY)
|
|
END
|
|
END;
|
|
IF (tag.img # 0) & destroy THEN
|
|
INC(Y, (sizeY DIV LineH) * LineH);
|
|
NewLine;
|
|
tag.Ymax := Y - Y MOD LineH;
|
|
LibImg.Destroy(tag.img)
|
|
END
|
|
END Image;
|
|
|
|
|
|
PROCEDURE layout(body: XML.ELEMENT);
|
|
VAR
|
|
cur : XML.ELEMENT;
|
|
tag : XML.TAG;
|
|
word : XML.WORD;
|
|
text : XML.TEXT;
|
|
tag_value : INTEGER;
|
|
_align : INTEGER;
|
|
title : XML.ELEMENT;
|
|
width : INTEGER;
|
|
height1 : INTEGER;
|
|
height2 : INTEGER;
|
|
|
|
BEGIN
|
|
cur := body;
|
|
WHILE cur # NIL DO
|
|
IF cur IS XML.TAG THEN
|
|
tag := cur(XML.TAG);
|
|
tag_value := tag.value;
|
|
CASE tag_value OF
|
|
|XML.tag_p, XML.tag_v:
|
|
Trim;
|
|
IF TextCount > 0 THEN
|
|
NewLine
|
|
END;
|
|
X := Settings.PARAGRAPH + Epigraph()
|
|
|XML.tag_epigraph:
|
|
NewLine;
|
|
INC(epigraph)
|
|
|XML.tag_contents_item:
|
|
INC(ref_depth);
|
|
Settings.EPIGRAPH := Settings.LEVEL * Depth(tag);
|
|
_align := align;
|
|
align := 3
|
|
|XML.tag_title:
|
|
INC(strong);
|
|
Font.Bold(TRUE);
|
|
_align := align;
|
|
align := 1;
|
|
IF MainBody THEN
|
|
tag.value := XML.tag_contents_item;
|
|
title := XML.Copy(tag);
|
|
XML.AddChild(contents, title);
|
|
title.parent := tag.parent;
|
|
tag.value := XML.tag_title
|
|
END
|
|
|XML.tag_subtitle:
|
|
NewLine;
|
|
_align := align;
|
|
align := 1
|
|
|XML.tag_text_author, XML.tag_date:
|
|
_align := align;
|
|
align := 2
|
|
|XML.tag_section, XML.tag_body, XML.tag_empty_line, XML.tag_poem, XML.tag_stanza, XML.tag_annotation, XML.tag_cite:
|
|
NewLine
|
|
|XML.tag_a:
|
|
INC(ref_depth);
|
|
IF XML.IsNote(tag) THEN
|
|
Sup(TRUE)
|
|
END
|
|
|XML.tag_sup:
|
|
Sup(TRUE)
|
|
|XML.tag_sub:
|
|
Sub(TRUE)
|
|
|XML.tag_code:
|
|
Font.sysfont(TRUE);
|
|
INC(code)
|
|
|XML.tag_image:
|
|
tag.X := 0;
|
|
NewLine;
|
|
NewLine
|
|
|XML.tag_coverpage:
|
|
cover := tag
|
|
|
|
|XML.tag_table:
|
|
NewLine;
|
|
tables.destroy(tag.table);
|
|
NEW(tag.table);
|
|
table(tag.table, tag, TRUE)
|
|
|XML.tag_td, XML.tag_th:
|
|
IF tag_value = XML.tag_th THEN
|
|
INC(strong);
|
|
Font.Bold(TRUE);
|
|
END;
|
|
SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_tr, 21);
|
|
NewLine; DEC(Y, LineH);
|
|
tag.Width := tables.get_width(tag.table, tag.cell);
|
|
tag.X := tables.get_x(tag.table, tag.cell);
|
|
width := W;
|
|
W := tag.Width - 2 * CellPadding;
|
|
IF W <= 0 THEN
|
|
W := 1
|
|
END
|
|
|XML.tag_tr:
|
|
SU.ErrorIf(tag.parent(XML.TAG).value # XML.tag_table, 20)
|
|
|
|
|XML.tag_strong:
|
|
INC(strong);
|
|
Font.Bold(TRUE)
|
|
ELSE
|
|
END;
|
|
|
|
tag.Ymin := Y - Y MOD LineH;
|
|
layout(tag.child.first);
|
|
tag.Ymax := Y - Y MOD LineH;
|
|
|
|
CASE tag_value OF
|
|
|XML.tag_epigraph:
|
|
NewLine;
|
|
DEC(epigraph)
|
|
|XML.tag_subtitle:
|
|
NewLine;
|
|
NewLine;
|
|
align := _align
|
|
|XML.tag_title, XML.tag_text_author, XML.tag_date:
|
|
DEC(strong);
|
|
Font.Bold(strong > 0);
|
|
NewLine;
|
|
align := _align
|
|
|XML.tag_contents_item:
|
|
DEC(ref_depth);
|
|
align := _align;
|
|
|XML.tag_section, XML.tag_poem, XML.tag_v, XML.tag_p, XML.tag_annotation, XML.tag_cite:
|
|
NewLine
|
|
|XML.tag_a:
|
|
DEC(ref_depth);
|
|
IF XML.IsNote(tag) THEN
|
|
Sup(FALSE)
|
|
END
|
|
|XML.tag_sup:
|
|
Sup(FALSE)
|
|
|XML.tag_sub:
|
|
Sub(FALSE)
|
|
|XML.tag_code:
|
|
DEC(code);
|
|
Font.sysfont(code > 0)
|
|
|XML.tag_image:
|
|
Image(tag, TRUE)
|
|
|XML.tag_table:
|
|
Y := tag.Ymin + tables.get_table_height(tag.table);
|
|
tag.Ymax := Y - Y MOD LineH;
|
|
NewLine;
|
|
|XML.tag_td, XML.tag_th:
|
|
IF tag_value = XML.tag_th THEN
|
|
DEC(strong);
|
|
Font.Bold(strong > 0)
|
|
END;
|
|
W := width;
|
|
NewLine;
|
|
Y := tag.Ymin + Settings.SUP; //!!!
|
|
height1 := tables.get_height(tag.table, tag.cell);
|
|
height2 := tag.Ymax - tag.Ymin + LineH;
|
|
IF height2 > height1 THEN
|
|
tables.set_height(tag.table, tag.cell, height2)
|
|
END;
|
|
INC(tag.Ymin, tables.get_y(tag.table, tag.cell));
|
|
INC(tag.Ymax, tables.get_height(tag.table, tag.cell));
|
|
shift(tag, tag.X + CellPadding, tables.get_y(tag.table, tag.cell));
|
|
|
|
|XML.tag_strong:
|
|
DEC(strong);
|
|
Font.Bold(strong > 0)
|
|
ELSE
|
|
END
|
|
ELSIF cur IS XML.WORD THEN
|
|
word := cur(XML.WORD);
|
|
word.length := S.Utf8Length(word.value);
|
|
word.width := Font.TextWidth(word.value, word.length);
|
|
IF W - X < word.width THEN
|
|
Align;
|
|
NewLine
|
|
END;
|
|
IF W < word.width THEN
|
|
Split(word)
|
|
END
|
|
ELSIF cur IS XML.SPACE THEN
|
|
IF W - X < SpaceWidth() THEN
|
|
cur(XML.SPACE).width := 0
|
|
ELSE
|
|
cur(XML.SPACE).width := SpaceWidth()
|
|
END
|
|
END;
|
|
IF cur IS XML.TEXT THEN
|
|
IF ref_depth > 0 THEN
|
|
V.push(references, cur)
|
|
END;
|
|
text := cur(XML.TEXT);
|
|
text.X := X;
|
|
text.Y := Y;
|
|
INC(X, text.width);
|
|
AddToLine(text)
|
|
END;
|
|
cur := cur.next
|
|
END
|
|
END layout;
|
|
|
|
|
|
PROCEDURE layout2(body: XML.ELEMENT);
|
|
VAR
|
|
color : INTEGER;
|
|
cur : XML.ELEMENT;
|
|
text : XML.TEXT;
|
|
tag : XML.TAG;
|
|
y, y0 : INTEGER;
|
|
value : INTEGER;
|
|
|
|
PROCEDURE DrawText(Col: Window.tRect; min, max, y0, y: INTEGER; right: BOOLEAN; VAR text: XML.TEXT);
|
|
VAR word: XML.WORD;
|
|
BEGIN
|
|
IF (min <= y0) & (y0 <= max) THEN
|
|
Font.sysfont(code > 0);
|
|
IF text IS XML.WORD THEN
|
|
word := text(XML.WORD);
|
|
Font.Text(Col, word.X, y - Col.height * ORD(right), word.value.first, word.length);
|
|
END;
|
|
Font.StrikeText(Col, text.X, y - Col.height * ORD(right), text.width)
|
|
END
|
|
END DrawText;
|
|
|
|
PROCEDURE DrawImage(VAR tag: XML.TAG);
|
|
VAR sizeX, sizeY, img, y: INTEGER;
|
|
BEGIN
|
|
IF tag.img # 0 THEN
|
|
y := Ycur;
|
|
LibImg.GetInf(tag.img, sizeX, sizeY, img);
|
|
IF (y <= tag.Ymax) & (tag.Ymin <= y + ColLeft.height) THEN
|
|
G.Image(ColLeft.left + tag.X, tag.Ymin - y + ColLeft.top, sizeX, sizeY, img, ColLeft.top, ColLeft.top + ColLeft.height - 1)
|
|
END;
|
|
IF Settings.TwoCol THEN
|
|
y := Ycur + ColLeft.height;
|
|
IF (y <= tag.Ymax) & (tag.Ymin <= y + ColRight.height) THEN
|
|
G.Image(ColRight.left + tag.X, tag.Ymin - y + ColLeft.top, sizeX, sizeY, img, ColRight.top, ColRight.top + ColRight.height - 1)
|
|
END
|
|
END
|
|
END
|
|
END DrawImage;
|
|
|
|
PROCEDURE td(VAR tag: XML.TAG);
|
|
VAR x1, y1, x2, y2, cl: INTEGER;
|
|
BEGIN
|
|
x1 := tag.X + ColLeft.left;
|
|
y1 := tag.Ymin - Ycur + ColLeft.top;
|
|
x2 := x1 + tag.Width;
|
|
y2 := y1 + tables.get_height(tag.table, tag.cell);
|
|
cl := G.GetColor();
|
|
G.SetColor(Settings.Colors[TEXT_COLOR]);
|
|
G.Rect(x1, y1, x2, y2);
|
|
IF Settings.TwoCol THEN
|
|
x1 := x1 - ColLeft.left + ColRight.left;
|
|
x2 := x2 - ColLeft.left + ColRight.left;
|
|
y1 := y1 - ColLeft.height;
|
|
y2 := y2 - ColLeft.height;
|
|
G.Rect(x1, y1, x2, y2)
|
|
END;
|
|
G.SetColor(cl)
|
|
END td;
|
|
|
|
BEGIN
|
|
cur := body;
|
|
WHILE cur # NIL DO
|
|
IF cur IS XML.TAG THEN
|
|
tag := cur(XML.TAG);
|
|
IF (tag.value = XML.tag_td) OR (tag.value = XML.tag_th) THEN
|
|
tag.Ymax := tag.Ymin + tables.get_height(tag.table, tag.cell)
|
|
END;
|
|
|
|
IF (tag.Ymin < Ycur + LineH * Lines * (ORD(Settings.TwoCol) + 1)) & (tag.Ymax >= Ycur) OR (tag.value = XML.tag_tr) THEN
|
|
|
|
value := tag.value;
|
|
CASE value OF
|
|
|XML.tag_a:
|
|
INC(refer);
|
|
color := Font.Font.color;
|
|
IF tag.Clicked THEN
|
|
Font.SetFontColor(Settings.Colors[CLICKED_COLOR])
|
|
ELSE
|
|
IF tag.Visited THEN
|
|
Font.SetFontColor(Settings.Colors[VISITED_COLOR])
|
|
ELSE
|
|
Font.SetFontColor(Settings.Colors[LINK_COLOR])
|
|
END
|
|
END
|
|
|XML.tag_contents_item:
|
|
IF tag.Clicked THEN
|
|
INC(refer);
|
|
color := Font.Font.color;
|
|
Font.SetFontColor(Settings.Colors[CLICKED_COLOR])
|
|
ELSIF tag.Visited THEN
|
|
INC(refer);
|
|
color := Font.Font.color;
|
|
Font.SetFontColor(Settings.Colors[VISITED_COLOR])
|
|
END
|
|
|XML.tag_title, XML.tag_strong, XML.tag_th:
|
|
INC(strong);
|
|
Font.Bold(TRUE)
|
|
|XML.tag_strikethrough:
|
|
INC(strike);
|
|
Font.Strike(TRUE)
|
|
|XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis:
|
|
INC(italic);
|
|
Font.Italic(TRUE, refer = 0)
|
|
|XML.tag_image:
|
|
Image(tag, FALSE);
|
|
DrawImage(tag);
|
|
LibImg.Destroy(tag.img)
|
|
|XML.tag_code:
|
|
INC(code)
|
|
ELSE
|
|
END;
|
|
layout2(tag.child.first);
|
|
CASE value OF
|
|
|XML.tag_a:
|
|
DEC(refer);
|
|
Font.SetFontColor(color)
|
|
|XML.tag_contents_item:
|
|
IF tag.Clicked OR tag.Visited THEN
|
|
DEC(refer);
|
|
Font.SetFontColor(color)
|
|
END
|
|
|XML.tag_title, XML.tag_strong:
|
|
DEC(strong);
|
|
Font.Bold(strong > 0)
|
|
|XML.tag_strikethrough:
|
|
DEC(strike);
|
|
Font.Strike(strike > 0)
|
|
|XML.tag_epigraph, XML.tag_cite, XML.tag_emphasis:
|
|
DEC(italic);
|
|
Font.Italic(italic > 0, refer = 0)
|
|
|XML.tag_td:
|
|
td(tag)
|
|
|XML.tag_th:
|
|
DEC(strong);
|
|
Font.Bold(strong > 0);
|
|
td(tag)
|
|
|XML.tag_code:
|
|
DEC(code)
|
|
ELSE
|
|
END
|
|
|
|
END
|
|
ELSIF cur IS XML.TEXT THEN
|
|
text := cur(XML.TEXT);
|
|
y := text.Y - Ycur;
|
|
y0 := y - y MOD LineH;
|
|
DrawText(ColLeft, 0, ColLeft.height - LineH, y0, y, FALSE, text);
|
|
IF Settings.TwoCol THEN
|
|
DrawText(ColRight, ColLeft.height, ColLeft.height + ColRight.height - LineH, y0, y, TRUE, text)
|
|
END
|
|
END;
|
|
cur := cur.next
|
|
END
|
|
END layout2;
|
|
|
|
|
|
PROCEDURE DrawFrame (color: INTEGER);
|
|
VAR max_X, max_Y: INTEGER;
|
|
BEGIN
|
|
max_X := G.Buffer.Width - 1;
|
|
max_Y := G.Buffer.Height - 1;
|
|
G.SetColor(color);
|
|
G.HLine(0, max_X, 0);
|
|
G.HLine(0, max_X, max_Y);
|
|
G.VLine(0, 0, max_Y);
|
|
sb.max_area := (Ymax - Ymin) DIV LineH + 50;
|
|
sb.cur_area := 50;
|
|
sb.position := (Ycur - Ymin) DIV LineH;
|
|
box_lib.scrollbar_v_draw(sb)
|
|
END DrawFrame;
|
|
|
|
|
|
PROCEDURE Draw*;
|
|
(*VAR max_Y: INTEGER;*)
|
|
BEGIN
|
|
(*max_Y := G.Buffer.Height - 1;*)
|
|
IF Settings.b_pict & (Settings.Picture # 0) THEN
|
|
G.Copy(G.BackImg, G.Buffer, 0, G.Buffer.Height, 0)
|
|
ELSE
|
|
G.Fill(G.Buffer, Settings.Colors[BACK_COLOR])
|
|
END;
|
|
Font.SetFontColor(Settings.Colors[TEXT_COLOR]);
|
|
IF ((body = description) OR (body = contents)) & Settings.TwoCol THEN
|
|
Settings.TwoCol := FALSE;
|
|
layout2(body.child.first);
|
|
Settings.TwoCol := TRUE;
|
|
Search.draw(body, ColLeft, ColRight, Ycur, LineH, FALSE)
|
|
ELSE
|
|
layout2(body.child.first);
|
|
Search.draw(body, ColLeft, ColRight, Ycur, LineH, Settings.TwoCol)
|
|
END;
|
|
(*G.Copy(G.BackImg, G.Buffer, 0, ColLeft.top + 1, 0);
|
|
G.Copy(G.BackImg, G.Buffer, max_Y - ColLeft.top, ColLeft.top + 1, max_Y - ColLeft.top);*)
|
|
DrawFrame(0);
|
|
G.Draw(Canvas_X, Canvas_Y);
|
|
DrawToolbar;
|
|
DrawStatus
|
|
END Draw;
|
|
|
|
|
|
PROCEDURE BackEnabled* (): BOOLEAN;
|
|
RETURN b_stk.first # NIL
|
|
END BackEnabled;
|
|
|
|
|
|
PROCEDURE FrwEnabled* (): BOOLEAN;
|
|
RETURN f_stk.first # NIL
|
|
END FrwEnabled;
|
|
|
|
|
|
PROCEDURE ContentsEnabled* (): BOOLEAN;
|
|
RETURN (contents # NIL) (*& (body # contents)*)
|
|
END ContentsEnabled;
|
|
|
|
|
|
PROCEDURE DescrEnabled* (): BOOLEAN;
|
|
RETURN (description # NIL) (*& (body # description)*)
|
|
END DescrEnabled;
|
|
|
|
|
|
PROCEDURE Back*;
|
|
BEGIN
|
|
IF b_stk.first # NIL THEN
|
|
Push(f_stk);
|
|
Pop(b_stk)
|
|
END
|
|
END Back;
|
|
|
|
|
|
PROCEDURE Forward*;
|
|
BEGIN
|
|
IF f_stk.first # NIL THEN
|
|
Push(b_stk);
|
|
Pop(f_stk)
|
|
END
|
|
END Forward;
|
|
|
|
|
|
PROCEDURE Contents*;
|
|
BEGIN
|
|
IF (contents # NIL) & (body # contents) THEN
|
|
Push(b_stk);
|
|
Clear(f_stk);
|
|
body := contents;
|
|
Ycur := Ycont;
|
|
Ymin := 0;
|
|
Ymax := body.Ymax
|
|
END
|
|
END Contents;
|
|
|
|
|
|
PROCEDURE Descr*;
|
|
BEGIN
|
|
IF (description # NIL) & (body # description) THEN
|
|
Push(b_stk);
|
|
Clear(f_stk);
|
|
body := description;
|
|
Ycur := 0;
|
|
Ymin := 0;
|
|
Ymax := body.Ymax
|
|
END
|
|
END Descr;
|
|
|
|
|
|
PROCEDURE Scroll* (n: INTEGER);
|
|
BEGIN
|
|
INC(Ycur, LineH*n);
|
|
SU.MinMax(Ycur, Ymin, Ymax)
|
|
END Scroll;
|
|
|
|
|
|
PROCEDURE PageUp*;
|
|
BEGIN
|
|
Scroll(-Lines * (ORD(Settings.TwoCol) + 1))
|
|
END PageUp;
|
|
|
|
|
|
PROCEDURE PageDown*;
|
|
BEGIN
|
|
Scroll(Lines * (ORD(Settings.TwoCol) + 1))
|
|
END PageDown;
|
|
|
|
|
|
PROCEDURE Home*;
|
|
BEGIN
|
|
IF Ycur # Ymin THEN
|
|
Push(b_stk);
|
|
Clear(f_stk);
|
|
Ycur := Ymin
|
|
END
|
|
END Home;
|
|
|
|
|
|
PROCEDURE End*;
|
|
BEGIN
|
|
IF Ycur # Ymax THEN
|
|
Push(b_stk);
|
|
Clear(f_stk);
|
|
Ycur := Ymax
|
|
END
|
|
END End;
|
|
|
|
|
|
PROCEDURE ScrollBar*;
|
|
BEGIN
|
|
Ycur := sb.position * LineH + Ymin
|
|
END ScrollBar;
|
|
|
|
|
|
PROCEDURE GetBody(tag: XML.TAG): XML.TAG;
|
|
BEGIN
|
|
WHILE (tag # NIL) & (tag.value # XML.tag_body) DO
|
|
tag := tag.parent(XML.TAG)
|
|
END
|
|
RETURN tag
|
|
END GetBody;
|
|
|
|
|
|
PROCEDURE layout3(Body: XML.ELEMENT; X, Y: INTEGER);
|
|
VAR
|
|
ptr : V.ANYPTR;
|
|
text : XML.TEXT;
|
|
sect : XML.TAG;
|
|
y : INTEGER;
|
|
i : INTEGER;
|
|
BEGIN
|
|
i := 0;
|
|
WHILE i < references.count DO
|
|
ptr := V.get(references, i);
|
|
text := ptr(XML.TEXT);
|
|
y := text.Y - Ycur;
|
|
IF (y <= Y) & (Y <= y + Font.FontH()) & (text.X <= X) & (X <= text.X + text.width) THEN
|
|
sect := text.parent(XML.TAG);
|
|
IF Body = contents THEN
|
|
WHILE (sect # NIL) & (sect.value # XML.tag_contents_item) DO
|
|
sect := sect.parent(XML.TAG)
|
|
END
|
|
ELSE
|
|
WHILE (sect # NIL) & (sect # Body) DO
|
|
IF sect.value = XML.tag_contents_item THEN
|
|
sect := NIL
|
|
ELSE
|
|
sect := sect.parent(XML.TAG)
|
|
END
|
|
END
|
|
END;
|
|
|
|
IF sect # NIL THEN
|
|
sect := text.parent(XML.TAG);
|
|
WHILE sect # NIL DO
|
|
IF (sect.value = XML.tag_contents_item) & (Body = contents) OR (sect.value = XML.tag_a) THEN
|
|
ref := sect;
|
|
sect := NIL;
|
|
i := references.count
|
|
ELSE
|
|
sect := sect.parent(XML.TAG)
|
|
END
|
|
END
|
|
END
|
|
END;
|
|
INC(i)
|
|
END
|
|
END layout3;
|
|
|
|
|
|
PROCEDURE getRefProp (VAR ref, body: XML.TAG; VAR URL: INTEGER; VAR note: BOOLEAN; VAR Y: INTEGER);
|
|
BEGIN
|
|
note := FALSE;
|
|
URL := 0;
|
|
Y := 0;
|
|
IF ref.value = XML.tag_a THEN
|
|
ref := XML.GetRef(ref, note, URL)
|
|
ELSE
|
|
ref := ref.parent(XML.TAG)
|
|
END;
|
|
IF ref # NIL THEN
|
|
Y := ref.Ymin;
|
|
END;
|
|
IF note THEN
|
|
body := ref
|
|
ELSE
|
|
body := GetBody(ref)
|
|
END
|
|
END getRefProp;
|
|
|
|
|
|
PROCEDURE zstreq (s1, s2: INTEGER): BOOLEAN;
|
|
VAR
|
|
c1, c2: CHAR;
|
|
BEGIN
|
|
REPEAT
|
|
sys.GET(s1, c1); INC(s1);
|
|
sys.GET(s2, c2); INC(s2);
|
|
UNTIL (c1 = 0X) OR (c2 = 0X)
|
|
|
|
RETURN c1 = c2
|
|
END zstreq;
|
|
|
|
|
|
PROCEDURE refeq (ref1, ref2: XML.TAG): BOOLEAN;
|
|
VAR
|
|
body1, body2: XML.TAG;
|
|
URL1, URL2: INTEGER;
|
|
note1, note2: BOOLEAN;
|
|
Y1, Y2: INTEGER;
|
|
BEGIN
|
|
getRefProp(ref1, body1, URL1, note1, Y1);
|
|
getRefProp(ref2, body2, URL2, note2, Y2);
|
|
RETURN (ref1 = ref2) & (body1 = body2) & (URL1 = 0) & (URL2 = 0) & (note1 = note2) & (Y1 = Y2) OR
|
|
(URL1 # 0) & (URL2 # 0) & zstreq(URL1, URL2)
|
|
END refeq;
|
|
|
|
|
|
PROCEDURE setVisited (ref: XML.TAG);
|
|
VAR
|
|
i: INTEGER;
|
|
cur: V.ANYPTR;
|
|
BEGIN
|
|
FOR i := 0 TO references.count - 1 DO
|
|
cur := V.get(references, i);
|
|
IF cur IS XML.TEXT THEN
|
|
cur := cur(XML.TEXT).parent;
|
|
IF refeq(cur(XML.TAG), ref) THEN
|
|
cur(XML.TAG).Visited := TRUE
|
|
END
|
|
END
|
|
END
|
|
END setVisited;
|
|
|
|
|
|
PROCEDURE MouseDown;
|
|
BEGIN
|
|
IF ~mouseDown THEN
|
|
mouseDown := TRUE;
|
|
clickRef := ref;
|
|
IF ref # NIL THEN
|
|
ref.Clicked := TRUE
|
|
END;
|
|
Draw
|
|
END
|
|
END MouseDown;
|
|
|
|
|
|
PROCEDURE MouseUp;
|
|
VAR
|
|
note : BOOLEAN;
|
|
URL : INTEGER;
|
|
redraw: BOOLEAN;
|
|
BEGIN
|
|
redraw := FALSE;
|
|
mouseDown := FALSE;
|
|
IF (ref # NIL) & (clickRef = ref) & ref.Clicked THEN
|
|
redraw := TRUE;
|
|
ref.Clicked := FALSE;
|
|
note := FALSE;
|
|
URL := 0;
|
|
IF ref.value = XML.tag_a THEN
|
|
ref := XML.GetRef(ref, note, URL)
|
|
ELSE
|
|
ref := ref.parent(XML.TAG)
|
|
END;
|
|
IF ref # NIL THEN
|
|
Push(b_stk);
|
|
Clear(f_stk);
|
|
Ycur := ref.Ymin;
|
|
IF note THEN
|
|
body := ref
|
|
ELSE
|
|
body := GetBody(ref)
|
|
END;
|
|
Ymax := body.Ymax;
|
|
Ymin := body.Ymin;
|
|
|
|
IF ~clickRef.Visited THEN
|
|
setVisited(clickRef);
|
|
clickRef.Visited := TRUE;
|
|
PushRef(clickRef)
|
|
END
|
|
ELSIF URL # 0 THEN
|
|
SU.Run(Ini.Browser, URL);
|
|
IF ~clickRef.Visited THEN
|
|
setVisited(clickRef);
|
|
clickRef.Visited := TRUE;
|
|
PushRef(clickRef)
|
|
END
|
|
END
|
|
END;
|
|
IF clickRef # NIL THEN
|
|
clickRef.Clicked := FALSE;
|
|
clickRef := NIL;
|
|
redraw := TRUE
|
|
END;
|
|
IF hoverRef # NIL THEN
|
|
hoverRef.Clicked := FALSE;
|
|
hoverRef := NIL;
|
|
redraw := TRUE
|
|
END;
|
|
IF redraw THEN
|
|
Draw
|
|
END
|
|
END MouseUp;
|
|
|
|
|
|
PROCEDURE Click*(X, Y: INTEGER; clicked: BOOLEAN);
|
|
VAR
|
|
note : BOOLEAN;
|
|
URL : INTEGER;
|
|
urlchars: S.CHARS;
|
|
urlstr1 : S.STRING;
|
|
BEGIN
|
|
DEC(Y, Settings.PADDING.Top);
|
|
DEC(X, Settings.PADDING.Left);
|
|
IF (0 <= Y) & (Y <= Lines * LineH) THEN
|
|
ref := NIL;
|
|
layout3(body, X, Y);
|
|
IF (ref = NIL) & Settings.TwoCol THEN
|
|
layout3(body, X - ColLeft.width - Settings.PADDING.ColInter, Y + Lines * LineH);
|
|
END;
|
|
hoverRef := ref;
|
|
IF clicked THEN
|
|
MouseDown
|
|
ELSE
|
|
MouseUp
|
|
END;
|
|
IF ref # NIL THEN
|
|
SU.SetCursor(cursor);
|
|
note := FALSE;
|
|
URL := 0;
|
|
IF ref.value = XML.tag_a THEN
|
|
ref := XML.GetRef(ref, note, URL)
|
|
END;
|
|
IF URL # 0 THEN
|
|
S.PtrToString(URL, urlstr1);
|
|
S.StrToChars(urlstr1, urlchars)
|
|
END
|
|
ELSE
|
|
SU.SetCursor(0);
|
|
urlstr1 := ""
|
|
END;
|
|
IF urlstr1 # urlstr THEN
|
|
urlstr := urlstr1;
|
|
DrawStatus
|
|
END
|
|
ELSE
|
|
SU.SetCursor(0);
|
|
urlstr := "";
|
|
ref := NIL;
|
|
DrawStatus
|
|
END
|
|
END Click;
|
|
|
|
|
|
PROCEDURE main(fb: XML.ELEMENT; Contents: BOOLEAN);
|
|
VAR
|
|
cur: XML.ELEMENT;
|
|
tag: XML.TAG;
|
|
par, epi: INTEGER;
|
|
|
|
|
|
PROCEDURE lout(body: XML.ELEMENT);
|
|
BEGIN
|
|
TextCount := 0;
|
|
X := 0;
|
|
Y := Settings.SUP;
|
|
layout(body(XML.TAG).child.first);
|
|
body(XML.TAG).Ymax := Y - Settings.SUP
|
|
END lout;
|
|
|
|
PROCEDURE lout_one_col(body: XML.ELEMENT);
|
|
BEGIN
|
|
IF body # NIL THEN
|
|
IF Settings.TwoCol THEN
|
|
W := W2;
|
|
Settings.TwoCol := FALSE;
|
|
lout(body);
|
|
Settings.TwoCol := TRUE;
|
|
W := W1
|
|
ELSE
|
|
lout(body)
|
|
END
|
|
END
|
|
END lout_one_col;
|
|
|
|
BEGIN
|
|
TextCount := 0;
|
|
sup := 0;
|
|
sub := 0;
|
|
epigraph := 0;
|
|
align := 0;
|
|
code := 0;
|
|
strong := 0;
|
|
italic := 0;
|
|
strike := 0;
|
|
refer := 0;
|
|
SU.ErrorIf(fb = NIL, 11);
|
|
MainBody := FALSE;
|
|
description := NIL;
|
|
mainbody := NIL;
|
|
cover := NIL;
|
|
cur := fb;
|
|
cur := cur(XML.TAG).child.first;
|
|
WHILE (cur # NIL) & (mainbody = NIL) DO
|
|
IF cur IS XML.TAG THEN
|
|
tag := cur(XML.TAG);
|
|
IF tag.value = XML.tag_description THEN
|
|
description := tag
|
|
ELSIF tag.value = XML.tag_body THEN
|
|
mainbody := tag
|
|
END
|
|
END;
|
|
cur := cur.next
|
|
END;
|
|
SU.ErrorIf(mainbody = NIL, 12);
|
|
|
|
WHILE cur # NIL DO
|
|
IF (cur IS XML.TAG) & (cur(XML.TAG).value = XML.tag_body) THEN
|
|
lout(cur)
|
|
END;
|
|
cur := cur.next
|
|
END;
|
|
|
|
IF Contents THEN
|
|
contents := XML.CreateTag();
|
|
MainBody := TRUE;
|
|
END;
|
|
lout(mainbody);
|
|
IF Contents & (contents.child.first = NIL) THEN
|
|
DISPOSE(contents)
|
|
END;
|
|
MainBody := FALSE;
|
|
epigraph := 1;
|
|
par := Settings.PARAGRAPH;
|
|
epi := Settings.EPIGRAPH;
|
|
Settings.PARAGRAPH := 0;
|
|
Settings.EPIGRAPH := 0;
|
|
lout_one_col(contents);
|
|
Settings.EPIGRAPH := epi;
|
|
Settings.PARAGRAPH := par;
|
|
epigraph := 0;
|
|
lout_one_col(description);
|
|
body := mainbody;
|
|
Ymax := body.Ymax;
|
|
Ycur := 0;
|
|
Ymin := 0;
|
|
Ycont := 0
|
|
END main;
|
|
|
|
|
|
PROCEDURE Find* (d: INTEGER);
|
|
VAR
|
|
y, min, max: INTEGER;
|
|
|
|
BEGIN
|
|
Search.fnext(body, y, d);
|
|
IF y >= 0 THEN
|
|
DEC(y, y MOD LineH);
|
|
min := Ycur;
|
|
max := min + ColLeft.height - LineH;
|
|
IF Settings.TwoCol THEN
|
|
INC(max, ColRight.height)
|
|
END;
|
|
|
|
IF (y < min) OR (y > max) THEN
|
|
Ycur := MAX(y - ColLeft.height DIV 2, 0)
|
|
END;
|
|
|
|
DEC(Ycur, Ycur MOD LineH)
|
|
END
|
|
END Find;
|
|
|
|
|
|
PROCEDURE OpenSearch*;
|
|
BEGIN
|
|
Search.open(Find)
|
|
END OpenSearch;
|
|
|
|
|
|
PROCEDURE CloseSearch*;
|
|
BEGIN
|
|
Search.close
|
|
END CloseSearch;
|
|
|
|
|
|
PROCEDURE found* (): BOOLEAN;
|
|
RETURN Search.found(body)
|
|
END found;
|
|
|
|
|
|
PROCEDURE FontSizeChange(fs: INTEGER);
|
|
BEGIN
|
|
Settings.SUP := fs DIV 4;
|
|
Settings.SUB := fs DIV 4;
|
|
Settings.SpaceW := fs DIV 2;
|
|
Settings.LEVEL := Settings.PARAGRAPH;
|
|
Settings.PADDING.Bottom := Settings.PADDING.Top;
|
|
Settings.PADDING.Left := G.Buffer.Width * Settings.PADDING.LRpc DIV 100;
|
|
IF Settings.PADDING.Left = 0 THEN
|
|
Settings.PADDING.Left := 1
|
|
END;
|
|
Settings.PADDING.Right := Settings.PADDING.Left;
|
|
Settings.PADDING.ColInter := G.Buffer.Width * Settings.PADDING.CInt DIV 100;
|
|
|
|
LineH := Font.FontH() + Settings.SUP + Settings.SUB + Settings.InterLin;
|
|
Window.initRect(
|
|
ColLeft, Settings.PADDING.Left, Settings.PADDING.Top,
|
|
G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right,
|
|
G.Buffer.Height - Settings.PADDING.Top - Settings.PADDING.Bottom);
|
|
IF Settings.TwoCol THEN
|
|
ColLeft.width := (ColLeft.width - Settings.PADDING.ColInter) DIV 2;
|
|
ColRight := ColLeft;
|
|
ColRight.left := ColLeft.left + ColLeft.width + Settings.PADDING.ColInter
|
|
END;
|
|
W := ColLeft.width;
|
|
Lines := ColLeft.height DIV LineH;
|
|
ColLeft.height := Lines * LineH;
|
|
ColRight.height := ColLeft.height;
|
|
END FontSizeChange;
|
|
|
|
|
|
PROCEDURE Resize*(Width, Height: INTEGER);
|
|
VAR d: REAL; resize: BOOLEAN; sizeX, sizeY, data, back_picture: INTEGER;
|
|
|
|
PROCEDURE stk1(stk: XML.LIST);
|
|
VAR cur: StackItem;
|
|
BEGIN
|
|
cur := stk.first(StackItem);
|
|
WHILE cur # NIL DO
|
|
cur.d := FLT(cur.Ycur - cur.body.Ymin) / FLT(cur.body.Ymax - cur.body.Ymin);
|
|
cur := cur.next(StackItem)
|
|
END
|
|
END stk1;
|
|
|
|
PROCEDURE stk2(stk: XML.LIST);
|
|
VAR cur: StackItem;
|
|
BEGIN
|
|
cur := stk.first(StackItem);
|
|
WHILE cur # NIL DO
|
|
cur.Ycur := FLOOR(FLT(cur.body.Ymax - cur.body.Ymin) * cur.d) + cur.body.Ymin;
|
|
cur.Ycur := cur.Ycur - cur.Ycur MOD LineH;
|
|
SU.MinMax(cur.Ycur, cur.body.Ymin, cur.body.Ymax);
|
|
cur := cur.next(StackItem)
|
|
END
|
|
END stk2;
|
|
|
|
BEGIN
|
|
resize := (Width # G.Buffer.Width) OR resized;
|
|
G.Resize(Width, Height);
|
|
IF (Settings.Picture # 0) & Settings.b_pict THEN
|
|
back_picture := LibImg.GetImg(Settings.Picture, Settings.picture_fsize, 1000000, sizeY);
|
|
IF back_picture # 0 THEN
|
|
LibImg.GetInf(back_picture, sizeX, sizeY, data);
|
|
G.CreateBackImg;
|
|
G.BackImage(sizeX, sizeY, data);
|
|
LibImg.Destroy(back_picture)
|
|
END
|
|
ELSE
|
|
G.DestroyBackImg;
|
|
G.Fill(G.Buffer, Settings.Colors[BACK_COLOR]);
|
|
//G.Fill(G.BackImg, Settings.Colors[BACK_COLOR])
|
|
END;
|
|
|
|
IF Font.FontH() # 0 THEN
|
|
FontSizeChange(Font.FontH());
|
|
ELSE
|
|
FontSizeChange(Settings.FontSize);
|
|
END;
|
|
|
|
ColLeft.width := G.Buffer.Width - Settings.PADDING.Left - Settings.PADDING.Right;
|
|
IF Settings.TwoCol THEN
|
|
ColLeft.width := (ColLeft.width - Settings.PADDING.ColInter) DIV 2;
|
|
ColRight.width := ColLeft.width;
|
|
ColRight.left := ColLeft.left + ColLeft.width + Settings.PADDING.ColInter
|
|
END;
|
|
ColLeft.height := G.Buffer.Height - Settings.PADDING.Top - Settings.PADDING.Bottom;
|
|
Lines := ColLeft.height DIV LineH;
|
|
ColLeft.height := Lines * LineH;
|
|
ColRight.height := ColLeft.height;
|
|
|
|
IF done & resize THEN
|
|
resized := FALSE;
|
|
Push(b_stk);
|
|
stk1(b_stk);
|
|
stk1(f_stk);
|
|
IF contents # NIL THEN
|
|
d := FLT(Ycont) / FLT(contents.Ymax)
|
|
END;
|
|
W := ColLeft.width;
|
|
W2 := ColLeft.width + ColRight.width + Settings.PADDING.ColInter;
|
|
W1 := W;
|
|
main(XML.FB, FALSE);
|
|
Search.resize;
|
|
stk2(b_stk);
|
|
stk2(f_stk);
|
|
IF contents # NIL THEN
|
|
Ycont := FLOOR(FLT(contents.Ymax) * d);
|
|
Ycont := Ycont - Ycont MOD LineH;
|
|
SU.MinMax(Ycont, 0, contents.Ymax)
|
|
END;
|
|
Pop(b_stk);
|
|
END
|
|
END Resize;
|
|
|
|
|
|
PROCEDURE SetColors*;
|
|
BEGIN
|
|
Settings.Colors[BACK_COLOR] := Ini.GetColor("back", Settings.Colors[BACK_COLOR]);
|
|
Settings.Colors[TEXT_COLOR] := Ini.GetColor("text", Settings.Colors[TEXT_COLOR]);
|
|
Settings.Colors[ITALIC_COLOR] := Ini.GetColor("italic", Settings.Colors[ITALIC_COLOR]);
|
|
Settings.Colors[LINK_COLOR] := Ini.GetColor("link", Settings.Colors[LINK_COLOR]);
|
|
Settings.Colors[VISITED_COLOR] := Ini.GetColor("visited", Settings.Colors[LINK_COLOR]);
|
|
END SetColors;
|
|
|
|
|
|
PROCEDURE Resized(set1, set2: TSettings): BOOLEAN;
|
|
RETURN (set1.FontSize # set2.FontSize) OR (set1.TwoCol # set2.TwoCol) OR
|
|
(set1.PARAGRAPH # set2.PARAGRAPH) OR (set1.EPIGRAPH # set2.EPIGRAPH) OR
|
|
(set1.PADDING.LRpc # set2.PADDING.LRpc) OR (set1.PADDING.CInt # set2.PADDING.CInt)
|
|
OR (set1.InterLin # set2.InterLin)
|
|
END Resized;
|
|
|
|
|
|
PROCEDURE SetSettings*(NewSet: TSettings);
|
|
BEGIN
|
|
resized := Resized(Settings, NewSet) OR resized;
|
|
Settings := NewSet;
|
|
Font.Init(Settings.Colors[ITALIC_COLOR], Settings.Colors[TEXT_COLOR], Settings.FontSize);
|
|
Resize(G.Buffer.Width, G.Buffer.Height)
|
|
END SetSettings;
|
|
|
|
|
|
PROCEDURE Init*(Left, Top, Width, Height: INTEGER);
|
|
BEGIN
|
|
G.Resize(Width, Height);
|
|
Canvas_X := Left;
|
|
Canvas_Y := Top
|
|
END Init;
|
|
|
|
|
|
PROCEDURE Start;
|
|
BEGIN
|
|
XML.Open(FileName);
|
|
main(XML.FB, TRUE);
|
|
done := TRUE;
|
|
SU.Halt
|
|
END Start;
|
|
|
|
|
|
PROCEDURE CleanHistory*(fname: S.STRING);
|
|
VAR F: File.FS; pos, pos2, fsize, size, buf, buf2: INTEGER; c: CHAR;
|
|
BEGIN
|
|
F := File.Open(fname);
|
|
IF F # NIL THEN
|
|
fsize := File.Seek(F, 0, 2);
|
|
pos := File.Seek(F, 0, 0);
|
|
buf := K.malloc(fsize + 1024);
|
|
buf2 := K.malloc(fsize + 1024);
|
|
pos := File.Read(F, buf, fsize);
|
|
File.Close(F);
|
|
pos := 0;
|
|
pos2 := 0;
|
|
WHILE pos < fsize DO
|
|
sys.GET(buf + pos, size);
|
|
sys.GET(buf + pos + 4, c);
|
|
IF c = 0X THEN
|
|
sys.MOVE(buf + pos, buf2 + pos2, size);
|
|
pos2 := pos2 + size
|
|
END;
|
|
pos := pos + size
|
|
END;
|
|
F := File.Create(fname);
|
|
pos := File.Write(F, buf2, pos2);
|
|
File.Close(F);
|
|
buf := K.free(buf);
|
|
buf2 := K.free(buf2)
|
|
END
|
|
END CleanHistory;
|
|
|
|
|
|
PROCEDURE Save;
|
|
VAR history: File.FS; size, pos: INTEGER;
|
|
|
|
PROCEDURE WriteInt(history: File.FS; x: INTEGER);
|
|
BEGIN
|
|
IF File.WriteInt(history, x) THEN END
|
|
END WriteInt;
|
|
|
|
PROCEDURE WriteStk(history: File.FS; VAR stk: XML.LIST; links: BOOLEAN);
|
|
VAR
|
|
cur: StackItem;
|
|
BEGIN
|
|
WriteInt(history, XML.ListCount(stk));
|
|
cur := stk.first(StackItem);
|
|
WHILE cur # NIL DO
|
|
WriteInt(history, cur.body.num);
|
|
IF ~links THEN
|
|
WriteInt(history, cur.Ycur)
|
|
END;
|
|
cur := cur.next(StackItem)
|
|
END
|
|
END WriteStk;
|
|
|
|
BEGIN
|
|
Ini.Save(Settings.Colors, Settings.b_pict);
|
|
history := File.Open(Ini.History);
|
|
IF history = NIL THEN
|
|
history := File.Create(Ini.History)
|
|
ELSE
|
|
pos := File.Seek(history, 0 , 2)
|
|
END;
|
|
size := 1 + 18*4 + 1 + 8*(XML.ListCount(b_stk) + XML.ListCount(f_stk)) + 4*XML.ListCount(vis_ref) + 12;
|
|
WriteInt(history, size);
|
|
IF File.WriteChar(history, 0X) THEN END;
|
|
WriteInt(history, fsize2);
|
|
WriteInt(history, chksum);
|
|
WriteInt(history, win_size_x);
|
|
WriteInt(history, win_size_y);
|
|
WriteInt(history, Settings.PADDING.LRpc);
|
|
WriteInt(history, Settings.PADDING.Top);
|
|
WriteInt(history, Settings.PADDING.CInt);
|
|
WriteInt(history, Settings.PARAGRAPH);
|
|
WriteInt(history, Settings.EPIGRAPH);
|
|
WriteInt(history, Settings.InterLin);
|
|
|
|
IF File.WriteBool(history, Settings.TwoCol) THEN END;
|
|
|
|
WriteInt(history, Settings.FontSize);
|
|
WriteInt(history, body.num);
|
|
WriteInt(history, Ymin);
|
|
WriteInt(history, Ymax);
|
|
WriteInt(history, Ycur);
|
|
WriteInt(history, Ycont);
|
|
|
|
WriteStk(history, b_stk, FALSE);
|
|
WriteStk(history, f_stk, FALSE);
|
|
WriteStk(history, vis_ref, TRUE);
|
|
|
|
WriteInt(history, size);
|
|
|
|
File.Close(history);
|
|
CleanHistory(Ini.History)
|
|
END Save;
|
|
|
|
|
|
PROCEDURE ReadInt(VAR x: INTEGER);
|
|
BEGIN
|
|
IF File.ReadInt(history, x) THEN END
|
|
END ReadInt;
|
|
|
|
|
|
PROCEDURE Load;
|
|
VAR body_num, ycur, size, pos: INTEGER;
|
|
|
|
PROCEDURE ReadStk(VAR stk: XML.LIST);
|
|
VAR n, num: INTEGER;
|
|
BEGIN
|
|
ReadInt(n);
|
|
WHILE n > 0 DO
|
|
ReadInt(num);
|
|
body := XML.GetTagByNum(num);
|
|
ReadInt(Ycur);
|
|
Push(stk);
|
|
DEC(n)
|
|
END
|
|
END ReadStk;
|
|
|
|
PROCEDURE ReadRef;
|
|
VAR
|
|
n, num: INTEGER;
|
|
ref: XML.TAG;
|
|
BEGIN
|
|
ReadInt(n);
|
|
WHILE n > 0 DO
|
|
ReadInt(num);
|
|
ref := XML.GetTagByNum(num);
|
|
IF ref # NIL THEN
|
|
setVisited(ref);
|
|
ref.Visited := TRUE;
|
|
PushRef(ref)
|
|
END;
|
|
DEC(n)
|
|
END
|
|
END ReadRef;
|
|
|
|
BEGIN
|
|
ReadInt(Settings.PADDING.LRpc);
|
|
ReadInt(Settings.PADDING.Top);
|
|
ReadInt(Settings.PADDING.CInt);
|
|
ReadInt(Settings.PARAGRAPH);
|
|
ReadInt(Settings.EPIGRAPH);
|
|
ReadInt(Settings.InterLin);
|
|
IF File.ReadBool(history, Settings.TwoCol) THEN END;
|
|
ReadInt(Settings.FontSize);
|
|
|
|
SetSettings(Settings);
|
|
|
|
ReadInt(body_num);
|
|
ReadInt(Ymin);
|
|
ReadInt(Ymax);
|
|
ReadInt(ycur);
|
|
ReadInt(Ycont);
|
|
|
|
ReadStk(b_stk);
|
|
ReadStk(f_stk);
|
|
ReadRef;
|
|
|
|
ReadInt(size);
|
|
pos := File.Seek(history, -size, 1);
|
|
pos := File.Seek(history, 4, 1);
|
|
IF File.WriteChar(history, 1X) THEN END;
|
|
|
|
Ycur := ycur;
|
|
body := XML.GetTagByNum(body_num);
|
|
File.Close(history)
|
|
END Load;
|
|
|
|
|
|
PROCEDURE GetWinSize*(hist_fn: S.STRING; VAR win_size_x, win_size_y: INTEGER);
|
|
VAR c: CHAR; size, pos, x, y, fsize, _chksum: INTEGER; found: BOOLEAN;
|
|
BEGIN
|
|
fsize2 := RF.FileSize(hist_fn);
|
|
chksum := RF.ChkSum(hist_fn);
|
|
found := FALSE;
|
|
history := File.Open(Ini.History);
|
|
pos := File.Seek(history, -4, 2);
|
|
last := FALSE;
|
|
WHILE pos >= 0 DO
|
|
IF File.ReadInt(history, size) THEN
|
|
pos := File.Seek(history, -size + 4, 1);
|
|
END;
|
|
IF File.ReadChar(history, c) THEN END;
|
|
ReadInt(fsize);
|
|
ReadInt(_chksum);
|
|
IF (c = 0X) & (fsize = fsize2) & (_chksum = chksum) THEN
|
|
found := TRUE;
|
|
IF File.ReadInt(history, x) & File.ReadInt(history, y) THEN
|
|
win_size_x := x;
|
|
win_size_y := y;
|
|
ELSE
|
|
found := FALSE
|
|
END;
|
|
pos := -1
|
|
ELSE
|
|
IF ~last THEN
|
|
last := TRUE;
|
|
ReadInt(x);
|
|
ReadInt(y);
|
|
ReadInt(Settings.PADDING.LRpc);
|
|
ReadInt(Settings.PADDING.Top);
|
|
ReadInt(Settings.PADDING.CInt);
|
|
ReadInt(Settings.PARAGRAPH);
|
|
ReadInt(Settings.EPIGRAPH);
|
|
ReadInt(Settings.InterLin);
|
|
IF File.ReadBool(history, Settings.TwoCol) THEN END;
|
|
ReadInt(Settings.FontSize);
|
|
END;
|
|
pos := File.Seek(history, pos - 8, 0)
|
|
END
|
|
END;
|
|
IF ~found THEN
|
|
File.Close(history)
|
|
END
|
|
END GetWinSize;
|
|
|
|
|
|
PROCEDURE Open*(FName: S.STRING; DrawWindow, _DrawStatus, _DrawToolbar: SU.ENTRY);
|
|
VAR PID, event: INTEGER;
|
|
BEGIN
|
|
DrawStatus := _DrawStatus;
|
|
DrawToolbar := _DrawToolbar;
|
|
cursor := SU.LoadCursor(Cursor.GetCursor());
|
|
references := V.create(1024);
|
|
ref_depth := 0;
|
|
done := FALSE;
|
|
loaded := FALSE;
|
|
FilePath := FName;
|
|
FileName := FName;
|
|
S.GetPath(FilePath);
|
|
W := ColLeft.width;
|
|
W1 := W;
|
|
W2 := ColLeft.width + ColRight.width + Settings.PADDING.ColInter;
|
|
Lines := ColLeft.height DIV LineH;
|
|
ColLeft.height := Lines * LineH;
|
|
PID := SU.NewThread(Start, Stack);
|
|
WHILE ~SU.IsTerminated(PID) DO
|
|
event := SU.CheckEvent();
|
|
IF event = 3 THEN
|
|
SU.TerminateThreadId(PID);
|
|
SU.Halt
|
|
END;
|
|
G.Progress(RF.Progress());
|
|
G.Draw(Canvas_X, Canvas_Y);
|
|
DrawWindow;
|
|
SU.Pause(30)
|
|
END;
|
|
IF ~done THEN
|
|
SU.Halt
|
|
END;
|
|
loaded := TRUE;
|
|
resized := TRUE;
|
|
IF history # NIL THEN
|
|
Load
|
|
ELSE
|
|
SetSettings(Settings)
|
|
END
|
|
END Open;
|
|
|
|
|
|
PROCEDURE Close*;
|
|
BEGIN
|
|
SU.DelCursor(cursor);
|
|
Save;
|
|
SU.Halt
|
|
END Close;
|
|
|
|
|
|
PROCEDURE SetScrollBar*(_sb: box_lib.scrollbar);
|
|
BEGIN
|
|
sb := _sb
|
|
END SetScrollBar;
|
|
|
|
|
|
PROCEDURE Set_b_pict*(b_pict: BOOLEAN);
|
|
BEGIN
|
|
Settings.b_pict := b_pict
|
|
END Set_b_pict;
|
|
|
|
|
|
PROCEDURE SetWinSize* (x, y: INTEGER);
|
|
BEGIN
|
|
win_size_x := x;
|
|
win_size_y := y
|
|
END SetWinSize;
|
|
|
|
|
|
BEGIN
|
|
clickRef := NIL;
|
|
hoverRef := NIL;
|
|
mouseDown := FALSE
|
|
END DOM.
|