xref: /inferno-os/libprefab/elistelement.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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 #include <kernel.h>
9 
10 List*
prefabwrap(void * elem)11 prefabwrap(void *elem)
12 {
13 	List *l;
14 	Heap *h, *e;
15 
16 	e = D2H(elem);
17 	h = nheap(sizeof(List) + sizeof(WORD*));
18 	h->t = &Tlist;
19 	Tlist.ref++;
20 	l = H2D(List*, h);
21 	l->tail = H;
22 	l->t = &Tptr;
23 	Tptr.ref++;
24 	e->ref++;
25 	*(WORD**)l->data = elem;
26 	return l;
27 }
28 
29 static
30 PElement*
elistelement1(Prefab_Environ * e,Prefab_Element * elem,Prefab_Element * new,enum Elementtype kind)31 elistelement1(Prefab_Environ *e, Prefab_Element *elem, Prefab_Element *new, enum Elementtype kind)
32 {
33 	int first;
34 	PElement *pelem;
35 	List *atom;
36 
37 	if(badenviron(e, 0))
38 		return H;
39 
40 	gchalt++;
41 	first = 0;
42 	if(new == H)
43 		atom = H;
44 	else
45 		atom = prefabwrap(new);
46 	if(elem == H){
47 		pelem = mkelement(e, kind);
48 		elem = &pelem->e;
49 		pelem->first = H;
50 		pelem->nkids = 0;
51 	}else
52 		pelem = (PElement*)elem;
53 	if(atom == H)
54 		goto Return;
55 
56 	if(elem->kids != pelem->first)
57 		error("list Element has been modified externally");
58 	if(elem->kids == H){
59 		elem->kids = atom;
60 		pelem->first = atom;
61 		pelem->last = atom;
62 		pelem->vfirst = atom;
63 		pelem->vlast = atom;
64 		first = 1;
65 	}
66 	if(new->kind!=ESeparator && Dx(elem->r)==0){
67 		elem->r = new->r;
68 		pelem->drawpt.x = elem->r.min.x;
69 		pelem->drawpt.y = elem->r.min.y;
70 	}
71 	pelem->nkids++;
72 	if(first)
73 		goto Return;
74 	pelem->last->tail = atom;
75 	pelem->last = atom;
76 	pelem->vlast = atom;
77 	if(new->kind != ESeparator){
78 		if(kind == EVertical){
79 			elem->r.max.y += Dy(new->r);
80 			if(elem->r.min.x > new->r.min.x)
81 				elem->r.min.x = new->r.min.x;
82 			if(elem->r.max.x < new->r.max.x)
83 				elem->r.max.x = new->r.max.x;
84 		}else{
85 			elem->r.max.x += Dx(new->r);
86 			if(elem->r.min.y > new->r.min.y)
87 				elem->r.min.y = new->r.min.y;
88 			if(elem->r.max.y < new->r.max.y)
89 				elem->r.max.y = new->r.max.y;
90 		}
91 	}
92 	pelem->pkind = kind;
93 
94     Return:
95 	gchalt--;
96 	return pelem;
97 }
98 
99 PElement*
elistelement(Prefab_Environ * e,Prefab_Element * new,enum Elementtype kind)100 elistelement(Prefab_Environ *e, Prefab_Element *new, enum Elementtype kind)
101 {
102 	return elistelement1(e, H, new, kind);
103 }
104 
105 PElement*
appendelist(Prefab_Element * elem,Prefab_Element * new)106 appendelist(Prefab_Element *elem, Prefab_Element *new)
107 {
108 	if(elem->kind!=EVertical && elem->kind!=EHorizontal){
109 		kwerrstr("appendelist to non-list");
110 		return H;
111 	}
112 	return elistelement1(elem->environ, elem, new, elem->kind);
113 }
114