/*
* Rich text with images.
* Should there be an offset field, to do subscripts & kerning?
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#include "rtext.h"
#define LEAD 4 /* extra space between lines */
#define BORD 2 /* extra border for images */
Rtext *pl_rtnew(Rtext **t, int space, int indent, int voff, Image *b, Panel *p, Font *f, char *s, int flags, void *user){
Rtext *new;
new=pl_emalloc(sizeof(Rtext));
new->flags=flags;
new->user=user;
new->space=space;
new->indent=indent;
new->voff=voff;
new->b=b;
new->p=p;
new->font=f;
new->text=s;
new->next=0;
new->nextline=0;
new->r=Rect(0,0,0,0);
if(*t)
(*t)->last->next=new;
else
*t=new;
(*t)->last=new;
return new;
}
Rtext *plrtpanel(Rtext **t, int space, int indent, int voff, Panel *p, void *user){
return pl_rtnew(t, space, indent, voff, 0, p, 0, 0, 1, user);
}
Rtext *plrtstr(Rtext **t, int space, int indent, int voff, Font *f, char *s, int flags, void *user){
return pl_rtnew(t, space, indent, voff, 0, 0, f, s, flags, user);
}
Rtext *plrtbitmap(Rtext **t, int space, int indent, int voff, Image *b, int flags, void *user){
return pl_rtnew(t, space, indent, voff, b, 0, 0, 0, flags, user);
}
void plrtfree(Rtext *t){
Rtext *next;
while(t){
next=t->next;
free(t);
t=next;
}
}
int pl_tabmin, pl_tabsize;
void pltabsize(int min, int size){
pl_tabmin=min;
pl_tabsize=size;
}
int pl_space(int space, int pos, int indent){
if(space>=0) return space;
switch(PL_OP(space)){
default:
return 0;
case PL_TAB:
return ((pos-indent+pl_tabmin)/pl_tabsize+PL_ARG(space))*pl_tabsize+indent-pos;
}
}
/*
* initialize rectangles & nextlines of text starting at t,
* galley width is wid. Returns the total width/height of the text
*/
Point pl_rtfmt(Rtext *t, int wid){
Rtext *tp, *eline;
int ascent, descent, x, space, a, d, w, topy, indent, maxwid;
Point p;
/*
* If we draw the text in a backup bitmap and copy it onto the screen,
* the bitmap pointers in all the subpanels point to the wrong bitmap.
* This code fixes them.
*/
void pl_stuffbitmap(Panel *p, Image *b){
p->b=b;
for(p=p->child;p;p=p->next)
pl_stuffbitmap(p, b);
}
void pl_rtdraw(Image *b, Rectangle r, Rtext *t, Point offs){
static Image *backup;
Point lp, sp;
Rectangle dr;
Image *bb;
bb = b;
if(backup==0 || backup->chan!=b->chan || rectinrect(r, backup->r)==0){
freeimage(backup);
backup=allocimage(display, bb->r, bb->chan, 0, DNofill);
}
if(backup)
b=backup;
pl_clr(b, r);
lp=ZP;
sp=ZP;
offs=subpt(r.min, offs);
for(;t;t=t->next) if(!eqrect(t->r, Rect(0,0,0,0))){
dr=rectaddpt(t->r, offs);
if(dr.max.y>r.min.y
&& dr.min.y<r.max.y
&& dr.max.x>r.min.x
&& dr.min.x<r.max.x){
if(t->b){
draw(b, insetrect(dr, BORD), t->b, 0, t->b->r.min);
if(t->flags&PL_STR) {
line(b, Pt(dr.min.x, dr.min.y), Pt(dr.max.x, dr.max.y),
Endsquare, Endsquare, 0,
display->black, ZP);
line(b, Pt(dr.min.x, dr.max.y), Pt(dr.max.x, dr.min.y),
Endsquare, Endsquare, 0,
display->black, ZP);
}
if(t->flags&PL_SEL)
pl_highlight(b, dr);
}
else if(t->p){
plmove(t->p, subpt(dr.min, t->p->r.min));
pldraw(t->p, b);
if(b!=bb)
pl_stuffbitmap(t->p, bb);
}
else{
if(t->flags&PL_HOT)
string(b, dr.min, pl_blue, ZP, t->font, t->text);
else
string(b, dr.min, display->black, ZP, t->font, t->text);
if(t->flags&PL_SEL)
pl_highlight(b, dr);
if(t->flags&PL_STR){
int y = dr.max.y - t->font->height/2;
if(sp.y != y)
sp = Pt(dr.min.x, y);
line(b, sp, Pt(dr.max.x, y),
Endsquare, Endsquare, 0,
display->black, ZP);
sp = Pt(dr.max.x, y);
} else
sp = ZP;
lp = ZP;
continue;
}
lp = ZP;
sp = ZP;
}
}
if(b!=bb)
draw(bb, r, b, 0, r.min);
}
/*
* Reposition text already drawn in the window.
* We just move the pixels and update the positions of any
* enclosed panels
*/
void pl_reposition(Rtext *t, Image *b, Point p, Rectangle r){
Point offs;
pl_cpy(b, p, r);
offs=subpt(p, r.min);
for(;t;t=t->next)
if(!eqrect(t->r, Rect(0,0,0,0)) && !t->b && t->p)
plmove(t->p, offs);
}
/*
* Rectangle r of Image b contains an image of Rtext t, offset by oldoffs.
* Redraw the text to have offset yoffs.
*/
void pl_rtredraw(Image *b, Rectangle r, Rtext *t, Point offs, Point oldoffs, int dir){
int d, size;