summaryrefslogtreecommitdiff
path: root/appl/charon/layout.m
blob: a91b7e8d08fec252ac9e4d8c07c24cf2c8ad4271 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
Layout: module
{
PATH: con "/dis/charon/layout.dis";

ReliefBd: con 2;
ReliefSunk, ReliefRaised : con iota;

# Frames

Frame: adt
{
	id: int;					# unique id
	doc: ref Build->Docinfo;		# various global attributes from HTML and headers
	src: ref Url->Parsedurl;
	name: string;				# current name (assigned by parent frame, or by default)
	marginw: int;				# margin on sides
	marginh: int;				# margin on top and bottom
	framebd: int;				# frame border desired
	flags: int;					# Build->FRnoresize, etc.
	layout: ref Lay;				# representation of layout
	sublays: array of ref Lay;		# table cells, captions
	sublayid: int;				# next sublayid to use
	controls: cyclic array of ref Control;	# controls
	controlid: int;				# next control id to use
	cim: ref Draw->Image;		# image where we draw contents
	r: Draw->Rect;				# part of cimage.r for this frame (including scrollbars)
	cr: Draw->Rect;			# part of r for contents (excluding scrollbars, including margins)
	totalr: Draw->Rect;			# total rectangle for page -- (0,0) is top left
	viewr: Draw->Rect;			# view: subrect of totalr currently on screen
	vscr: cyclic ref Control;		# vertical scrollbar
	hscr: cyclic ref Control;		# horizontal scrollbar
	parent: cyclic ref Frame;		# if this frame is in a frameset
	kids: cyclic list of ref Frame;	# if this frame is a frameset
	animpid: int;				# image animating thread
	prctxt: ref Printcontext;		# nil if not printing

# TEMP
dirtyr: Draw->Rect;
dirty: fn (f: self ref Frame, r: Draw->Rect);
isdirty: int;

	# reset() clears everything but parent, cim and r
	# new() and newkid() call reset
	# newkid() fills in name, etc., from ki, and copies cim from parent
	new: fn() : ref Frame;
	newkid: fn(parent: ref Frame, ki: ref Build->Kidinfo, r: Draw->Rect) : ref Frame;
	reset: fn(f: self ref Frame);
	addcontrol: fn(f: self ref Frame, c: ref Control) : int;
	lptosp: fn(f: self ref Frame, lp: Draw->Point) : Draw->Point;
	sptolp: fn(f: self ref Frame, sp: Draw->Point) : Draw->Point;
	xscroll: fn(f: self ref Frame, kind, val: int); # kind is CAscrollpage, etc
	yscroll: fn(f: self ref Frame, kind, val: int);
	scrollabs: fn(f : self ref Frame, p : Draw->Point);
	scrollrel: fn(f : self ref Frame, p : Draw->Point);
	find: fn(f: self ref Frame, p: Draw->Point, it: ref Build->Item) : ref Loc;
	swapimage: fn(f: self ref Frame, it: ref Build->Item.Iimage, src: string);
	focus: fn(f : self ref Frame, focus, raisex : int);
};

Printcontext: adt {
	mask: ref Draw->Image;
	endy: int;
};

# Line flags
Ldrawn, Lmoved, Lchanged: con byte (1<<iota);

# Layout engine organizes Items into Lines
Line: adt
{
	items: ref Build->Item;
	next: cyclic ref Line;
	prev: cyclic ref Line;
	pos: Draw->Point;
	width: int;
	height: int;
	ascent: int;
	flags: byte;

	new: fn() : ref Line;
};

# A place where an item, or a where mouse or keyboard focus could be.
Loc: adt
{
	le:		array of Locelem;
	n:		int;					# locs[0:n] form access path
	pos:		Draw->Point;				# offset in final item

	new:		fn() : ref Loc;
	add:		fn(loc: self ref Loc, kind: int, pos: Draw->Point);
	lastframe:	fn(loc: self ref Loc) : ref Frame;
	print:	fn(loc: self ref Loc, msg: string);
};

# Don't use pick so that can make array of Locelems (rather than ref Locelems),
# which saves a lot of alloc/frees in search functions.
# (Also, saves memory overall, in Limbo).
Locelem: adt
{
	kind:	int;				# LEframe, etc.
	pos: Draw->Point;			# position in screen coords of this element
	frame: ref Frame;		# root, or kid of previous (a frame)
	line: ref Line;			# a line in lay of previous
	item: ref Build->Item;		# an item in previous (a line or item)
	tcell: ref Build->Tablecell;	# a cell in previous (a table item)
	control: ref Control;		# a control in previous item, or scrollbar in previous frame
};

# Locelem kinds
LEframe, LEline, LEitem, LEtablecell, LEcontrol : con iota;

# One of the possible controls, and possible associated form field
Control: adt {
	f: cyclic ref Frame;
	ff: ref Build->Formfield;
	r: Draw->Rect;			# coords in f.cim coord system
	flags:	int;
	popup:	ref Gui->Popup;
	pick {
		Cbutton =>
			pic:		ref Draw->Image;		# picture on button (if no label)
			picmask:	ref Draw->Image;		# mask for pic
			dpic:	ref Draw->Image;		# disabled ("greyed out") pic
			dpicmask:	ref Draw->Image;	# mask for dpic
			label:	string;		# label on button (if no pic), or else flyover hint
			dorelief:	int;			# draw background & relief?
		Centry =>
			scr:		ref Control;
			s:		string;		# current contents
			sel:		(int,int);	# range of characters in s that are selected
			left:		int;			# index of character in s that is at left of window
			linewrap:	int;			# true if supposed to line-wrap
			onchange:	int;		# true if want onchange event
		Ccheckbox=>
			isradio: 	int;			# true if for radio button
		Cselect =>
			#
			owner:	ref Control;	# if this is a popup
			scr:		ref Control;	# if needed
			nvis:		int;			# number of visible options
			first:		int;			# index of current top visible option
			options:	array of Build->Option;
#			onchange:	int;		# true if want onchange event
		Clistbox =>
			hscr:		ref Control;
			vscr:		ref Control;
			nvis:		int;
			first:		int;			# index of current top visible option
			start:		int;			# index of current start column
			maxcol:		int;			# max column
			options:	array of Build->Option;
			grab:		cyclic ref Control;
		Cscrollbar =>
			top:		int;			# pixels in trough above/left of slider
			bot:		int;			# pixels in trough below/right of slider
			mindelta:	int;			# need delta of at least this (pixels)
			deltaval: int;
			ctl:		cyclic ref Control;	# if non-nil, scrolls this control
			holdstate: (int, int);
		Canimimage =>
			cim:		ref CharonUtils->CImage;
			cur:		int;				# current frame
			redraw:	int;				# need to redraw all?
			ts:		big;				# timestamp of current frame
			bg:		Build->Background;	# if need restore-to-background
		Clabel =>
			s:		string;
	}

	newff: fn(f: ref Frame, ff: ref Build->Formfield) : ref Control;
	newscroll: fn(f: ref Frame, isvert, length, breadth: int) : ref Control;
	newentry: fn(f: ref Frame, nh, nv, linewrap: int) : ref Control;
	newbutton: fn(f: ref Frame, pic, picmask: ref Draw->Image, lab: string, it: ref Build->Item.Iimage, candisable, dorelief: int) : ref Control;
	newcheckbox: fn(f: ref Frame, isradio: int) : ref Control;
	newselect: fn(f: ref Frame, nvis: int, options: array of Build->Option) : ref Control;
	newlistbox: fn(f: ref Frame, nvis, w: int, options: array of Build->Option) : ref Control;
	newanimimage: fn(f: ref Frame, cim: ref CharonUtils->CImage, bg: Build->Background) : ref Control;
	newlabel: fn(f: ref Frame, s: string) : ref Control;
	disable: fn(b: self ref Control);
	enable: fn(b: self ref Control);
	losefocus: fn(b: self ref Control, raisex: int);
	gainfocus: fn(b: self ref Control, raisex: int);
	scrollset: fn(sc: self ref Control, v1, v2, vmax, nsteps, draw: int);
	entryset: fn(e: self ref Control, s: string);
	# returns CAnone, etc.
	dokey: fn(c: self ref Control, keychar: int) : int;
	# domouse returns (action, grab) action = CAnone etc, grab = control that has grabbed mouse
	domouse: fn(c: self ref Control, p: Draw->Point, mtype: int, oldgrab : ref Control) : (int, ref Control);
	dopopup: fn(c: self ref Control): ref Control;
	donepopup: fn(c: self ref Control): ref Control;
	reset: fn(c: self ref Control);
	draw: fn(c: self ref Control, flush: int);
};

# Control flags
CFactive, CFenabled, CFsecure, CFhasfocus, CFscrvert, CFscracta1, CFscracta2, CFscracttr1, CFscracttr2: con (1<<iota);
CFscrallact : con (CFactive|CFscracta1|CFscracta2|CFscracttr1|CFscracttr2);

# Control Actions
CAnone, CAscrollpage, CAscrollline, CAscrolldelta, CAscrollabs,
CAbuttonpush, CAflyover, CAreturnkey, CAtabkey, CAkeyfocus, CAselected, CAchanged, CAdopopup, CAdonepopup: con iota;

# Result of layout
Lay: adt
{
	start: ref Line;			# fake before-the-first-line
	end: ref Line;			# fake after-the-last-line
	targetwidth: int;		# target width
	width: int;				# actual width
	height: int;			# actual height
	margin: int;			# extra space on all four sides
	floats:list of ref Build->Item.Ifloat;	# floats, from bottom up
	background: Build->Background;	# background for layout
	just: byte;				# default line justification
	flags: byte;			# Lchanged

	new: fn(targetwidth: int, just: byte, margin: int, bg: Build->Background) : ref Lay;
};

#B: Build;

init: fn(cu: CharonUtils);
layout: fn(f: ref Frame, bs: ref CharonUtils->ByteSource, linkclick: int) : array of byte;

drawrelief: fn(im: ref Draw->Image, r: Draw->Rect, style: int);
drawborder: fn(im: ref Draw->Image, r: Draw->Rect, n, color: int);
drawfill: fn(im: ref Draw->Image, r: Draw->Rect, color: int);
drawstring: fn(im: ref Draw->Image, p: Draw->Point, s: string);
measurestring: fn(s: string) : Draw->Point;
drawall: fn(f: ref Frame);
relayout: fn(f: ref Frame, l: ref Lay, targetw: int, just: byte);

stringwidth: fn(s: string): int;
};