Subversion Repositories planix.SVN

Rev

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

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