xref: /inferno-os/libprefab/textelement.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include <lib9.h>
2*37da2899SCharles.Forsyth #include <draw.h>
3*37da2899SCharles.Forsyth #include <interp.h>
4*37da2899SCharles.Forsyth #include <isa.h>
5*37da2899SCharles.Forsyth #include "../libinterp/runt.h"
6*37da2899SCharles.Forsyth #include <drawif.h>
7*37da2899SCharles.Forsyth #include <prefab.h>
8*37da2899SCharles.Forsyth #include <kernel.h>
9*37da2899SCharles.Forsyth 
10*37da2899SCharles.Forsyth typedef struct State State;
11*37da2899SCharles.Forsyth 
12*37da2899SCharles.Forsyth struct State
13*37da2899SCharles.Forsyth {
14*37da2899SCharles.Forsyth 	Prefab_Environ	*env;
15*37da2899SCharles.Forsyth 	List			*list;
16*37da2899SCharles.Forsyth 	char			word[Maxchars+UTFmax];
17*37da2899SCharles.Forsyth 	char			*s;
18*37da2899SCharles.Forsyth 	char			*pending;
19*37da2899SCharles.Forsyth 	Draw_Font	*font;
20*37da2899SCharles.Forsyth 	Draw_Image	*color;
21*37da2899SCharles.Forsyth 	Draw_Image	*icon;
22*37da2899SCharles.Forsyth 	Draw_Image	*mask;
23*37da2899SCharles.Forsyth 	String		*tag;
24*37da2899SCharles.Forsyth 	Point			p;
25*37da2899SCharles.Forsyth 	int			mainkind;
26*37da2899SCharles.Forsyth 	int			kind;
27*37da2899SCharles.Forsyth 	int			wid;
28*37da2899SCharles.Forsyth 	int			newelem;
29*37da2899SCharles.Forsyth 	int			ascent;
30*37da2899SCharles.Forsyth 	int			descent;
31*37da2899SCharles.Forsyth };
32*37da2899SCharles.Forsyth 
33*37da2899SCharles.Forsyth static
34*37da2899SCharles.Forsyth char*
advword(char * s,char * word)35*37da2899SCharles.Forsyth advword(char *s, char *word)
36*37da2899SCharles.Forsyth {
37*37da2899SCharles.Forsyth 	char *e;
38*37da2899SCharles.Forsyth 	int w;
39*37da2899SCharles.Forsyth 	Rune r;
40*37da2899SCharles.Forsyth 
41*37da2899SCharles.Forsyth 	e = s+Maxchars-1;
42*37da2899SCharles.Forsyth 	switch(*word++ = *s){
43*37da2899SCharles.Forsyth 	case '\t':		/* BUG: what to do about tabs? */
44*37da2899SCharles.Forsyth 		strcpy(word-1, "    ");
45*37da2899SCharles.Forsyth 		return s+1;
46*37da2899SCharles.Forsyth 	case '\n':
47*37da2899SCharles.Forsyth 	case ' ':
48*37da2899SCharles.Forsyth 		*word = 0;
49*37da2899SCharles.Forsyth 		return s+1;
50*37da2899SCharles.Forsyth 	case '\0':
51*37da2899SCharles.Forsyth 		return s;
52*37da2899SCharles.Forsyth 	}
53*37da2899SCharles.Forsyth 	s++;
54*37da2899SCharles.Forsyth 	while(s<e && *s && *s!=' ' && *s!='\t' && *s!='\n'){
55*37da2899SCharles.Forsyth 		if(*(uchar*)s < Runeself)
56*37da2899SCharles.Forsyth 			*word++ = *s++;
57*37da2899SCharles.Forsyth 		else{
58*37da2899SCharles.Forsyth 			w = chartorune(&r, s);
59*37da2899SCharles.Forsyth 			memmove(word, s, w);
60*37da2899SCharles.Forsyth 			word += w;
61*37da2899SCharles.Forsyth 			s += w;
62*37da2899SCharles.Forsyth 		}
63*37da2899SCharles.Forsyth 	}
64*37da2899SCharles.Forsyth 	*word = 0;
65*37da2899SCharles.Forsyth 	return s;
66*37da2899SCharles.Forsyth }
67*37da2899SCharles.Forsyth 
68*37da2899SCharles.Forsyth static
69*37da2899SCharles.Forsyth int
ismore(State * state)70*37da2899SCharles.Forsyth ismore(State *state)
71*37da2899SCharles.Forsyth {
72*37da2899SCharles.Forsyth 	Prefab_Style *style;
73*37da2899SCharles.Forsyth 	Prefab_Layout *lay;
74*37da2899SCharles.Forsyth 	int text, icon;
75*37da2899SCharles.Forsyth 
76*37da2899SCharles.Forsyth 	state->newelem = 0;
77*37da2899SCharles.Forsyth 	if(state->kind==EIcon || (state->s && state->s[0]) || state->pending)
78*37da2899SCharles.Forsyth 		return 1;
79*37da2899SCharles.Forsyth 	if(state->list == H)
80*37da2899SCharles.Forsyth 		return 0;
81*37da2899SCharles.Forsyth 	lay = (Prefab_Layout*)state->list->data;
82*37da2899SCharles.Forsyth 	text = (lay->text!=H && lay->text->len != 0);
83*37da2899SCharles.Forsyth 	icon = (lay->icon!=H && lay->mask!=H);
84*37da2899SCharles.Forsyth 	if(!text && !icon)
85*37da2899SCharles.Forsyth 		return 0;
86*37da2899SCharles.Forsyth 	state->newelem = 1;
87*37da2899SCharles.Forsyth 	state->s = string2c(lay->text);
88*37da2899SCharles.Forsyth 	state->font = lay->font;
89*37da2899SCharles.Forsyth 	state->color = lay->color;
90*37da2899SCharles.Forsyth 	state->icon = lay->icon;
91*37da2899SCharles.Forsyth 	state->mask = lay->mask;
92*37da2899SCharles.Forsyth 	state->tag = lay->tag;
93*37da2899SCharles.Forsyth 	style = state->env->style;
94*37da2899SCharles.Forsyth 	if(icon)	/* has precedence; if lay->icon is set, we ignore the text */
95*37da2899SCharles.Forsyth 		state->kind = EIcon;
96*37da2899SCharles.Forsyth 	else{
97*37da2899SCharles.Forsyth 		if(state->mainkind == ETitle){
98*37da2899SCharles.Forsyth 			if(state->font == H)
99*37da2899SCharles.Forsyth 				state->font = style->titlefont;
100*37da2899SCharles.Forsyth 			if(state->color == H)
101*37da2899SCharles.Forsyth 				state->color = style->titlecolor;
102*37da2899SCharles.Forsyth 		}else{
103*37da2899SCharles.Forsyth 			if(state->font == H)
104*37da2899SCharles.Forsyth 				state->font = style->textfont;
105*37da2899SCharles.Forsyth 			if(state->color == H)
106*37da2899SCharles.Forsyth 				state->color = style->textcolor;
107*37da2899SCharles.Forsyth 		}
108*37da2899SCharles.Forsyth 		state->kind = state->mainkind;
109*37da2899SCharles.Forsyth 	}
110*37da2899SCharles.Forsyth 	state->list = state->list->tail;
111*37da2899SCharles.Forsyth 	return 1;
112*37da2899SCharles.Forsyth }
113*37da2899SCharles.Forsyth 
114*37da2899SCharles.Forsyth PElement*
growtext(PElement * pline,State * state,char * w,int minx,int maxx)115*37da2899SCharles.Forsyth growtext(PElement *pline, State *state, char *w, int minx, int maxx)
116*37da2899SCharles.Forsyth {
117*37da2899SCharles.Forsyth 	String *s;
118*37da2899SCharles.Forsyth 	PElement *pe, *plist;
119*37da2899SCharles.Forsyth 	Prefab_Element *e;
120*37da2899SCharles.Forsyth 	List *atom;
121*37da2899SCharles.Forsyth 	Point size;
122*37da2899SCharles.Forsyth 	Image *image;
123*37da2899SCharles.Forsyth 
124*37da2899SCharles.Forsyth 	if(state->newelem || pline==H) {
125*37da2899SCharles.Forsyth 		pe = mkelement(state->env, state->kind);
126*37da2899SCharles.Forsyth 		e = &pe->e;
127*37da2899SCharles.Forsyth 		e->r.min.x = minx;
128*37da2899SCharles.Forsyth 		if(state->kind == EIcon){
129*37da2899SCharles.Forsyth 			e->image = state->icon;
130*37da2899SCharles.Forsyth 			D2H(e->image)->ref++;
131*37da2899SCharles.Forsyth 			e->mask = state->mask;
132*37da2899SCharles.Forsyth 			D2H(e->mask)->ref++;
133*37da2899SCharles.Forsyth 		}else{
134*37da2899SCharles.Forsyth 			e->image = state->color;
135*37da2899SCharles.Forsyth 			D2H(e->image)->ref++;
136*37da2899SCharles.Forsyth 			e->font = state->font;
137*37da2899SCharles.Forsyth 			D2H(e->font)->ref++;
138*37da2899SCharles.Forsyth 		}
139*37da2899SCharles.Forsyth 		e->tag = state->tag;
140*37da2899SCharles.Forsyth 		if(e->tag != H)
141*37da2899SCharles.Forsyth 			D2H(e->tag)->ref++;
142*37da2899SCharles.Forsyth 		if(pline == H)
143*37da2899SCharles.Forsyth 			pline = pe;
144*37da2899SCharles.Forsyth 		else{
145*37da2899SCharles.Forsyth 			if(pline->pkind != EHorizontal){
146*37da2899SCharles.Forsyth 				/* promote pline to list encapsulating current contents */
147*37da2899SCharles.Forsyth 				atom = prefabwrap(pline);
148*37da2899SCharles.Forsyth 				plist = mkelement(state->env, EHorizontal);
149*37da2899SCharles.Forsyth 				destroy(pline);
150*37da2899SCharles.Forsyth 				/* rest of plist->e.r will be set later */
151*37da2899SCharles.Forsyth 				plist->e.r.min.x = state->p.x;
152*37da2899SCharles.Forsyth 				plist->drawpt = state->p;
153*37da2899SCharles.Forsyth 				plist->e.kids = atom;
154*37da2899SCharles.Forsyth 				plist->first = atom;
155*37da2899SCharles.Forsyth 				plist->last = atom;
156*37da2899SCharles.Forsyth 				plist->vfirst = atom;
157*37da2899SCharles.Forsyth 				plist->vlast = atom;
158*37da2899SCharles.Forsyth 				pline = plist;
159*37da2899SCharles.Forsyth 			}
160*37da2899SCharles.Forsyth 			/* add e to line */
161*37da2899SCharles.Forsyth 			atom = prefabwrap(e);
162*37da2899SCharles.Forsyth 			destroy(e);	/* relevant data now in wrapper */
163*37da2899SCharles.Forsyth 			e = *(Prefab_Element**)atom->data;
164*37da2899SCharles.Forsyth 			pline->last->tail = atom;
165*37da2899SCharles.Forsyth 			pline->last = atom;
166*37da2899SCharles.Forsyth 			pline->vlast = atom;
167*37da2899SCharles.Forsyth 			pline->nkids++;
168*37da2899SCharles.Forsyth 		}
169*37da2899SCharles.Forsyth 		state->newelem = 0;
170*37da2899SCharles.Forsyth 	}else{
171*37da2899SCharles.Forsyth 		pe = pline;
172*37da2899SCharles.Forsyth 		if(pe->pkind == EHorizontal)
173*37da2899SCharles.Forsyth 			pe = *(PElement**)pe->last->data;
174*37da2899SCharles.Forsyth 		e = &pe->e;
175*37da2899SCharles.Forsyth 	}
176*37da2899SCharles.Forsyth 
177*37da2899SCharles.Forsyth 	if(state->kind == EIcon){
178*37da2899SCharles.Forsyth 		/* guaranteed OK by buildine */
179*37da2899SCharles.Forsyth 		image = lookupimage(state->icon);
180*37da2899SCharles.Forsyth 		size = iconsize(image);
181*37da2899SCharles.Forsyth 		/* put one pixel on each side */
182*37da2899SCharles.Forsyth 		e->r.max.x = e->r.min.x+1+size.x+1;
183*37da2899SCharles.Forsyth 		pline->e.r.max.x = e->r.max.x;
184*37da2899SCharles.Forsyth 		if(state->ascent < size.y)
185*37da2899SCharles.Forsyth 			state->ascent = size.y;
186*37da2899SCharles.Forsyth 		state->kind = -1;	/* consume EIcon from state */
187*37da2899SCharles.Forsyth 		return pline;
188*37da2899SCharles.Forsyth 	}
189*37da2899SCharles.Forsyth 
190*37da2899SCharles.Forsyth 	e->r.max.x = maxx;
191*37da2899SCharles.Forsyth 	pline->e.r.max.x = maxx;
192*37da2899SCharles.Forsyth 	if(*w == '\n') {
193*37da2899SCharles.Forsyth 		pline->newline = 1;
194*37da2899SCharles.Forsyth 		return pline;
195*37da2899SCharles.Forsyth 	}
196*37da2899SCharles.Forsyth 
197*37da2899SCharles.Forsyth 	s = addstring(e->str, c2string(w, strlen(w)), 0);
198*37da2899SCharles.Forsyth 	destroy(e->str);
199*37da2899SCharles.Forsyth 	e->str = s;
200*37da2899SCharles.Forsyth 
201*37da2899SCharles.Forsyth 	if(state->ascent < e->font->ascent)
202*37da2899SCharles.Forsyth 		state->ascent = e->font->ascent;
203*37da2899SCharles.Forsyth 	if(state->descent < e->font->height-e->font->ascent)
204*37da2899SCharles.Forsyth 		state->descent = e->font->height-e->font->ascent;
205*37da2899SCharles.Forsyth 	return pline;
206*37da2899SCharles.Forsyth }
207*37da2899SCharles.Forsyth 
208*37da2899SCharles.Forsyth PElement*
buildline(State * state,int * ok)209*37da2899SCharles.Forsyth buildline(State *state, int *ok)
210*37da2899SCharles.Forsyth {
211*37da2899SCharles.Forsyth 	int wordwid, linewid, nb, rwid, x;
212*37da2899SCharles.Forsyth 	char tmp[UTFmax+1], *w, *t;
213*37da2899SCharles.Forsyth 	PElement *pl, *pe;
214*37da2899SCharles.Forsyth 	Rune r;
215*37da2899SCharles.Forsyth 	Font *f;
216*37da2899SCharles.Forsyth 	List *l;
217*37da2899SCharles.Forsyth 	Image *icon;
218*37da2899SCharles.Forsyth 	Point size;
219*37da2899SCharles.Forsyth 
220*37da2899SCharles.Forsyth 	*ok = 1;
221*37da2899SCharles.Forsyth 	linewid = 0;
222*37da2899SCharles.Forsyth 	pl = H;
223*37da2899SCharles.Forsyth 	state->ascent = 0;
224*37da2899SCharles.Forsyth 	state->descent = 0;
225*37da2899SCharles.Forsyth 	x = state->p.x;
226*37da2899SCharles.Forsyth 	while(ismore(state)){
227*37da2899SCharles.Forsyth 		f = nil;
228*37da2899SCharles.Forsyth 		if(state->kind == EIcon){
229*37da2899SCharles.Forsyth 			icon = lookupimage(state->icon);
230*37da2899SCharles.Forsyth 			if(icon == nil){
231*37da2899SCharles.Forsyth     Error:
232*37da2899SCharles.Forsyth 				destroy(pl);
233*37da2899SCharles.Forsyth 				*ok = 0;
234*37da2899SCharles.Forsyth 				return H;
235*37da2899SCharles.Forsyth 			}
236*37da2899SCharles.Forsyth 			size = iconsize(icon);
237*37da2899SCharles.Forsyth 			wordwid = 1+size.x+1;
238*37da2899SCharles.Forsyth 		}else{
239*37da2899SCharles.Forsyth 			if(state->pending == 0){
240*37da2899SCharles.Forsyth 				state->s = advword(state->s, state->word);
241*37da2899SCharles.Forsyth 				state->pending = state->word;
242*37da2899SCharles.Forsyth 			}
243*37da2899SCharles.Forsyth 			if(*(state->pending) == '\n'){
244*37da2899SCharles.Forsyth 				pl = growtext(pl, state, state->pending, x, x);
245*37da2899SCharles.Forsyth 				if(pl == H){
246*37da2899SCharles.Forsyth 					*ok = 0;
247*37da2899SCharles.Forsyth 					return H;
248*37da2899SCharles.Forsyth 				}
249*37da2899SCharles.Forsyth 				state->pending = 0;
250*37da2899SCharles.Forsyth 				break;
251*37da2899SCharles.Forsyth 			}
252*37da2899SCharles.Forsyth 			f = lookupfont(state->font);
253*37da2899SCharles.Forsyth 			if(f == nil)
254*37da2899SCharles.Forsyth 				goto Error;
255*37da2899SCharles.Forsyth 			wordwid = stringwidth(f, state->pending);
256*37da2899SCharles.Forsyth 		}
257*37da2899SCharles.Forsyth 		if(linewid+wordwid<=state->wid){
258*37da2899SCharles.Forsyth     Easy:
259*37da2899SCharles.Forsyth 			pl = growtext(pl, state, state->pending, x, x+wordwid);
260*37da2899SCharles.Forsyth 			if(pl == H){
261*37da2899SCharles.Forsyth 				*ok = 0;
262*37da2899SCharles.Forsyth 				return H;
263*37da2899SCharles.Forsyth 			}
264*37da2899SCharles.Forsyth 			linewid += wordwid;
265*37da2899SCharles.Forsyth 			state->pending = 0;
266*37da2899SCharles.Forsyth 			x += wordwid;
267*37da2899SCharles.Forsyth 			continue;
268*37da2899SCharles.Forsyth 		}
269*37da2899SCharles.Forsyth 		/* this word doesn't fit on this line */
270*37da2899SCharles.Forsyth 		/* if it's white space or an icon, just generate a line break */
271*37da2899SCharles.Forsyth 		if(state->word[0]==' ' || state->kind==EIcon){
272*37da2899SCharles.Forsyth 			if(linewid == 0)	/* it's just too wide; emit it and it'll get clipped */
273*37da2899SCharles.Forsyth 				goto Easy;
274*37da2899SCharles.Forsyth 			state->pending = 0;
275*37da2899SCharles.Forsyth 			break;
276*37da2899SCharles.Forsyth 		}
277*37da2899SCharles.Forsyth 		/* if word would fit were we to break the line now, do so */
278*37da2899SCharles.Forsyth 		if(wordwid <= state->wid)
279*37da2899SCharles.Forsyth 			break;
280*37da2899SCharles.Forsyth 		/* worst case: bite off the biggest piece that fits */
281*37da2899SCharles.Forsyth 		w = state->pending;
282*37da2899SCharles.Forsyth 		while(*w){
283*37da2899SCharles.Forsyth 			nb = chartorune(&r, w);
284*37da2899SCharles.Forsyth 			memmove(tmp, w, nb);
285*37da2899SCharles.Forsyth 			tmp[nb] = 0;
286*37da2899SCharles.Forsyth 			rwid = stringwidth(f, tmp);
287*37da2899SCharles.Forsyth 			if(linewid+rwid > state->wid)
288*37da2899SCharles.Forsyth 				break;
289*37da2899SCharles.Forsyth 			linewid += rwid;
290*37da2899SCharles.Forsyth 			w += nb;
291*37da2899SCharles.Forsyth 		}
292*37da2899SCharles.Forsyth 		if(w == state->pending){
293*37da2899SCharles.Forsyth 			/* first char too wide for remaining space */
294*37da2899SCharles.Forsyth 			if(linewid > 0)
295*37da2899SCharles.Forsyth 				break;
296*37da2899SCharles.Forsyth 			/* remaining space is all we'll get */
297*37da2899SCharles.Forsyth 			kwerrstr("can't handle wide word in textelement\n");
298*37da2899SCharles.Forsyth 			goto Error;
299*37da2899SCharles.Forsyth 		}
300*37da2899SCharles.Forsyth 		nb = w-state->pending;
301*37da2899SCharles.Forsyth 		t = malloc(nb+1);
302*37da2899SCharles.Forsyth 		if(t == nil)
303*37da2899SCharles.Forsyth 			goto Error;
304*37da2899SCharles.Forsyth 		memmove(t, state->pending, nb);
305*37da2899SCharles.Forsyth 		t[nb] = 0;
306*37da2899SCharles.Forsyth 		pl = growtext(pl, state, t, x, state->p.x+linewid);
307*37da2899SCharles.Forsyth 		free(t);
308*37da2899SCharles.Forsyth 		if(pl == H){
309*37da2899SCharles.Forsyth 			*ok = 0;
310*37da2899SCharles.Forsyth 			return H;
311*37da2899SCharles.Forsyth 		}
312*37da2899SCharles.Forsyth 		state->pending = w;
313*37da2899SCharles.Forsyth 		break;
314*37da2899SCharles.Forsyth 	}
315*37da2899SCharles.Forsyth 	pl->e.r.min.y = state->p.y;
316*37da2899SCharles.Forsyth 	pl->e.r.max.y = state->p.y+state->ascent+state->descent;
317*37da2899SCharles.Forsyth 	P2P(pl->drawpt, pl->e.r.min);
318*37da2899SCharles.Forsyth 	if(pl->pkind==EHorizontal){
319*37da2899SCharles.Forsyth 		for(l=pl->first; l!=H; l=l->tail){
320*37da2899SCharles.Forsyth 			pe = *(PElement**)l->data;
321*37da2899SCharles.Forsyth 			pe->e.r.min.y = state->p.y;
322*37da2899SCharles.Forsyth 			pe->e.r.max.y = state->p.y+state->ascent+state->descent;
323*37da2899SCharles.Forsyth 			pe->drawpt.x = pe->e.r.min.x;
324*37da2899SCharles.Forsyth 			if(pe->e.kind == EIcon){
325*37da2899SCharles.Forsyth 				/* add a pixel on the left; room was left in growtext */
326*37da2899SCharles.Forsyth 				pe->drawpt.x += 1;
327*37da2899SCharles.Forsyth 				pe->drawpt.y = pe->e.r.min.y+(state->ascent-Dy(pe->e.image->r));
328*37da2899SCharles.Forsyth 			}else
329*37da2899SCharles.Forsyth 				pe->drawpt.y = pe->e.r.min.y+(state->ascent-pe->e.font->ascent);
330*37da2899SCharles.Forsyth 		}
331*37da2899SCharles.Forsyth 	}
332*37da2899SCharles.Forsyth 	return pl;
333*37da2899SCharles.Forsyth }
334*37da2899SCharles.Forsyth 
335*37da2899SCharles.Forsyth PElement*
layoutelement(Prefab_Environ * env,List * laylist,Draw_Rect rr,enum Elementtype kind)336*37da2899SCharles.Forsyth layoutelement(Prefab_Environ *env, List *laylist, Draw_Rect rr, enum Elementtype kind)
337*37da2899SCharles.Forsyth {
338*37da2899SCharles.Forsyth 	PElement *pline, *plist, *firstpline;
339*37da2899SCharles.Forsyth 	List *lines, *atom, *tail;
340*37da2899SCharles.Forsyth 	State state;
341*37da2899SCharles.Forsyth 	int nlines, linewid, maxwid, wid, trim, maxy, ok;
342*37da2899SCharles.Forsyth 	Point p;
343*37da2899SCharles.Forsyth 	Rectangle r;
344*37da2899SCharles.Forsyth 	Screen *screen;
345*37da2899SCharles.Forsyth 
346*37da2899SCharles.Forsyth 	nlines = 0;
347*37da2899SCharles.Forsyth 	trim = 0;
348*37da2899SCharles.Forsyth 	wid = Dx(rr);
349*37da2899SCharles.Forsyth 	if(wid < 25){
350*37da2899SCharles.Forsyth 		if(wid <= 0)
351*37da2899SCharles.Forsyth 			trim = 1;
352*37da2899SCharles.Forsyth 		screen = lookupscreen(env->screen);
353*37da2899SCharles.Forsyth 		if(screen == nil)
354*37da2899SCharles.Forsyth 			return H;
355*37da2899SCharles.Forsyth 		wid = Dx(screen->display->image->r)-32;
356*37da2899SCharles.Forsyth 		if(wid < 100)
357*37da2899SCharles.Forsyth 			wid = 100;
358*37da2899SCharles.Forsyth 	}
359*37da2899SCharles.Forsyth 	wid -= 3+3;	/* three pixels left and right */
360*37da2899SCharles.Forsyth 
361*37da2899SCharles.Forsyth 	gchalt++;
362*37da2899SCharles.Forsyth 	state.env = env;
363*37da2899SCharles.Forsyth 	state.list = laylist;
364*37da2899SCharles.Forsyth 	state.s = 0;
365*37da2899SCharles.Forsyth 	state.pending = 0;
366*37da2899SCharles.Forsyth 	state.font = H;
367*37da2899SCharles.Forsyth 	state.color = H;
368*37da2899SCharles.Forsyth 	state.tag = H;
369*37da2899SCharles.Forsyth 	p = IPOINT(rr.min);
370*37da2899SCharles.Forsyth 	p.x += 3;
371*37da2899SCharles.Forsyth 	state.p = p;
372*37da2899SCharles.Forsyth 	state.kind = EText;	/* anything but EIcon */
373*37da2899SCharles.Forsyth 	state.mainkind = kind;
374*37da2899SCharles.Forsyth 	state.wid = wid;
375*37da2899SCharles.Forsyth 	lines = H;
376*37da2899SCharles.Forsyth 	tail = H;
377*37da2899SCharles.Forsyth 	firstpline = H;
378*37da2899SCharles.Forsyth 	maxwid = 0;
379*37da2899SCharles.Forsyth 	maxy = 0;
380*37da2899SCharles.Forsyth 	while(ismore(&state)){
381*37da2899SCharles.Forsyth 		pline = buildline(&state, &ok);
382*37da2899SCharles.Forsyth 		if(ok == 0){
383*37da2899SCharles.Forsyth 			plist = H;
384*37da2899SCharles.Forsyth 			goto Return;
385*37da2899SCharles.Forsyth 		}
386*37da2899SCharles.Forsyth 		if(pline == H)
387*37da2899SCharles.Forsyth 			break;
388*37da2899SCharles.Forsyth 		linewid = Dx(pline->e.r);
389*37da2899SCharles.Forsyth 		if(linewid > maxwid)
390*37da2899SCharles.Forsyth 			maxwid = linewid;
391*37da2899SCharles.Forsyth 		if(firstpline == H)
392*37da2899SCharles.Forsyth 			firstpline = pline;
393*37da2899SCharles.Forsyth 		else{
394*37da2899SCharles.Forsyth 			atom = prefabwrap(pline);
395*37da2899SCharles.Forsyth 			destroy(pline);	/* relevant data now in wrapper */
396*37da2899SCharles.Forsyth 			pline = *(PElement**)atom->data;
397*37da2899SCharles.Forsyth 			if(lines == H){
398*37da2899SCharles.Forsyth 				lines = prefabwrap(firstpline);
399*37da2899SCharles.Forsyth 				destroy(firstpline);
400*37da2899SCharles.Forsyth 				firstpline = 0;	/* never used again; this proves it! */
401*37da2899SCharles.Forsyth 				tail = lines;
402*37da2899SCharles.Forsyth 			}
403*37da2899SCharles.Forsyth 			tail->tail = atom;
404*37da2899SCharles.Forsyth 			tail = atom;
405*37da2899SCharles.Forsyth 		}
406*37da2899SCharles.Forsyth 		nlines++;
407*37da2899SCharles.Forsyth 		state.p.y = pline->e.r.max.y;
408*37da2899SCharles.Forsyth 		if(maxy==0 || state.p.y<=rr.max.y)
409*37da2899SCharles.Forsyth 			maxy = state.p.y;
410*37da2899SCharles.Forsyth 	}
411*37da2899SCharles.Forsyth 	if(trim == 0)
412*37da2899SCharles.Forsyth 		maxwid = wid;
413*37da2899SCharles.Forsyth 	if(nlines == 0){
414*37da2899SCharles.Forsyth 		plist = H;
415*37da2899SCharles.Forsyth 		goto Return;
416*37da2899SCharles.Forsyth 	}
417*37da2899SCharles.Forsyth 	if(nlines == 1){
418*37da2899SCharles.Forsyth 		if(trim == 0){	/* restore clipping around element */
419*37da2899SCharles.Forsyth 			firstpline->e.r.min.x = rr.min.x;
420*37da2899SCharles.Forsyth 			firstpline->e.r.max.x = rr.min.x+3+maxwid+3;
421*37da2899SCharles.Forsyth 		}
422*37da2899SCharles.Forsyth 		plist = firstpline;
423*37da2899SCharles.Forsyth 		goto Return;
424*37da2899SCharles.Forsyth 	}
425*37da2899SCharles.Forsyth 	plist = mkelement(env, EVertical);
426*37da2899SCharles.Forsyth 	plist->e.r.min.x = rr.min.x;
427*37da2899SCharles.Forsyth 	plist->e.r.min.y = p.y;
428*37da2899SCharles.Forsyth 	plist->e.r.max.x = rr.min.x+3+maxwid+3;
429*37da2899SCharles.Forsyth 	plist->e.r.max.y = (*(Prefab_Element**)tail->data)->r.max.y;
430*37da2899SCharles.Forsyth 	plist->drawpt = p;
431*37da2899SCharles.Forsyth 	plist->e.kids = lines;
432*37da2899SCharles.Forsyth 	plist->first = lines;
433*37da2899SCharles.Forsyth 	plist->last = tail;
434*37da2899SCharles.Forsyth 	plist->vfirst = lines;
435*37da2899SCharles.Forsyth 	plist->vlast = tail;
436*37da2899SCharles.Forsyth 	plist->nkids = nlines;
437*37da2899SCharles.Forsyth 	/* if asked for a fixed size and list is too long, clip */
438*37da2899SCharles.Forsyth 	if(Dy(rr)>0 && rr.max.y<plist->e.r.max.y){
439*37da2899SCharles.Forsyth 		R2R(r, plist->e.r);
440*37da2899SCharles.Forsyth 		r.max.y = maxy;
441*37da2899SCharles.Forsyth 		clipelement(&plist->e, r);
442*37da2899SCharles.Forsyth 	}
443*37da2899SCharles.Forsyth 
444*37da2899SCharles.Forsyth Return:
445*37da2899SCharles.Forsyth 	gchalt--;
446*37da2899SCharles.Forsyth 	return plist;
447*37da2899SCharles.Forsyth }
448*37da2899SCharles.Forsyth 
449*37da2899SCharles.Forsyth /*
450*37da2899SCharles.Forsyth  * Create List with one Layout in it, using malloc instead of heap to
451*37da2899SCharles.Forsyth  * keep it out of the eyes of the garbage collector
452*37da2899SCharles.Forsyth  */
453*37da2899SCharles.Forsyth List*
listoflayout(Prefab_Style * style,String * text,int kind)454*37da2899SCharles.Forsyth listoflayout(Prefab_Style *style, String *text, int kind)
455*37da2899SCharles.Forsyth {
456*37da2899SCharles.Forsyth 	List *listp;
457*37da2899SCharles.Forsyth 	Prefab_Layout *layp;
458*37da2899SCharles.Forsyth 
459*37da2899SCharles.Forsyth 	listp = malloc(sizeof(List) + TLayout->size);
460*37da2899SCharles.Forsyth 	if(listp == nil)
461*37da2899SCharles.Forsyth 		return H;
462*37da2899SCharles.Forsyth 	listp->tail = H;
463*37da2899SCharles.Forsyth 	layp = (Prefab_Layout*)listp->data;
464*37da2899SCharles.Forsyth 	if(kind == EText){
465*37da2899SCharles.Forsyth 		layp->font = style->textfont;
466*37da2899SCharles.Forsyth 		layp->color = style->textcolor;
467*37da2899SCharles.Forsyth 	}else{
468*37da2899SCharles.Forsyth 		layp->font = style->titlefont;
469*37da2899SCharles.Forsyth 		layp->color = style->titlecolor;
470*37da2899SCharles.Forsyth 	}
471*37da2899SCharles.Forsyth 	layp->text = text;
472*37da2899SCharles.Forsyth 	layp->icon = H;
473*37da2899SCharles.Forsyth 	layp->mask = H;
474*37da2899SCharles.Forsyth 	layp->tag = H;
475*37da2899SCharles.Forsyth 	return listp;
476*37da2899SCharles.Forsyth }
477*37da2899SCharles.Forsyth 
478*37da2899SCharles.Forsyth PElement*
textelement(Prefab_Environ * env,String * str,Draw_Rect rr,enum Elementtype kind)479*37da2899SCharles.Forsyth textelement(Prefab_Environ *env, String *str, Draw_Rect rr, enum Elementtype kind)
480*37da2899SCharles.Forsyth {
481*37da2899SCharles.Forsyth 	PElement *pe;
482*37da2899SCharles.Forsyth 	List *l;
483*37da2899SCharles.Forsyth 
484*37da2899SCharles.Forsyth 	l = listoflayout(env->style, str, kind);
485*37da2899SCharles.Forsyth 	pe = layoutelement(env, l, rr, kind);
486*37da2899SCharles.Forsyth 	free(l);
487*37da2899SCharles.Forsyth 	return pe;
488*37da2899SCharles.Forsyth }
489