xref: /plan9/sys/src/cmd/abaco/html.c (revision 7ab27030036b6c877a6f81728daeda263d1ca3cf)
1*7ab27030SDavid du Colombier #include <u.h>
2*7ab27030SDavid du Colombier #include <libc.h>
3*7ab27030SDavid du Colombier #include <draw.h>
4*7ab27030SDavid du Colombier #include <memdraw.h>
5*7ab27030SDavid du Colombier #include <thread.h>
6*7ab27030SDavid du Colombier #include <cursor.h>
7*7ab27030SDavid du Colombier #include <mouse.h>
8*7ab27030SDavid du Colombier #include <keyboard.h>
9*7ab27030SDavid du Colombier #include <frame.h>
10*7ab27030SDavid du Colombier #include <plumb.h>
11*7ab27030SDavid du Colombier #include <html.h>
12*7ab27030SDavid du Colombier #include "dat.h"
13*7ab27030SDavid du Colombier #include "fns.h"
14*7ab27030SDavid du Colombier 
15*7ab27030SDavid du Colombier static void sizeitem(Lay *, Item *);
16*7ab27030SDavid du Colombier 
17*7ab27030SDavid du Colombier static
18*7ab27030SDavid du Colombier void
sizetext(Lay * lay,Itext * i)19*7ab27030SDavid du Colombier sizetext(Lay *lay, Itext *i)
20*7ab27030SDavid du Colombier {
21*7ab27030SDavid du Colombier 	lay->font = getfont(i->fnt);
22*7ab27030SDavid du Colombier 	i->height = lay->font->height + 2*Space;
23*7ab27030SDavid du Colombier 	i->width = runestringwidth(lay->font, i->s);
24*7ab27030SDavid du Colombier 	i->width += runestringnwidth(lay->font, L" ", 1);
25*7ab27030SDavid du Colombier }
26*7ab27030SDavid du Colombier 
27*7ab27030SDavid du Colombier static
28*7ab27030SDavid du Colombier void
sizerule(Lay * lay,Irule * i)29*7ab27030SDavid du Colombier sizerule(Lay *lay, Irule *i)
30*7ab27030SDavid du Colombier {
31*7ab27030SDavid du Colombier 	i->width = lay->width;
32*7ab27030SDavid du Colombier 	i->height = Space + i->size + Space;
33*7ab27030SDavid du Colombier }
34*7ab27030SDavid du Colombier 
35*7ab27030SDavid du Colombier static
36*7ab27030SDavid du Colombier void
sizeimage(Lay *,Iimage * i)37*7ab27030SDavid du Colombier sizeimage(Lay *, Iimage *i)
38*7ab27030SDavid du Colombier {
39*7ab27030SDavid du Colombier 	Cimage *ci;
40*7ab27030SDavid du Colombier 
41*7ab27030SDavid du Colombier 	ci = (Cimage *)i->aux;
42*7ab27030SDavid du Colombier 
43*7ab27030SDavid du Colombier 	if(ci==nil)
44*7ab27030SDavid du Colombier 		return;
45*7ab27030SDavid du Colombier 
46*7ab27030SDavid du Colombier 	if(ci->i == nil)
47*7ab27030SDavid du Colombier 		getimage(ci, i->altrep);
48*7ab27030SDavid du Colombier 	if(ci->i == nil)
49*7ab27030SDavid du Colombier 		return;
50*7ab27030SDavid du Colombier 	i->width = Dx(ci->i->r) + i->border + i->hspace;
51*7ab27030SDavid du Colombier 	i->height = Dy(ci->i->r) + i->border + i->vspace;
52*7ab27030SDavid du Colombier }
53*7ab27030SDavid du Colombier 
54*7ab27030SDavid du Colombier static
55*7ab27030SDavid du Colombier void
sizetextfield(Lay *,Iformfield * i)56*7ab27030SDavid du Colombier sizetextfield(Lay *, Iformfield *i)
57*7ab27030SDavid du Colombier {
58*7ab27030SDavid du Colombier 	Formfield *ff;
59*7ab27030SDavid du Colombier 	Font *f;
60*7ab27030SDavid du Colombier 	int w, h;
61*7ab27030SDavid du Colombier 
62*7ab27030SDavid du Colombier 	ff = i->formfield;
63*7ab27030SDavid du Colombier 	if(ff->ftype == Ftextarea){
64*7ab27030SDavid du Colombier 		w = ff->cols;
65*7ab27030SDavid du Colombier 		h = ff->rows;
66*7ab27030SDavid du Colombier 	}else{
67*7ab27030SDavid du Colombier 		w = ff->size;
68*7ab27030SDavid du Colombier 		h = 1;
69*7ab27030SDavid du Colombier 	}
70*7ab27030SDavid du Colombier 	f = getfont(WFont);
71*7ab27030SDavid du Colombier 	i->width = runestringnwidth(f, L"0", 1)*w + 2*(Space+Border+Margin);
72*7ab27030SDavid du Colombier 	i->width += Scrollsize+Scrollgap;
73*7ab27030SDavid du Colombier 	i->height = f->height*h + 2*(Space+Border+Margin);
74*7ab27030SDavid du Colombier }
75*7ab27030SDavid du Colombier 
76*7ab27030SDavid du Colombier static
77*7ab27030SDavid du Colombier void
sizecheck(Lay *,Iformfield * i)78*7ab27030SDavid du Colombier sizecheck(Lay *, Iformfield *i)
79*7ab27030SDavid du Colombier {
80*7ab27030SDavid du Colombier 	i->width = Boxsize + Space;
81*7ab27030SDavid du Colombier 	i->height = Boxsize;
82*7ab27030SDavid du Colombier }
83*7ab27030SDavid du Colombier 
84*7ab27030SDavid du Colombier static
85*7ab27030SDavid du Colombier void
sizebutton(Lay *,Iformfield * i)86*7ab27030SDavid du Colombier sizebutton(Lay *, Iformfield *i)
87*7ab27030SDavid du Colombier {
88*7ab27030SDavid du Colombier 	Font *f;
89*7ab27030SDavid du Colombier 	int x;
90*7ab27030SDavid du Colombier 
91*7ab27030SDavid du Colombier 	x = Margin + Border + Space;
92*7ab27030SDavid du Colombier 	f = getfont(WFont);
93*7ab27030SDavid du Colombier 	i->width = runestringwidth(f, i->formfield->value) + 2*x + Space;
94*7ab27030SDavid du Colombier 	i->height = f->height + 2*x;
95*7ab27030SDavid du Colombier }
96*7ab27030SDavid du Colombier 
97*7ab27030SDavid du Colombier static
98*7ab27030SDavid du Colombier void
sizefimage(Lay * lay,Iformfield * i)99*7ab27030SDavid du Colombier sizefimage(Lay *lay, Iformfield *i)
100*7ab27030SDavid du Colombier {
101*7ab27030SDavid du Colombier 	Iimage *ii;
102*7ab27030SDavid du Colombier 
103*7ab27030SDavid du Colombier 	ii = (Iimage *)i->formfield->image;
104*7ab27030SDavid du Colombier 	sizeimage(lay, ii);
105*7ab27030SDavid du Colombier 	i->width = ii->width;
106*7ab27030SDavid du Colombier 	i->height = ii->height;
107*7ab27030SDavid du Colombier }
108*7ab27030SDavid du Colombier 
109*7ab27030SDavid du Colombier static
110*7ab27030SDavid du Colombier void
sizeselect(Lay *,Iformfield * i)111*7ab27030SDavid du Colombier sizeselect(Lay *, Iformfield *i)
112*7ab27030SDavid du Colombier {
113*7ab27030SDavid du Colombier 	Option *o;
114*7ab27030SDavid du Colombier 	Font *f;
115*7ab27030SDavid du Colombier 	int x;
116*7ab27030SDavid du Colombier 
117*7ab27030SDavid du Colombier 	f = getfont(WFont);
118*7ab27030SDavid du Colombier 	i->width = 0;
119*7ab27030SDavid du Colombier 	for(o=i->formfield->options; o!=nil; o=o->next)
120*7ab27030SDavid du Colombier 		i->width = max(i->width, runestringwidth(f, o->display));
121*7ab27030SDavid du Colombier 	x = Margin + Border + Space;
122*7ab27030SDavid du Colombier 	i->width += 2*x;
123*7ab27030SDavid du Colombier 	i->height = f->height+2*x;
124*7ab27030SDavid du Colombier }
125*7ab27030SDavid du Colombier 
126*7ab27030SDavid du Colombier static
127*7ab27030SDavid du Colombier void
sizeformfield(Lay * lay,Iformfield * i)128*7ab27030SDavid du Colombier sizeformfield(Lay *lay, Iformfield *i)
129*7ab27030SDavid du Colombier {
130*7ab27030SDavid du Colombier 	int type;
131*7ab27030SDavid du Colombier 
132*7ab27030SDavid du Colombier 	type = i->formfield->ftype;
133*7ab27030SDavid du Colombier 
134*7ab27030SDavid du Colombier 	if(type==Ftext || type==Ftextarea || type==Fpassword)
135*7ab27030SDavid du Colombier 		sizetextfield(lay, i);
136*7ab27030SDavid du Colombier 	else if(type==Fcheckbox || type==Fradio)
137*7ab27030SDavid du Colombier 		sizecheck(lay, i);
138*7ab27030SDavid du Colombier 	else if(type==Fbutton || type==Freset || type==Fsubmit)
139*7ab27030SDavid du Colombier 		sizebutton(lay, i);
140*7ab27030SDavid du Colombier 	else if(type == Fimage)
141*7ab27030SDavid du Colombier 		sizefimage(lay, i);
142*7ab27030SDavid du Colombier 	else if(type == Fselect)
143*7ab27030SDavid du Colombier 		sizeselect(lay, i);
144*7ab27030SDavid du Colombier }
145*7ab27030SDavid du Colombier 
146*7ab27030SDavid du Colombier static
147*7ab27030SDavid du Colombier void
sizetable(Lay * lay,Itable * i)148*7ab27030SDavid du Colombier sizetable(Lay *lay, Itable *i)
149*7ab27030SDavid du Colombier {
150*7ab27030SDavid du Colombier 	tablesize(i->table, lay->width);
151*7ab27030SDavid du Colombier 	i->width = i->table->totw;
152*7ab27030SDavid du Colombier 	i->height = i->table->toth;
153*7ab27030SDavid du Colombier }
154*7ab27030SDavid du Colombier 
155*7ab27030SDavid du Colombier static
156*7ab27030SDavid du Colombier void
sizefloat(Lay * lay,Ifloat * i)157*7ab27030SDavid du Colombier sizefloat(Lay *lay, Ifloat *i)
158*7ab27030SDavid du Colombier {
159*7ab27030SDavid du Colombier 	sizeitem(lay, i->item);
160*7ab27030SDavid du Colombier 	i->width = i->item->width;
161*7ab27030SDavid du Colombier 	i->height = i->item->height;
162*7ab27030SDavid du Colombier }
163*7ab27030SDavid du Colombier 
164*7ab27030SDavid du Colombier static
165*7ab27030SDavid du Colombier void
sizespacer(Lay * lay,Ispacer * i)166*7ab27030SDavid du Colombier sizespacer(Lay *lay, Ispacer *i)
167*7ab27030SDavid du Colombier {
168*7ab27030SDavid du Colombier 	if(i->spkind != ISPnull){
169*7ab27030SDavid du Colombier 		if(i->spkind == ISPhspace)
170*7ab27030SDavid du Colombier 			i->width = stringnwidth(lay->font, " ", 1);
171*7ab27030SDavid du Colombier 		i->height = lay->font->height + 2*Space;
172*7ab27030SDavid du Colombier 	}
173*7ab27030SDavid du Colombier }
174*7ab27030SDavid du Colombier 
175*7ab27030SDavid du Colombier static
176*7ab27030SDavid du Colombier void
sizeitem(Lay * lay,Item * i)177*7ab27030SDavid du Colombier sizeitem(Lay *lay, Item *i)
178*7ab27030SDavid du Colombier {
179*7ab27030SDavid du Colombier 
180*7ab27030SDavid du Colombier 	switch(i->tag){
181*7ab27030SDavid du Colombier 	case Itexttag:
182*7ab27030SDavid du Colombier 		sizetext(lay, (Itext *)i);
183*7ab27030SDavid du Colombier 		break;
184*7ab27030SDavid du Colombier 	case Iruletag:
185*7ab27030SDavid du Colombier 		sizerule(lay, (Irule *)i);
186*7ab27030SDavid du Colombier 		break;
187*7ab27030SDavid du Colombier 	case Iimagetag:
188*7ab27030SDavid du Colombier 		sizeimage(lay, (Iimage *)i);
189*7ab27030SDavid du Colombier 		break;
190*7ab27030SDavid du Colombier 	case Iformfieldtag:
191*7ab27030SDavid du Colombier 		sizeformfield(lay, (Iformfield *)i);
192*7ab27030SDavid du Colombier 		break;
193*7ab27030SDavid du Colombier 	case Itabletag:
194*7ab27030SDavid du Colombier 		sizetable(lay, (Itable *)i);
195*7ab27030SDavid du Colombier 		break;
196*7ab27030SDavid du Colombier 	case Ifloattag:
197*7ab27030SDavid du Colombier 		sizefloat(lay, (Ifloat *)i);
198*7ab27030SDavid du Colombier 		break;
199*7ab27030SDavid du Colombier 	case Ispacertag:
200*7ab27030SDavid du Colombier 		sizespacer(lay, (Ispacer *)i);
201*7ab27030SDavid du Colombier 		break;
202*7ab27030SDavid du Colombier 	default:
203*7ab27030SDavid du Colombier 		error("can't happen");
204*7ab27030SDavid du Colombier 	}
205*7ab27030SDavid du Colombier }
206*7ab27030SDavid du Colombier 
207*7ab27030SDavid du Colombier static
208*7ab27030SDavid du Colombier void
drawtext(Box * b,Page * p,Image * im)209*7ab27030SDavid du Colombier drawtext(Box *b, Page *p, Image *im)
210*7ab27030SDavid du Colombier {
211*7ab27030SDavid du Colombier 	Rectangle r, r1;
212*7ab27030SDavid du Colombier 	Image *c;
213*7ab27030SDavid du Colombier 	Point pt;
214*7ab27030SDavid du Colombier 	Font *f;
215*7ab27030SDavid du Colombier 	Itext *i;
216*7ab27030SDavid du Colombier 	int q0, q1;
217*7ab27030SDavid du Colombier 
218*7ab27030SDavid du Colombier 	r = rectsubpt(b->r, p->pos);
219*7ab27030SDavid du Colombier 	i = (Itext *)b->i;
220*7ab27030SDavid du Colombier 	f = getfont(i->fnt);
221*7ab27030SDavid du Colombier 	if(istextsel(p, b->r, &q0, &q1, i->s, f)){
222*7ab27030SDavid du Colombier 		r1 = r;
223*7ab27030SDavid du Colombier 		if(q0 > 0)
224*7ab27030SDavid du Colombier 			r1.min.x += runestringnwidth(f, i->s, q0);
225*7ab27030SDavid du Colombier 		if(q1 > 0)
226*7ab27030SDavid du Colombier 			r1.max.x = r1.min.x + runestringnwidth(f, i->s+q0, q1-q0);
227*7ab27030SDavid du Colombier 		draw(im, r1, textcols[HIGH], nil, ZP);
228*7ab27030SDavid du Colombier 	}
229*7ab27030SDavid du Colombier 	c = getcolor(i->fg);
230*7ab27030SDavid du Colombier 	runestringbg(im, r.min, c, ZP, f, i->s, im, addpt(r.min, im->r.min));
231*7ab27030SDavid du Colombier 
232*7ab27030SDavid du Colombier 	if(i->ul == ULnone)
233*7ab27030SDavid du Colombier 		return;
234*7ab27030SDavid du Colombier 
235*7ab27030SDavid du Colombier 	if(i->ul == ULmid)
236*7ab27030SDavid du Colombier 		r.min.y += f->height/2;
237*7ab27030SDavid du Colombier 	else
238*7ab27030SDavid du Colombier 		r.min.y +=f->height-1;
239*7ab27030SDavid du Colombier 	pt = r.min;
240*7ab27030SDavid du Colombier 	pt.x +=  runestringwidth(f, i->s);
241*7ab27030SDavid du Colombier 	line(im, r.min, pt, Enddisc, Enddisc, 0, c, ZP);
242*7ab27030SDavid du Colombier }
243*7ab27030SDavid du Colombier 
244*7ab27030SDavid du Colombier static
245*7ab27030SDavid du Colombier void
drawrule(Box * b,Page * p,Image * im)246*7ab27030SDavid du Colombier drawrule(Box *b, Page *p, Image *im)
247*7ab27030SDavid du Colombier {
248*7ab27030SDavid du Colombier 	Rectangle r;
249*7ab27030SDavid du Colombier 	Irule *i;
250*7ab27030SDavid du Colombier 
251*7ab27030SDavid du Colombier 	i = ((Irule *)b->i);
252*7ab27030SDavid du Colombier 	r = rectsubpt(b->r, p->pos);
253*7ab27030SDavid du Colombier 	r.min.y += Space;
254*7ab27030SDavid du Colombier 	r.max.y -=Space;
255*7ab27030SDavid du Colombier 	draw(im, r, getcolor(i->color), nil, ZP);
256*7ab27030SDavid du Colombier }
257*7ab27030SDavid du Colombier 
258*7ab27030SDavid du Colombier static
259*7ab27030SDavid du Colombier void
drawimage(Box * b,Page * p,Image * im)260*7ab27030SDavid du Colombier drawimage(Box *b, Page *p, Image *im)
261*7ab27030SDavid du Colombier {
262*7ab27030SDavid du Colombier 	Rectangle r;
263*7ab27030SDavid du Colombier 	Cimage *ci;
264*7ab27030SDavid du Colombier 	Iimage *i;
265*7ab27030SDavid du Colombier 	Image *c;
266*7ab27030SDavid du Colombier 
267*7ab27030SDavid du Colombier 	if(b->i->tag==Iimagetag)
268*7ab27030SDavid du Colombier 		i = (Iimage *)b->i;
269*7ab27030SDavid du Colombier 	else
270*7ab27030SDavid du Colombier 		i = (Iimage *)((Iformfield *)b->i)->formfield->image;
271*7ab27030SDavid du Colombier 
272*7ab27030SDavid du Colombier 	ci = (Cimage *)i->aux;
273*7ab27030SDavid du Colombier 	if(ci==nil || ci->i==nil)
274*7ab27030SDavid du Colombier 		return;
275*7ab27030SDavid du Colombier 
276*7ab27030SDavid du Colombier 	r = rectsubpt(b->r, p->pos);
277*7ab27030SDavid du Colombier 	r.min.x += i->border + i->hspace;
278*7ab27030SDavid du Colombier 	r.min.y += i->border + i->vspace;
279*7ab27030SDavid du Colombier 	r.max.x -= i->border + i->hspace;
280*7ab27030SDavid du Colombier 	r.max.y -= i->border + i->vspace;
281*7ab27030SDavid du Colombier 
282*7ab27030SDavid du Colombier 	draw(im, r,  ci->i, nil, ci->i->r.min);
283*7ab27030SDavid du Colombier 
284*7ab27030SDavid du Colombier 	if(i->border){
285*7ab27030SDavid du Colombier 		if(i->anchorid >= 0)
286*7ab27030SDavid du Colombier 			c = getcolor(p->doc->link);
287*7ab27030SDavid du Colombier 		else
288*7ab27030SDavid du Colombier 			c = display->black;
289*7ab27030SDavid du Colombier 
290*7ab27030SDavid du Colombier 		border(im, r, i->border, c, ZP);
291*7ab27030SDavid du Colombier 	}
292*7ab27030SDavid du Colombier }
293*7ab27030SDavid du Colombier 
294*7ab27030SDavid du Colombier static
295*7ab27030SDavid du Colombier void
drawtextfield(Image * im,Rectangle r,Iformfield * i)296*7ab27030SDavid du Colombier drawtextfield(Image *im, Rectangle r, Iformfield *i)
297*7ab27030SDavid du Colombier {
298*7ab27030SDavid du Colombier 	Formfield *ff;
299*7ab27030SDavid du Colombier 	Image *c[3];
300*7ab27030SDavid du Colombier 	Text *t;
301*7ab27030SDavid du Colombier 	Font *f;
302*7ab27030SDavid du Colombier 
303*7ab27030SDavid du Colombier 	r = insetrect(r, Space);
304*7ab27030SDavid du Colombier 	colarray(c, getcolor(Dark), getcolor(Light), display->white, 1);
305*7ab27030SDavid du Colombier 	rect3d(im, r, Border, c, ZP);
306*7ab27030SDavid du Colombier 	r = insetrect(r, Border+Margin);
307*7ab27030SDavid du Colombier 
308*7ab27030SDavid du Colombier 	if(i->aux == nil){
309*7ab27030SDavid du Colombier 		ff = i->formfield;
310*7ab27030SDavid du Colombier 		t = emalloc(sizeof(Text));
311*7ab27030SDavid du Colombier 		if(ff->ftype == Ftextarea)
312*7ab27030SDavid du Colombier 			t->what = Textarea;
313*7ab27030SDavid du Colombier 		else
314*7ab27030SDavid du Colombier 			t->what = Entry;
315*7ab27030SDavid du Colombier 		if(ff->ftype == Fpassword)
316*7ab27030SDavid du Colombier 			f = passfont;
317*7ab27030SDavid du Colombier 		else
318*7ab27030SDavid du Colombier 			f = getfont(WFont);
319*7ab27030SDavid du Colombier 		textinit(t, im, r, f, textcols);
320*7ab27030SDavid du Colombier 		if(ff->value!=nil){
321*7ab27030SDavid du Colombier 			textinsert(t, 0, ff->value, runestrlen(ff->value));
322*7ab27030SDavid du Colombier 			textsetselect(t, t->rs.nr, t->rs.nr);
323*7ab27030SDavid du Colombier 		}
324*7ab27030SDavid du Colombier 		if(t->what == Textarea)
325*7ab27030SDavid du Colombier 			textscrdraw(t);
326*7ab27030SDavid du Colombier 		i->aux = t;
327*7ab27030SDavid du Colombier 	}else
328*7ab27030SDavid du Colombier 		textresize(i->aux, im, r);
329*7ab27030SDavid du Colombier }
330*7ab27030SDavid du Colombier 
331*7ab27030SDavid du Colombier void
drawcheck(Image * im,Rectangle r,Formfield * f)332*7ab27030SDavid du Colombier drawcheck(Image *im, Rectangle r, Formfield *f)
333*7ab27030SDavid du Colombier {
334*7ab27030SDavid du Colombier 	Image *c[3];
335*7ab27030SDavid du Colombier 	Point pt;
336*7ab27030SDavid du Colombier 	int n;
337*7ab27030SDavid du Colombier 
338*7ab27030SDavid du Colombier 	if(f->flags & FFchecked)
339*7ab27030SDavid du Colombier 		colarray(c, getcolor(Dark), getcolor(Light), getcolor(Red), TRUE);
340*7ab27030SDavid du Colombier 	else
341*7ab27030SDavid du Colombier 		colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), FALSE);
342*7ab27030SDavid du Colombier 
343*7ab27030SDavid du Colombier 	if(f->ftype == Fradio){
344*7ab27030SDavid du Colombier 		n = Boxsize/2-1;
345*7ab27030SDavid du Colombier 		pt = addpt(r.min, Pt(n,n));
346*7ab27030SDavid du Colombier 		ellipse3d(im, pt, n, Border, c, ZP);
347*7ab27030SDavid du Colombier 	}else
348*7ab27030SDavid du Colombier 		rect3d(im, r, Border, c, ZP);
349*7ab27030SDavid du Colombier }
350*7ab27030SDavid du Colombier 
351*7ab27030SDavid du Colombier void
drawbutton(Image * im,Rectangle r,Formfield * f,int checked)352*7ab27030SDavid du Colombier drawbutton(Image *im, Rectangle r, Formfield *f, int checked)
353*7ab27030SDavid du Colombier {
354*7ab27030SDavid du Colombier 	Image *c[3];
355*7ab27030SDavid du Colombier 
356*7ab27030SDavid du Colombier 	r = insetrect(r, Space);
357*7ab27030SDavid du Colombier 	colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), checked);
358*7ab27030SDavid du Colombier 	rect3d(im, r, Border, c, ZP);
359*7ab27030SDavid du Colombier 	r.min.x += Border + Margin;
360*7ab27030SDavid du Colombier 	r.min.y += Border + Margin;
361*7ab27030SDavid du Colombier 	runestringbg(im, r.min, display->black, ZP,  getfont(WFont), f->value, c[2], ZP);
362*7ab27030SDavid du Colombier }
363*7ab27030SDavid du Colombier 
364*7ab27030SDavid du Colombier void
drawselect(Image * im,Rectangle r,Iformfield * i)365*7ab27030SDavid du Colombier drawselect(Image *im, Rectangle r,	Iformfield *i)
366*7ab27030SDavid du Colombier {
367*7ab27030SDavid du Colombier 	Formfield *f;
368*7ab27030SDavid du Colombier 	Image *c[3];
369*7ab27030SDavid du Colombier 
370*7ab27030SDavid du Colombier 	f = i->formfield;
371*7ab27030SDavid du Colombier 	if(f->options == nil)
372*7ab27030SDavid du Colombier 		return;
373*7ab27030SDavid du Colombier 	r = insetrect(r, Space);
374*7ab27030SDavid du Colombier 	colarray(c, getcolor(Dark), getcolor(Light), display->white, 1);
375*7ab27030SDavid du Colombier 	rect3d(im, r, Border, c, ZP);
376*7ab27030SDavid du Colombier 	r = insetrect(r, Border+Margin);
377*7ab27030SDavid du Colombier 	draw(im, r, textcols[HIGH], nil, ZP);
378*7ab27030SDavid du Colombier 	if(i->aux==nil){
379*7ab27030SDavid du Colombier 		i->aux = f->options->display;
380*7ab27030SDavid du Colombier 		i->formfield->value = erunestrdup(f->options->value);
381*7ab27030SDavid du Colombier 	}
382*7ab27030SDavid du Colombier 	runestring(im, r.min, display->black, ZP,  getfont(WFont), i->aux);
383*7ab27030SDavid du Colombier }
384*7ab27030SDavid du Colombier 
385*7ab27030SDavid du Colombier /* Formfields are a special case */
386*7ab27030SDavid du Colombier static
387*7ab27030SDavid du Colombier void
drawformfield(Box * b,Page * p,Image * im)388*7ab27030SDavid du Colombier drawformfield(Box *b, Page *p, Image *im)
389*7ab27030SDavid du Colombier {
390*7ab27030SDavid du Colombier 	Formfield *f;
391*7ab27030SDavid du Colombier 	int type;
392*7ab27030SDavid du Colombier 
393*7ab27030SDavid du Colombier 	f = ((Iformfield *)b->i)->formfield;
394*7ab27030SDavid du Colombier 	type =f->ftype;
395*7ab27030SDavid du Colombier 	if(istextfield(b->i))
396*7ab27030SDavid du Colombier 		drawtextfield(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i);
397*7ab27030SDavid du Colombier 	else if(type==Fcheckbox || type==Fradio)
398*7ab27030SDavid du Colombier 		drawcheck(im, rectsubpt(b->r, p->pos), f);
399*7ab27030SDavid du Colombier 	else if(type==Fbutton || type==Freset || type==Fsubmit)
400*7ab27030SDavid du Colombier 		drawbutton(im, rectsubpt(b->r, p->pos), f, FALSE);
401*7ab27030SDavid du Colombier 	else if(type == Fimage)
402*7ab27030SDavid du Colombier 		drawimage(b, p, im);
403*7ab27030SDavid du Colombier 	else if(type == Fselect)
404*7ab27030SDavid du Colombier 		drawselect(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i);
405*7ab27030SDavid du Colombier }
406*7ab27030SDavid du Colombier 
407*7ab27030SDavid du Colombier static
408*7ab27030SDavid du Colombier void
drawnull(Box *,Page *,Image *)409*7ab27030SDavid du Colombier drawnull(Box *, Page *, Image *)
410*7ab27030SDavid du Colombier {
411*7ab27030SDavid du Colombier }
412*7ab27030SDavid du Colombier 
413*7ab27030SDavid du Colombier static
414*7ab27030SDavid du Colombier Page *
whichtarget1(Page * p,Rune * r)415*7ab27030SDavid du Colombier whichtarget1(Page *p, Rune *r)
416*7ab27030SDavid du Colombier {
417*7ab27030SDavid du Colombier 	Kidinfo *k;
418*7ab27030SDavid du Colombier 	Page *c, *ret;
419*7ab27030SDavid du Colombier 
420*7ab27030SDavid du Colombier 	k = p->kidinfo;
421*7ab27030SDavid du Colombier 	if(k && k->name && runestrcmp(k->name, r)==0)
422*7ab27030SDavid du Colombier 		return p;
423*7ab27030SDavid du Colombier 	for(c=p->child; c; c=c->next){
424*7ab27030SDavid du Colombier 		ret = whichtarget1(c, r);
425*7ab27030SDavid du Colombier 		if(ret)
426*7ab27030SDavid du Colombier 			return ret;
427*7ab27030SDavid du Colombier 	}
428*7ab27030SDavid du Colombier 	return nil;
429*7ab27030SDavid du Colombier }
430*7ab27030SDavid du Colombier 
431*7ab27030SDavid du Colombier static
432*7ab27030SDavid du Colombier Page *
whichtarget(Page * p,int t)433*7ab27030SDavid du Colombier whichtarget(Page *p, int t)
434*7ab27030SDavid du Colombier {
435*7ab27030SDavid du Colombier 	Page *r;
436*7ab27030SDavid du Colombier 
437*7ab27030SDavid du Colombier 	switch(t){
438*7ab27030SDavid du Colombier 	case FTblank:
439*7ab27030SDavid du Colombier 	case FTtop:
440*7ab27030SDavid du Colombier 		r = &p->w->page;
441*7ab27030SDavid du Colombier 		break;
442*7ab27030SDavid du Colombier 	case FTself:
443*7ab27030SDavid du Colombier 		r = p;
444*7ab27030SDavid du Colombier 		break;
445*7ab27030SDavid du Colombier 	case FTparent:
446*7ab27030SDavid du Colombier 		r = p->parent;
447*7ab27030SDavid du Colombier 		break;
448*7ab27030SDavid du Colombier 	default:
449*7ab27030SDavid du Colombier 		if(targetname(t) == L"?")
450*7ab27030SDavid du Colombier 			error("targetname");
451*7ab27030SDavid du Colombier 		r = whichtarget1(&p->w->page, targetname(t));
452*7ab27030SDavid du Colombier 	}
453*7ab27030SDavid du Colombier 
454*7ab27030SDavid du Colombier 	return r ? r: &p->w->page;
455*7ab27030SDavid du Colombier }
456*7ab27030SDavid du Colombier 
457*7ab27030SDavid du Colombier static
458*7ab27030SDavid du Colombier void
mouselink(Box * b,Page * p,int but)459*7ab27030SDavid du Colombier mouselink(Box *b, Page *p, int but)
460*7ab27030SDavid du Colombier {
461*7ab27030SDavid du Colombier 	Runestr rs;
462*7ab27030SDavid du Colombier 	Anchor *a;
463*7ab27030SDavid du Colombier 
464*7ab27030SDavid du Colombier 	/* eat mouse */
465*7ab27030SDavid du Colombier 	while(mousectl->buttons)
466*7ab27030SDavid du Colombier 		readmouse(mousectl);
467*7ab27030SDavid du Colombier 
468*7ab27030SDavid du Colombier 	if(b->i->anchorid < 0)
469*7ab27030SDavid du Colombier 		return;
470*7ab27030SDavid du Colombier 
471*7ab27030SDavid du Colombier 	/* binary search would be better */
472*7ab27030SDavid du Colombier 	for(a=p->doc->anchors; a!=nil; a=a->next)
473*7ab27030SDavid du Colombier 		if(a->index == b->i->anchorid)
474*7ab27030SDavid du Colombier 			break;
475*7ab27030SDavid du Colombier 
476*7ab27030SDavid du Colombier 	if(a==nil || a->href==nil)
477*7ab27030SDavid du Colombier 		return;
478*7ab27030SDavid du Colombier 
479*7ab27030SDavid du Colombier 	p = whichtarget(p, a->target);
480*7ab27030SDavid du Colombier 	rs.r = urlcombine(getbase(p), a->href);
481*7ab27030SDavid du Colombier 	if(rs.r == nil)
482*7ab27030SDavid du Colombier 		return;
483*7ab27030SDavid du Colombier 	rs.nr = runestrlen(rs.r);
484*7ab27030SDavid du Colombier 
485*7ab27030SDavid du Colombier 	if(but == 1)
486*7ab27030SDavid du Colombier 		pageget(p, &rs, nil, HGet, p==&p->w->page);
487*7ab27030SDavid du Colombier 	else if(but == 2)
488*7ab27030SDavid du Colombier 		textset(&p->w->status, rs.r, rs.nr);
489*7ab27030SDavid du Colombier 	else if(but == 3)
490*7ab27030SDavid du Colombier 		plumbrunestr(&rs, nil);
491*7ab27030SDavid du Colombier 	closerunestr(&rs);
492*7ab27030SDavid du Colombier }
493*7ab27030SDavid du Colombier 
494*7ab27030SDavid du Colombier static
495*7ab27030SDavid du Colombier void
submit(Page * p,Formfield * formfield,int subfl)496*7ab27030SDavid du Colombier submit(Page *p, Formfield *formfield, int subfl)
497*7ab27030SDavid du Colombier {
498*7ab27030SDavid du Colombier 	Formfield *f;
499*7ab27030SDavid du Colombier 	Form *form;
500*7ab27030SDavid du Colombier 	Runestr src, post;
501*7ab27030SDavid du Colombier 	Rune *x, *sep, *y, *z;
502*7ab27030SDavid du Colombier 
503*7ab27030SDavid du Colombier 	form = formfield->form;
504*7ab27030SDavid du Colombier 	x = erunestrdup(L"");
505*7ab27030SDavid du Colombier 	sep = L"";
506*7ab27030SDavid du Colombier 	for(f=form->fields; f!=nil; f=f->next){
507*7ab27030SDavid du Colombier 		if(f->ftype == Freset)
508*7ab27030SDavid du Colombier 			continue;
509*7ab27030SDavid du Colombier 		if((f->ftype==Fradio || f->ftype==Fcheckbox) && !(f->flags&FFchecked))
510*7ab27030SDavid du Colombier 			continue;
511*7ab27030SDavid du Colombier 		if(f->ftype==Fsubmit && (f!=formfield || !subfl))
512*7ab27030SDavid du Colombier 			continue;
513*7ab27030SDavid du Colombier 		if(f->value==nil || f->name==nil || runestrcmp(f->name, L"_no_name_submit_")==0)
514*7ab27030SDavid du Colombier 			continue;
515*7ab27030SDavid du Colombier 
516*7ab27030SDavid du Colombier 		z = ucvt(f->value);
517*7ab27030SDavid du Colombier 		y = runesmprint("%S%S%S=%S", x, sep, f->name, z);
518*7ab27030SDavid du Colombier 		free(z);
519*7ab27030SDavid du Colombier 		sep = L"&";
520*7ab27030SDavid du Colombier 		free(x);
521*7ab27030SDavid du Colombier 		x = y;
522*7ab27030SDavid du Colombier 	}
523*7ab27030SDavid du Colombier 	p = whichtarget(p, form->target);
524*7ab27030SDavid du Colombier 	y = urlcombine(getbase(p), form->action);
525*7ab27030SDavid du Colombier 
526*7ab27030SDavid du Colombier 	memset(&src, 0, sizeof(Runestr));
527*7ab27030SDavid du Colombier 	memset(&post, 0, sizeof(Runestr));
528*7ab27030SDavid du Colombier 	if(form->method == HGet){
529*7ab27030SDavid du Colombier 		if(y[runestrlen(y)-1] == L'?')
530*7ab27030SDavid du Colombier 			sep = L"";
531*7ab27030SDavid du Colombier 		else
532*7ab27030SDavid du Colombier 			sep = L"?";
533*7ab27030SDavid du Colombier 		src.r = runesmprint("%S%S%S",y, sep,  x);
534*7ab27030SDavid du Colombier 		free(x);
535*7ab27030SDavid du Colombier 		free(y);
536*7ab27030SDavid du Colombier 	}else{
537*7ab27030SDavid du Colombier 		src.r = y;
538*7ab27030SDavid du Colombier 		post.r = x;
539*7ab27030SDavid du Colombier 		post.nr = runestrlen(x);
540*7ab27030SDavid du Colombier 		if(post.nr == 0){
541*7ab27030SDavid du Colombier 			free(post.r);
542*7ab27030SDavid du Colombier 			post.r = nil;
543*7ab27030SDavid du Colombier 		}
544*7ab27030SDavid du Colombier 	}
545*7ab27030SDavid du Colombier 	src.nr = runestrlen(src.r);
546*7ab27030SDavid du Colombier 	pageget(p, &src, &post, form->method, p==&p->w->page);
547*7ab27030SDavid du Colombier 	closerunestr(&src);
548*7ab27030SDavid du Colombier 	closerunestr(&post);
549*7ab27030SDavid du Colombier }
550*7ab27030SDavid du Colombier 
551*7ab27030SDavid du Colombier static
552*7ab27030SDavid du Colombier void
setradios(Formfield * formfield)553*7ab27030SDavid du Colombier setradios(Formfield *formfield)
554*7ab27030SDavid du Colombier {
555*7ab27030SDavid du Colombier 	Formfield *f;
556*7ab27030SDavid du Colombier 
557*7ab27030SDavid du Colombier 	for(f=formfield->form->fields; f!=nil; f=f->next)
558*7ab27030SDavid du Colombier 		if(f->ftype==Fradio && f!=formfield && runestrcmp(f->name, formfield->name)==0)
559*7ab27030SDavid du Colombier 			f->flags &=~FFchecked;
560*7ab27030SDavid du Colombier }
561*7ab27030SDavid du Colombier 
562*7ab27030SDavid du Colombier static
563*7ab27030SDavid du Colombier void
selectmouse(Box * b,Page * p,int but)564*7ab27030SDavid du Colombier selectmouse(Box *b, Page *p, int but)
565*7ab27030SDavid du Colombier {
566*7ab27030SDavid du Colombier 	Formfield *f;
567*7ab27030SDavid du Colombier 	Option *o;
568*7ab27030SDavid du Colombier 	Menu m;
569*7ab27030SDavid du Colombier 	char **item;
570*7ab27030SDavid du Colombier 	int i, n;
571*7ab27030SDavid du Colombier 
572*7ab27030SDavid du Colombier 	f = ((Iformfield *)b->i)->formfield;
573*7ab27030SDavid du Colombier 	n = 0;
574*7ab27030SDavid du Colombier 	item = nil;
575*7ab27030SDavid du Colombier 	for(o=f->options; o!=nil; o=o->next){
576*7ab27030SDavid du Colombier 		item = erealloc(item, ++n*sizeof(char *));
577*7ab27030SDavid du Colombier 		if(o->display)
578*7ab27030SDavid du Colombier 			item[n-1] = smprint("%S", o->display);
579*7ab27030SDavid du Colombier 		else
580*7ab27030SDavid du Colombier 			item[n-1] = estrdup("--");
581*7ab27030SDavid du Colombier 	}
582*7ab27030SDavid du Colombier 	if(item == nil)
583*7ab27030SDavid du Colombier 		return;
584*7ab27030SDavid du Colombier 
585*7ab27030SDavid du Colombier 	item[n] = 0;
586*7ab27030SDavid du Colombier 	m.item = item;
587*7ab27030SDavid du Colombier 	i = menuhit(but, mousectl, &m, nil);
588*7ab27030SDavid du Colombier 	if(i >= 0){
589*7ab27030SDavid du Colombier 		for(o=f->options; o!=nil; o=o->next, i--){
590*7ab27030SDavid du Colombier 			if(i == 0)
591*7ab27030SDavid du Colombier 				break;
592*7ab27030SDavid du Colombier 		}
593*7ab27030SDavid du Colombier 		((Iformfield *)b->i)->aux = o->display;
594*7ab27030SDavid du Colombier 		drawselect(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
595*7ab27030SDavid du Colombier 		if(f->value != nil)
596*7ab27030SDavid du Colombier 			free(f->value);
597*7ab27030SDavid du Colombier 		f->value = erunestrdup(o->value);
598*7ab27030SDavid du Colombier 	}
599*7ab27030SDavid du Colombier 	for(i=0; i< n; i++)
600*7ab27030SDavid du Colombier 		free(item[i]);
601*7ab27030SDavid du Colombier //	free(item);
602*7ab27030SDavid du Colombier }
603*7ab27030SDavid du Colombier 
604*7ab27030SDavid du Colombier static
605*7ab27030SDavid du Colombier void
mouseform(Box * b,Page * p,int but)606*7ab27030SDavid du Colombier mouseform(Box *b, Page *p, int but)
607*7ab27030SDavid du Colombier {
608*7ab27030SDavid du Colombier 	Rectangle r, cr;
609*7ab27030SDavid du Colombier 	Formfield *f;
610*7ab27030SDavid du Colombier 	Text *t;
611*7ab27030SDavid du Colombier 
612*7ab27030SDavid du Colombier 	f = ((Iformfield *)b->i)->formfield;
613*7ab27030SDavid du Colombier 	r = rectaddpt(rectsubpt(b->r, p->pos), p->r.min);
614*7ab27030SDavid du Colombier 	if(istextfield(b->i)){
615*7ab27030SDavid du Colombier 		cr = p->b->clipr;
616*7ab27030SDavid du Colombier 		replclipr(p->b, 0, p->r);
617*7ab27030SDavid du Colombier 		t = ((Iformfield *)b->i)->aux;
618*7ab27030SDavid du Colombier 		if(p->b != t->b)
619*7ab27030SDavid du Colombier 			drawtextfield(p->b, r, (Iformfield *)b->i);
620*7ab27030SDavid du Colombier 		textmouse(t, mouse->xy, but);
621*7ab27030SDavid du Colombier 		if(f->value)
622*7ab27030SDavid du Colombier 			free(f->value);
623*7ab27030SDavid du Colombier 		f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
624*7ab27030SDavid du Colombier 		replclipr(p->b, 0, cr);
625*7ab27030SDavid du Colombier 		return;
626*7ab27030SDavid du Colombier 	}
627*7ab27030SDavid du Colombier 
628*7ab27030SDavid du Colombier 	if(but != 1)
629*7ab27030SDavid du Colombier 		return;
630*7ab27030SDavid du Colombier 
631*7ab27030SDavid du Colombier 	if(f->ftype==Fselect){
632*7ab27030SDavid du Colombier 		selectmouse(b, p, but);
633*7ab27030SDavid du Colombier 		return;
634*7ab27030SDavid du Colombier 	}
635*7ab27030SDavid du Colombier 	if(f->ftype==Fsubmit || f->ftype==Fimage){
636*7ab27030SDavid du Colombier 		if(f->ftype == Fsubmit)
637*7ab27030SDavid du Colombier 			drawbutton(p->b, r, f, TRUE);
638*7ab27030SDavid du Colombier 		while(mouse->buttons == but)
639*7ab27030SDavid du Colombier 			readmouse(mousectl);
640*7ab27030SDavid du Colombier 		if(f->ftype == Fsubmit)
641*7ab27030SDavid du Colombier 			drawbutton(p->b, r, f, FALSE);
642*7ab27030SDavid du Colombier 		if(mouse->buttons==0 && ptinrect(mouse->xy, r))
643*7ab27030SDavid du Colombier 			submit(p, f, TRUE);
644*7ab27030SDavid du Colombier 		return;
645*7ab27030SDavid du Colombier 	}
646*7ab27030SDavid du Colombier 	if(f->ftype==Fradio || f->ftype==Fcheckbox){
647*7ab27030SDavid du Colombier 		if(f->flags&FFchecked){
648*7ab27030SDavid du Colombier 			if(f->ftype==Fcheckbox)
649*7ab27030SDavid du Colombier 				f->flags &=~FFchecked;
650*7ab27030SDavid du Colombier 		}else{
651*7ab27030SDavid du Colombier 			f->flags |= FFchecked;
652*7ab27030SDavid du Colombier 		}
653*7ab27030SDavid du Colombier 		if(f->ftype == Fradio)
654*7ab27030SDavid du Colombier 			setradios(f);
655*7ab27030SDavid du Colombier 		pageredraw(p);
656*7ab27030SDavid du Colombier 	}
657*7ab27030SDavid du Colombier }
658*7ab27030SDavid du Colombier 
659*7ab27030SDavid du Colombier static
660*7ab27030SDavid du Colombier void
keyform(Box * b,Page * p,Rune r)661*7ab27030SDavid du Colombier keyform(Box *b, Page *p, Rune r)
662*7ab27030SDavid du Colombier {
663*7ab27030SDavid du Colombier 	Rectangle cr;
664*7ab27030SDavid du Colombier 	Formfield *f;
665*7ab27030SDavid du Colombier 	Text *t;
666*7ab27030SDavid du Colombier 
667*7ab27030SDavid du Colombier 	f = ((Iformfield *)b->i)->formfield;
668*7ab27030SDavid du Colombier 	if(r==L'\n' && f->ftype==Ftext){
669*7ab27030SDavid du Colombier 		submit(p, f, FALSE);
670*7ab27030SDavid du Colombier 		return;
671*7ab27030SDavid du Colombier 	}
672*7ab27030SDavid du Colombier 	t = ((Iformfield *)b->i)->aux;
673*7ab27030SDavid du Colombier 	cr = p->b->clipr;
674*7ab27030SDavid du Colombier 	replclipr(p->b, 0, p->r);
675*7ab27030SDavid du Colombier 	if(t->b != p->b)
676*7ab27030SDavid du Colombier 		drawtextfield(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
677*7ab27030SDavid du Colombier 	texttype(t, r);
678*7ab27030SDavid du Colombier 	if(f->value)
679*7ab27030SDavid du Colombier 		free(f->value);
680*7ab27030SDavid du Colombier 	f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
681*7ab27030SDavid du Colombier 	replclipr(p->b, 0, cr);
682*7ab27030SDavid du Colombier }
683*7ab27030SDavid du Colombier 
684*7ab27030SDavid du Colombier void
boxinit(Box * b)685*7ab27030SDavid du Colombier boxinit(Box *b)
686*7ab27030SDavid du Colombier {
687*7ab27030SDavid du Colombier 	if(b->i->anchorid)
688*7ab27030SDavid du Colombier 		b->mouse = mouselink;
689*7ab27030SDavid du Colombier 	/* override mouselink for forms */
690*7ab27030SDavid du Colombier 	if(b->i->tag == Iformfieldtag){
691*7ab27030SDavid du Colombier 		b->mouse = mouseform;
692*7ab27030SDavid du Colombier 		if(istextfield(b->i))
693*7ab27030SDavid du Colombier 			b->key = keyform;
694*7ab27030SDavid du Colombier 	}
695*7ab27030SDavid du Colombier 	switch(b->i->tag){
696*7ab27030SDavid du Colombier 	case Itexttag:
697*7ab27030SDavid du Colombier 		b->draw = drawtext;
698*7ab27030SDavid du Colombier 		break;
699*7ab27030SDavid du Colombier 	case Iruletag:
700*7ab27030SDavid du Colombier 		b->draw = drawrule;
701*7ab27030SDavid du Colombier 		break;
702*7ab27030SDavid du Colombier 	case Iimagetag:
703*7ab27030SDavid du Colombier 		b->draw = drawimage;
704*7ab27030SDavid du Colombier 		break;
705*7ab27030SDavid du Colombier 	case Iformfieldtag:
706*7ab27030SDavid du Colombier 		b->draw = drawformfield;
707*7ab27030SDavid du Colombier 		break;
708*7ab27030SDavid du Colombier 	case Itabletag:
709*7ab27030SDavid du Colombier 		b->draw = drawtable;
710*7ab27030SDavid du Colombier 		break;
711*7ab27030SDavid du Colombier 	case Ifloattag:
712*7ab27030SDavid du Colombier 		b->draw = drawnull;
713*7ab27030SDavid du Colombier 		break;
714*7ab27030SDavid du Colombier 	case Ispacertag:
715*7ab27030SDavid du Colombier 		b->draw = drawnull;
716*7ab27030SDavid du Colombier 	}
717*7ab27030SDavid du Colombier }
718*7ab27030SDavid du Colombier 
719*7ab27030SDavid du Colombier Box *
boxalloc(Line * l,Item * i,Rectangle r)720*7ab27030SDavid du Colombier boxalloc(Line *l, Item *i, Rectangle r)
721*7ab27030SDavid du Colombier {
722*7ab27030SDavid du Colombier 	Box *b;
723*7ab27030SDavid du Colombier 
724*7ab27030SDavid du Colombier 	b = emalloc(sizeof(Box));
725*7ab27030SDavid du Colombier 	b->i = i;
726*7ab27030SDavid du Colombier 	b->r = r;
727*7ab27030SDavid du Colombier 	if(l->boxes == nil)
728*7ab27030SDavid du Colombier 		l->boxes = b;
729*7ab27030SDavid du Colombier 	else{
730*7ab27030SDavid du Colombier 		b->prev = l->lastbox;
731*7ab27030SDavid du Colombier 		l->lastbox->next = b;
732*7ab27030SDavid du Colombier 	}
733*7ab27030SDavid du Colombier 	l->lastbox = b;
734*7ab27030SDavid du Colombier 
735*7ab27030SDavid du Colombier 	return b;
736*7ab27030SDavid du Colombier }
737*7ab27030SDavid du Colombier 
738*7ab27030SDavid du Colombier Box *
pttobox(Line * l,Point xy)739*7ab27030SDavid du Colombier pttobox(Line *l, Point xy)
740*7ab27030SDavid du Colombier {
741*7ab27030SDavid du Colombier 	Box *b;
742*7ab27030SDavid du Colombier 
743*7ab27030SDavid du Colombier 	for(b=l->boxes; b!=nil; b=b->next)
744*7ab27030SDavid du Colombier 		if(ptinrect(xy, b->r))
745*7ab27030SDavid du Colombier 			return b;
746*7ab27030SDavid du Colombier 
747*7ab27030SDavid du Colombier 	return nil;
748*7ab27030SDavid du Colombier }
749*7ab27030SDavid du Colombier 
750*7ab27030SDavid du Colombier static
751*7ab27030SDavid du Colombier Line *
tbtoline(Itable * i,Point xy)752*7ab27030SDavid du Colombier tbtoline(Itable *i, Point xy)
753*7ab27030SDavid du Colombier {
754*7ab27030SDavid du Colombier 	Tablecell *c;
755*7ab27030SDavid du Colombier 
756*7ab27030SDavid du Colombier 	for(c=i->table->cells; c!=nil; c=c->next)
757*7ab27030SDavid du Colombier 		if(ptinrect(xy, c->lay->r))
758*7ab27030SDavid du Colombier 			return linewhich(c->lay, xy);
759*7ab27030SDavid du Colombier 
760*7ab27030SDavid du Colombier 	return nil;
761*7ab27030SDavid du Colombier }
762*7ab27030SDavid du Colombier 
763*7ab27030SDavid du Colombier Line *
linewhich(Lay * lay,Point xy)764*7ab27030SDavid du Colombier linewhich(Lay *lay, Point xy)
765*7ab27030SDavid du Colombier {
766*7ab27030SDavid du Colombier 	Line *l, *t;
767*7ab27030SDavid du Colombier 	Box *b;
768*7ab27030SDavid du Colombier 
769*7ab27030SDavid du Colombier 	t = nil;
770*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=l->next)
771*7ab27030SDavid du Colombier 		if(ptinrect(xy, l->r))
772*7ab27030SDavid du Colombier 			break;
773*7ab27030SDavid du Colombier 
774*7ab27030SDavid du Colombier 	if(l!=nil && l->hastable){
775*7ab27030SDavid du Colombier 		b = pttobox(l, xy);
776*7ab27030SDavid du Colombier 		if(b!=nil && b->i->tag==Itabletag)
777*7ab27030SDavid du Colombier 			t = tbtoline((Itable *)b->i, xy);
778*7ab27030SDavid du Colombier 	}
779*7ab27030SDavid du Colombier 	return t? t: l;
780*7ab27030SDavid du Colombier }
781*7ab27030SDavid du Colombier 
782*7ab27030SDavid du Colombier Box *
boxwhich(Lay * lay,Point xy)783*7ab27030SDavid du Colombier boxwhich(Lay *lay, Point xy)
784*7ab27030SDavid du Colombier {
785*7ab27030SDavid du Colombier 	Line *l;
786*7ab27030SDavid du Colombier 
787*7ab27030SDavid du Colombier 	l = linewhich(lay, xy);
788*7ab27030SDavid du Colombier 	if(l)
789*7ab27030SDavid du Colombier 		return pttobox(l, xy);
790*7ab27030SDavid du Colombier 
791*7ab27030SDavid du Colombier 	return nil;
792*7ab27030SDavid du Colombier }
793*7ab27030SDavid du Colombier 
794*7ab27030SDavid du Colombier static void justline1(Line *, int);
795*7ab27030SDavid du Colombier 
796*7ab27030SDavid du Colombier static
797*7ab27030SDavid du Colombier void
justlay(Lay * lay,int x)798*7ab27030SDavid du Colombier justlay(Lay *lay, int x)
799*7ab27030SDavid du Colombier {
800*7ab27030SDavid du Colombier 	Line *l;
801*7ab27030SDavid du Colombier 
802*7ab27030SDavid du Colombier 	lay->r.min.x += x;
803*7ab27030SDavid du Colombier 	lay->r.max.x += x;
804*7ab27030SDavid du Colombier 
805*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=l->next)
806*7ab27030SDavid du Colombier 		justline1(l, x);
807*7ab27030SDavid du Colombier }
808*7ab27030SDavid du Colombier 
809*7ab27030SDavid du Colombier static
810*7ab27030SDavid du Colombier void
justtable(Itable * i,int x)811*7ab27030SDavid du Colombier justtable(Itable *i, int x)
812*7ab27030SDavid du Colombier {
813*7ab27030SDavid du Colombier 	Tablecell *c;
814*7ab27030SDavid du Colombier 
815*7ab27030SDavid du Colombier 	for(c=i->table->cells; c!=nil; c=c->next)
816*7ab27030SDavid du Colombier 		justlay(c->lay, x);
817*7ab27030SDavid du Colombier }
818*7ab27030SDavid du Colombier 
819*7ab27030SDavid du Colombier static
820*7ab27030SDavid du Colombier void
justline1(Line * l,int x)821*7ab27030SDavid du Colombier justline1(Line *l, int x)
822*7ab27030SDavid du Colombier {
823*7ab27030SDavid du Colombier 	Box *b;
824*7ab27030SDavid du Colombier 
825*7ab27030SDavid du Colombier 	l->r.min.x += x;
826*7ab27030SDavid du Colombier 	l->r.max.x += x;
827*7ab27030SDavid du Colombier 	for(b=l->boxes; b!=nil; b=b->next){
828*7ab27030SDavid du Colombier 		if(b->i->tag == Itabletag)
829*7ab27030SDavid du Colombier 			justtable((Itable *)b->i, x);
830*7ab27030SDavid du Colombier 		b->r.min.x += x;
831*7ab27030SDavid du Colombier 		b->r.max.x += x;
832*7ab27030SDavid du Colombier 	}
833*7ab27030SDavid du Colombier }
834*7ab27030SDavid du Colombier 
835*7ab27030SDavid du Colombier static
836*7ab27030SDavid du Colombier void
justline(Lay * lay,Line * l)837*7ab27030SDavid du Colombier justline(Lay *lay, Line *l)
838*7ab27030SDavid du Colombier {
839*7ab27030SDavid du Colombier 
840*7ab27030SDavid du Colombier 	int w, x;
841*7ab27030SDavid du Colombier 
842*7ab27030SDavid du Colombier 	w = Dx(l->r);
843*7ab27030SDavid du Colombier 	if(w>0 && w<lay->width){
844*7ab27030SDavid du Colombier 		x = 0;
845*7ab27030SDavid du Colombier 		if(l->state & IFrjust)
846*7ab27030SDavid du Colombier 			x = lay->width - w;
847*7ab27030SDavid du Colombier 		else if(l->state & IFcjust)
848*7ab27030SDavid du Colombier 			x = lay->width/2 - w/2;
849*7ab27030SDavid du Colombier 		if(x > 0)
850*7ab27030SDavid du Colombier 			justline1(l, x);
851*7ab27030SDavid du Colombier 	}
852*7ab27030SDavid du Colombier }
853*7ab27030SDavid du Colombier 
854*7ab27030SDavid du Colombier static
855*7ab27030SDavid du Colombier void
newline(Lay * lay,int state)856*7ab27030SDavid du Colombier newline(Lay *lay, int state)
857*7ab27030SDavid du Colombier {
858*7ab27030SDavid du Colombier 	Line *l, *last;
859*7ab27030SDavid du Colombier 	int indent, nl;
860*7ab27030SDavid du Colombier 
861*7ab27030SDavid du Colombier 	last = lay->lastline;
862*7ab27030SDavid du Colombier 	if(lay->laying == TRUE)
863*7ab27030SDavid du Colombier 		justline(lay, last);
864*7ab27030SDavid du Colombier 
865*7ab27030SDavid du Colombier 	lay->r.max.x = max(lay->r.max.x, last->r.max.x);
866*7ab27030SDavid du Colombier 	lay->r.max.y = last->r.max.y;
867*7ab27030SDavid du Colombier 
868*7ab27030SDavid du Colombier 	indent = ((state&IFindentmask)>>IFindentshift) * Tabspace;
869*7ab27030SDavid du Colombier 	nl = (state & IFbrksp) ? 1 : 0;
870*7ab27030SDavid du Colombier 
871*7ab27030SDavid du Colombier 	l = emalloc(sizeof(Line));
872*7ab27030SDavid du Colombier 	l->state = state;
873*7ab27030SDavid du Colombier 	l->hastext = FALSE;
874*7ab27030SDavid du Colombier 	l->hastable = FALSE;
875*7ab27030SDavid du Colombier 	l->r.min.x = lay->r.min.x + indent;
876*7ab27030SDavid du Colombier 	l->r.min.y = last->r.max.y + font->height*nl;
877*7ab27030SDavid du Colombier 	l->r.max = l->r.min;
878*7ab27030SDavid du Colombier 	l->prev = last;
879*7ab27030SDavid du Colombier 	last->next = l;
880*7ab27030SDavid du Colombier 	lay->lastline = l;
881*7ab27030SDavid du Colombier }
882*7ab27030SDavid du Colombier 
883*7ab27030SDavid du Colombier 
884*7ab27030SDavid du Colombier static
885*7ab27030SDavid du Colombier void
layitem(Lay * lay,Item * i)886*7ab27030SDavid du Colombier layitem(Lay *lay, Item *i)
887*7ab27030SDavid du Colombier {
888*7ab27030SDavid du Colombier 	Rectangle r;
889*7ab27030SDavid du Colombier 	Line *l;
890*7ab27030SDavid du Colombier 	Box *b;
891*7ab27030SDavid du Colombier 
892*7ab27030SDavid du Colombier 	if(i->state&IFbrk || i->state&IFbrksp)
893*7ab27030SDavid du Colombier 		newline(lay, i->state);
894*7ab27030SDavid du Colombier 	else	if(lay->lastline->r.max.x+i->width>lay->xwall && forceitem(i)==FALSE)
895*7ab27030SDavid du Colombier 		newline(lay, i->state);
896*7ab27030SDavid du Colombier 
897*7ab27030SDavid du Colombier 	l = lay->lastline;
898*7ab27030SDavid du Colombier 	r = Rect(l->r.max.x, l->r.min.y, l->r.max.x+i->width, l->r.min.y+i->height);
899*7ab27030SDavid du Colombier 	l->r.max.x = r.max.x;
900*7ab27030SDavid du Colombier 	if(l->r.max.y < r.max.y)
901*7ab27030SDavid du Colombier 		l->r.max.y = r.max.y;
902*7ab27030SDavid du Colombier 
903*7ab27030SDavid du Colombier 	if(i->tag == Ifloattag)
904*7ab27030SDavid du Colombier 		i = ((Ifloat *)i)->item;
905*7ab27030SDavid du Colombier 	if(i->tag == Itexttag)
906*7ab27030SDavid du Colombier 		l->hastext = TRUE;
907*7ab27030SDavid du Colombier 	else if(i->tag == Itabletag && lay->laying==TRUE){
908*7ab27030SDavid du Colombier 		laytable((Itable *)i, r);
909*7ab27030SDavid du Colombier 		l->hastable = TRUE;
910*7ab27030SDavid du Colombier 	}
911*7ab27030SDavid du Colombier 	b = boxalloc(l, i, r);
912*7ab27030SDavid du Colombier 	if(lay->laying)
913*7ab27030SDavid du Colombier 		boxinit(b);
914*7ab27030SDavid du Colombier }
915*7ab27030SDavid du Colombier 
916*7ab27030SDavid du Colombier static
917*7ab27030SDavid du Colombier void
linefix(Lay * lay)918*7ab27030SDavid du Colombier linefix(Lay *lay)
919*7ab27030SDavid du Colombier {
920*7ab27030SDavid du Colombier 	Line *l;
921*7ab27030SDavid du Colombier 
922*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=l->next){
923*7ab27030SDavid du Colombier 		l->r.min.x = lay->r.min.x;
924*7ab27030SDavid du Colombier 		l->r.max.x = lay->r.max.x;
925*7ab27030SDavid du Colombier 	}
926*7ab27030SDavid du Colombier }
927*7ab27030SDavid du Colombier 
928*7ab27030SDavid du Colombier Lay *
layitems(Item * items,Rectangle r,int laying)929*7ab27030SDavid du Colombier layitems(Item *items, Rectangle r, int laying)
930*7ab27030SDavid du Colombier {
931*7ab27030SDavid du Colombier 	Lay *lay;
932*7ab27030SDavid du Colombier 	Line *l;
933*7ab27030SDavid du Colombier 	Item *i;
934*7ab27030SDavid du Colombier 
935*7ab27030SDavid du Colombier 	lay = emalloc(sizeof(Lay));
936*7ab27030SDavid du Colombier 	lay->r.min = r.min;
937*7ab27030SDavid du Colombier 	lay->r.max = r.min;
938*7ab27030SDavid du Colombier 	lay->xwall = r.max.x;
939*7ab27030SDavid du Colombier 	lay->width = Dx(r);
940*7ab27030SDavid du Colombier 	lay->laying = laying;
941*7ab27030SDavid du Colombier 	l = emalloc(sizeof(Line));
942*7ab27030SDavid du Colombier 	l->r.min = lay->r.min;
943*7ab27030SDavid du Colombier 	l->r.max = lay->r.min;
944*7ab27030SDavid du Colombier 	l->state = IFbrk;
945*7ab27030SDavid du Colombier 	l->boxes = nil;
946*7ab27030SDavid du Colombier 	lay->lines = l;
947*7ab27030SDavid du Colombier 	lay->lastline = l;
948*7ab27030SDavid du Colombier 	lay->font = font;
949*7ab27030SDavid du Colombier 
950*7ab27030SDavid du Colombier 	for(i=items; i; i=i->next){
951*7ab27030SDavid du Colombier 		sizeitem(lay, i);
952*7ab27030SDavid du Colombier 		layitem(lay, i);
953*7ab27030SDavid du Colombier 	}
954*7ab27030SDavid du Colombier 	newline(lay, IFbrk);
955*7ab27030SDavid du Colombier 	if(laying)
956*7ab27030SDavid du Colombier 		linefix(lay);
957*7ab27030SDavid du Colombier 
958*7ab27030SDavid du Colombier 	return lay;
959*7ab27030SDavid du Colombier }
960*7ab27030SDavid du Colombier 
961*7ab27030SDavid du Colombier void
laypage(Page * p)962*7ab27030SDavid du Colombier laypage(Page *p)
963*7ab27030SDavid du Colombier {
964*7ab27030SDavid du Colombier 	settables(p);
965*7ab27030SDavid du Colombier 	layfree(p->lay);
966*7ab27030SDavid du Colombier 	p->lay = layitems(p->items, Rect(0,0,Dx(p->r),Dy(p->r)), TRUE);
967*7ab27030SDavid du Colombier 	p->lay->r.max.y = max(p->lay->r.max.y, Dy(p->r));
968*7ab27030SDavid du Colombier }
969*7ab27030SDavid du Colombier 
970*7ab27030SDavid du Colombier static
971*7ab27030SDavid du Colombier void
drawline(Page * p,Image * im,Line * l)972*7ab27030SDavid du Colombier drawline(Page *p, Image *im, Line *l)
973*7ab27030SDavid du Colombier {
974*7ab27030SDavid du Colombier 	Box *b;
975*7ab27030SDavid du Colombier 
976*7ab27030SDavid du Colombier 	for(b=l->boxes; b!=nil; b=b->next)
977*7ab27030SDavid du Colombier 		b->draw(b, p, im);
978*7ab27030SDavid du Colombier }
979*7ab27030SDavid du Colombier 
980*7ab27030SDavid du Colombier void
laydraw(Page * p,Image * im,Lay * lay)981*7ab27030SDavid du Colombier laydraw(Page *p, Image *im, Lay *lay)
982*7ab27030SDavid du Colombier {
983*7ab27030SDavid du Colombier 	Rectangle r;
984*7ab27030SDavid du Colombier 	Line *l;
985*7ab27030SDavid du Colombier 
986*7ab27030SDavid du Colombier 	r = rectaddpt(p->lay->r, p->pos);
987*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=l->next){
988*7ab27030SDavid du Colombier 		if(rectXrect(r, l->r))
989*7ab27030SDavid du Colombier 			drawline(p, im, l);
990*7ab27030SDavid du Colombier 	}
991*7ab27030SDavid du Colombier }
992*7ab27030SDavid du Colombier 
993*7ab27030SDavid du Colombier static
994*7ab27030SDavid du Colombier void
laytablefree(Table * t)995*7ab27030SDavid du Colombier laytablefree(Table *t)
996*7ab27030SDavid du Colombier {
997*7ab27030SDavid du Colombier 	Tablecell *c;
998*7ab27030SDavid du Colombier 
999*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
1000*7ab27030SDavid du Colombier 		layfree(c->lay);
1001*7ab27030SDavid du Colombier 		c->lay = nil;
1002*7ab27030SDavid du Colombier 	}
1003*7ab27030SDavid du Colombier }
1004*7ab27030SDavid du Colombier 
1005*7ab27030SDavid du Colombier void
layfree(Lay * lay)1006*7ab27030SDavid du Colombier layfree(Lay *lay)
1007*7ab27030SDavid du Colombier {
1008*7ab27030SDavid du Colombier 	Line *l, *nextline;
1009*7ab27030SDavid du Colombier 	Box *b, *nextbox;
1010*7ab27030SDavid du Colombier 	void **aux;
1011*7ab27030SDavid du Colombier 
1012*7ab27030SDavid du Colombier 	if(lay == nil)
1013*7ab27030SDavid du Colombier 		return;
1014*7ab27030SDavid du Colombier 
1015*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=nextline){
1016*7ab27030SDavid du Colombier 		for(b=l->boxes; b!=nil; b=nextbox){
1017*7ab27030SDavid du Colombier 			nextbox = b->next;
1018*7ab27030SDavid du Colombier 			if(b->i->tag==Iformfieldtag && istextfield(b->i)){
1019*7ab27030SDavid du Colombier 				aux = &((Iformfield *)b->i)->aux;
1020*7ab27030SDavid du Colombier 				if(*aux){
1021*7ab27030SDavid du Colombier 					textclose(*aux);
1022*7ab27030SDavid du Colombier 					free(*aux);
1023*7ab27030SDavid du Colombier 				}
1024*7ab27030SDavid du Colombier 				*aux = nil;
1025*7ab27030SDavid du Colombier 			}else if(b->i->tag == Itabletag)
1026*7ab27030SDavid du Colombier 				laytablefree(((Itable *)b->i)->table);
1027*7ab27030SDavid du Colombier 
1028*7ab27030SDavid du Colombier 			free(b);
1029*7ab27030SDavid du Colombier 		}
1030*7ab27030SDavid du Colombier 		nextline = l->next;
1031*7ab27030SDavid du Colombier 		free(l);
1032*7ab27030SDavid du Colombier 	}
1033*7ab27030SDavid du Colombier 	free(lay);
1034*7ab27030SDavid du Colombier }
1035*7ab27030SDavid du Colombier 
1036*7ab27030SDavid du Colombier void
laysnarf(Page * p,Lay * lay,Runestr * rs)1037*7ab27030SDavid du Colombier laysnarf(Page *p, Lay *lay, Runestr *rs)
1038*7ab27030SDavid du Colombier {
1039*7ab27030SDavid du Colombier 	Tablecell *c;
1040*7ab27030SDavid du Colombier 	Itext *i;
1041*7ab27030SDavid du Colombier 	Font *f;
1042*7ab27030SDavid du Colombier 	Line *l;
1043*7ab27030SDavid du Colombier 	Box *b;
1044*7ab27030SDavid du Colombier 	int q0, q1, n;
1045*7ab27030SDavid du Colombier 
1046*7ab27030SDavid du Colombier 	for(l=lay->lines; l!=nil; l=l->next) for(b=l->boxes; b!=nil; b=b->next){
1047*7ab27030SDavid du Colombier 		if(p->selecting && hasbrk(b->i->state)){
1048*7ab27030SDavid du Colombier 			rs->r = runerealloc(rs->r, rs->nr+2);
1049*7ab27030SDavid du Colombier 			rs->r[rs->nr++] = L'\n';
1050*7ab27030SDavid du Colombier 			rs->r[rs->nr] = L'\0';
1051*7ab27030SDavid du Colombier 		}
1052*7ab27030SDavid du Colombier 		if(b->i->tag==Itexttag){
1053*7ab27030SDavid du Colombier 			i = (Itext *)b->i;
1054*7ab27030SDavid du Colombier 			f = getfont(i->fnt);
1055*7ab27030SDavid du Colombier 			if(istextsel(p, b->r, &q0, &q1, i->s, f)){
1056*7ab27030SDavid du Colombier 				if(q1 == 0)
1057*7ab27030SDavid du Colombier 					q1 = runestrlen(i->s);
1058*7ab27030SDavid du Colombier 				n = q1-q0;
1059*7ab27030SDavid du Colombier 				if(n == 0)
1060*7ab27030SDavid du Colombier 					n = runestrlen(i->s);
1061*7ab27030SDavid du Colombier 				rs->r = runerealloc(rs->r, rs->nr+n+2);
1062*7ab27030SDavid du Colombier 				runemove(rs->r+rs->nr, i->s+q0, n);
1063*7ab27030SDavid du Colombier 				rs->nr += n;
1064*7ab27030SDavid du Colombier 				rs->r[rs->nr++] = L' ';
1065*7ab27030SDavid du Colombier 				rs->r[rs->nr] = L'\0';
1066*7ab27030SDavid du Colombier 			}
1067*7ab27030SDavid du Colombier 		}else if(b->i->tag == Itabletag)
1068*7ab27030SDavid du Colombier 			for(c=((Itable *)b->i)->table->cells; c!=nil; c=c->next)
1069*7ab27030SDavid du Colombier 				if(c->lay)
1070*7ab27030SDavid du Colombier 					laysnarf(p, c->lay, rs);
1071*7ab27030SDavid du Colombier 	}
1072*7ab27030SDavid du Colombier }
1073