2 * Rich text with images.
3 * Should there be an offset field, to do subscripts & kerning?
13 #define LEAD 4 /* extra space between lines */
14 #define BORD 2 /* extra border for images */
16 Rtext *pl_rtnew(Rtext **t, int space, int indent, Image *b, Panel *p, Font *f, char *s, int flags, void *user){
18 new=pl_emalloc(sizeof(Rtext));
37 Rtext *plrtpanel(Rtext **t, int space, int indent, Panel *p, void *user){
38 return pl_rtnew(t, space, indent, 0, p, 0, 0, 1, user);
40 Rtext *plrtstr(Rtext **t, int space, int indent, Font *f, char *s, int flags, void *user){
41 return pl_rtnew(t, space, indent, 0, 0, f, s, flags, user);
43 Rtext *plrtbitmap(Rtext **t, int space, int indent, Image *b, int flags, void *user){
44 return pl_rtnew(t, space, indent, b, 0, 0, 0, flags, user);
46 void plrtfree(Rtext *t){
54 int pl_tabmin, pl_tabsize;
55 void pltabsize(int min, int size){
59 int pl_space(int space, int pos, int indent){
60 if(space>=0) return space;
65 return ((pos-indent+pl_tabmin)/pl_tabsize+PL_ARG(space))*pl_tabsize+indent-pos;
69 * initialize rectangles & nextlines of text starting at t,
70 * galley width is wid. Returns the total width/height of the text
72 Point pl_rtfmt(Rtext *t, int wid){
74 int ascent, descent, x, space, a, d, w, topy, indent, maxwid;
83 indent=space=pl_space(t->indent, 0, 0);
88 a=tp->b->r.max.y-tp->b->r.min.y+BORD;
90 w=tp->b->r.max.x-tp->b->r.min.x+BORD*2;
93 /* what if plpack fails? */
94 plpack(tp->p, Rect(0,0,wid,wid));
95 plmove(tp->p, subpt(Pt(0,0), tp->p->r.min));
96 a=tp->p->r.max.y-tp->p->r.min.y;
98 w=tp->p->r.max.x-tp->p->r.min.x;
102 d=tp->font->height-a;
103 w=tp->wid=stringwidth(tp->font, tp->text);
105 if(x+w+space>wid) break;
106 if(a>ascent) ascent=a;
107 if(d>descent) descent=d;
114 space=pl_space(tp->space, x, indent);
117 if(eline==t){ /* No progress! Force fit the first block! */
119 if(a>ascent) ascent=a;
120 if(d>descent) descent=d;
127 p.x=indent=pl_space(t->indent, 0, 0);
133 t->r.min.y=p.y-(t->b->r.max.y-t->b->r.min.y)-BORD;
134 p.x+=(t->b->r.max.x-t->b->r.min.x)+BORD*2;
138 t->r.min.y=p.y-t->p->r.max.y;
142 t->r.min.y=p.y-t->font->ascent;
143 t->r.max.y=t->r.min.y+t->font->height;
150 p.x+=pl_space(t->space, p.x, indent);
152 if(p.x>maxwid) maxwid=p.x;
155 return Pt(maxwid, p.y);
159 * If we draw the text in a backup bitmap and copy it onto the screen,
160 * the bitmap pointers in all the subpanels point to the wrong bitmap.
161 * This code fixes them.
163 void pl_stuffbitmap(Panel *p, Image *b){
165 for(p=p->child;p;p=p->next)
166 pl_stuffbitmap(p, b);
169 void pl_rtdraw(Image *b, Rectangle r, Rtext *t, Point offs){
170 static Image *backup;
176 if(backup==0 || backup->chan!=b->chan || rectinrect(r, backup->r)==0){
178 backup=allocimage(display, bb->r, bb->chan, 0, DNofill);
185 offs=subpt(r.min, offs);
186 for(;t;t=t->next) if(!eqrect(t->r, Rect(0,0,0,0))){
187 dr=rectaddpt(t->r, offs);
191 && dr.min.x<r.max.x){
193 draw(b, insetrect(dr, BORD), t->b, 0, t->b->r.min);
194 if(t->flags&PL_HOT) border(b, dr, 1, display->black, ZP);
195 if(t->flags&PL_STR) {
196 line(b, Pt(dr.min.x, dr.min.y), Pt(dr.max.x, dr.max.y),
197 Endsquare, Endsquare, 0,
199 line(b, Pt(dr.min.x, dr.max.y), Pt(dr.max.x, dr.min.y),
200 Endsquare, Endsquare, 0,
207 plmove(t->p, subpt(dr.min, t->p->r.min));
210 pl_stuffbitmap(t->p, bb);
213 string(b, dr.min, display->black, ZP, t->font, t->text);
217 int y = dr.max.y - t->font->height/2;
219 sp = Pt(dr.min.x, y);
220 line(b, sp, Pt(dr.max.x, y),
221 Endsquare, Endsquare, 0,
223 sp = Pt(dr.max.x, y);
227 int y = dr.max.y - 1;
229 lp = Pt(dr.min.x, y);
230 line(b, lp, Pt(dr.max.x, y),
231 Endsquare, Endsquare, 0,
233 lp = Pt(dr.max.x, y);
243 draw(bb, r, b, 0, r.min);
246 * Reposition text already drawn in the window.
247 * We just move the pixels and update the positions of any
250 void pl_reposition(Rtext *t, Image *b, Point p, Rectangle r){
253 offs=subpt(p, r.min);
255 if(!eqrect(t->r, Rect(0,0,0,0)) && !t->b && t->p)
259 * Rectangle r of Image b contains an image of Rtext t, offset by oldoffs.
260 * Redraw the text to have offset yoffs.
262 void pl_rtredraw(Image *b, Rectangle r, Rtext *t, Point offs, Point oldoffs, int dir){
267 size=r.max.y-r.min.y;
268 if(d>=size || -d>=size) /* move more than screenful */
269 pl_rtdraw(b, r, t, offs);
270 else if(d<0){ /* down */
271 pl_reposition(t, b, r.min,
272 Rect(r.min.x, r.min.y-d, r.max.x, r.max.y));
273 pl_rtdraw(b, Rect(r.min.x, r.max.y+d, r.max.x, r.max.y),
274 t, Pt(offs.x, offs.y+size+d));
276 else if(d>0){ /* up */
277 pl_reposition(t, b, Pt(r.min.x, r.min.y+d),
278 Rect(r.min.x, r.min.y, r.max.x, r.max.y-d));
279 pl_rtdraw(b, Rect(r.min.x, r.min.y, r.max.x, r.min.y+d),
282 }else{ /* dir==HORIZ */
284 size=r.max.x-r.min.x;
285 if(d>=size || -d>=size) /* move more than screenful */
286 pl_rtdraw(b, r, t, offs);
287 else if(d<0){ /* right */
288 pl_reposition(t, b, r.min,
289 Rect(r.min.x-d, r.min.y, r.max.x, r.max.y));
290 pl_rtdraw(b, Rect(r.max.x+d, r.min.y, r.max.x, r.max.y),
291 t, Pt(offs.x+size+d, offs.y));
293 else if(d>0){ /* left */
294 pl_reposition(t, b, Pt(r.min.x+d, r.min.y),
295 Rect(r.min.x, r.min.y, r.max.x-d, r.max.y));
296 pl_rtdraw(b, Rect(r.min.x, r.min.y, r.min.x+d, r.max.y),
301 Rtext *pl_rthit(Rtext *t, Point offs, Point p, Point ul){
307 while(t->nextline && t->nextline->topy<=p.y) t=t->nextline;
309 for(;t!=0;t=t->next){
310 if(t->topy>p.y) return 0;
312 if((t->flags&PL_HOT) != 0 && t->b == nil && t->p == nil){
313 if(lp.y == r.max.y && lp.x < r.min.x)
318 if(ptinrect(p, r)) return t;
323 void plrtseltext(Rtext *t, Rtext *s, Rtext *e){
330 for(t=s; t!=0 && t!=e; t=t->next)
333 for(t=s; t!=e; t=t->next)
336 for(t=e; t!=s; t=t->next)
342 char *plrtsnarftext(Rtext *w){
347 for(; w; w = w->next){
348 if((w->flags&PL_SEL)==0 || w->text==0)
350 n = strlen(w->text)+64;
353 t = pl_erealloc(b, n);
359 p += sprint(p, "%s", w->text);
360 else if(w->space > 0)
361 p += sprint(p, " %s", w->text);
362 else if(PL_OP(w->space) == PL_TAB)
363 p += sprint(p, "\t%s", w->text);
364 if(w->nextline == w->next)
365 p += sprint(p, "\n");