1 #include <lib9.h>
2 #include <draw.h>
3 #include <interp.h>
4 #include <isa.h>
5 #include "../libinterp/runt.h"
6 #include <drawif.h>
7 #include <prefab.h>
8
9
10 void icondraw(Prefab_Element*, Image*, Rectangle, int, int);
11 void textdraw(Prefab_Element*, Image*, Rectangle, int, int);
12 void listdraw(Prefab_Element*, Image*, Rectangle, int, int);
13 void outlinehighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
14 void texthighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
15 void simpleclip(Prefab_Element*, Rectangle);
16 void horizontalclip(Prefab_Element*, Rectangle);
17 void verticalclip(Prefab_Element*, Rectangle);
18 void textscroll(Prefab_Element*, Point, int*);
19 void horizontalscroll(Prefab_Element*, Point, int*);
20 void verticalscroll(Prefab_Element*, Point, int*);
21 void iconscroll(Prefab_Element*, Point, int*);
22
23 struct
24 {
25 void (*draw)(Prefab_Element*, Image*, Rectangle, int, int);
26 void (*highlight)(Prefab_Element*, Image*, Prefab_Compound*, int);
27 void (*clip)(Prefab_Element*, Rectangle);
28 void (*scroll)(Prefab_Element*, Point, int*);
29 }elemfn[] = {
30 /* EIcon */ { icondraw, outlinehighlight, simpleclip, iconscroll, },
31 /* EText */ { textdraw, texthighlight, simpleclip, textscroll, },
32 /* ETitle */ { textdraw, outlinehighlight, simpleclip, textscroll, },
33 /* EHorizontal */ { listdraw, outlinehighlight, horizontalclip, horizontalscroll, },
34 /* EVertical */ { listdraw, outlinehighlight, verticalclip, verticalscroll, },
35 /* ESeparator */ { icondraw, outlinehighlight, simpleclip, iconscroll, },
36 };
37
38 Point
iconsize(Image * image)39 iconsize(Image *image)
40 {
41 Point dd;
42
43 if(image->repl){
44 dd.x = Dx(image->clipr);
45 dd.y = Dy(image->clipr);
46 }else{
47 dd.x = Dx(image->r);
48 dd.y = Dy(image->r);
49 }
50 return dd;
51 }
52
53 void
icondraw(Prefab_Element * elem,Image * i,Rectangle clipr,int clean,int highlight)54 icondraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
55 {
56 Prefab_Style *style;
57 Rectangle r;
58 Point p;
59 PElement *pelem;
60 Image *image, *c;
61 Point size;
62
63 USED(highlight);
64 pelem = lookupelement(elem);
65 if(pelem == H)
66 return;
67 if(!rectclip(&clipr, i->clipr))
68 return;
69 R2R(r, elem->r);
70 if(!rectclip(&clipr, r))
71 return;
72 if(elem->image==H || elem->mask==H || badenviron(elem->environ, 0))
73 return;
74 style = elem->environ->style;
75 if(!clean){
76 c = lookupimage(style->elemcolor);
77 if(c != nil)
78 draw(i, clipr, c, nil, clipr.min);
79 }
80 r.min = pelem->drawpt;
81 image = lookupimage(elem->image);
82 if(image == nil)
83 return;
84 size = iconsize(image);
85 r.max.x = r.min.x+size.x;
86 r.max.y = r.min.y+size.y;
87 if(rectclip(&r, clipr)){
88 p = image->r.min;
89 p.x += r.min.x-pelem->drawpt.x;
90 p.y += r.min.y-pelem->drawpt.y;
91 c = lookupimage(elem->mask);
92 if(c != nil)
93 draw(i, r, image, c, p);
94 }
95 }
96
97 void
textdraw(Prefab_Element * elem,Image * i,Rectangle clipr,int clean,int highlight)98 textdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
99 {
100 Prefab_Style *style;
101 Rectangle r;
102 PElement *pelem;
103 Image *color, *c;
104 Font *font;
105
106 USED(highlight);
107 pelem = lookupelement(elem);
108 if(pelem == H)
109 return;
110 if(!rectclip(&clipr, i->clipr))
111 return;
112 R2R(r, elem->r);
113 if(!rectclip(&clipr, r))
114 return;
115 if(elem->str==H || badenviron(elem->environ, 0))
116 return;
117 style = elem->environ->style;
118 font = lookupfont(elem->font);
119 if(font == nil)
120 return;
121 if(highlight)
122 color = lookupimage(style->highlightcolor);
123 else
124 color = lookupimage(elem->image);
125 if(!clean){
126 c = lookupimage(style->elemcolor);
127 if(c != nil)
128 draw(i, clipr, c, nil, clipr.min);
129 }
130 if(color != nil)
131 _string(i, pelem->drawpt, color, pelem->drawpt, font, string2c(elem->str), nil, 1<<24, clipr, nil, pelem->drawpt, SoverD);
132 }
133
134 void
listdraw(Prefab_Element * elem,Image * i,Rectangle clipr,int clean,int highlight)135 listdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
136 {
137 Prefab_Style *style;
138 Prefab_Element *e;
139 List *l;
140 Rectangle r;
141 PElement *pelem;
142 Image *c;
143
144 pelem = lookupelement(elem);
145 if(pelem == H)
146 return;
147 if(!rectclip(&clipr, i->clipr))
148 return;
149 R2R(r, elem->r);
150 if(!rectclip(&clipr, r))
151 return;
152 if(elem->kids==H || badenviron(elem->environ, 0))
153 return;
154 if(pelem->first != elem->kids) /* error? */
155 return;
156 style = elem->environ->style;
157 if(!clean){
158 c = lookupimage(style->elemcolor);
159 if(c != nil)
160 draw(i, clipr, c, nil, clipr.min);
161 }
162 for(l=pelem->vfirst; l!=H; l=l->tail){
163 e = *(Prefab_Element**)l->data;
164 R2R(r, e->r);
165 if(rectXrect(r, clipr))
166 drawelement(e, i, clipr, elem->environ==e->environ, highlight);
167 if(l == pelem->vlast)
168 break;
169 }
170 }
171
172 void
drawelement(Prefab_Element * elem,Image * i,Rectangle clipr,int clean,int highlight)173 drawelement(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
174 {
175 PElement *pelem;
176
177 if(elem != H){
178 pelem = lookupelement(elem);
179 if(pelem == H)
180 return;
181 (*elemfn[elem->kind].draw)(elem, i, clipr, clean, highlight);
182 if(!highlight && pelem->highlight!=H)
183 (*elemfn[elem->kind].highlight)(elem, i, pelem->highlight, 1);
184 }
185 }
186
187 void
translateelement(Prefab_Element * elem,Point delta)188 translateelement(Prefab_Element *elem, Point delta)
189 {
190 PElement *pelem;
191 List *l;
192
193 if(elem == H)
194 return;
195 pelem = lookupelement(elem);
196 if(pelem == H)
197 return;
198 elem->r.min.x += delta.x;
199 elem->r.min.y += delta.y;
200 elem->r.max.x += delta.x;
201 elem->r.max.y += delta.y;
202 pelem->drawpt.x += delta.x;
203 pelem->drawpt.y += delta.y;
204 switch(elem->kind){
205 case EHorizontal:
206 case EVertical:
207 if(pelem->first != elem->kids)
208 return;
209 for(l=elem->kids; l!=H; l=l->tail)
210 translateelement(*(Prefab_Element**)l->data, delta);
211 break;
212 }
213 }
214
215 int
fitrect(Rectangle * r,Rectangle sr)216 fitrect(Rectangle *r, Rectangle sr)
217 {
218 if(r->max.x > sr.max.x){
219 r->min.x -= r->max.x-sr.max.x;
220 r->max.x = sr.max.x;
221 }
222 if(r->max.y > sr.max.y){
223 r->min.y -= r->max.y-sr.max.y;
224 r->max.y = sr.max.y;
225 }
226 if(r->min.x < sr.min.x){
227 r->max.x += sr.min.x-r->min.x;
228 r->min.x = sr.min.x;
229 }
230 if(r->min.y < sr.min.y){
231 r->max.y += sr.min.y-r->min.y;
232 r->min.y = sr.min.y;
233 }
234 return rectinrect(*r, sr);
235 }
236
237 void
adjusthorizontal(Prefab_Element * elem,int spacing,int position)238 adjusthorizontal(Prefab_Element *elem, int spacing, int position)
239 {
240 int edx, dx, i, x;
241 int nlist; /* BUG: should precompute */
242 List *l;
243 PElement *pelem;
244 Prefab_Element *e;
245 Point p;
246
247 pelem = lookupelement(elem);
248 if(pelem == H)
249 return;
250 if(pelem->first != elem->kids)
251 return;
252 p.y = 0;
253 switch(spacing){
254 default: /* shouldn't happen; protected by adjustelement */
255 case Adjpack:
256 x = elem->r.min.x;
257 for(l=elem->kids; l!=H; l=l->tail){
258 e = *(Prefab_Element**)l->data;
259 p.x = x - e->r.min.x;
260 translateelement(e, p);
261 x += Dx(e->r);
262 }
263 elem->r.max.x = x;
264 return;
265
266 case Adjequal:
267 dx = 0;
268 nlist = 0;
269 for(l=elem->kids; l!=H; l=l->tail){
270 e = *(Prefab_Element**)l->data;
271 if(dx < Dx(e->r))
272 dx = Dx(e->r);
273 nlist++;
274 }
275 elem->r.max.x = elem->r.min.x+nlist*dx;
276 break;
277
278 case Adjfill:
279 nlist = 0;
280 for(l=elem->kids; l!=H; l=l->tail)
281 nlist++;
282 dx = Dx(elem->r)/nlist;
283 break;
284 }
285 i = 0;
286 for(l=elem->kids; l!=H; l=l->tail){
287 e = *(Prefab_Element**)l->data;
288 edx = Dx(e->r);
289 if(position == Adjleft)
290 edx = 0;
291 else if(position == Adjcenter)
292 edx = (dx-edx)/2;
293 else /* right */
294 edx = dx-edx;
295 p.x = (elem->r.min.x+i*dx + edx) - e->r.min.x;
296 translateelement(e, p);
297 i++;
298 }
299 }
300
301 void
adjustvertical(Prefab_Element * elem,int spacing,int position)302 adjustvertical(Prefab_Element *elem, int spacing, int position)
303 {
304 int edy, dy, i, y;
305 int nlist; /* BUG: should precompute */
306 List *l;
307 PElement *pelem;
308 Prefab_Element *e;
309 Point p;
310
311 pelem = lookupelement(elem);
312 if(pelem == H)
313 return;
314 if(pelem->first != elem->kids)
315 return;
316 p.x = 0;
317 switch(spacing){
318 default: /* shouldn't happen; protected by adjustelement */
319 case Adjpack:
320 y = elem->r.min.y;
321 for(l=elem->kids; l!=H; l=l->tail){
322 e = *(Prefab_Element**)l->data;
323 p.y = y - e->r.min.y;
324 translateelement(e, p);
325 y += Dy(e->r);
326 }
327 elem->r.max.y = y;
328 return;
329
330 case Adjequal:
331 dy = 0;
332 nlist = 0;
333 for(l=elem->kids; l!=H; l=l->tail){
334 e = *(Prefab_Element**)l->data;
335 if(dy < Dy(e->r))
336 dy = Dy(e->r);
337 nlist++;
338 }
339 elem->r.max.y = elem->r.min.y+nlist*dy;
340 break;
341
342 case Adjfill:
343 nlist = 0;
344 for(l=elem->kids; l!=H; l=l->tail)
345 nlist++;
346 dy = Dy(elem->r)/nlist;
347 break;
348 }
349 i = 0;
350 for(l=elem->kids; l!=H; l=l->tail){
351 e = *(Prefab_Element**)l->data;
352 edy = Dy(e->r);
353 if(position == Adjup)
354 edy = 0;
355 else if(position == Adjcenter)
356 edy = (dy-edy)/2;
357 else /* down */
358 edy = dy-edy;
359 p.y = (elem->r.min.y+i*dy + edy) - e->r.min.y;
360 translateelement(e, p);
361 i++;
362 }
363 }
364
365 void
adjustelement(Prefab_Element * elem,int spacing,int position)366 adjustelement(Prefab_Element *elem, int spacing, int position)
367 {
368 if(lookupelement(elem) == H)
369 return;
370 if(spacing<Adjpack || spacing>Adjfill || position<Adjleft || position>Adjdown)
371 return;
372 switch(elem->kind){
373 case EVertical:
374 adjustvertical(elem, spacing, position);
375 break;
376 case EHorizontal:
377 adjusthorizontal(elem, spacing, position);
378 break;
379 }
380 }
381
382 void
highlightelement(Prefab_Element * elem,Image * i,Prefab_Compound * comp,int on)383 highlightelement(Prefab_Element *elem, Image *i, Prefab_Compound *comp, int on)
384 {
385 PElement *pelem;
386
387 pelem = lookupelement(elem);
388 if(pelem!=H && lookupcompound(comp)!=H){
389 if(on)
390 pelem->highlight = comp;
391 else
392 pelem->highlight = H;
393 (*elemfn[elem->kind].highlight)(elem, i, comp, on);
394 }
395 }
396
397 static
398 int
anytextelements(Prefab_Element * e)399 anytextelements(Prefab_Element *e)
400 {
401 Prefab_Element *t;
402 List *l;
403
404 for(l=e->kids; l!=H; l=l->tail){
405 t = *(Prefab_Element**)l->data;
406 if(t->kind == EText)
407 return 1;
408 }
409 return 0;
410 }
411
412 void
textlisthighlight(Prefab_Element * e,Image * i,Prefab_Compound * c,int on)413 textlisthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
414 {
415 Prefab_Element *t;
416 List *l;
417
418 for(l=e->kids; l!=H; l=l->tail){
419 t = *(Prefab_Element**)l->data;
420 if(t->kind == EText)
421 texthighlight(t, i, c, on);
422 }
423 }
424
425 void
outlinehighlight(Prefab_Element * e,Image * i,Prefab_Compound * c,int on)426 outlinehighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
427 {
428 List *l;
429 Prefab_Element *t;
430 Image *color;
431 Rectangle r, r1, r2;
432 Point dp;
433 int done;
434
435 /* see if we can do it by highlighting just a text element */
436 if((e->kind==EVertical || e->kind==EHorizontal) && e->kids!=H){
437 /* is any child a text element? */
438 if(anytextelements(e)){
439 textlisthighlight(e, i, c, on);
440 return;
441 }
442 /* grandchild? */
443 done = 0;
444 for(l=e->kids; l!=H; l=l->tail){
445 t = *(Prefab_Element**)l->data;
446 if(t->kind==EVertical || t->kind==EHorizontal)
447 if(anytextelements(t)){
448 textlisthighlight(t, i, c, on);
449 done = 1;
450 }
451 }
452 if(done)
453 return;
454 }
455 if(on){
456 color = lookupimage(e->environ->style->highlightcolor);
457 if(color == nil)
458 return;
459 R2R(r, e->r);
460 /* avoid outlining empty space around images */
461 dp = ((PElement*)e)->drawpt;
462 if(e->kind==EIcon && e->image->repl==0 && ptinrect(dp, r)){
463 R2R(r1, e->image->r);
464 R2R(r2, e->image->clipr);
465 if(rectclip(&r1, r2)){
466 dp.x += Dx(r1);
467 dp.y += Dy(r1);
468 if(ptinrect(dp, r))
469 r = Rpt(((PElement*)e)->drawpt, dp);
470 }
471 }
472 draw(i, r, color, nil, r.min);
473 drawelement(e, i, insetrect(r, 2), Dirty, 1);
474 }else{
475 drawelement(e, i, IRECT(e->r), Dirty, 0);
476 edge(c->environ, i, c->r, e->r);
477 }
478 }
479
480 void
texthighlight(Prefab_Element * e,Image * i,Prefab_Compound * c,int on)481 texthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
482 {
483 drawelement(e, i, IRECT(e->r), Clean, on);
484 edge(c->environ, i, c->r, e->r);
485 }
486
487 void
clipelement(Prefab_Element * elem,Rectangle r)488 clipelement(Prefab_Element *elem, Rectangle r)
489 {
490 if(lookupelement(elem) != H)
491 (*elemfn[elem->kind].clip)(elem, r);
492 }
493
494 void
simpleclip(Prefab_Element * elem,Rectangle r)495 simpleclip(Prefab_Element *elem, Rectangle r)
496 {
497 R2R(elem->r, r);
498 }
499
500 void
horizontalclip(Prefab_Element * elem,Rectangle r)501 horizontalclip(Prefab_Element *elem, Rectangle r)
502 {
503 int x;
504 List *l;
505 Prefab_Element *e;
506 PElement *pelem;
507
508 x = r.min.x;
509 pelem = lookupelement(elem);
510 if(pelem == H)
511 return;
512 for(l=pelem->vfirst; l!=H && x<r.max.x; l=l->tail){
513 e = *(Prefab_Element**)l->data;
514 x += Dx(e->r);
515 }
516 pelem->vlast = l;
517 R2R(elem->r, r);
518 }
519
520 void
verticalclip(Prefab_Element * elem,Rectangle r)521 verticalclip(Prefab_Element *elem, Rectangle r)
522 {
523 int y;
524 List *l;
525 Prefab_Element *e;
526 PElement *pelem;
527
528 y = r.min.y;
529 pelem = lookupelement(elem);
530 if(pelem == H)
531 return;
532 for(l=pelem->vfirst; l!=H && y<r.max.y; l=l->tail){
533 e = *(Prefab_Element**)l->data;
534 y += Dy(e->r);
535 }
536 pelem->vlast = l;
537 R2R(elem->r, r);
538 }
539
540 void
scrollelement(Prefab_Element * elem,Point d,int * moved)541 scrollelement(Prefab_Element *elem, Point d, int *moved)
542 {
543 if(lookupelement(elem) != H)
544 (*elemfn[elem->kind].scroll)(elem, d, moved);
545 }
546
547 void
textscroll(Prefab_Element * elem,Point d,int * moved)548 textscroll(Prefab_Element *elem, Point d, int *moved)
549 {
550 PElement *pelem;
551
552 pelem = lookupelement(elem);
553 if(pelem==H || (d.x==0 && d.y==0))
554 return;
555 pelem->drawpt = subpt(pelem->drawpt, d);
556 *moved = 1;
557 }
558
559 void
iconscroll(Prefab_Element * elem,Point d,int * moved)560 iconscroll(Prefab_Element *elem, Point d, int *moved)
561 {
562 Point p;
563 Image *i;
564 PElement *pelem;
565
566 pelem = lookupelement(elem);
567 if(pelem==H || elem->image==H || (d.x==0 && d.y==0))
568 return;
569 i = lookupimage(elem->image);
570 if(i == nil)
571 return;
572 p = subpt(pelem->drawpt, d);
573 if(i->repl == 0){
574 if(p.x+Dx(i->clipr) < elem->r.max.x)
575 p.x = elem->r.max.x - Dx(i->clipr);
576 if(p.y+Dy(i->clipr) < elem->r.max.y)
577 p.y = elem->r.max.y - Dy(i->clipr);
578 if(p.x > elem->r.min.x)
579 p.x = elem->r.min.x;
580 if(p.y > elem->r.min.y)
581 p.y = elem->r.min.y;
582 }
583 *moved = !eqpt(pelem->drawpt, p);
584 pelem->drawpt = p;
585 }
586
587 void
horizontalscroll(Prefab_Element * elem,Point d,int * moved)588 horizontalscroll(Prefab_Element *elem, Point d, int *moved)
589 {
590 List *l;
591 Prefab_Element *e;
592 PElement *pelem;
593
594 pelem = lookupelement(elem);
595 if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
596 return;
597 for(l=pelem->first; l!=H; l=l->tail){
598 e = *(Prefab_Element**)l->data;
599 translateelement(e, d);
600 }
601 for(l=pelem->first; l!=H; l=l->tail){
602 e = *(Prefab_Element**)l->data;
603 if(e->r.max.x > elem->r.min.x)
604 break;
605 }
606 pelem->vfirst = l;
607 pelem->vlast = l;
608 for(; l!=H; l=l->tail){
609 e = *(Prefab_Element**)l->data;
610 pelem->vlast = l;
611 if(e->r.min.x >= elem->r.max.x)
612 break;
613 }
614 *moved = 1;
615 }
616
617 void
verticalscroll(Prefab_Element * elem,Point d,int * moved)618 verticalscroll(Prefab_Element *elem, Point d, int *moved)
619 {
620 List *l;
621 Prefab_Element *e;
622 PElement *pelem;
623
624 pelem = lookupelement(elem);
625 if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
626 return;
627 for(l=pelem->first; l!=H; l=l->tail){
628 e = *(Prefab_Element**)l->data;
629 translateelement(e, d);
630 }
631 for(l=pelem->first; l!=H; l=l->tail){
632 e = *(Prefab_Element**)l->data;
633 if(e->r.max.y > elem->r.min.y)
634 break;
635 }
636 pelem->vfirst = l;
637 pelem->vlast = l;
638 for(; l!=H; l=l->tail){
639 e = *(Prefab_Element**)l->data;
640 pelem->vlast = l;
641 if(e->r.min.y >= elem->r.max.y)
642 break;
643 }
644 *moved = 1;
645 }
646
647 /*
648 * Make e visible within list. Return value is whether any change was made;
649 * if so, must redraw (BUG: should probably do this here)
650 */
651 int
showelement(Prefab_Element * list,Prefab_Element * e)652 showelement(Prefab_Element *list, Prefab_Element *e)
653 {
654 Point p;
655 Prefab_Element *h, *t;
656 PElement *plist;
657 int moved;
658
659 p.x = p.y = 0;
660 if(list->kids == H)
661 return 0;
662 plist = lookupelement(list);
663 if(plist == H)
664 return 0;
665 h = *(Prefab_Element**)plist->first->data;
666 t = *(Prefab_Element**)plist->last->data;
667 if(list->kind == EHorizontal){
668 p.x = (list->r.min.x+Dx(list->r)/2) - e->r.min.x;
669 if(e->r.min.x < list->r.min.x){ /* scroll to right */
670 if(e->r.max.x+p.x > list->r.max.x)
671 p.x = list->r.min.x-e->r.min.x;
672 if(h->r.min.x + p.x > list->r.min.x)
673 p.x = list->r.min.x-h->r.min.x;
674 }else if(e->r.max.x > list->r.max.x){ /* scroll to left */
675 if(e->r.min.x+p.x < list->r.min.x)
676 p.x = list->r.min.x-e->r.min.x;
677 if(t->r.max.x + p.x < list->r.max.x)
678 p.x = list->r.max.x-t->r.max.x;
679 }else
680 return 0;
681 }else if(list->kind == EVertical){
682 p.y = (list->r.min.y+Dy(list->r)/2) - e->r.min.y;
683 if(e->r.min.y < list->r.min.y){ /* scroll towards bottom */
684 if(e->r.max.y+p.y > list->r.max.y)
685 p.y = list->r.min.y-e->r.min.y;
686 if(h->r.min.y + p.y > list->r.min.y)
687 p.y = list->r.min.y-h->r.min.y;
688 }else if(e->r.max.y > list->r.max.y){ /* scroll towards top */
689 if(e->r.min.y+p.y < list->r.min.y)
690 p.y = list->r.min.y-e->r.min.y;
691 if(t->r.max.y + p.y < list->r.max.y)
692 p.y = list->r.max.y-t->r.max.y;
693 }else
694 return 0;
695 }else
696 return 0;
697 if(p.x!=0 || p.y!=0){
698 scrollelement(list, p, &moved);
699 return 1;
700 }
701 return 0;
702 }
703
704 PElement*
mkelement(Prefab_Environ * env,enum Elementtype t)705 mkelement(Prefab_Environ *env, enum Elementtype t)
706 {
707 Heap *h;
708 PElement *p;
709
710 h = heapz(TElement);
711 p = H2D(PElement*, h);
712 p->highlight = H;
713 p->first = H;
714 p->last = H;
715 p->vfirst = H;
716 p->vlast = H;
717 p->nkids = 1;
718 p->pkind = t;
719 p->e.kind = t;
720 p->e.environ = env;
721 D2H(env)->ref++;
722 return p;
723 }
724