xref: /inferno-os/libprefab/compound.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 
9 extern void queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr);
10 
11 Draw_Rect
edgerect(Prefab_Environ * e,Draw_Point p,Draw_Rect * rin)12 edgerect(Prefab_Environ *e, Draw_Point p, Draw_Rect *rin)
13 {
14 	Draw_Rect r;
15 	Screen *s;
16 
17 	r.min.x = p.x;
18 	r.min.y = p.y;
19 	r.max.x = p.x + 1 + Dx(*rin) + 1;
20 	r.max.y = p.y + 1 + Dy(*rin) + 1;
21 	/* outer box computed; now make sure it's all visible */
22 	s = lookupscreen(e->screen);
23 	if(s != nil)
24 		fitrect((Rectangle*)&r, s->display->image->r);
25 
26 	rin->min.x = r.min.x+1;
27 	rin->min.y = r.min.y+1;
28 	rin->max.x = r.max.x-1;
29 	rin->max.y = r.max.y-1;
30 
31 	return r;
32 }
33 
34 /*
35  * Draw edge around r.
36  * Assume geometry has already been clipped and adjusted.
37  */
38 void
edge(Prefab_Environ * e,Image * box,Draw_Rect dr,Draw_Rect dclipr)39 edge(Prefab_Environ *e, Image *box, Draw_Rect dr, Draw_Rect dclipr)
40 {
41 	Rectangle r, r1, clipr;
42 	Image *ec;
43 	Screen *s;
44 
45 	R2R(r, dr);
46 	R2R(clipr, dclipr);
47 	r.min.x -= 1;
48 	r.min.y -= 1;
49 	r.max.x += 1;
50 	r.max.y += 1;
51 	s = lookupscreen(e->screen);
52 	if(s == nil)
53 		return;
54 	ec = lookupimage(e->style->edgecolor);
55 	if(ec == nil)
56 		return;
57 
58 	r1 = r;
59 	r1.min.y++;
60 	r1.max.y = r1.min.y+2;
61 	r1.max.x = r1.min.x+2*(r1.max.x-r1.min.x)/3;
62 	if(rectclip(&r1, clipr))
63 		draw(box, r1, ec, nil, r1.min);
64 	r1 = r;
65 	r1.min.x++;
66 	r1.max.x = r1.min.x+2;
67 	r1.max.y = r1.min.y+2*(r1.max.y-r1.min.y)/3;
68 	if(rectclip(&r1, clipr))
69 		draw(box, r1, ec, nil, r1.min);
70 	r1=r;
71 	r1.min.x = r1.max.x-1;
72 	if(rectclip(&r1, clipr))
73 		draw(box, r1, ec, nil, r1.min);
74 	r1=r;
75 	r1.min.y = r1.max.y-1;
76 	if(rectclip(&r1, clipr))
77 		draw(box, r1, ec, nil, r1.min);
78 	r1 = r;
79 	r1.max.y = r1.min.y+1;
80 	if(rectclip(&r1, clipr))
81 		draw(box, r1, ec, nil, r1.min);
82 	r1=r;
83 	r1.max.x = r1.min.x+1;
84 	if(rectclip(&r1, clipr))
85 		draw(box, r1, ec, nil, r1.min);
86 }
87 
88 void
redrawcompound(Image * i,Rectangle clipr,Prefab_Compound * c)89 redrawcompound(Image *i, Rectangle clipr, Prefab_Compound *c)
90 {
91 	Rectangle r1, rt, r;
92 	int l, len;
93 	Prefab_Style *s;
94 	Image *elemcolor, *edgecolor;
95 	List *list;
96 	Font *font;
97 	Prefab_Element *e;
98 
99 	if(c==H || badenviron(c->environ, 0))
100 		return;
101 
102 	r = clipr;
103 	s = c->environ->style;
104 	elemcolor = lookupimage(s->elemcolor);
105 	edgecolor = lookupimage(s->edgecolor);
106 	if(elemcolor==nil || edgecolor==nil)
107 		return;
108 	draw(i, r, elemcolor, nil, r.min);
109 	if(lookupelement(c->title) != H){
110 		R2R(rt, c->title->r);
111 		if(c->title->environ!=H && c->title->environ->style!=H && rectXrect(r, rt)){
112 			drawelement(c->title, i, r, c->environ==c->title->environ, 0);
113 			r1.min.x = c->r.min.x;
114 			r1.min.y = c->title->r.max.y;
115 			s = c->title->environ->style;
116 			len = 0;
117 			switch(c->title->kind){
118 			case ETitle:
119 				font = lookupfont(s->titlefont);
120 				if(font != nil)
121 					len = 2+1+stringwidth(font, string2c(c->title->str));
122 				break;
123 			case EVertical:
124 				font = lookupfont(s->titlefont);
125 				if(font != nil)
126 					for(list=c->title->kids; list!=H; list=list->tail){
127 						e = *(Prefab_Element**)list->data;
128 						l = stringwidth(font, string2c(e->str));
129 						if(l > len)
130 							len = l;
131 					}
132 				len += 2+1;
133 				break;
134 			default:
135 				len = r1.min.x+2*Dx(c->r)/3;
136 			}
137 			r1.max.x = r1.min.x + len;
138 			r1.max.y = r1.min.y+1;
139 			draw(i, r1, edgecolor, nil, r.min);
140 			r.min.y = r1.max.y;
141 		}
142 	}
143 	if(c->contents!=H)
144 		drawelement(c->contents, i, r, c->environ==c->contents->environ, 0);
145 	edge(c->environ, i, c->r, DRECT(clipr));
146 }
147 
148 void
refreshcompound(Image * i,Rectangle r,void * ptr)149 refreshcompound(Image *i, Rectangle r, void *ptr)
150 {
151 	Prefab_Compound *c;
152 
153 	c = ptr;
154 	if(c == nil)
155 		return;
156 	if(i == nil){	/* called from flushimage */
157 		i = lookupimage(c->image);
158 		if(i  == nil)
159 			return;
160 	}
161 	redrawcompound(i, r, c);
162 }
163 
164 void
localrefreshcompound(Memimage * mi,Rectangle r,void * ptr)165 localrefreshcompound(Memimage *mi, Rectangle r, void *ptr)
166 {
167 	Prefab_Compound *c;
168 	Image *i;
169 
170 	USED(mi);	/* can't do anything with this, but it's part of the memlayer interface */
171 	c = ptr;
172 	if(c == nil)
173 		return;
174 	i = lookupimage(c->image);
175 	if(i == nil)
176 		return;
177 	queuerefresh(i, r, refreshcompound, ptr);
178 }
179 
180 void
drawcompound(Prefab_Compound * c)181 drawcompound(Prefab_Compound *c)
182 {
183 	Image *i;
184 
185 	if(c==H || c->image==H)
186 		return;
187 	i = lookupimage(c->image);
188 	redrawcompound(i, insetrect(IRECT(c->r), -1), c);
189 	if(i->display->local && i->refptr==nil)
190 		if(drawlsetrefresh(i->display->dataqid, i->id, localrefreshcompound, c) <= 0)
191 			fprint(2, "drawcompound: can't set refresh\n");
192 	i->refptr = c;	/* can now be refreshed */
193 }
194