Compare commits

...

2 commits

Author SHA1 Message Date
xfnw 4d744454c7 Merge commit '856abd2f7d2a8b4cef547762a0c125a54ca4c366' as 'sys/src/cmd/gopher' 2022-07-01 15:46:23 -04:00
xfnw 856abd2f7d Squashed 'sys/src/cmd/gopher/' content from commit 3680728b6
git-subtree-dir: sys/src/cmd/gopher
git-subtree-split: 3680728b631ed65201b397f4ae3e5d1b03be42f9
2022-07-01 15:46:23 -04:00
37 changed files with 5257 additions and 0 deletions

View file

@ -0,0 +1,25 @@
gopher
=======
A mostly functional gopher browser for plan9.
![gopher](gopher.png)
Most gopher item types are handled:
- Text and submenu items are displayed within the browser
- Images and documents are opened through page(1)
- HTML items are sent to the plumber(4)
- Binary items (bin, dos, uuencoded files and sound) are downloaded to disk
- Other types are not handled (e.g. telnet)
Following keyboard shortcuts are available:
- b: previous page in history
- n: next page in history
- q: quit
This has not been thoroughly tested so many bugs are just waiting to be found.
Usage:
------
Install with ``mk install``
Run with ``gopher [address]``

46
sys/src/cmd/gopher/dat.h Normal file
View file

@ -0,0 +1,46 @@
typedef struct Gmenu Gmenu;
typedef struct Link Link;
typedef struct Hist Hist;
struct Gmenu
{
Link *link;
Rtext *text;
};
struct Link
{
char *addr;
char *sel;
int type;
};
struct Hist
{
Hist *p;
Hist *n;
Gmenu *m;
};
enum
{
Ttext,
Tmenu,
Tns,
Terror,
Tbinhex,
Tdos,
Tuuencoded,
Tsearch,
Ttelnet,
Tbinary,
Tmirror,
Tgif,
Timage,
Tt3270,
Tdoc,
Thtml,
Tinfo,
Tsound,
Teof
};

941
sys/src/cmd/gopher/gopher.c Normal file
View file

@ -0,0 +1,941 @@
#include <u.h>
#include <libc.h>
#include <String.h>
#include <regexp.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>
#include <panel.h>
#include <bio.h>
#include <plumb.h>
#include "dat.h"
#include "icons.h"
void texthit(Panel *p, int b, Rtext *t);
void message(char *s, ...);
Image *backi;
Image *fwdi;
Image *reloadi;
Panel *root;
Panel *backp;
Panel *fwdp;
Panel *reloadp;
Panel *entryp;
Panel *urlp;
Panel *textp;
Panel *statusp;
Panel *popup;
char *url;
Mouse *mouse;
Hist *hist = nil;
char *bdir;
enum
{
Msearch,
Maddbookmark,
Mbookmarks,
Mexit,
};
char *menu3[] = {
"search",
"add bookmark",
"bookmarks",
"exit",
0
};
Link*
mklink(char *addr, char *sel, int type)
{
Link *l;
l = malloc(sizeof *l);
if(l==nil)
sysfatal("malloc: %r");
l->addr = strdup(addr);
l->sel = sel!=nil ? strdup(sel) : nil;
l->type = type;
return l;
}
Link*
clonelink(Link *l)
{
if(l==nil)
return nil;
return mklink(l->addr, l->sel, l->type);
}
int
seltype(char c)
{
int t;
t = -c;
switch(c){
case '0': t = Ttext; break;
case '1': t = Tmenu; break;
case '2': t = Tns; break;
case '3': t = Terror; break;
case '4': t = Tbinhex; break;
case '5': t = Tdos; break;
case '6': t = Tuuencoded; break;
case '7': t = Tsearch; break;
case '8': t = Ttelnet; break;
case '9': t = Tbinary; break;
case '+': t = Tmirror; break;
case 'g': t = Tgif; break;
case 'I': t = Timage; break;
case 'T': t = Tt3270; break;
case 'd': t = Tdoc; break;
case 'h': t = Thtml; break;
case 'i': t = Tinfo; break;
case 's': t = Tsound; break;
case '.': t = Teof; break;
default: break;
}
return t;
}
static char Typechar[] = {
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '+', 'g',
'I', 'T', 'd', 'h', 'i', 's',
'.',
};
static char *Typestr[] = {
"FILE", "DIR", "NS", "ERR", "HEX",
"DOS", "UU", "?", "TELNET", "BIN",
"MIRROR", "GIF", "IMG", "T3270", "DOC",
"HTML", "", "SND", "EOF",
};
char*
seltypestr(int type)
{
if(type<0)
return smprint("UNKN:%c", (char) -type);
return smprint("%6s", Typestr[type]);
};
Gmenu*
rendermenu(Link *l, Biobuf *bp)
{
char *s, *f[5], *t;
Gmenu *m;
Link *n;
int type;
m = malloc(sizeof *m);
if(m==nil)
sysfatal("malloc: %r");
m->link = clonelink(l);
m->text = nil;
plrtstr(&m->text, 1000000, 0, 0, font, strdup(" "), 0, 0);
for(;;){
n = nil;
s = Brdstr(bp, '\n', 0);
if(s==nil || s[0]=='.')
break;
type = seltype(s[0]);
getfields(s+1, f, 5, 0, "\t\r\n");
switch(type){
case Tinfo:
break;
case Thtml:
n = mklink(strdup(f[1]+4), nil, Thtml); /* +4 skip URL: */
break;
default:
n = mklink(netmkaddr(f[2], "tcp", f[3]), strdup(f[1]), type);
break;
}
t = strdup(f[0]);
plrtstr(&m->text, 1000000, 8, 0, font, seltypestr(type), PL_HEAD, 0);
if(type == Tinfo || type < 0)
plrtstr(&m->text, 8, 0, 0, font, t, 0, 0);
else
plrtstr(&m->text, 8, 0, 0, font, t, PL_HOT, n);
}
return m;
}
Gmenu*
rendertext(Link *l, Biobuf *bp)
{
Gmenu *m;
String *buf;
int c, n;
m = malloc(sizeof *m);
if(m==nil)
sysfatal("malloc: %r");
m->link = clonelink(l);
m->text = nil;
plrtstr(&m->text, 1000000, 0, 0, font, strdup(" "), 0, 0);
n = 0;
buf = s_new();
for(;;){
c = Bgetc(bp);
if(c<0)
break;
else if(c=='\r' || c=='\n'){
if(c=='\r' && Bgetc(bp)!='\n')
Bungetc(bp);
if(n==1 && s_to_c(buf)[0]=='.')
break;
s_terminate(buf);
plrtstr(&m->text, 1000000, 8, 0, font, strdup(s_to_c(buf)), 0, 0);
s_reset(buf);
n = 0;
}else if(c=='\t'){
n += 4;
s_append(buf, " ");
}else{
n++;
s_putc(buf, c);
}
}
s_free(buf);
return m;
}
Gmenu*
render(Link *l)
{
int fd;
Biobuf *bp;
Gmenu *m;
fd = dial(l->addr, 0, 0, 0);
if(fd < 0){
message("unable to connect to %s: %r", l->addr);
return nil;
}
fprint(fd, "%s\r\n", l->sel);
bp = Bfdopen(fd, OREAD);
if(bp==nil){
close(fd);
sysfatal("bfdopen: %r");
}
switch(l->type){
case Tmenu:
m = rendermenu(l, bp);
break;
case Ttext:
m = rendertext(l, bp);
break;
default:
/* TODO error */
m = nil;
break;
}
Bterm(bp);
close(fd);
return m;
}
void
message(char *s, ...)
{
static char buf[1024];
char *out;
va_list args;
va_start(args, s);
out = buf + vsnprint(buf, sizeof(buf), s, args);
va_end(args);
*out='\0';
plinitlabel(statusp, PACKN|FILLX, buf);
pldraw(statusp, screen);
flushimage(display, 1);
}
Link*
urltolink(char *url)
{
char *a, *sel, *hostport, *p;
int type;
Link *l;
a = strdup(url);
hostport = a;
if(strncmp(a, "gopher://", 9) == 0)
hostport += 9;
p = strchr(hostport, '/');
if(p){
*p++ = 0;
type = *p ? seltype(*p++) : Tmenu;
if(type < 0)
return nil;
sel = *p ? p : "";
}else{
type = Tmenu;
sel = "";
}
p = strchr(hostport, ':');
if(p){
*p++ = 0;
l = mklink(netmkaddr(hostport, "tcp", p), sel, type);
}else{
l = mklink(netmkaddr(hostport, "tcp", "70"), sel, type);
}
free(a);
return l;
}
char*
linktourl(Link *l)
{
char *f[3], *a, *s;
int n;
a = strdup(l->addr);
n = getfields(a, f, 3, 0, "!");
if(n != 3)
s = smprint("Url: gopher://%s/%d%s", l->addr, l->type, l->sel);
else if(atoi(f[2])!=70)
s = smprint("Url: gopher://%s:%s/%d%s", f[1], f[2], l->type, l->sel);
else
s = smprint("Url: gopher://%s/%d%s", f[1], l->type, l->sel);
free(a);
return s;
}
void
seturl(Link *l)
{
free(url);
url = linktourl(l);
}
void
show(Gmenu *m)
{
plinittextview(textp, PACKE|EXPAND, ZP, m->text, texthit);
pldraw(textp, screen);
plinitlabel(urlp, PACKN|FILLX, url);
pldraw(urlp, screen);
message("gopher!");
}
void
freetext(Rtext *t){
Rtext *tt;
Link *l;
tt = t;
for(; t!=0; t = t->next){
t->b=0;
free(t->text);
t->text = 0;
if(l = t->user){
t->user = 0;
free(l->addr);
if(l->sel!=nil && l->sel[0]!=0)
free(l->sel);
free(l);
}
}
plrtfree(tt);
}
void
freehist(Hist *h)
{
Hist *n;
Gmenu *m;
for(n = h->n; h; h = n){
m = h->m;
freetext(m->text);
if(m->link!=nil){
free(m->link->addr);
free(m->link->sel);
free(m->link);
}
free(h);
}
}
void
visit(Link *l, int sethist)
{
Gmenu *m;
Hist *h;
seturl(l);
message("loading %s...", url);
m = render(l);
if(m==nil)
return;
show(m);
if(!sethist)
return;
h = malloc(sizeof *h);
if(h == nil)
sysfatal("malloc: %r");
/* FIXME
if(hist != nil && hist->n != nil)
freehist(hist->n);
*/
h->p = hist;
h->n = nil;
h->m = m;
hist = h;
}
void
plumburl(char *u)
{
int fd;
fd = plumbopen("send", OWRITE|OCEXEC);
if(fd<0)
return;
plumbsendtext(fd, "gopher", nil, nil, u);
close(fd);
}
void
dupfds(int fd, ...)
{
int mfd, n, i;
va_list arg;
Dir *dir;
va_start(arg, fd);
for(mfd = 0; fd >= 0; fd = va_arg(arg, int), mfd++)
if(fd != mfd)
if(dup(fd, mfd) < 0)
sysfatal("dup: %r");
va_end(arg);
if((fd = open("/fd", OREAD)) < 0)
sysfatal("open: %r");
n = dirreadall(fd, &dir);
for(i=0; i<n; i++){
if(strstr(dir[i].name, "ctl"))
continue;
fd = atoi(dir[i].name);
if(fd >= mfd)
close(fd);
}
free(dir);
}
void
page(Link *l)
{
int fd;
fd = dial(l->addr, 0, 0, 0);
if(fd < 0)
sysfatal("dial: %r");
fprint(fd, "%s\r\n", l->sel);
switch(rfork(RFFDG|RFPROC|RFMEM|RFREND|RFNOWAIT|RFNOTEG)){
case -1:
fprint(2, "Can't fork!");
break;
case 0:
dupfds(fd, 1, 2, -1);
execl("/bin/rc", "rc", "-c", "page -w", nil);
_exits(0);
}
close(fd);
}
void
save(Link *l, char *name){
char buf[1024];
int ifd, ofd;
ifd = dial(l->addr, 0, 0, 0);
if(ifd < 0){
message("save: %s: %r", name);
return;
}
fprint(ifd, "%s\r\n", l->sel);
ofd=create(name, OWRITE, 0666);
if(ofd < 0){
message("save: %s: %r", name);
return;
}
switch(rfork(RFNOTEG|RFNAMEG|RFFDG|RFMEM|RFPROC|RFNOWAIT)){
case -1:
message("Can't fork: %r");
break;
case 0:
dup(ifd, 0);
close(ifd);
dup(ofd, 1);
close(ofd);
snprint(buf, sizeof(buf),
"{tput -p || cat} |[2] {aux/statusmsg -k %q >/dev/null || cat >/dev/null}", name);
execl("/bin/rc", "rc", "-c", buf, nil);
exits("exec");
}
close(ifd);
close(ofd);
}
void
search(void)
{
static char last[256];
char buf[256];
Reprog *re;
Rtext *tp;
int yoff;
for(;;){
if(hist == nil || hist->m == nil || hist->m->text == nil)
return;
strncpy(buf, last, sizeof(buf)-1);
if(eenter("Search for", buf, sizeof(buf), mouse) <= 0)
return;
strncpy(last, buf, sizeof(buf)-1);
re = regcompnl(buf);
if(re == nil){
message("%r");
continue;
}
for(tp=hist->m->text;tp;tp=tp->next)
if(tp->flags & PL_SEL)
break;
if(tp == nil)
tp = hist->m->text;
else {
tp->flags &= ~PL_SEL;
tp = tp->next;
}
while(tp != nil){
tp->flags &= ~PL_SEL;
if(tp->text && *tp->text)
if(regexec(re, tp->text, nil, 0)){
tp->flags |= PL_SEL;
plsetpostextview(textp, tp->topy);
break;
}
tp = tp->next;
}
free(re);
yoff = plgetpostextview(textp);
plinittextview(textp, PACKE|EXPAND, ZP, hist->m->text, texthit);
plsetpostextview(textp, yoff);
pldraw(textp, screen);
}
}
void
addbookmark(void)
{
Link *l;
char buf[255] = {0}, *f, *u[3];
int n, fd;
if(hist==nil)
return;
l = hist->m->link;
n = eenter("Name:", buf, sizeof buf, mouse);
if(n<=0)
return;
f = smprint("%s/bookmarks", bdir);
fd = open(f, OWRITE);
if(fd<0){
fd = create(f, OWRITE, 0644);
if(fd<0){
message("cannot open %s", f);
free(f);
return;
}
fprint(fd, "iGOPHER Bookmarks\n");
fprint(fd, "i=================\n");
fprint(fd, "i \n");
}
free(f);
f = strdup(l->addr);
getfields(f, u, 3, 0, "!");
seek(fd, 0, 2);
fprint(fd, "%c%s\t%s\t%s\t%s\n", Typechar[l->type], buf, l->sel, u[1], u[2]);
fprint(fd, "i%s\n", linktourl(l));
free(f);
close(fd);
message("added bookmark %s", buf);
}
void
showbookmarks(void)
{
char *f;
Biobuf *bp;
Gmenu *m;
f = smprint("%s/bookmarks", bdir);
bp = Bopen(f, OREAD);
if(bp==nil){
message("cannot open %s", f);
free(f);
return;
}
m = rendermenu(nil, bp);
show(m);
free(f);
Bterm(bp);
}
char*
linktofile(Link *l){
char *n, *s;
if(l==nil)
return nil;
n = l->sel;
if(n==nil || n[0]==0)
n = "/";
if(s = strrchr(n, '/'))
n = s+1;
if(n[0]==0)
n = "file";
return n;
}
void
texthit(Panel *p, int b, Rtext *t)
{
Link *l;
char *s, buf[1024] = {0};
USED(p);
if(b!=1)
return;
if(t->user==nil)
return;
l = t->user;
switch(l->type){
case Tmenu:
case Ttext:
visit(l, 1);
break;
case Thtml:
plumburl(l->addr);
break;
case Tdoc:
case Tgif:
case Timage:
page(l);
break;
case Tsearch:
if(eenter("Search:", buf, sizeof buf, mouse)>0){
s = smprint("%s\t%s", l->sel, buf);
visit(mklink(l->addr, s, Tmenu), 1);
free(s);
}
break;
case Tdos:
case Tbinary:
case Tbinhex:
case Tuuencoded:
snprint(buf, sizeof buf, "%s", linktofile(l));
if(eenter("Save as:", buf, sizeof buf, mouse)>0){
save(l, buf);
}
break;
default:
message("unhandled item type '%s'", Typestr[l->type]);
break;
}
}
void
backhit(Panel *p, int b)
{
USED(p);
if(b!=1)
return;
if(hist==nil || hist->p==nil)
return;
hist->p->n = hist;
hist = hist->p;
seturl(hist->m->link);
show(hist->m);
}
void
nexthit(Panel *p, int b)
{
USED(p);
if(b!=1)
return;
if(hist==nil || hist->n==nil)
return;
hist = hist->n;
seturl(hist->m->link);
show(hist->m);
}
void
reloadhit(Panel *p, int b)
{
USED(p);
if(b!=1)
return;
visit(hist->m->link, 0);
}
void
menuhit(int button, int item)
{
USED(button);
switch(item){
case Msearch:
search();
break;
case Maddbookmark:
addbookmark();
break;
case Mbookmarks:
showbookmarks();
break;
case Mexit:
exits(nil);
break;
}
}
void
entryhit(Panel *p, char *t)
{
Link *l;
USED(p);
switch(strlen(t)){
case 0:
return;
case 1:
switch(*t){
case 'b':
backhit(backp, 1);
break;
case 'n':
nexthit(fwdp, 1);
break;
case 'q':
exits(nil);
break;
default:
message("unknown command %s", t);
break;
}
break;
default:
l = urltolink(t);
if(l==nil)
message("invalid url %s", t);
else
visit(l, 1);
}
plinitentry(entryp, PACKN|FILLX, 0, "", entryhit);
pldraw(root, screen);
}
void
mkpanels(void)
{
Panel *p, *ybar, *xbar, *m;
m = plmenu(0, 0, menu3, PACKN|FILLX, menuhit);
root = plpopup(0, EXPAND, 0, 0, m);
p = plgroup(root, PACKN|FILLX);
statusp = pllabel(p, PACKN|FILLX, "gopher!");
plplacelabel(statusp, PLACEW);
plbutton(p, PACKW|BITMAP|NOBORDER, backi, backhit);
plbutton(p, PACKW|BITMAP|NOBORDER, fwdi, nexthit);
plbutton(p, PACKW|BITMAP|NOBORDER, reloadi, reloadhit);
pllabel(p, PACKW, "Go:");
entryp = plentry(p, PACKN|FILLX, 0, "", entryhit);
p = plgroup(root, PACKN|FILLX);
urlp = pllabel(p, PACKN|FILLX, "");
plplacelabel(urlp, PLACEW);
p = plgroup(root, PACKN|EXPAND);
ybar = plscrollbar(p, PACKW|USERFL);
xbar = plscrollbar(p, IGNORE);
textp = pltextview(p, PACKE|EXPAND, ZP, nil, nil);
plscroll(textp, xbar, ybar);
plgrabkb(entryp);
}
void
eresized(int new)
{
if(new && getwindow(display, Refnone)<0)
sysfatal("cannot reattach: %r");
plpack(root, screen->r);
pldraw(root, screen);
}
Image*
loadicon(Rectangle r, uchar *data, int ndata)
{
Image *i;
int n;
i = allocimage(display, r, RGBA32, 0, DNofill);
if(i==nil)
sysfatal("allocimage: %r");
n = loadimage(i, r, data, ndata);
if(n<0)
sysfatal("loadimage: %r");
return i;
}
void
loadicons(void)
{
Rectangle r = Rect(0,0,16,16);
backi = loadicon(r, ibackdata, sizeof ibackdata);
fwdi = loadicon(r, ifwddata, sizeof ifwddata);
reloadi = loadicon(r, ireloaddata, sizeof ireloaddata);
}
void scrolltext(int dy, int whence)
{
Scroll s;
s = plgetscroll(textp);
switch(whence){
case 0:
s.pos.y = dy;
break;
case 1:
s.pos.y += dy;
break;
case 2:
s.pos.y = s.size.y+dy;
break;
}
if(s.pos.y > s.size.y)
s.pos.y = s.size.y;
if(s.pos.y < 0)
s.pos.y = 0;
plsetscroll(textp, s);
/* BUG: there is a redraw issue when scrolling
This fixes the issue albeit not properly */
pldraw(textp, screen);
}
void
ensurebdir(void)
{
char *home, *tmp;
int fd;
home = getenv("home");
if(home){
tmp = smprint("%s/lib", home);
fd = create(tmp, OREAD, DMDIR|0777);
if(fd>0)
close(fd);
free(tmp);
bdir = smprint("%s/lib/gopher", home);
fd = create(bdir, OREAD, DMDIR|0777);
if(fd>0)
close(fd);
}else
bdir = strdup("/tmp");
}
void
main(int argc, char *argv[])
{
enum { Eplumb = 128 };
Event e;
Link *l;
char *url;
Plumbmsg *pm;
if(argc == 2)
url = argv[1];
else
url = "gopher.floodgap.com";
quotefmtinstall();
ensurebdir();
if(initdraw(nil, nil, "gopher")<0)
sysfatal("initdraw: %r");
einit(Emouse|Ekeyboard);
plinit(screen->depth);
loadicons();
mkpanels();
l = urltolink(url);
if(l==nil)
message("invalid url %s", url);
else
visit(l, 1);
eresized(0);
eplumb(Eplumb, "gopher");
for(;;){
switch(event(&e)){
case Eplumb:
pm = e.v;
if(pm->ndata > 0){
l = urltolink(pm->data);
if(l!=nil)
visit(l, 1);
}
plumbfree(pm);
break;
case Ekeyboard:
switch(e.kbdc){
default:
plgrabkb(entryp);
plkeyboard(e.kbdc);
break;
case Khome:
scrolltext(0, 0);
break;
case Kup:
scrolltext(-textp->size.y/4, 1);
break;
case Kpgup:
scrolltext(-textp->size.y/2, 1);
break;
case Kdown:
scrolltext(textp->size.y/4, 1);
break;
case Kpgdown:
scrolltext(textp->size.y/2, 1);
break;
case Kend:
scrolltext(-textp->size.y, 2);
break;
case Kdel:
exits(nil);
break;
}
break;
case Emouse:
mouse = &e.mouse;
if(mouse->buttons & (8|16) && ptinrect(mouse->xy, textp->r)){
if(mouse->buttons & 8)
scrolltext(textp->r.min.y - mouse->xy.y, 1);
else
scrolltext(mouse->xy.y - textp->r.min.y, 1);
break;
}
plmouse(root, mouse);
/* BUG: there is a redraw issue when scrolling
This fixes the issue albeit not properly */
//pldraw(textp, screen);
break;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

200
sys/src/cmd/gopher/icons.h Normal file
View file

@ -0,0 +1,200 @@
uchar ibackdata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00,
0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
0xf5, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00,
0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x54, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x58, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00,
0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
uchar ifwddata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00,
0xfb, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf1, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00,
0xfb, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00,
0xfb, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
uchar ireloaddata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x85, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00,
0xd9, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb3, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbb, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00,
0xdb, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xed, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0xaf, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

View file

@ -0,0 +1,189 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Button Button;
struct Button{
int btype; /* button type */
Icon *icon; /* what to write on the button */
int check; /* for check/radio buttons */
void (*hit)(Panel *, int, int); /* call back user code on check/radio hit */
void (*menuhit)(int, int); /* call back user code on menu item hit */
void (*pl_buttonhit)(Panel *, int); /* call back user code on button hit */
int index; /* arg to menuhit */
int buttons;
};
/*
* Button types
*/
#define BUTTON 1
#define CHECK 2
#define RADIO 3
void pl_drawbutton(Panel *p){
Rectangle r;
Button *bp;
bp=p->data;
r=pl_boxf(p->b, p->r, p->flags, p->state);
switch(bp->btype){
case CHECK:
r=pl_check(p->b, r, bp->check);
break;
case RADIO:
r=pl_radio(p->b, r, bp->check);
break;
}
pl_drawicon(p->b, r, PLACECEN, p->flags, bp->icon);
}
int pl_hitbutton(Panel *p, Mouse *m){
int oldstate, hitme;
Panel *sib;
Button *bp;
bp=p->data;
oldstate=p->state;
if(m->buttons&OUT){
hitme=0;
p->state=UP;
}
else if(m->buttons&7){
hitme=0;
p->state=DOWN;
bp->buttons=m->buttons;
}
else{ /* mouse inside, but no buttons down */
hitme=p->state==DOWN;
p->state=UP;
}
if(hitme) switch(bp->btype){
case CHECK:
if(hitme) bp->check=!bp->check;
break;
case RADIO:
if(bp->check) bp->check=0;
else{
if(p->parent){
for(sib=p->parent->child;sib;sib=sib->next){
if(sib->hit==pl_hitbutton
&& ((Button *)sib->data)->btype==RADIO
&& ((Button *)sib->data)->check){
((Button *)sib->data)->check=0;
pldraw(sib, p->b);
}
}
}
bp->check=1;
}
break;
}
if(hitme || oldstate!=p->state) pldraw(p, p->b);
if(hitme && bp->hit){
bp->hit(p, bp->buttons, bp->check);
p->state=UP;
}
return 0;
}
void pl_typebutton(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizebutton(Panel *p, Point children){
Point s;
int ckw;
Button *bp;
USED(children); /* shouldn't have any children */
bp=p->data;
s=pl_iconsize(p->flags, bp->icon);
if(bp->btype!=BUTTON){
ckw=pl_ckwid();
if(s.y<ckw){
s.x+=ckw;
s.y=ckw;
}
else s.x+=s.y;
}
return pl_boxsize(s, p->state);
}
void pl_childspacebutton(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void pl_initbtype(Panel *v, int flags, Icon *icon, void (*hit)(Panel *, int, int), int btype){
Button *bp;
bp=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawbutton;
v->hit=pl_hitbutton;
v->type=pl_typebutton;
v->getsize=pl_getsizebutton;
v->childspace=pl_childspacebutton;
bp->btype=btype;
bp->check=0;
bp->hit=hit;
bp->icon=icon;
switch(btype){
case BUTTON: v->kind="button"; break;
case CHECK: v->kind="checkbutton"; break;
case RADIO: v->kind="radiobutton"; break;
}
}
void pl_buttonhit(Panel *p, int buttons, int check){
USED(check);
if(((Button *)p->data)->pl_buttonhit) ((Button *)p->data)->pl_buttonhit(p, buttons);
}
void plinitbutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int)){
((Button *)p->data)->pl_buttonhit=hit;
pl_initbtype(p, flags, icon, pl_buttonhit, BUTTON);
}
void plinitcheckbutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
pl_initbtype(p, flags, icon, hit, CHECK);
}
void plinitradiobutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
pl_initbtype(p, flags, icon, hit, RADIO);
}
Panel *plbutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitbutton(p, flags, icon, hit);
return p;
}
Panel *plcheckbutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitcheckbutton(p, flags, icon, hit);
return p;
}
Panel *plradiobutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitradiobutton(p, flags, icon, hit);
return p;
}
void pl_hitmenu(Panel *p, int buttons){
void (*hit)(int, int);
hit=((Button *)p->data)->menuhit;
if(hit) hit(buttons, ((Button *)p->data)->index);
}
void plinitmenu(Panel *v, int flags, Icon **item, int cflags, void (*hit)(int, int)){
Panel *b;
int i;
v->flags=flags;
v->kind="menu";
if(v->child){
plfree(v->child);
v->child=0;
}
for(i=0;item[i];i++){
b=plbutton(v, cflags, item[i], pl_hitmenu);
((Button *)b->data)->menuhit=hit;
((Button *)b->data)->index=i;
}
}
Panel *plmenu(Panel *parent, int flags, Icon **item, int cflags, void (*hit)(int, int)){
Panel *v;
v=plgroup(parent, flags);
plinitmenu(v, flags, item, cflags, hit);
return v;
}
void plsetbutton(Panel *p, int val){
((Button *)p->data)->check=val;
}

View file

@ -0,0 +1,51 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Canvas Canvas;
struct Canvas{
void (*draw)(Panel *);
void (*hit)(Panel *, Mouse *);
};
void pl_drawcanvas(Panel *p){
Canvas *c;
c=p->data;
if(c->draw) c->draw(p);
}
int pl_hitcanvas(Panel *p, Mouse *m){
Canvas *c;
c=p->data;
if(c->hit) c->hit(p, m);
return 0;
}
void pl_typecanvas(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizecanvas(Panel *p, Point children){
USED(p, children);
return Pt(0,0);
}
void pl_childspacecanvas(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
void plinitcanvas(Panel *v, int flags, void (*draw)(Panel *), void (*hit)(Panel *, Mouse *)){
Canvas *c;
v->flags=flags|LEAF;
v->draw=pl_drawcanvas;
v->hit=pl_hitcanvas;
v->type=pl_typecanvas;
v->getsize=pl_getsizecanvas;
v->childspace=pl_childspacecanvas;
v->kind="canvas";
c=v->data;
c->draw=draw;
c->hit=hit;
}
Panel *plcanvas(Panel *parent, int flags, void (*draw)(Panel *), void (*hit)(Panel *, Mouse *)){
Panel *p;
p=pl_newpanel(parent, sizeof(Canvas));
plinitcanvas(p, flags, draw, hit);
return p;
}

View file

@ -0,0 +1,322 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#define PWID 1 /* width of label border */
#define BWID 1 /* width of button relief */
#define FWID 2 /* width of frame relief */
#define SPACE 1 /* space inside relief of button or frame */
#define CKSIZE 3 /* size of check mark */
#define CKSPACE 2 /* space around check mark */
#define CKWID 1 /* width of frame around check mark */
#define CKINSET 1 /* space around check mark frame */
#define CKBORDER 2 /* space around X inside frame */
static int plldepth;
static Image *pl_white, *pl_light, *pl_dark, *pl_black, *pl_hilit;
int pl_drawinit(int ldepth){
plldepth=ldepth;
pl_white=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFFFFFFF);
//pl_light=allocimagemix(display, DPalebluegreen, DWhite);
pl_light=display->white;
//pl_dark =allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
pl_dark = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0X999999FF);
pl_black=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000FF);
pl_hilit=allocimage(display, Rect(0,0,1,1), CHAN1(CAlpha,8), 1, 0x80);
if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0) return 0;
return 1;
}
void pl_relief(Image *b, Image *ul, Image *lr, Rectangle r, int wid){
int x, y;
draw(b, Rect(r.min.x, r.max.y-wid, r.max.x, r.max.y), lr, 0, ZP); /* bottom */
draw(b, Rect(r.max.x-wid, r.min.y, r.max.x, r.max.y), lr, 0, ZP); /* right */
draw(b, Rect(r.min.x, r.min.y, r.min.x+wid, r.max.y), ul, 0, ZP); /* left */
draw(b, Rect(r.min.x, r.min.y, r.max.x, r.min.y+wid), ul, 0, ZP); /* top */
for(x=0;x!=wid;x++) for(y=wid-1-x;y!=wid;y++){
draw(b, rectaddpt(Rect(0,0,1,1), Pt(x+r.max.x-wid, y+r.min.y)), lr, 0, ZP);
draw(b, rectaddpt(Rect(0,0,1,1), Pt(x+r.min.x, y+r.max.y-wid)), lr, 0, ZP);
}
}
Rectangle pl_boxoutline(Image *b, Rectangle r, int style, int fill){
if(plldepth==0) switch(style){
case UP:
pl_relief(b, pl_black, pl_black, r, BWID);
r=insetrect(r, BWID);
if(fill) draw(b, r, pl_white, 0, ZP);
else border(b, r, SPACE, pl_white, ZP);
break;
case DOWN:
case DOWN1:
case DOWN2:
case DOWN3:
pl_relief(b, pl_black, pl_black, r, BWID);
r=insetrect(r, BWID);
if(fill) draw(b, r, pl_black, 0, ZP);
border(b, r, SPACE, pl_black, ZP);
break;
case PASSIVE:
if(fill) draw(b, r, pl_white, 0, ZP);
r=insetrect(r, PWID);
if(!fill) border(b, r, SPACE, pl_white, ZP);
break;
case FRAME:
pl_relief(b, pl_white, pl_black, r, FWID);
r=insetrect(r, FWID);
pl_relief(b, pl_black, pl_white, r, FWID);
r=insetrect(r, FWID);
if(fill) draw(b, r, pl_white, 0, ZP);
else border(b, r, SPACE, pl_white, ZP);
break;
}
else switch(style){
case UP:
/*
pl_relief(b, pl_white, pl_black, r, BWID);
r=insetrect(r, BWID);
if(fill) draw(b, r, pl_light, 0, ZP);
else border(b, r, SPACE, pl_white, ZP);
*/
draw(b, r, pl_light, 0, ZP);
border(b, r, 1, pl_black, ZP);
break;
case DOWN:
case DOWN1:
case DOWN2:
case DOWN3:
pl_relief(b, pl_black, pl_white, r, BWID);
r=insetrect(r, BWID);
if(fill) draw(b, r, pl_dark, 0, ZP);
else border(b, r, SPACE, pl_black, ZP);
break;
case PASSIVE:
if(fill) draw(b, r, pl_light, 0, ZP);
r=insetrect(r, PWID);
if(!fill) border(b, r, SPACE, pl_white, ZP);
break;
case FRAME:
border(b, r, 1, pl_black, ZP);
/*
pl_relief(b, pl_white, pl_black, r, FWID);
r=insetrect(r, FWID);
pl_relief(b, pl_black, pl_white, r, FWID);
r=insetrect(r, FWID);
if(fill) draw(b, r, pl_light, 0, ZP);
else border(b, r, SPACE, pl_white, ZP);
*/
break;
}
return insetrect(r, SPACE);
}
Rectangle pl_outline(Image *b, Rectangle r, int style){
return pl_boxoutline(b, r, style, 0);
}
Rectangle pl_box(Image *b, Rectangle r, int style){
return pl_boxoutline(b, r, style, 1);
}
Rectangle pl_boxoutlinef(Image *b, Rectangle r, int flags, int style, int fill){
switch(style){
case UP:
draw(b, r, pl_light, 0, ZP);
if(!(flags&NOBORDER))
border(b, r, 1, pl_black, ZP);
break;
case DOWN:
case DOWN1:
case DOWN2:
case DOWN3:
if(!(flags&NOBORDER))
pl_relief(b, pl_black, pl_white, r, BWID);
r=insetrect(r, BWID);
if(fill) draw(b, r, pl_dark, 0, ZP);
else if(!(flags&NOBORDER)) border(b, r, SPACE, pl_black, ZP);
break;
case PASSIVE:
if(fill) draw(b, r, pl_light, 0, ZP);
r=insetrect(r, PWID);
if(!fill) border(b, r, SPACE, pl_white, ZP);
break;
case FRAME:
border(b, r, 1, pl_black, ZP);
break;
}
return insetrect(r, SPACE);
}
Rectangle pl_outlinef(Image *b, Rectangle r, int flags, int style){
return pl_boxoutlinef(b, r, flags, style, 0);
}
Rectangle pl_boxf(Image *b, Rectangle r, int flags, int style){
return pl_boxoutlinef(b, r, flags, style, 1);
}
Point pl_boxsize(Point interior, int state){
switch(state){
case UP:
case DOWN:
case DOWN1:
case DOWN2:
case DOWN3:
return addpt(interior, Pt(2*(BWID+SPACE), 2*(BWID+SPACE)));
case PASSIVE:
return addpt(interior, Pt(2*(PWID+SPACE), 2*(PWID+SPACE)));
case FRAME:
return addpt(interior, Pt(4*FWID+2*SPACE, 4*FWID+2*SPACE));
}
return Pt(0, 0);
}
void pl_interior(int state, Point *ul, Point *size){
switch(state){
case UP:
case DOWN:
case DOWN1:
case DOWN2:
case DOWN3:
*ul=addpt(*ul, Pt(BWID+SPACE, BWID+SPACE));
*size=subpt(*size, Pt(2*(BWID+SPACE), 2*(BWID+SPACE)));
break;
case PASSIVE:
*ul=addpt(*ul, Pt(PWID+SPACE, PWID+SPACE));
*size=subpt(*size, Pt(2*(PWID+SPACE), 2*(PWID+SPACE)));
break;
case FRAME:
*ul=addpt(*ul, Pt(2*FWID+SPACE, 2*FWID+SPACE));
*size=subpt(*size, Pt(4*FWID+2*SPACE, 4*FWID+2*SPACE));
}
}
void pl_drawicon(Image *b, Rectangle r, int stick, int flags, Icon *s){
Rectangle save;
Point ul, offs;
ul=r.min;
offs=subpt(subpt(r.max, r.min), pl_iconsize(flags, s));
switch(stick){
case PLACENW: break;
case PLACEN: ul.x+=offs.x/2; break;
case PLACENE: ul.x+=offs.x; break;
case PLACEW: ul.y+=offs.y/2; break;
case PLACECEN: ul.x+=offs.x/2; ul.y+=offs.y/2; break;
case PLACEE: ul.x+=offs.x; break;
case PLACESW: ul.y+=offs.y; break;
case PLACES: ul.x+=offs.x/2; ul.y+=offs.y; break;
case PLACESE: ul.x+=offs.x; ul.y+=offs.y; break;
}
save=b->clipr;
if(!rectclip(&r, save))
return;
replclipr(b, b->repl, r);
if(flags&BITMAP) draw(b, Rpt(ul, addpt(ul, pl_iconsize(flags, s))), s, 0, ZP);
else string(b, ul, pl_black, ZP, font, s);
replclipr(b, b->repl, save);
}
/*
* Place a check mark at the left end of r. Return the unused space.
* Caller must guarantee that r.max.x-r.min.x>=r.max.y-r.min.y!
*/
Rectangle pl_radio(Image *b, Rectangle r, int val){
Rectangle remainder;
remainder=r;
r.max.x=r.min.x+r.max.y-r.min.y;
remainder.min.x=r.max.x;
r=insetrect(r, CKINSET);
if(plldepth==0)
pl_relief(b, pl_black, pl_black, r, CKWID);
else
pl_relief(b, pl_black, pl_white, r, CKWID);
r=insetrect(r, CKWID);
if(plldepth==0)
draw(b, r, pl_white, 0, ZP);
else
draw(b, r, pl_light, 0, ZP);
if(val) draw(b, insetrect(r, CKSPACE), pl_black, 0, ZP);
return remainder;
}
Rectangle pl_check(Image *b, Rectangle r, int val){
Rectangle remainder;
remainder=r;
r.max.x=r.min.x+r.max.y-r.min.y;
remainder.min.x=r.max.x;
r=insetrect(r, CKINSET);
if(plldepth==0)
pl_relief(b, pl_black, pl_black, r, CKWID);
else
pl_relief(b, pl_black, pl_white, r, CKWID);
r=insetrect(r, CKWID);
if(plldepth==0)
draw(b, r, pl_white, 0, ZP);
else
draw(b, r, pl_light, 0, ZP);
r=insetrect(r, CKBORDER);
if(val){
line(b, Pt(r.min.x, r.min.y+1), Pt(r.max.x-1, r.max.y ), Endsquare, Endsquare, 0, pl_black, ZP);
line(b, Pt(r.min.x, r.min.y ), Pt(r.max.x, r.max.y ), Endsquare, Endsquare, 0, pl_black, ZP);
line(b, Pt(r.min.x+1, r.min.y ), Pt(r.max.x, r.max.y-1), Endsquare, Endsquare, 0, pl_black, ZP);
line(b, Pt(r.min.x , r.max.y-2), Pt(r.max.x-1, r.min.y-1), Endsquare, Endsquare, 0, pl_black, ZP);
line(b, Pt(r.min.x, r.max.y-1), Pt(r.max.x, r.min.y-1), Endsquare, Endsquare, 0, pl_black, ZP);
line(b, Pt(r.min.x+1, r.max.y-1), Pt(r.max.x, r.min.y ), Endsquare, Endsquare, 0, pl_black, ZP);
}
return remainder;
}
int pl_ckwid(void){
return 2*(CKINSET+CKSPACE+CKWID)+CKSIZE;
}
void pl_sliderupd(Image *b, Rectangle r1, int dir, int lo, int hi){
Rectangle r2, r3;
r2=r1;
r3=r1;
if(lo<0) lo=0;
if(hi<=lo) hi=lo+1;
switch(dir){
case HORIZ:
r1.max.x=r1.min.x+lo;
r2.min.x=r1.max.x;
r2.max.x=r1.min.x+hi;
if(r2.max.x>r3.max.x) r2.max.x=r3.max.x;
r3.min.x=r2.max.x;
break;
case VERT:
r1.max.y=r1.min.y+lo;
r2.min.y=r1.max.y;
r2.max.y=r1.min.y+hi;
if(r2.max.y>r3.max.y) r2.max.y=r3.max.y;
r3.min.y=r2.max.y;
break;
}
draw(b, r1, pl_light, 0, ZP);
draw(b, r2, pl_dark, 0, ZP);
draw(b, r3, pl_light, 0, ZP);
}
void pl_draw1(Panel *p, Image *b);
void pl_drawall(Panel *p, Image *b){
if(p->flags&INVIS || p->flags&IGNORE) return;
p->b=b;
p->draw(p);
for(p=p->child;p;p=p->next) pl_draw1(p, b);
}
void pl_draw1(Panel *p, Image *b){
if(b!=0)
pl_drawall(p, b);
}
void pldraw(Panel *p, Image *b){
pl_draw1(p, b);
}
void pl_invis(Panel *p, int v){
for(;p;p=p->next){
if(v) p->flags|=INVIS; else p->flags&=~INVIS;
pl_invis(p->child, v);
}
}
Point pl_iconsize(int flags, Icon *p){
if(flags&BITMAP) return subpt(((Image *)p)->r.max, ((Image *)p)->r.min);
return stringsize(font, (char *)p);
}
void pl_highlight(Image *b, Rectangle r){
draw(b, r, pl_dark, pl_hilit, ZP);
}
void pl_clr(Image *b, Rectangle r){
draw(b, r, display->white, 0, ZP);
}
void pl_fill(Image *b, Rectangle r){
draw(b, r, plldepth==0? pl_white : pl_light, 0, ZP);
}
void pl_cpy(Image *b, Point dst, Rectangle src){
draw(b, Rpt(dst, addpt(dst, subpt(src.max, src.min))), b, 0, src.min);
}

View file

@ -0,0 +1,297 @@
/*
* Interface includes:
* void plescroll(Panel *p, int top);
* move the given character position onto the top line
* void plegetsel(Panel *p, int *sel0, int *sel1);
* read the selection back
* int plelen(Panel *p);
* read the length of the text back
* Rune *pleget(Panel *p);
* get a pointer to the text
* void plesel(Panel *p, int sel0, int sel1);
* set the selection -- adjusts hiliting
* void plepaste(Panel *p, Rune *text, int ntext);
* replace the selection with the given text
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#include <keyboard.h>
typedef struct Edit Edit;
struct Edit{
Point minsize;
void (*hit)(Panel *);
int sel0, sel1;
Textwin *t;
Rune *text;
int ntext;
};
void pl_drawedit(Panel *p){
Edit *ep;
Panel *sb;
ep=p->data;
if(ep->t==0){
ep->t=twnew(p->b, font, ep->text, ep->ntext);
if(ep->t==0){
fprint(2, "pl_drawedit: can't allocate\n");
exits("no mem");
}
}
ep->t->b=p->b;
twreshape(ep->t, p->r);
twhilite(ep->t, ep->sel0, ep->sel1, 1);
sb=p->yscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, ep->t->top, ep->t->bot, ep->t->etext-ep->t->text);
}
char *pl_snarfedit(Panel *p){
int s0, s1;
Rune *t;
t=pleget(p);
plegetsel(p, &s0, &s1);
if(t==0 || s0>=s1)
return nil;
return smprint("%.*S", s1-s0, t+s0);
}
void pl_pasteedit(Panel *p, char *s){
Rune *t;
if(t=runesmprint("%s", s)){
plepaste(p, t, runestrlen(t));
free(t);
}
}
/*
* Should do double-clicks:
* If ep->sel0==ep->sel1 on entry and the
* call to twselect returns the same selection, then
* expand selections (| marks possible selection points, ... is expanded selection)
* <|...|> <> must nest
* (|...|) () must nest
* [|...|] [] must nest
* {|...|} {} must nest
* '|...|' no ' in ...
* "|...|" no " in ...
* \n|...|\n either newline may be the corresponding end of text
* include the trailing newline in the selection
* ...|I... I and ... are characters satisfying pl_idchar(I)
* ...I|
*/
int pl_hitedit(Panel *p, Mouse *m){
Edit *ep;
ep=p->data;
if(ep->t && m->buttons&1){
plgrabkb(p);
ep->t->b=p->b;
twhilite(ep->t, ep->sel0, ep->sel1, 0);
twselect(ep->t, m);
ep->sel0=ep->t->sel0;
ep->sel1=ep->t->sel1;
if((m->buttons&7)==3){
plsnarf(p);
plepaste(p, 0, 0); /* cut */
}
else if((m->buttons&7)==5)
plpaste(p);
else if(ep->hit)
(*ep->hit)(p);
}
return 0;
}
void pl_scrolledit(Panel *p, int dir, int buttons, int num, int den){
Edit *ep;
Textwin *t;
Panel *sb;
int index, nline;
if(dir!=VERT) return;
ep=p->data;
t=ep->t;
if(t==0) return;
t->b=p->b;
switch(buttons){
default:
return;
case 1: /* top line moves to mouse position */
nline=(t->r.max.y-t->r.min.y)/t->hgt*num/den;
index=t->top;
while(index!=0 && nline!=0)
if(t->text[--index]=='\n') --nline;
break;
case 2: /* absolute */
index=(t->etext-t->text)*num/den;
break;
case 4: /* mouse points at new top line */
index=twpt2rune(t,
Pt(t->r.min.x, t->r.min.y+(t->r.max.y-t->r.min.y)*num/den));
break;
}
while(index!=0 && t->text[index-1]!='\n') --index;
if(index!=t->top){
twhilite(ep->t, ep->sel0, ep->sel1, 0);
twscroll(t, index);
p->scr.pos.y=t->top;
twhilite(ep->t, ep->sel0, ep->sel1, 1);
sb=p->yscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, t->top, t->bot, t->etext-t->text);
}
}
void pl_typeedit(Panel *p, Rune c){
Edit *ep;
Textwin *t;
int bot, scrolled;
Panel *sb;
ep=p->data;
t=ep->t;
if(t==0) return;
t->b=p->b;
twhilite(t, ep->sel0, ep->sel1, 0);
switch(c){
case Kesc:
plsnarf(p);
plepaste(p, 0, 0); /* cut */
break;
case Kdel: /* clear */
ep->sel0=0;
ep->sel1=plelen(p);
plepaste(p, 0, 0); /* cut */
break;
case Kbs: /* ^H: erase character */
if(ep->sel0!=0) --ep->sel0;
twreplace(t, ep->sel0, ep->sel1, 0, 0);
break;
case Knack: /* ^U: erase line */
while(ep->sel0!=0 && t->text[ep->sel0-1]!='\n') --ep->sel0;
twreplace(t, ep->sel0, ep->sel1, 0, 0);
break;
case Ketb: /* ^W: erase word */
while(ep->sel0!=0 && !pl_idchar(t->text[ep->sel0-1])) --ep->sel0;
while(ep->sel0!=0 && pl_idchar(t->text[ep->sel0-1])) --ep->sel0;
twreplace(t, ep->sel0, ep->sel1, 0, 0);
break;
default:
if((c & 0xFF00) == KF || (c & 0xFF00) == Spec)
break;
twreplace(t, ep->sel0, ep->sel1, &c, 1);
++ep->sel0;
break;
}
ep->sel1=ep->sel0;
/*
* Scroll up until ep->sel0 is above t->bot.
*/
scrolled=0;
do{
bot=t->bot;
if(ep->sel0<=bot) break;
twscroll(t, twpt2rune(t, Pt(t->r.min.x, t->r.min.y+font->height)));
scrolled++;
}while(bot!=t->bot);
if(scrolled){
sb=p->yscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, t->top, t->bot, t->etext-t->text);
}
twhilite(t, ep->sel0, ep->sel1, 1);
}
Point pl_getsizeedit(Panel *p, Point children){
USED(children);
return pl_boxsize(((Edit *)p->data)->minsize, p->state);
}
void pl_childspaceedit(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void pl_freeedit(Panel *p){
Edit *ep;
ep=p->data;
if(ep->t) twfree(ep->t);
ep->t=0;
}
void plinitedit(Panel *v, int flags, Point minsize, Rune *text, int ntext, void (*hit)(Panel *)){
Edit *ep;
ep=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawedit;
v->hit=pl_hitedit;
v->type=pl_typeedit;
v->getsize=pl_getsizeedit;
v->childspace=pl_childspaceedit;
v->free=pl_freeedit;
v->snarf=pl_snarfedit;
v->paste=pl_pasteedit;
v->kind="edit";
ep->hit=hit;
ep->minsize=minsize;
ep->text=text;
ep->ntext=ntext;
if(ep->t!=0) twfree(ep->t);
ep->t=0;
ep->sel0=-1;
ep->sel1=-1;
v->scroll=pl_scrolledit;
v->scr.pos=Pt(0,0);
v->scr.size=Pt(ntext,0);
}
Panel *pledit(Panel *parent, int flags, Point minsize, Rune *text, int ntext, void (*hit)(Panel *)){
Panel *v;
v=pl_newpanel(parent, sizeof(Edit));
((Edit *)v->data)->t=0;
plinitedit(v, flags, minsize, text, ntext, hit);
return v;
}
void plescroll(Panel *p, int top){
Textwin *t;
t=((Edit*)p->data)->t;
if(t) twscroll(t, top);
}
void plegetsel(Panel *p, int *sel0, int *sel1){
Edit *ep;
ep=p->data;
*sel0=ep->sel0;
*sel1=ep->sel1;
}
int plelen(Panel *p){
Textwin *t;
t=((Edit*)p->data)->t;
if(t==0) return 0;
return t->etext-t->text;
}
Rune *pleget(Panel *p){
Textwin *t;
t=((Edit*)p->data)->t;
if(t==0) return 0;
return t->text;
}
void plesel(Panel *p, int sel0, int sel1){
Edit *ep;
ep=p->data;
if(ep->t==0) return;
ep->t->b=p->b;
twhilite(ep->t, ep->sel0, ep->sel1, 0);
ep->sel0=sel0;
ep->sel1=sel1;
twhilite(ep->t, ep->sel0, ep->sel1, 1);
}
void plepaste(Panel *p, Rune *text, int ntext){
Edit *ep;
ep=p->data;
if(ep->t==0) return;
ep->t->b=p->b;
twhilite(ep->t, ep->sel0, ep->sel1, 0);
twreplace(ep->t, ep->sel0, ep->sel1, text, ntext);
ep->sel1=ep->sel0+ntext;
twhilite(ep->t, ep->sel0, ep->sel1, 1);
p->scr.size.y=ep->t->etext-ep->t->text;
p->scr.pos.y=ep->t->top;
}
void plemove(Panel *p, Point d){
Edit *ep;
ep=p->data;
if(ep->t && !eqpt(d, Pt(0,0))) twmove(ep->t, d);
}

View file

@ -0,0 +1,192 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#include <keyboard.h>
typedef struct Entry Entry;
struct Entry{
char *entry;
char *entp;
char *eent;
void (*hit)(Panel *, char *);
Point minsize;
};
#define SLACK 7 /* enough for one extra rune and ◀ and a nul */
char *pl_snarfentry(Panel *p){
Entry *ep;
int n;
if(p->flags&USERFL) /* no snarfing from password entry */
return nil;
ep=p->data;
n=utfnlen(ep->entry, ep->entp-ep->entry);
if(n<1) return nil;
return smprint("%.*s", n, ep->entry);
}
void pl_pasteentry(Panel *p, char *s){
Entry *ep;
char *e;
int n, m;
ep=p->data;
n=ep->entp-ep->entry;
m=strlen(s);
e=pl_erealloc(ep->entry,n+m+SLACK);
ep->entry=e;
e+=n;
strncpy(e, s, m);
e+=m;
*e='\0';
ep->entp=ep->eent=e;
pldraw(p, p->b);
}
void pl_drawentry(Panel *p){
Rectangle r;
Entry *ep;
char *s;
ep=p->data;
r=pl_box(p->b, p->r, p->state);
s=ep->entry;
if(p->flags & USERFL){
char *p;
s=strdup(s);
for(p=s; *p; p++)
*p='*';
}
if(stringwidth(font, s)<=r.max.x-r.min.x)
pl_drawicon(p->b, r, PLACEW, 0, s);
else
pl_drawicon(p->b, r, PLACEE, 0, s);
if(s != ep->entry)
free(s);
}
int pl_hitentry(Panel *p, Mouse *m){
if((m->buttons&7)==1){
plgrabkb(p);
p->state=DOWN;
pldraw(p, p->b);
while(m->buttons&1){
int old;
old=m->buttons;
if(display->bufp > display->buf)
flushimage(display, 1);
*m=emouse();
if((old&7)==1){
if((m->buttons&7)==3){
Entry *ep;
plsnarf(p);
/* cut */
ep=p->data;
ep->entp=ep->entry;
*ep->entp='\0';
pldraw(p, p->b);
}
if((m->buttons&7)==5)
plpaste(p);
}
}
p->state=UP;
pldraw(p, p->b);
}
return 0;
}
void pl_typeentry(Panel *p, Rune c){
int n;
Entry *ep;
ep=p->data;
switch(c){
case '\n':
case '\r':
*ep->entp='\0';
if(ep->hit) ep->hit(p, ep->entry);
return;
case Kesc:
plsnarf(p);
/* no break */
case Kdel: /* clear */
case Knack: /* ^U: erase line */
ep->entp=ep->entry;
*ep->entp='\0';
break;
case Kbs: /* ^H: erase character */
while(ep->entp!=ep->entry && !pl_rune1st(ep->entp[-1])) *--ep->entp='\0';
if(ep->entp!=ep->entry) *--ep->entp='\0';
break;
case Ketb: /* ^W: erase word */
while(ep->entp!=ep->entry && !pl_idchar(ep->entp[-1]))
--ep->entp;
while(ep->entp!=ep->entry && pl_idchar(ep->entp[-1]))
--ep->entp;
*ep->entp='\0';
break;
default:
if(c < 0x20 || (c & 0xFF00) == KF || (c & 0xFF00) == Spec)
break;
ep->entp+=runetochar(ep->entp, &c);
if(ep->entp>ep->eent){
n=ep->entp-ep->entry;
ep->entry=pl_erealloc(ep->entry, n+100+SLACK);
ep->entp=ep->entry+n;
ep->eent=ep->entp+100;
}
*ep->entp='\0';
break;
}
pldraw(p, p->b);
}
Point pl_getsizeentry(Panel *p, Point children){
USED(children);
return pl_boxsize(((Entry *)p->data)->minsize, p->state);
}
void pl_childspaceentry(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
void pl_freeentry(Panel *p){
Entry *ep;
ep = p->data;
free(ep->entry);
ep->entry = ep->eent = ep->entp = 0;
}
void plinitentry(Panel *v, int flags, int wid, char *str, void (*hit)(Panel *, char *)){
int elen;
Entry *ep;
ep=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawentry;
v->hit=pl_hitentry;
v->type=pl_typeentry;
v->getsize=pl_getsizeentry;
v->childspace=pl_childspaceentry;
ep->minsize=Pt(wid, font->height);
v->free=pl_freeentry;
v->snarf=pl_snarfentry;
v->paste=pl_pasteentry;
elen=100;
if(str) elen+=strlen(str);
ep->entry=pl_erealloc(ep->entry, elen+SLACK);
ep->eent=ep->entry+elen;
strecpy(ep->entry, ep->eent, str ? str : "");
ep->entp=ep->entry+strlen(ep->entry);
ep->hit=hit;
v->kind="entry";
}
Panel *plentry(Panel *parent, int flags, int wid, char *str, void (*hit)(Panel *, char *)){
Panel *v;
v=pl_newpanel(parent, sizeof(Entry));
plinitentry(v, flags, wid, str, hit);
return v;
}
char *plentryval(Panel *p){
Entry *ep;
ep=p->data;
*ep->entp='\0';
return ep->entry;
}

View file

@ -0,0 +1,48 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void plgrabkb(Panel *g){
plkbfocus=g;
}
void plkeyboard(Rune c){
if(plkbfocus)
plkbfocus->type(plkbfocus, c);
}
/*
* Return the most leafward, highest priority panel containing p
*/
Panel *pl_ptinpanel(Point p, Panel *g){
Panel *v;
for(;g;g=g->next) if(ptinrect(p, g->r)){
v=pl_ptinpanel(p, g->child);
if(v && v->pri(v, p)>=g->pri(g, p)) return v;
return g;
}
return 0;
}
void plmouse(Panel *g, Mouse *m){
Panel *hit, *last;
if(g->flags&REMOUSE)
hit=g->lastmouse;
else{
hit=pl_ptinpanel(m->xy, g);
last=g->lastmouse;
if(last && last!=hit){
m->buttons|=OUT;
last->hit(last, m);
m->buttons&=~OUT;
}
}
if(hit){
if(hit->hit(hit, m))
g->flags|=REMOUSE;
else
g->flags&=~REMOUSE;
g->lastmouse=hit;
}
}

View file

@ -0,0 +1,39 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void pl_drawframe(Panel *p){
pl_box(p->b, p->r, FRAME);
}
int pl_hitframe(Panel *p, Mouse *m){
USED(p, m);
return 0;
}
void pl_typeframe(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizeframe(Panel *p, Point children){
USED(p);
return pl_boxsize(children, FRAME);
}
void pl_childspaceframe(Panel *p, Point *ul, Point *size){
USED(p);
pl_interior(FRAME, ul, size);
}
void plinitframe(Panel *v, int flags){
v->flags=flags;
v->draw=pl_drawframe;
v->hit=pl_hitframe;
v->type=pl_typeframe;
v->getsize=pl_getsizeframe;
v->childspace=pl_childspaceframe;
v->kind="frame";
}
Panel *plframe(Panel *parent, int flags){
Panel *p;
p=pl_newpanel(parent, 0);
plinitframe(p, flags);
return p;
}

View file

@ -0,0 +1,38 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void pl_drawgroup(Panel *p){
USED(p);
}
int pl_hitgroup(Panel *p, Mouse *m){
USED(p, m);
return 0;
}
void pl_typegroup(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizegroup(Panel *p, Point children){
USED(p);
return children;
}
void pl_childspacegroup(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
void plinitgroup(Panel *v, int flags){
v->flags=flags;
v->draw=pl_drawgroup;
v->hit=pl_hitgroup;
v->type=pl_typegroup;
v->getsize=pl_getsizegroup;
v->childspace=pl_childspacegroup;
v->kind="group";
}
Panel *plgroup(Panel *parent, int flags){
Panel *p;
p=pl_newpanel(parent, 0);
plinitgroup(p, flags);
return p;
}

View file

@ -0,0 +1,13 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
/*
* Just a wrapper for all the initialization routines
*/
int plinit(int ldepth){
if(!pl_drawinit(ldepth)) return 0;
return 1;
}

View file

@ -0,0 +1,50 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Label Label;
struct Label{
int placement;
Icon *icon;
};
void pl_drawlabel(Panel *p){
Label *l;
l=p->data;
pl_drawicon(p->b, pl_box(p->b, p->r, PASSIVE), l->placement, p->flags, l->icon);
}
int pl_hitlabel(Panel *p, Mouse *m){
USED(p, m);
return 0;
}
void pl_typelabel(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizelabel(Panel *p, Point children){
USED(children); /* shouldn't have any children */
return pl_boxsize(pl_iconsize(p->flags, ((Label *)p->data)->icon), PASSIVE);
}
void pl_childspacelabel(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void plinitlabel(Panel *v, int flags, Icon *icon){
v->flags=flags|LEAF;
((Label *)(v->data))->icon=icon;
v->draw=pl_drawlabel;
v->hit=pl_hitlabel;
v->type=pl_typelabel;
v->getsize=pl_getsizelabel;
v->childspace=pl_childspacelabel;
v->kind="label";
}
Panel *pllabel(Panel *parent, int flags, Icon *icon){
Panel *p;
p=pl_newpanel(parent, sizeof(Label));
plinitlabel(p, flags, icon);
plplacelabel(p, PLACECEN);
return p;
}
void plplacelabel(Panel *p, int placement){
((Label *)(p->data))->placement=placement;
}

View file

@ -0,0 +1,190 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct List List;
struct List{
void (*hit)(Panel *, int, int); /* call user back on hit */
char *(*gen)(Panel *, int); /* return text given index or 0 if out of range */
int lo; /* indices of first, last items displayed */
int sel; /* index of hilited item */
int len; /* # of items in list */
Rectangle listr;
Point minsize;
int buttons;
};
#define MAXHGT 12
void pl_listsel(Panel *p, int sel, int on){
List *lp;
int hi;
Rectangle r;
lp=p->data;
hi=lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height;
if(lp->lo>=0 && lp->lo<=sel && sel<hi && sel<lp->len){
r=lp->listr;
r.min.y+=(sel-lp->lo)*font->height;
r.max.y=r.min.y+font->height;
if(on)
pl_highlight(p->b, r);
else{
pl_fill(p->b, r);
pl_drawicon(p->b, r, PLACEW, 0, lp->gen(p, sel));
}
}
}
void pl_liststrings(Panel *p, int lo, int hi, Rectangle r){
Panel *sb;
List *lp;
char *s;
int i;
lp=p->data;
for(i=lo;i!=hi && (s=lp->gen(p, i));i++){
r.max.y=r.min.y+font->height;
pl_drawicon(p->b, r, PLACEW, 0, s);
r.min.y+=font->height;
}
if(lo<=lp->sel && lp->sel<hi) pl_listsel(p, lp->sel, 1);
sb=p->yscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, lp->lo,
lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height, lp->len);
}
void pl_drawlist(Panel *p){
List *lp;
lp=p->data;
lp->listr=pl_box(p->b, p->r, UP);
pl_liststrings(p, lp->lo, lp->lo+(lp->listr.max.y-lp->listr.min.y)/font->height,
lp->listr);
}
int pl_hitlist(Panel *p, Mouse *m){
int oldsel, hitme;
Point ul, size;
List *lp;
lp=p->data;
hitme=0;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
oldsel=lp->sel;
if(m->buttons&OUT){
p->state=UP;
if(m->buttons&~OUT) lp->sel=-1;
}
else if(p->state==DOWN || m->buttons&7){
lp->sel=(m->xy.y-ul.y)/font->height+lp->lo;
if(m->buttons&7){
lp->buttons=m->buttons;
p->state=DOWN;
}
else{
hitme=1;
p->state=UP;
}
}
if(oldsel!=lp->sel){
pl_listsel(p, oldsel, 0);
pl_listsel(p, lp->sel, 1);
}
if(hitme && 0<=lp->sel && lp->sel<lp->len && lp->hit)
lp->hit(p, lp->buttons, lp->sel);
return 0;
}
void pl_scrolllist(Panel *p, int dir, int buttons, int val, int len){
Point ul, size;
int nlist, oldlo, hi, nline, y;
List *lp;
Rectangle r;
lp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
nlist=size.y/font->height;
oldlo=lp->lo;
if(dir==VERT) switch(buttons){
case 1: lp->lo-=nlist*val/len; break;
case 2: lp->lo=lp->len*val/len; break;
case 4: lp->lo+=nlist*val/len; break;
}
if(lp->lo<0) lp->lo=0;
if(lp->lo>=lp->len) lp->lo=lp->len-1;
if(lp->lo==oldlo) return;
p->scr.pos.y=lp->lo;
r=lp->listr;
nline=(r.max.y-r.min.y)/font->height;
hi=lp->lo+nline;
if(hi<=oldlo || lp->lo>=oldlo+nline){
pl_box(p->b, r, PASSIVE);
pl_liststrings(p, lp->lo, hi, r);
}
else if(lp->lo<oldlo){
y=r.min.y+(oldlo-lp->lo)*font->height;
pl_cpy(p->b, Pt(r.min.x, y),
Rect(r.min.x, r.min.y, r.max.x, r.min.y+(hi-oldlo)*font->height));
r.max.y=y;
pl_box(p->b, r, PASSIVE);
pl_liststrings(p, lp->lo, oldlo, r);
}
else{
pl_cpy(p->b, r.min, Rect(r.min.x, r.min.y+(lp->lo-oldlo)*font->height,
r.max.x, r.max.y));
r.min.y=r.min.y+(oldlo+nline-lp->lo)*font->height;
pl_box(p->b, r, PASSIVE);
pl_liststrings(p, oldlo+nline, hi, r);
}
}
void pl_typelist(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizelist(Panel *p, Point children){
USED(children);
return pl_boxsize(((List *)p->data)->minsize, p->state);
}
void pl_childspacelist(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void plinitlist(Panel *v, int flags, char *(*gen)(Panel *, int), int nlist, void (*hit)(Panel *, int, int)){
List *lp;
int wid, max;
char *str;
lp=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawlist;
v->hit=pl_hitlist;
v->type=pl_typelist;
v->getsize=pl_getsizelist;
v->childspace=pl_childspacelist;
lp->gen=gen;
lp->hit=hit;
max=0;
for(lp->len=0;str=gen(v, lp->len);lp->len++){
wid=stringwidth(font, str);
if(wid>max) max=wid;
}
if(flags&(FILLX|EXPAND)){
for(lp->len=0;gen(v, lp->len);lp->len++);
lp->minsize=Pt(0, nlist*font->height);
}
else{
max=0;
for(lp->len=0;str=gen(v, lp->len);lp->len++){
wid=stringwidth(font, str);
if(wid>max) max=wid;
}
lp->minsize=Pt(max, nlist*font->height);
}
lp->sel=-1;
lp->lo=0;
v->scroll=pl_scrolllist;
v->scr.pos=Pt(0,0);
v->scr.size=Pt(0,lp->len);
v->kind="list";
}
Panel *pllist(Panel *parent, int flags, char *(*gen)(Panel *, int), int nlist, void (*hit)(Panel *, int, int)){
Panel *v;
v=pl_newpanel(parent, sizeof(List));
plinitlist(v, flags, gen, nlist, hit);
return v;
}

View file

@ -0,0 +1,123 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void *pl_emalloc(int n){
void *v;
v=mallocz(n, 1);
if(v==0){
fprint(2, "Can't malloc!\n");
exits("no mem");
}
setmalloctag(v, getcallerpc(&n));
return v;
}
void *pl_erealloc(void *v, int n)
{
v=realloc(v, n);
if(v==0){
fprint(2, "Can't realloc!\n");
exits("no mem");
}
setrealloctag(v, getcallerpc(&v));
return v;
}
void pl_unexpected(Panel *g, char *rou){
fprint(2, "%s called unexpectedly (%s %#p)\n", rou, g->kind, g);
abort();
}
void pl_drawerror(Panel *g){
pl_unexpected(g, "draw");
}
int pl_hiterror(Panel *g, Mouse *m){
USED(m);
pl_unexpected(g, "hit");
return 0;
}
void pl_typeerror(Panel *g, Rune c){
USED(c);
pl_unexpected(g, "type");
}
Point pl_getsizeerror(Panel *g, Point childsize){
pl_unexpected(g, "getsize");
return childsize;
}
void pl_childspaceerror(Panel *g, Point *ul, Point *size){
USED(ul, size);
pl_unexpected(g, "childspace");
}
void pl_scrollerror(Panel *g, int dir, int button, int num, int den){
USED(dir, button, num, den);
pl_unexpected(g, "scroll");
}
void pl_setscrollbarerror(Panel *g, int top, int bot, int den){
USED(top, bot, den);
pl_unexpected(g, "setscrollbar");
}
int pl_prinormal(Panel *, Point){
return PRI_NORMAL;
}
Panel *pl_newpanel(Panel *parent, int ndata){
Panel *v;
if(parent && parent->flags&LEAF){
fprint(2, "newpanel: can't create child of %s %#p\n", parent->kind, parent);
exits("bad newpanel");
}
v=pl_emalloc(sizeof(Panel));
v->r=Rect(0,0,0,0);
v->flags=0;
v->ipad=Pt(0,0);
v->pad=Pt(0,0);
v->size=Pt(0,0);
v->sizereq=Pt(0,0);
v->lastmouse=0;
v->next=0;
v->child=0;
v->echild=0;
v->b=0;
v->pri=pl_prinormal;
v->scrollee=0;
v->xscroller=0;
v->yscroller=0;
v->parent=parent;
v->scr.pos=Pt(0,0);
v->scr.size=Pt(0,0);
if(parent){
if(parent->child==0)
parent->child=v;
else
parent->echild->next=v;
parent->echild=v;
}
v->draw=pl_drawerror;
v->hit=pl_hiterror;
v->type=pl_typeerror;
v->getsize=pl_getsizeerror;
v->childspace=pl_childspaceerror;
v->scroll=pl_scrollerror;
v->setscrollbar=pl_setscrollbarerror;
v->free=0;
v->snarf=0;
v->paste=0;
if(ndata)
v->data=pl_emalloc(ndata);
else
v->data=0;
return v;
}
void plfree(Panel *p){
Panel *cp, *ncp;
if(p==0)
return;
if(p==plkbfocus)
plkbfocus=0;
for(cp=p->child;cp;cp=ncp){
ncp=cp->next;
plfree(cp);
}
if(p->free) p->free(p);
if(p->data) free(p->data);
free(p);
}

View file

@ -0,0 +1,104 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Message Message;
struct Message{
char *text;
Point minsize;
};
void pl_textmsg(Image *b, Rectangle r, Font *f, char *s){
char *start, *end; /* of line */
Point where;
int lwid, c, wid;
where=r.min;
wid=r.max.x-r.min.x;
do{
start=s;
lwid=0;
end=s;
do{
for(;*s!=' ' && *s!='\0';s=pl_nextrune(s)) lwid+=pl_runewidth(f, s);
if(lwid>wid) break;
end=s;
for(;*s==' ';s=pl_nextrune(s)) lwid+=pl_runewidth(f, s);
}while(*s!='\0');
if(end==start) /* can't even fit one word on line! */
end=s;
c=*end;
*end='\0';
string(b, where, display->black, ZP, f, start);
*end=c;
where.y+=font->height;
s=end;
while(*s==' ') s=pl_nextrune(s);
}while(*s!='\0');
}
Point pl_foldsize(Font *f, char *s, int wid){
char *start, *end; /* of line */
Point size;
int lwid, ewid;
size=Pt(0,0);
do{
start=s;
lwid=0;
end=s;
ewid=lwid;
do{
for(;*s!=' ' && *s!='\0';s=pl_nextrune(s)) lwid+=pl_runewidth(f, s);
if(lwid>wid) break;
end=s;
ewid=lwid;
for(;*s==' ';s=pl_nextrune(s)) lwid+=pl_runewidth(f, s);
}while(*s!='\0');
if(end==start){ /* can't even fit one word on line! */
ewid=lwid;
end=s;
}
if(ewid>size.x) size.x=ewid;
size.y+=font->height;
s=end;
while(*s==' ') s=pl_nextrune(s);
}while(*s!='\0');
return size;
}
void pl_drawmessage(Panel *p){
pl_textmsg(p->b, pl_box(p->b, p->r, PASSIVE), font, ((Message *)p->data)->text);
}
int pl_hitmessage(Panel *g, Mouse *m){
USED(g, m);
return 0;
}
void pl_typemessage(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizemessage(Panel *p, Point children){
Message *mp;
USED(children);
mp=p->data;
return pl_boxsize(pl_foldsize(font, mp->text, mp->minsize.x), PASSIVE);
}
void pl_childspacemessage(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
void plinitmessage(Panel *v, int flags, int wid, char *msg){
Message *mp;
mp=v->data;
v->flags=flags|LEAF;
v->draw=pl_drawmessage;
v->hit=pl_hitmessage;
v->type=pl_typemessage;
v->getsize=pl_getsizemessage;
v->childspace=pl_childspacemessage;
mp->text=msg;
mp->minsize=Pt(wid, font->height);
v->kind="message";
}
Panel *plmessage(Panel *parent, int flags, int wid, char *msg){
Panel *v;
v=pl_newpanel(parent, sizeof(Message));
plinitmessage(v, flags, wid, msg);
return v;
}

View file

@ -0,0 +1,34 @@
</$objtype/mkfile
LIB=libpanel.$O.a
OFILES=\
button.$O\
canvas.$O\
draw.$O\
edit.$O\
entry.$O\
event.$O\
frame.$O\
group.$O\
# idollist.$O\
init.$O\
label.$O\
list.$O\
mem.$O\
message.$O\
pack.$O\
popup.$O\
print.$O\
pulldown.$O\
rtext.$O\
scroll.$O\
scrollbar.$O\
slider.$O\
textview.$O\
textwin.$O\
utf.$O\
snarf.$O
HFILES=panel.h pldefs.h rtext.h
</sys/src/cmd/mklib

View file

@ -0,0 +1,161 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
int pl_max(int a, int b){
return a>b?a:b;
}
Point pl_sizesibs(Panel *p){
Point s;
if(p==0) return Pt(0,0);
s=pl_sizesibs(p->next);
switch(p->flags&PACK){
case PACKN:
case PACKS:
s.x=pl_max(s.x, p->sizereq.x);
s.y+=p->sizereq.y;
break;
case PACKE:
case PACKW:
s.x+=p->sizereq.x;
s.y=pl_max(s.y, p->sizereq.y);
break;
}
return s;
}
/*
* Compute the requested size of p and its descendants.
*/
void pl_sizereq(Panel *p){
Panel *cp;
Point maxsize;
maxsize=Pt(0,0);
for(cp=p->child;cp;cp=cp->next){
pl_sizereq(cp);
if(cp->sizereq.x>maxsize.x) maxsize.x=cp->sizereq.x;
if(cp->sizereq.y>maxsize.y) maxsize.y=cp->sizereq.y;
}
for(cp=p->child;cp;cp=cp->next){
if(cp->flags&MAXX) cp->sizereq.x=maxsize.x;
if(cp->flags&MAXY) cp->sizereq.y=maxsize.y;
}
p->childreq=pl_sizesibs(p->child);
p->sizereq=addpt(addpt(p->getsize(p, p->childreq), p->ipad), p->pad);
if(p->flags&FIXEDX) p->sizereq.x=p->fixedsize.x;
if(p->flags&FIXEDY) p->sizereq.y=p->fixedsize.y;
}
Point pl_getshare(Panel *p){
Point share;
if(p==0) return Pt(0,0);
share=pl_getshare(p->next);
if(p->flags&EXPAND) switch(p->flags&PACK){
case PACKN:
case PACKS:
if(share.x==0) share.x=1;
share.y++;
break;
case PACKE:
case PACKW:
share.x++;
if(share.y==0) share.y=1;
break;
}
return share;
}
/*
* Set the sizes and rectangles of p and its descendants, given their requested sizes.
*/
void pl_setrect(Panel *p, Point ul, Point avail){
Point space, newul, newspace, slack, share;
int l;
Panel *c;
p->size=subpt(p->sizereq, p->pad);
ul=addpt(ul, divpt(p->pad, 2));
avail=subpt(avail, p->pad);
if(p->size.x>avail.x)
p->size.x = avail.x;
if(p->size.y>avail.y)
p->size.y = avail.y;
if(p->flags&(FILLX|EXPAND)) p->size.x=avail.x;
if(p->flags&(FILLY|EXPAND)) p->size.y=avail.y;
switch(p->flags&PLACE){
case PLACECEN: ul.x+=(avail.x-p->size.x)/2; ul.y+=(avail.y-p->size.y)/2; break;
case PLACES: ul.x+=(avail.x-p->size.x)/2; ul.y+= avail.y-p->size.y ; break;
case PLACEE: ul.x+= avail.x-p->size.x ; ul.y+=(avail.y-p->size.y)/2; break;
case PLACEW: ul.y+=(avail.y-p->size.y)/2; break;
case PLACEN: ul.x+=(avail.x-p->size.x)/2; break;
case PLACENE: ul.x+= avail.x-p->size.x ; break;
case PLACENW: break;
case PLACESE: ul.x+= avail.x-p->size.x ; ul.y+= avail.y-p->size.y ; break;
case PLACESW: ul.y+= avail.y-p->size.y ; break;
}
p->r=Rpt(ul, addpt(ul, p->size));
space=p->size;
p->childspace(p, &ul, &space);
slack=subpt(space, p->childreq);
share=pl_getshare(p->child);
for(c=p->child;c;c=c->next){
if(c->flags&IGNORE) continue;
if(c->flags&EXPAND){
switch(c->flags&PACK){
case PACKN:
case PACKS:
c->sizereq.x+=slack.x;
l=slack.y/share.y;
c->sizereq.y+=l;
slack.y-=l;
--share.y;
break;
case PACKE:
case PACKW:
l=slack.x/share.x;
c->sizereq.x+=l;
slack.x-=l;
--share.x;
c->sizereq.y+=slack.y;
break;
}
}
switch(c->flags&PACK){
case PACKN:
newul=Pt(ul.x, ul.y+c->sizereq.y);
newspace=Pt(space.x, space.y-c->sizereq.y);
pl_setrect(c, ul, Pt(space.x, c->sizereq.y));
break;
case PACKW:
newul=Pt(ul.x+c->sizereq.x, ul.y);
newspace=Pt(space.x-c->sizereq.x, space.y);
pl_setrect(c, ul, Pt(c->sizereq.x, space.y));
break;
case PACKS:
newul=ul;
newspace=Pt(space.x, space.y-c->sizereq.y);
pl_setrect(c, Pt(ul.x, ul.y+space.y-c->sizereq.y),
Pt(space.x, c->sizereq.y));
break;
case PACKE:
newul=ul;
newspace=Pt(space.x-c->sizereq.x, space.y);
pl_setrect(c, Pt(ul.x+space.x-c->sizereq.x, ul.y),
Pt(c->sizereq.x, space.y));
break;
}
ul=newul;
space=newspace;
}
}
void plpack(Panel *p, Rectangle where){
pl_sizereq(p);
pl_setrect(p, where.min, subpt(where.max, where.min));
}
/*
* move an already-packed panel so that p->r=raddp(p->r, d)
*/
void plmove(Panel *p, Point d){
if(strcmp(p->kind, "edit") == 0) /* sorry */
plemove(p, d);
p->r=rectaddpt(p->r, d);
for(p=p->child;p;p=p->next) plmove(p, d);
}

View file

@ -0,0 +1,203 @@
//#pragma src "/sys/src/libpanel"
//#pragma lib "libpanel.a"
typedef struct Scroll Scroll;
typedef struct Panel Panel; /* a Graphical User Interface element */
typedef struct Rtext Rtext; /* formattable text */
typedef void Icon; /* Always used as Icon * -- Image or char */
typedef struct Idol Idol; /* A picture/text combo */
struct Scroll{
Point pos, size;
};
struct Rtext{
int flags; /* responds to hits? text selection? */
void *user; /* user data */
int space; /* how much space before, if no break */
int indent; /* how much space before, after a break */
int voff; /* vertical offset (for subscripts and superscripts) */
Image *b; /* what to display, if nonzero */
Panel *p; /* what to display, if nonzero and b==0 */
Font *font; /* font in which to draw text */
char *text; /* what to display, if b==0 and p==0 */
Rtext *next; /* next piece */
/* private below */
Rtext *nextline; /* links line to line */
Rtext *last; /* last, for append */
Rectangle r; /* where to draw, if origin were Pt(0,0) */
int topy; /* y coord of top of line */
int wid; /* not including space */
};
struct Panel{
Point ipad, pad; /* extra space inside and outside */
Point fixedsize; /* size of Panel, if FIXED */
int user; /* available for user */
void *userp; /* available for user */
Rectangle r; /* where the Panel goes */
/* private below */
Panel *next; /* It's a list! */
Panel *child, *echild, *parent; /* No, it's a tree! */
Image *b; /* where we're drawn */
int flags; /* position flags, see below */
char *kind; /* what kind of panel? */
int state; /* for hitting & drawing purposes */
Point size; /* space for this Panel */
Point sizereq; /* size requested by this Panel */
Point childreq; /* total size needed by children */
Panel *lastmouse; /* who got the last mouse event? */
Panel *scrollee; /* pointer to scrolled window */
Panel *xscroller, *yscroller; /* pointers to scroll bars */
Scroll scr; /* scroll data */
void *data; /* kind-specific data */
void (*draw)(Panel *); /* draw panel and children */
int (*pri)(Panel *, Point); /* priority for hitting */
int (*hit)(Panel *, Mouse *); /* process mouse event */
void (*type)(Panel *, Rune); /* process keyboard event */
Point (*getsize)(Panel *, Point); /* return size, given child size */
void (*childspace)(Panel *, Point *, Point *); /* child ul & size given our size */
void (*scroll)(Panel *, int, int, int, int); /* scroll bar to scrollee */
void (*setscrollbar)(Panel *, int, int, int); /* scrollee to scroll bar */
void (*free)(Panel *); /* free fields of data when done */
char* (*snarf)(Panel *); /* snarf text from panel */
void (*paste)(Panel *, char *); /* paste text into panel */
};
/*
* Panel flags
*/
#define PACK 0x0007 /* which side of the parent is the Panel attached to? */
#define PACKN 0x0000
#define PACKE 0x0001
#define PACKS 0x0002
#define PACKW 0x0003
#define PACKCEN 0x0004 /* only used by pulldown */
#define FILLX 0x0008 /* grow horizontally to fill the available space */
#define FILLY 0x0010 /* grow vertically to fill the available space */
#define PLACE 0x01e0 /* which side of its space should the Panel adhere to? */
#define PLACECEN 0x0000
#define PLACES 0x0020
#define PLACEE 0x0040
#define PLACEW 0x0060
#define PLACEN 0x0080
#define PLACENE 0x00a0
#define PLACENW 0x00c0
#define PLACESE 0x00e0
#define PLACESW 0x0100
#define EXPAND 0x0200 /* use up all extra space in the parent */
#define FIXED 0x0c00 /* don't pass children's size requests through to parent */
#define FIXEDX 0x0400
#define FIXEDY 0x0800
#define MAXX 0x1000 /* make x size as big as biggest sibling's */
#define MAXY 0x2000 /* make y size as big as biggest sibling's */
#define BITMAP 0x4000 /* text argument is a bitmap, not a string */
#define NOBORDER 0x8000
/* pldefs.h flags 0x08000-0x40000 */
#define IGNORE 0x080000 /* ignore this panel totally */
#define USERFL 0x100000 /* start of user flag */
/*
* An extra bit in Mouse.buttons
*/
#define OUT 8 /* Mouse.buttons bit, set when mouse leaves Panel */
/*
* Priorities
*/
#define PRI_NORMAL 0 /* ordinary panels */
#define PRI_POPUP 1 /* popup menus */
#define PRI_SCROLLBAR 2 /* scroll bars */
/* Rtext.flags */
#define PL_HOT 1
#define PL_SEL 2
#define PL_STR 4
#define PL_HEAD 8
Panel *plkbfocus; /* the panel in keyboard focus */
int plinit(int); /* initialization */
void plpack(Panel *, Rectangle); /* figure out where to put the Panel & children */
void plmove(Panel *, Point); /* move an already-packed panel to a new location */
void pldraw(Panel *, Image *); /* display the panel on the bitmap */
void plfree(Panel *); /* give back space */
void plgrabkb(Panel *); /* this Panel should receive keyboard events */
void plkeyboard(Rune); /* send a keyboard event to the appropriate Panel */
void plmouse(Panel *, Mouse *); /* send a Mouse event to a Panel tree */
void plscroll(Panel *, Panel *, Panel *); /* link up scroll bars */
char *plentryval(Panel *); /* entry delivers its value */
void plsetbutton(Panel *, int); /* set or clear the mark on a button */
void plsetslider(Panel *, int, int); /* set the value of a slider */
Rune *pleget(Panel *); /* get the text from an edit window */
int plelen(Panel *); /* get the length of the text from an edit window */
void plegetsel(Panel *, int *, int *); /* get the selection from an edit window */
void plepaste(Panel *, Rune *, int); /* paste in an edit window */
void plesel(Panel *, int, int); /* set the selection in an edit window */
void plescroll(Panel *, int); /* scroll an edit window */
Scroll plgetscroll(Panel *); /* get scrolling information from panel */
void plsetscroll(Panel *, Scroll); /* set scrolling information */
void plplacelabel(Panel *, int); /* label placement */
/*
* Panel creation & reinitialization functions
*/
Panel *plbutton(Panel *pl, int, Icon *, void (*)(Panel *pl, int));
Panel *plcanvas(Panel *pl, int, void (*)(Panel *), void (*)(Panel *pl, Mouse *));
Panel *plcheckbutton(Panel *pl, int, Icon *, void (*)(Panel *pl, int, int));
Panel *pledit(Panel *, int, Point, Rune *, int, void (*)(Panel *));
Panel *plentry(Panel *pl, int, int, char *, void (*)(Panel *pl, char *));
Panel *plframe(Panel *pl, int);
Panel *plgroup(Panel *pl, int);
Panel *plidollist(Panel*, int, Point, Font*, Idol*, void (*)(Panel*, int, void*));
Panel *pllabel(Panel *pl, int, Icon *);
Panel *pllist(Panel *pl, int, char *(*)(Panel *, int), int, void(*)(Panel *pl, int, int));
Panel *plmenu(Panel *pl, int, Icon **, int, void (*)(int, int));
Panel *plmenubar(Panel *pl, int, int, Icon *, Panel *pl, Icon *, ...);
Panel *plmessage(Panel *pl, int, int, char *);
Panel *plpopup(Panel *pl, int, Panel *pl, Panel *pl, Panel *pl);
Panel *plpulldown(Panel *pl, int, Icon *, Panel *pl, int);
Panel *plradiobutton(Panel *pl, int, Icon *, void (*)(Panel *pl, int, int));
Panel *plscrollbar(Panel *plparent, int flags);
Panel *plslider(Panel *pl, int, Point, void(*)(Panel *pl, int, int, int));
Panel *pltextview(Panel *, int, Point, Rtext *, void (*)(Panel *, int, Rtext *));
void plinitbutton(Panel *, int, Icon *, void (*)(Panel *, int));
void plinitcanvas(Panel *, int, void (*)(Panel *), void (*)(Panel *, Mouse *));
void plinitcheckbutton(Panel *, int, Icon *, void (*)(Panel *, int, int));
void plinitedit(Panel *, int, Point, Rune *, int, void (*)(Panel *));
void plinitentry(Panel *, int, int, char *, void (*)(Panel *, char *));
void plinitframe(Panel *, int);
void plinitgroup(Panel *, int);
void plinitidollist(Panel*, int, Point, Font*, Idol*, void (*)(Panel*, int, void*));
void plinitlabel(Panel *, int, Icon *);
void plinitlist(Panel *, int, char *(*)(Panel *, int), int, void(*)(Panel *, int, int));
void plinitmenu(Panel *, int, Icon **, int, void (*)(int, int));
void plinitmessage(Panel *, int, int, char *);
void plinitpopup(Panel *, int, Panel *, Panel *, Panel *);
void plinitpulldown(Panel *, int, Icon *, Panel *, int);
void plinitradiobutton(Panel *, int, Icon *, void (*)(Panel *, int, int));
void plinitscrollbar(Panel *parent, int flags);
void plinitslider(Panel *, int, Point, void(*)(Panel *, int, int, int));
void plinittextview(Panel *, int, Point, Rtext *, void (*)(Panel *, int, Rtext *));
/*
* Rtext constructors & destructor
*/
Rtext *plrtstr(Rtext **, int, int, int, Font *, char *, int, void *);
Rtext *plrtbitmap(Rtext **, int, int, int, Image *, int, void *);
Rtext *plrtpanel(Rtext **, int, int, int, Panel *, void *);
void plrtfree(Rtext *);
void plrtseltext(Rtext *, Rtext *, Rtext *);
char *plrtsnarftext(Rtext *);
int plgetpostextview(Panel *);
void plsetpostextview(Panel *, int);
/*
* Idols
*/
Idol *plmkidol(Idol**, Image*, Image*, char*, void*);
void plfreeidol(Idol*);
Point plidolsize(Idol*, Font*, int);
void *plidollistgetsel(Panel*);
/*
* Snarf
*/
void plputsnarf(char *);
char *plgetsnarf(void);
void plsnarf(Panel *); /* snarf a panel */
void plpaste(Panel *); /* paste a panel */

Binary file not shown.

View file

@ -0,0 +1,105 @@
/*
* Definitions for internal use only
*/
/*
* Variable-font text routines
* These could make a separate library.
*/
Point pl_rtfmt(Rtext *, int);
void pl_rtdraw(Image *, Rectangle, Rtext *, Point);
void pl_rtredraw(Image *, Rectangle, Rtext *, Point, Point, int);
Rtext *pl_rthit(Rtext *, Point, Point, Point);
#define HITME 0x08000 /* tells ptinpanel not to look at children */
#define LEAF 0x10000 /* newpanel will refuse to attach children */
#define INVIS 0x20000 /* don't draw this */
#define REMOUSE 0x40000 /* send next mouse event here, even if not inside */
/*
* States, also styles
*/
enum{
UP,
DOWN1,
DOWN2,
DOWN3,
DOWN,
PASSIVE,
FRAME
};
/*
* Scroll flags
*/
enum{
SCROLLUP,
SCROLLDOWN,
SCROLLABSY,
SCROLLLEFT,
SCROLLRIGHT,
SCROLLABSX,
};
/*
* Scrollbar, slider orientations
*/
enum{
HORIZ,
VERT
};
Panel *pl_newpanel(Panel *, int); /* make a new Panel, given parent & data size */
void *pl_emalloc(int); /* allocate some space, exit on error */
void *pl_erealloc(void*,int); /* reallocate some space, exit on error */
void pl_print(Panel *); /* print a Panel tree */
Panel *pl_ptinpanel(Point, Panel *); /* highest-priority subpanel containing point */
/*
* Drawing primitives
*/
int pl_drawinit(int);
Rectangle pl_box(Image *, Rectangle, int);
Rectangle pl_boxf(Image *b, Rectangle r, int flags, int style);
Rectangle pl_outline(Image *, Rectangle, int);
Point pl_boxsize(Point, int);
void pl_interior(int, Point *, Point *);
void pl_drawicon(Image *, Rectangle, int, int, Icon *);
Rectangle pl_check(Image *, Rectangle, int);
Rectangle pl_radio(Image *, Rectangle, int);
int pl_ckwid(void);
void pl_sliderupd(Image *, Rectangle, int, int, int);
void pl_invis(Panel *, int);
Point pl_iconsize(int, Icon *);
void pl_highlight(Image *, Rectangle);
void pl_clr(Image *, Rectangle);
void pl_fill(Image *, Rectangle);
void pl_cpy(Image *, Point, Rectangle);
/*
* Rune mangling functions
*/
int pl_idchar(int);
int pl_rune1st(int);
char *pl_nextrune(char *);
int pl_runewidth(Font *, char *);
/*
* Fixed-font Text-window routines
* These could be separated out into a separate library.
*/
typedef struct Textwin Textwin;
struct Textwin{
Rune *text, *etext, *eslack; /* text, with some slack off the end */
int top, bot; /* range of runes visible on screen */
int sel0, sel1; /* selection */
Point *loc, *eloc; /* ul corners of visible runes (+1 more at end!) */
Image *b; /* bitmap the text is drawn in */
Rectangle r; /* rectangle the text is drawn in */
Font *font; /* font text is drawn in */
int hgt; /* same as font->height */
int tabstop; /* tab settings are every tabstop pixels */
int mintab; /* the minimum size of a tab */
};
Textwin *twnew(Image *, Font *, Rune *, int);
void twfree(Textwin *);
void twhilite(Textwin *, int, int, int);
void twselect(Textwin *, Mouse *);
void twreplace(Textwin *, int, int, Rune *, int);
void twscroll(Textwin *, int);
int twpt2rune(Textwin *, Point);
void twreshape(Textwin *, Rectangle);
void twmove(Textwin *, Point);
void plemove(Panel *, Point);

View file

@ -0,0 +1,116 @@
/*
* popup
* looks like a group, except diverts hits on certain buttons to
* panels that it temporarily pops up.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Popup Popup;
struct Popup{
Image *save; /* where to save what the popup covers */
Panel *pop[3]; /* what to pop up */
};
void pl_drawpopup(Panel *p){
USED(p);
}
int pl_hitpopup(Panel *g, Mouse *m){
Panel *p;
Point d;
Popup *pp;
pp=g->data;
if(g->state==UP){
switch(m->buttons&7){
case 0: p=g->child; break;
case 1: p=pp->pop[0]; g->state=DOWN1; break;
case 2: p=pp->pop[1]; g->state=DOWN2; break;
case 4: p=pp->pop[2]; g->state=DOWN3; break;
default: p=0; break;
}
if(p==0){
p=g->child;
g->state=DOWN;
}
else if(g->state!=UP){
plpack(p, screen->clipr);
if(p->lastmouse)
d=subpt(m->xy, divpt(addpt(p->lastmouse->r.min,
p->lastmouse->r.max), 2));
else
d=subpt(m->xy, divpt(addpt(p->r.min, p->r.max), 2));
if(p->r.min.x+d.x<g->r.min.x) d.x=g->r.min.x-p->r.min.x;
if(p->r.max.x+d.x>g->r.max.x) d.x=g->r.max.x-p->r.max.x;
if(p->r.min.y+d.y<g->r.min.y) d.y=g->r.min.y-p->r.min.y;
if(p->r.max.y+d.y>g->r.max.y) d.y=g->r.max.y-p->r.max.y;
plmove(p, d);
pp->save=allocimage(display, p->r, g->b->chan, 0, DNofill);
if(pp->save!=0) draw(pp->save, p->r, g->b, 0, p->r.min);
pl_invis(p, 0);
pldraw(p, g->b);
}
}
else{
switch(g->state){
default: SET(p); break; /* can't happen! */
case DOWN1: p=pp->pop[0]; break;
case DOWN2: p=pp->pop[1]; break;
case DOWN3: p=pp->pop[2]; break;
case DOWN: p=g->child; break;
}
if((m->buttons&7)==0){
if(g->state!=DOWN){
if(pp->save!=0){
draw(g->b, p->r, pp->save, 0, p->r.min);
freeimage(pp->save);
pp->save=0;
}
pl_invis(p, 1);
}
g->state=UP;
}
}
plmouse(p, m);
if((m->buttons&7)==0)
g->state=UP;
return (m->buttons&7)!=0;
}
void pl_typepopup(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizepopup(Panel *g, Point children){
USED(g);
return children;
}
void pl_childspacepopup(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
int pl_pripopup(Panel *, Point){
return PRI_POPUP;
}
void plinitpopup(Panel *v, int flags, Panel *pop0, Panel *pop1, Panel *pop2){
Popup *pp;
pp=v->data;
v->flags=flags;
v->pri=pl_pripopup;
v->state=UP;
v->draw=pl_drawpopup;
v->hit=pl_hitpopup;
v->type=pl_typepopup;
v->getsize=pl_getsizepopup;
v->childspace=pl_childspacepopup;
pp->pop[0]=pop0;
pp->pop[1]=pop1;
pp->pop[2]=pop2;
pp->save=0;
v->kind="popup";
}
Panel *plpopup(Panel *parent, int flags, Panel *pop0, Panel *pop1, Panel *pop2){
Panel *v;
v=pl_newpanel(parent, sizeof(Popup));
plinitpopup(v, flags, pop0, pop1, pop2);
return v;
}

View file

@ -0,0 +1,56 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void pl_iprint(int indent, char *fmt, ...){
char buf[8192];
va_list arg;
memset(buf, '\t', indent);
va_start(arg, fmt);
write(1, buf, vsnprint(buf+indent, sizeof(buf)-indent, fmt, arg));
va_end(arg);
}
void pl_ipprint(Panel *p, int n){
Panel *c;
char *place, *stick;
pl_iprint(n, "%s (0x%.8x)\n", p->kind, p);
pl_iprint(n, " r=(%d %d, %d %d)\n",
p->r.min.x, p->r.min.y, p->r.max.x, p->r.max.y);
switch(p->flags&PACK){
default: SET(place); break;
case PACKN: place="n"; break;
case PACKE: place="e"; break;
case PACKS: place="s"; break;
case PACKW: place="w"; break;
}
switch(p->flags&PLACE){
default: SET(stick); break;
case PLACECEN: stick=""; break;
case PLACES: stick=" stick s"; break;
case PLACEE: stick=" stick e"; break;
case PLACEW: stick=" stick w"; break;
case PLACEN: stick=" stick n"; break;
case PLACENE: stick=" stick ne"; break;
case PLACENW: stick=" stick nw"; break;
case PLACESE: stick=" stick se"; break;
case PLACESW: stick=" stick sw"; break;
}
pl_iprint(n, " place %s%s%s%s%s%s\n",
place,
p->flags&FILLX?" fill x":"",
p->flags&FILLY?" fill y":"",
stick,
p->flags&EXPAND?" expand":"",
p->flags&FIXED?" fixed":"");
if(!eqpt(p->pad, Pt(0, 0))) pl_iprint(n, " pad=%d,%d)\n", p->pad.x, p->pad.y);
if(!eqpt(p->ipad, Pt(0, 0))) pl_iprint(n, " ipad=%d,%d)\n", p->ipad.x, p->ipad.y);
pl_iprint(n, " size=(%d,%d), sizereq=(%d,%d)\n",
p->size.x, p->size.y, p->sizereq.x, p->sizereq.y);
for(c=p->child;c;c=c->next)
pl_ipprint(c, n+1);
}
void pl_print(Panel *p){
pl_ipprint(p, 0);
}

View file

@ -0,0 +1,160 @@
/*
* pulldown
* makes a button that pops up a panel when hit
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Pulldown Pulldown;
struct Pulldown{
Icon *icon; /* button label */
Panel *pull; /* Panel to pull down */
int side; /* which side of the button to put the panel on */
Image *save; /* where to save what we draw the panel on */
};
void pl_drawpulldown(Panel *p){
pl_drawicon(p->b, pl_box(p->b, p->r, p->state), PLACECEN,
p->flags, ((Pulldown *)p->data)->icon);
}
int pl_hitpulldown(Panel *g, Mouse *m){
int oldstate, passon;
Rectangle r;
Panel *p, *hitme;
Pulldown *pp;
pp=g->data;
oldstate=g->state;
p=pp->pull;
hitme=0;
switch(g->state){
case UP:
if(!ptinrect(m->xy, g->r))
g->state=UP;
else if(m->buttons&7){
r=g->b->r;
p->flags&=~PLACE;
switch(pp->side){
case PACKN:
r.min.x=g->r.min.x;
r.max.y=g->r.min.y;
p->flags|=PLACESW;
break;
case PACKS:
r.min.x=g->r.min.x;
r.min.y=g->r.max.y;
p->flags|=PLACENW;
break;
case PACKE:
r.min.x=g->r.max.x;
r.min.y=g->r.min.y;
p->flags|=PLACENW;
break;
case PACKW:
r.max.x=g->r.min.x;
r.min.y=g->r.min.y;
p->flags|=PLACENE;
break;
case PACKCEN:
r.min=g->r.min;
p->flags|=PLACENW;
break;
}
plpack(p, r);
pp->save=allocimage(display, p->r, g->b->chan, 0, DNofill);
if(pp->save!=0) draw(pp->save, p->r, g->b, 0, p->r.min);
pl_invis(p, 0);
pldraw(p, g->b);
g->state=DOWN;
}
break;
case DOWN:
if(!ptinrect(m->xy, g->r)){
switch(pp->side){
default: SET(passon); break; /* doesn't happen */
case PACKN: passon=m->xy.y<g->r.min.y; break;
case PACKS: passon=m->xy.y>=g->r.max.y; break;
case PACKE: passon=m->xy.x>=g->r.max.x; break;
case PACKW: passon=m->xy.x<g->r.min.x; break;
case PACKCEN: passon=1; break;
}
if(passon){
hitme=p;
if((m->buttons&7)==0) g->state=UP;
}
else g->state=UP;
}
else if((m->buttons&7)==0) g->state=UP;
else hitme=p;
if(g->state!=DOWN && pp->save){
draw(g->b, p->r, pp->save, 0, p->r.min);
freeimage(pp->save);
pp->save=0;
pl_invis(p, 1);
hitme=p;
}
}
if(g->state!=oldstate) pldraw(g, g->b);
if(hitme) plmouse(hitme, m);
return g->state==DOWN;
}
void pl_typepulldown(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizepulldown(Panel *p, Point children){
USED(p, children);
return pl_boxsize(pl_iconsize(p->flags, ((Pulldown *)p->data)->icon), p->state);
}
void pl_childspacepulldown(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
void plinitpulldown(Panel *v, int flags, Icon *icon, Panel *pullthis, int side){
Pulldown *pp;
pp=v->data;
v->flags=flags|LEAF;
v->draw=pl_drawpulldown;
v->hit=pl_hitpulldown;
v->type=pl_typepulldown;
v->getsize=pl_getsizepulldown;
v->childspace=pl_childspacepulldown;
pp->pull=pullthis;
pp->side=side;
pp->icon=icon;
v->kind="pulldown";
}
Panel *plpulldown(Panel *parent, int flags, Icon *icon, Panel *pullthis, int side){
Panel *v;
v=pl_newpanel(parent, sizeof(Pulldown));
v->state=UP;
((Pulldown *)v->data)->save=0;
plinitpulldown(v, flags, icon, pullthis, side);
return v;
}
Panel *plmenubar(Panel *parent, int flags, int cflags, Icon *l1, Panel *m1, Icon *l2, ...){
Panel *v;
va_list arg;
Icon *s;
int pulldir;
switch(cflags&PACK){
default:
SET(pulldir);
break;
case PACKE:
case PACKW:
pulldir=PACKS;
break;
case PACKN:
case PACKS:
pulldir=PACKE;
break;
}
v=plgroup(parent, flags);
va_start(arg, cflags);
while((s=va_arg(arg, Icon *))!=0)
plpulldown(v, cflags, s, va_arg(arg, Panel *), pulldir);
va_end(arg);
USED(l1, m1, l2);
v->kind="menubar";
return v;
}

View file

@ -0,0 +1,383 @@
/*
* 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 */
static Image *head, *blue;
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;
p=Pt(0,0);
eline=t;
maxwid=0;
while(t){
ascent=0;
descent=0;
indent=space=pl_space(t->indent, 0, 0);
x=0;
tp=t;
for(;;){
if(tp->b){
a=tp->b->r.max.y-tp->b->r.min.y+BORD;
d=BORD;
w=tp->b->repl?wid-x:tp->b->r.max.x-tp->b->r.min.x+BORD*2;
}
else if(tp->p){
/* what if plpack fails? */
plpack(tp->p, Rect(0,0,wid,wid));
plmove(tp->p, subpt(Pt(0,0), tp->p->r.min));
a=tp->p->r.max.y-tp->p->r.min.y;
d=0;
w=tp->p->r.max.x-tp->p->r.min.x;
}
else{
a=tp->font->ascent;
d=tp->font->height-a;
w=tp->wid=stringwidth(tp->font, tp->text);
}
a-=tp->voff,d+=tp->voff;
if(x+w+space>wid) break;
if(a>ascent) ascent=a;
if(d>descent) descent=d;
x+=w+space;
tp=tp->next;
if(tp==0){
eline=0;
break;
}
space=pl_space(tp->space, x, indent);
if(space) eline=tp;
}
if(eline==t){ /* No progress! Force fit the first block! */
if(tp==t){
if(a>ascent) ascent=a;
if(d>descent) descent=d;
eline=tp->next;
}else
eline=tp;
}
topy=p.y;
p.y+=ascent;
p.x=indent=pl_space(t->indent, 0, 0);
for(;;){
t->topy=topy;
t->r.min.x=p.x;
p.y+=t->voff;
if(t->b){
t->r.max.y=p.y+BORD;
t->r.min.y=p.y-(t->b->r.max.y-t->b->r.min.y)-BORD;
p.x+=t->b->repl?wid-p.x:(t->b->r.max.x-t->b->r.min.x)+BORD*2;
}
else if(t->p){
t->r.max.y=p.y;
t->r.min.y=p.y-t->p->r.max.y;
p.x+=t->p->r.max.x;
}
else{
t->r.min.y=p.y-t->font->ascent;
t->r.max.y=t->r.min.y+t->font->height;
p.x+=t->wid;
}
p.y-=t->voff;
t->r.max.x=p.x;
t->nextline=eline;
t=t->next;
if(t==eline) break;
p.x+=pl_space(t->space, p.x, indent);
}
if(p.x>maxwid) maxwid=p.x;
p.y+=descent+LEAD;
}
return Pt(maxwid, p.y);
}
/*
* 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_HOT) border(b, dr, 1, display->black, ZP);
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_HEAD){
if(head==nil)
head=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
string(b, dr.min, head, ZP, t->font, t->text);
}else if(t->flags&PL_HOT){
if(blue==nil)
blue=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x0000FFFF);
string(b, dr.min, 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;
/*if(t->flags&PL_HOT){
int y = dr.max.y - 1;
if(lp.y != y)
lp = Pt(dr.min.x, y);
line(b, lp, Pt(dr.max.x, y),
Endsquare, Endsquare, 0,
display->black, ZP);
lp = Pt(dr.max.x, y);
} else*/
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;
if(dir==VERT){
d=oldoffs.y-offs.y;
size=r.max.y-r.min.y;
if(d>=size || -d>=size) /* move more than screenful */
pl_rtdraw(b, r, t, offs);
else if(d<0){ /* down */
pl_reposition(t, b, r.min,
Rect(r.min.x, r.min.y-d, r.max.x, r.max.y));
pl_rtdraw(b, Rect(r.min.x, r.max.y+d, r.max.x, r.max.y),
t, Pt(offs.x, offs.y+size+d));
}
else if(d>0){ /* up */
pl_reposition(t, b, Pt(r.min.x, r.min.y+d),
Rect(r.min.x, r.min.y, r.max.x, r.max.y-d));
pl_rtdraw(b, Rect(r.min.x, r.min.y, r.max.x, r.min.y+d),
t, offs);
}
}else{ /* dir==HORIZ */
d=oldoffs.x-offs.x;
size=r.max.x-r.min.x;
if(d>=size || -d>=size) /* move more than screenful */
pl_rtdraw(b, r, t, offs);
else if(d<0){ /* right */
pl_reposition(t, b, r.min,
Rect(r.min.x-d, r.min.y, r.max.x, r.max.y));
pl_rtdraw(b, Rect(r.max.x+d, r.min.y, r.max.x, r.max.y),
t, Pt(offs.x+size+d, offs.y));
}
else if(d>0){ /* left */
pl_reposition(t, b, Pt(r.min.x+d, r.min.y),
Rect(r.min.x, r.min.y, r.max.x-d, r.max.y));
pl_rtdraw(b, Rect(r.min.x, r.min.y, r.min.x+d, r.max.y),
t, offs);
}
}
}
Rtext *pl_rthit(Rtext *t, Point offs, Point p, Point ul){
Rectangle r;
Point lp;
if(t==0) return 0;
p.x+=offs.x-ul.x;
p.y+=offs.y-ul.y;
while(t->nextline && t->nextline->topy<=p.y) t=t->nextline;
lp=ZP;
for(;t!=0;t=t->next){
if(t->topy>p.y) return 0;
r = t->r;
if((t->flags&PL_HOT) != 0 && t->b == nil && t->p == nil){
if(lp.y == r.max.y && lp.x < r.min.x)
r.min.x=lp.x;
lp=r.max;
} else
lp=ZP;
if(ptinrect(p, r)) return t;
}
return 0;
}
void plrtseltext(Rtext *t, Rtext *s, Rtext *e){
while(t){
t->flags &= ~PL_SEL;
t = t->next;
}
if(s==0 || e==0)
return;
for(t=s; t!=0 && t!=e; t=t->next)
;
if(t==e){
for(t=s; t!=e; t=t->next)
t->flags |= PL_SEL;
}else{
for(t=e; t!=s; t=t->next)
t->flags |= PL_SEL;
}
t->flags |= PL_SEL;
}
char *plrtsnarftext(Rtext *w){
char *b, *p, *e, *t;
int n;
b=p=e=0;
for(; w; w = w->next){
if((w->flags&PL_SEL)==0 || w->text==0)
continue;
n = strlen(w->text)+64;
if(p+n >= e){
n = (p+n+64)-b;
t = pl_erealloc(b, n);
p = t+(p-b);
e = t+n;
b = t;
}
if(w->space == 0)
p += sprint(p, "%s", w->text);
else if(w->space > 0)
p += sprint(p, " %s", w->text);
else if(PL_OP(w->space) == PL_TAB)
p += sprint(p, "\t%s", w->text);
if(w->nextline == w->next)
p += sprint(p, "\n");
}
return b;
}

View file

@ -0,0 +1,11 @@
/*
* Rtext definitions
*/
#define PL_NOPBIT 4
#define PL_NARGBIT 12
#define PL_ARGMASK ((1<<PL_NARGBIT)-1)
#define PL_SPECIAL(op) (((-1<<PL_NOPBIT)|op)<<PL_NARGBIT)
#define PL_OP(t) ((t)&~PL_ARGMASK)
#define PL_ARG(t) ((t)&PL_ARGMASK)
#define PL_TAB PL_SPECIAL(0) /* # of tab stops before text */
void pltabsize(int, int); /* set min tab and tab size */

View file

@ -0,0 +1,65 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
Panel *root, *list;
char *genlist(Panel *, int which){
static char buf[7];
if(which<0 || 26<=which) return 0;
sprint(buf, "item %c", which+'a');
return buf;
}
void hitgen(Panel *p, int buttons, int sel){
USED(p, buttons, sel);
}
void ereshaped(Rectangle r){
screen.r=r;
r=inset(r, 4);
plpack(root, r);
bitblt(&screen, screen.r.min, &screen, screen.r, Zero);
pldraw(root, &screen);
}
void done(Panel *p, int buttons){
USED(p, buttons);
bitblt(&screen, screen.r.min, &screen, screen.r, Zero);
exits(0);
}
Panel *msg;
void message(char *s, ...){
char buf[1024], *out;
va_list arg;
va_start(arg, s);
out = doprint(buf, buf+sizeof(buf), s, arg);
va_end(arg);
*out='\0';
plinitlabel(msg, PACKN|FILLX, buf);
pldraw(msg, &screen);
}
Scroll s;
void save(Panel *p, int buttons){
USED(p, buttons);
s=plgetscroll(list);
message("save %d %d %d %d", s);
}
void revert(Panel *p, int buttons){
USED(p, buttons);
plsetscroll(list, s, &screen);
message("revert %d %d %d %d", s);
}
void main(void){
Panel *g;
binit(0,0,0);
einit(Emouse);
plinit(screen.ldepth);
root=plgroup(0, 0);
g=plgroup(root, PACKN|EXPAND);
list=pllist(g, PACKE|EXPAND, genlist, 8, hitgen);
plscroll(list, 0, plscrollbar(g, PACKW));
msg=pllabel(root, PACKN|FILLX, "");
plbutton(root, PACKW, "save", save);
plbutton(root, PACKW, "revert", revert);
plbutton(root, PACKE, "done", done);
ereshaped(screen.r);
for(;;) plmouse(root, emouse(), &screen);
}

View file

@ -0,0 +1,21 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void plscroll(Panel *scrollee, Panel *xscroller, Panel *yscroller){
scrollee->xscroller=xscroller;
scrollee->yscroller=yscroller;
if(xscroller) xscroller->scrollee=scrollee;
if(yscroller) yscroller->scrollee=scrollee;
}
Scroll plgetscroll(Panel *p){
return p->scr;
}
void plsetscroll(Panel *p, Scroll s){
if(p->scroll){
if(s.size.x) p->scroll(p, HORIZ, 2, s.pos.x, s.size.x);
if(s.size.y) p->scroll(p, VERT, 2, s.pos.y, s.size.y);
}
}

View file

@ -0,0 +1,146 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Scrollbar Scrollbar;
struct Scrollbar{
int dir; /* HORIZ or VERT */
int lo, hi; /* setting, in screen coordinates */
int buttons; /* saved mouse buttons for transmittal to scrollee */
Rectangle interior;
Point minsize;
};
#define SBWID 8 /* should come from draw.c? */
void pl_drawscrollbar(Panel *p){
Scrollbar *sp;
sp=p->data;
sp->interior=pl_outline(p->b, p->r, p->state);
pl_sliderupd(p->b, sp->interior, sp->dir, sp->lo, sp->hi);
}
int pl_hitscrollbar(Panel *g, Mouse *m){
int oldstate, pos, len, dy;
Point ul, size;
Scrollbar *sp;
sp=g->data;
ul=g->r.min;
size=subpt(g->r.max, g->r.min);
pl_interior(g->state, &ul, &size);
oldstate=g->state;
if(!(g->flags & USERFL) && (m->buttons&OUT || !ptinrect(m->xy, g->r))){
m->buttons&=~OUT;
g->state=UP;
goto out;
}
if(sp->dir==HORIZ){
pos=m->xy.x-ul.x;
len=size.x;
}
else{
pos=m->xy.y-ul.y;
len=size.y;
}
if(pos<0) pos=0;
else if(pos>len) pos=len;
if(m->buttons&7){
g->state=DOWN;
sp->buttons=m->buttons;
switch(m->buttons){
case 1:
dy=pos*(sp->hi-sp->lo)/len;
pl_sliderupd(g->b, sp->interior, sp->dir, sp->lo-dy,
sp->hi-dy);
break;
case 2:
if(g->scrollee && g->scrollee->scroll)
g->scrollee->scroll(g->scrollee, sp->dir,
m->buttons, pos, len);
break;
case 4:
dy=pos*(sp->hi-sp->lo)/len;
pl_sliderupd(g->b, sp->interior, sp->dir, sp->lo+dy,
sp->hi+dy);
break;
}
}
else{
if(!(sp->buttons&2) && g->state==DOWN && g->scrollee && g->scrollee->scroll)
g->scrollee->scroll(g->scrollee, sp->dir, sp->buttons,
pos, len);
g->state=UP;
}
out:
if(oldstate!=g->state) pldraw(g, g->b);
return g->state==DOWN;
}
void pl_typescrollbar(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizescrollbar(Panel *p, Point children){
USED(children);
return pl_boxsize(((Scrollbar *)p->data)->minsize, p->state);
}
void pl_childspacescrollbar(Panel *p, Point *ul, Point *size){
USED(p, ul, size);
}
/*
* Arguments lo, hi and len are in the scrollee's natural coordinates
*/
void pl_setscrollbarscrollbar(Panel *p, int lo, int hi, int len){
Point ul, size;
int mylen;
Scrollbar *sp;
sp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
mylen=sp->dir==HORIZ?size.x:size.y;
if(len==0) len=1;
sp->lo=lo*mylen/len;
sp->hi=hi*mylen/len;
if(sp->lo<0) sp->lo=0;
if(sp->lo>=mylen) sp->hi=mylen-1;
if(sp->hi<=sp->lo) sp->hi=sp->lo+1;
if(sp->hi>mylen) sp->hi=mylen;
pldraw(p, p->b);
}
int pl_priscrollbar(Panel *, Point){
return PRI_SCROLLBAR;
}
void plinitscrollbar(Panel *v, int flags){
Scrollbar *sp;
sp=v->data;
v->flags=flags|LEAF;
v->pri=pl_priscrollbar;
v->state=UP;
v->draw=pl_drawscrollbar;
v->hit=pl_hitscrollbar;
v->type=pl_typescrollbar;
v->getsize=pl_getsizescrollbar;
v->childspace=pl_childspacescrollbar;
v->setscrollbar=pl_setscrollbarscrollbar;
switch(flags&PACK){
case PACKN:
case PACKS:
sp->dir=HORIZ;
sp->minsize=Pt(0, SBWID);
v->flags|=FILLX;
break;
case PACKE:
case PACKW:
sp->dir=VERT;
sp->minsize=Pt(SBWID, 0);
v->flags|=FILLY;
break;
}
sp->lo=0;
sp->hi=0;
v->kind="scrollbar";
}
Panel *plscrollbar(Panel *parent, int flags){
Panel *v;
v=pl_newpanel(parent, sizeof(Scrollbar));
plinitscrollbar(v, flags);
return v;
}

View file

@ -0,0 +1,97 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Slider Slider;
struct Slider{
int dir; /* HORIZ or VERT */
int val; /* setting, in screen coordinates */
Point minsize;
void (*hit)(Panel *, int, int, int); /* call back to user when slider changes */
int buttons;
};
void pl_drawslider(Panel *p){
Rectangle r;
Slider *sp;
sp=p->data;
r=pl_box(p->b, p->r, UP);
switch(sp->dir){
case HORIZ: pl_sliderupd(p->b, r, sp->dir, 0, sp->val); break;
case VERT: pl_sliderupd(p->b, r, sp->dir, r.max.y-sp->val, r.max.y); break;
}
}
int pl_hitslider(Panel *p, Mouse *m){
int oldstate, oldval, len;
Point ul, size;
Slider *sp;
sp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
oldstate=p->state;
oldval=sp->val;
SET(len);
if(m->buttons&OUT)
p->state=UP;
else if(m->buttons&7){
p->state=DOWN;
sp->buttons=m->buttons;
if(sp->dir==HORIZ){
sp->val=m->xy.x-ul.x;
len=size.x;
}
else{
sp->val=ul.y+size.y-m->xy.y;
len=size.y;
}
if(sp->val<0) sp->val=0;
else if(sp->val>len) sp->val=len;
}
else /* mouse inside, but no buttons down */
p->state=UP;
if(oldval!=sp->val || oldstate!=p->state) pldraw(p, p->b);
if(oldval!=sp->val && sp->hit) sp->hit(p, sp->buttons, sp->val, len);
return 0;
}
void pl_typeslider(Panel *p, Rune c){
USED(p, c);
}
Point pl_getsizeslider(Panel *p, Point children){
USED(children);
return pl_boxsize(((Slider *)p->data)->minsize, p->state);
}
void pl_childspaceslider(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void plinitslider(Panel *v, int flags, Point size, void (*hit)(Panel *, int, int, int)){
Slider *sp;
sp=v->data;
v->r=Rect(0,0,size.x,size.y);
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawslider;
v->hit=pl_hitslider;
v->type=pl_typeslider;
v->getsize=pl_getsizeslider;
v->childspace=pl_childspaceslider;
sp->minsize=size;
sp->dir=size.x>size.y?HORIZ:VERT;
sp->hit=hit;
v->kind="slider";
}
Panel *plslider(Panel *parent, int flags, Point size, void (*hit)(Panel *, int, int, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Slider));
plinitslider(p, flags, size, hit);
return p;
}
void plsetslider(Panel *p, int value, int range){
Slider *sp;
sp=p->data;
if(value<0) value=0;
else if(value>range) value=range;
if(sp->dir==HORIZ) sp->val=value*(p->r.max.x-p->r.min.x)/range;
else sp->val=value*(p->r.max.y-p->r.min.y)/range;
}

View file

@ -0,0 +1,58 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
void plputsnarf(char *s){
int fd;
if(s==0 || *s=='\0')
return;
if((fd=open("/dev/snarf", OWRITE|OTRUNC))>=0){
write(fd, s, strlen(s));
close(fd);
}
}
char *plgetsnarf(void){
int fd, n, r;
char *s;
if((fd=open("/dev/snarf", OREAD))<0)
return nil;
n=0;
s=nil;
for(;;){
s=pl_erealloc(s, n+1024);
if((r = read(fd, s+n, 1024)) <= 0)
break;
n += r;
}
close(fd);
if(n <= 0){
free(s);
return nil;
}
s[n] = '\0';
return s;
}
void plsnarf(Panel *p){
char *s;
if(p==0 || p->snarf==0)
return;
s=p->snarf(p);
plputsnarf(s);
free(s);
}
void plpaste(Panel *p){
char *s;
if(p==0 || p->paste==0)
return;
if(s=plgetsnarf()){
p->paste(p, s);
free(s);
}
}

View file

@ -0,0 +1,250 @@
/*
* Fonted text viewer, calls out to code in rtext.c
*
* Should redo this to copy the already-visible parts on scrolling & only
* update the newly appearing stuff -- then the offscreen assembly bitmap can go away.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Textview Textview;
struct Textview{
void (*hit)(Panel *, int, Rtext *); /* call back to user on hit */
Rtext *text; /* text */
Point offs; /* offset of left/top of screen */
Rtext *hitword; /* text to hilite */
Rtext *hitfirst; /* first word in range select */
int twid; /* text width (visible) */
int thgt; /* text height (total) */
int maxwid; /* width of longest line */
Point minsize; /* smallest acceptible window size */
int buttons;
};
void pl_setscrpos(Panel *p, Textview *tp, Rectangle r){
Panel *sb;
int lo, hi;
lo=tp->offs.y;
hi=lo+r.max.y-r.min.y; /* wrong? */
sb=p->yscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, lo, hi, tp->thgt);
lo=tp->offs.x;
hi=lo+r.max.x-r.min.x;
sb=p->xscroller;
if(sb && sb->setscrollbar)
sb->setscrollbar(sb, lo, hi, tp->maxwid);
}
void pl_drawtextview(Panel *p){
int twid;
Rectangle r;
Textview *tp;
Point size;
tp=p->data;
r=pl_outline(p->b, p->r, UP);
twid=r.max.x-r.min.x;
if(twid!=tp->twid){
tp->twid=twid;
size=pl_rtfmt(tp->text, tp->twid);
p->scr.size.x=tp->maxwid=size.x;
p->scr.size.y=tp->thgt=size.y;
}
p->scr.pos = tp->offs;
pl_rtdraw(p->b, r, tp->text, tp->offs);
pl_setscrpos(p, tp, r);
}
/*
* If t is a panel word, pass the mouse event on to it
*/
void pl_passon(Rtext *t, Mouse *m){
if(t && t->b==0 && t->p!=0)
plmouse(t->p, m);
}
int pl_hittextview(Panel *p, Mouse *m){
Rtext *oldhitword, *oldhitfirst;
int hitme, oldstate;
Point ul, size;
Textview *tp;
tp=p->data;
hitme=0;
oldstate=p->state;
oldhitword=tp->hitword;
oldhitfirst=tp->hitfirst;
if(oldhitword==oldhitfirst)
pl_passon(oldhitword, m);
if(m->buttons&OUT)
p->state=UP;
else if(m->buttons&7){
p->state=DOWN;
tp->buttons=m->buttons;
if(oldhitword==0 || oldhitword->p==0 || (oldhitword->p->flags&REMOUSE)==0){
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
tp->hitword=pl_rthit(tp->text, tp->offs, m->xy, ul);
if(tp->hitword==0)
if(oldhitword!=0 && oldstate==DOWN)
tp->hitword=oldhitword;
else
tp->hitfirst=0;
if(tp->hitword!=0 && oldstate!=DOWN)
tp->hitfirst=tp->hitword;
}
}
else{
if(p->state==DOWN) hitme=1;
p->state=UP;
}
if(tp->hitfirst!=oldhitfirst || tp->hitword!=oldhitword){
plrtseltext(tp->text, tp->hitword, tp->hitfirst);
pl_drawtextview(p);
if(tp->hitword==tp->hitfirst)
pl_passon(tp->hitword, m);
}
if(hitme && tp->hit && tp->hitword!=0 && tp->hitword==tp->hitfirst){
plrtseltext(tp->text, 0, 0);
pl_drawtextview(p);
tp->hit(p, tp->buttons, tp->hitword);
tp->hitword=0;
tp->hitfirst=0;
}
return 0;
}
void pl_scrolltextview(Panel *p, int dir, int buttons, int num, int den){
int xoffs, yoffs;
Point ul, size;
Textview *tp;
Rectangle r;
tp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
if(dir==VERT){
switch(buttons){
default:
SET(yoffs);
break;
case 1: /* left -- top moves to pointer */
yoffs=(vlong)tp->offs.y-num*size.y/den;
if(yoffs<0) yoffs=0;
break;
case 2: /* middle -- absolute index of file */
yoffs=(vlong)tp->thgt*num/den;
break;
case 4: /* right -- line pointed at moves to top */
yoffs=tp->offs.y+(vlong)num*size.y/den;
if(yoffs>tp->thgt) yoffs=tp->thgt;
break;
}
if(yoffs!=tp->offs.y){
r=pl_outline(p->b, p->r, p->state);
pl_rtredraw(p->b, r, tp->text,
Pt(tp->offs.x, yoffs), tp->offs, dir);
p->scr.pos.y=tp->offs.y=yoffs;
pl_setscrpos(p, tp, r);
}
}else{ /* dir==HORIZ */
switch(buttons){
default:
SET(xoffs);
break;
case 1: /* left */
xoffs=(vlong)tp->offs.x-num*size.x/den;
if(xoffs<0) xoffs=0;
break;
case 2: /* middle */
xoffs=(vlong)tp->maxwid*num/den;
break;
case 4: /* right */
xoffs=tp->offs.x+(vlong)num*size.x/den;
if(xoffs>tp->maxwid) xoffs=tp->maxwid;
break;
}
if(xoffs!=tp->offs.x){
r=pl_outline(p->b, p->r, p->state);
pl_rtredraw(p->b, r, tp->text,
Pt(xoffs, tp->offs.y), tp->offs, dir);
p->scr.pos.x=tp->offs.x=xoffs;
pl_setscrpos(p, tp, r);
}
}
}
void pl_typetextview(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizetextview(Panel *p, Point children){
USED(children);
return pl_boxsize(((Textview *)p->data)->minsize, p->state);
}
void pl_childspacetextview(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
/*
* Priority depends on what thing inside the panel we're pointing at.
*/
int pl_pritextview(Panel *p, Point xy){
Point ul, size;
Textview *tp;
Rtext *h;
tp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
h=pl_rthit(tp->text, tp->offs, xy, ul);
if(h && h->b==0 && h->p!=0){
p=pl_ptinpanel(xy, h->p);
if(p) return p->pri(p, xy);
}
return PRI_NORMAL;
}
char* pl_snarftextview(Panel *p){
return plrtsnarftext(((Textview *)p->data)->text);
}
void plinittextview(Panel *v, int flags, Point minsize, Rtext *t, void (*hit)(Panel *, int, Rtext *)){
Textview *tp;
tp=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawtextview;
v->hit=pl_hittextview;
v->type=pl_typetextview;
v->getsize=pl_getsizetextview;
v->childspace=pl_childspacetextview;
v->kind="textview";
v->pri=pl_pritextview;
tp->hit=hit;
tp->minsize=minsize;
tp->text=t;
tp->offs=ZP;
tp->hitfirst=0;
tp->hitword=0;
v->scroll=pl_scrolltextview;
v->snarf=pl_snarftextview;
tp->twid=-1;
tp->maxwid=0;
v->scr.pos=Pt(0,0);
v->scr.size=Pt(0,1);
}
Panel *pltextview(Panel *parent, int flags, Point minsize, Rtext *t, void (*hit)(Panel *, int, Rtext *)){
Panel *v;
v=pl_newpanel(parent, sizeof(Textview));
plinittextview(v, flags, minsize, t, hit);
return v;
}
int plgetpostextview(Panel *p){
return ((Textview *)p->data)->offs.y;
}
void plsetpostextview(Panel *p, int yoffs){
((Textview *)p->data)->offs.y=yoffs;
pldraw(p, p->b);
}

View file

@ -0,0 +1,474 @@
/*
* Text windows
* void twhilite(Textwin *t, int sel0, int sel1, int on)
* hilite (on=1) or unhilite (on=0) a range of characters
* void twselect(Textwin *t, Mouse *m)
* set t->sel0, t->sel1 from mouse input.
* Also hilites selection.
* Caller should first unhilite previous selection.
* void twreplace(Textwin *t, int r0, int r1, Rune *ins, int nins)
* Replace the given range of characters with the given insertion.
* Caller should unhilite selection while this is called.
* void twscroll(Textwin *t, int top)
* Character with index top moves to the top line of the screen.
* int twpt2rune(Textwin *t, Point p)
* which character is displayed at point p?
* void twreshape(Textwin *t, Rectangle r)
* save r and redraw the text
* Textwin *twnew(Bitmap *b, Font *f, Rune *text, int ntext)
* create a new text window
* void twfree(Textwin *t)
* get rid of a surplus Textwin
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#define SLACK 100
/*
* Is text at point a before or after that at point b?
*/
int tw_before(Textwin *t, Point a, Point b){
return a.y<b.y || a.y<b.y+t->hgt && a.x<b.x;
}
/*
* Return the character index indicated by point p, or -1
* if its off-screen. The screen must be up-to-date.
*
* Linear search should be binary search.
*/
int twpt2rune(Textwin *t, Point p){
Point *el, *lp;
el=t->loc+(t->bot-t->top);
for(lp=t->loc;lp!=el;lp++)
if(tw_before(t, p, *lp)){
if(lp==t->loc) return t->top;
return lp-t->loc+t->top-1;
}
return t->bot;
}
/*
* Return ul corner of the character with the given index
*/
Point tw_rune2pt(Textwin *t, int i){
if(i<t->top) return t->r.min;
if(i>t->bot) return t->r.max;
return t->loc[i-t->top];
}
/*
* Store p at t->loc[l], extending t->loc if necessary
*/
void tw_storeloc(Textwin *t, int l, Point p){
int nloc;
if(l>=t->eloc-t->loc){
nloc=l+SLACK;
t->loc=pl_erealloc(t->loc, nloc*sizeof(Point));
t->eloc=t->loc+nloc;
}
t->loc[l]=p;
}
/*
* Set the locations at which the given runes should appear.
* Returns the index of the first rune not set, which might not
* be last because we reached the bottom of the window.
*
* N.B. this zaps the loc of r[last], so that value should be saved first,
* if it's important.
*/
int tw_setloc(Textwin *t, int first, int last, Point ul){
Rune *r, *er;
int x, dt, lp;
char buf[UTFmax+1];
er=t->text+last;
for(r=t->text+first,lp=first-t->top;r!=er && ul.y+t->hgt<=t->r.max.y;r++,lp++){
tw_storeloc(t, lp, ul);
switch(*r){
case '\n':
ul.x=t->r.min.x;
ul.y+=t->hgt;
break;
case '\t':
x=ul.x-t->r.min.x+t->mintab+t->tabstop;
x-=x%t->tabstop;
ul.x=x+t->r.min.x;
if(ul.x>t->r.max.x){
ul.x=t->r.min.x;
ul.y+=t->hgt;
tw_storeloc(t, lp, ul);
if(ul.y+t->hgt>t->r.max.y) return r-t->text;
ul.x+=+t->tabstop;
}
break;
default:
buf[runetochar(buf, r)]='\0';
dt=stringwidth(t->font, buf);
ul.x+=dt;
if(ul.x>t->r.max.x){
ul.x=t->r.min.x;
ul.y+=t->hgt;
tw_storeloc(t, lp, ul);
if(ul.y+t->hgt>t->r.max.y) return r-t->text;
ul.x+=dt;
}
break;
}
}
tw_storeloc(t, lp, ul);
return r-t->text;
}
/*
* Draw the given runes at their locations.
* Bug -- saving up multiple characters would
* reduce the number of calls to string,
* and probably make this a lot faster.
*/
void tw_draw(Textwin *t, int first, int last){
Rune *r, *er;
Point *lp, ul, ur;
char buf[UTFmax+1];
if(first<t->top) first=t->top;
if(last>t->bot) last=t->bot;
if(last<=first) return;
er=t->text+last;
for(r=t->text+first,lp=t->loc+(first-t->top);r!=er;r++,lp++){
if(lp->y+t->hgt>t->r.max.y){
fprint(2, "chr %C, index %ld of %d, loc %d %d, off bottom\n",
*r, lp-t->loc, t->bot-t->top, lp->x, lp->y);
return;
}
switch(*r){
case '\n':
ur=*lp;
break;
case '\t':
ur=*lp;
if(lp[1].y!=lp[0].y)
ul=Pt(t->r.min.x, lp[1].y);
else
ul=*lp;
pl_clr(t->b, Rpt(ul, Pt(lp[1].x, ul.y+t->hgt)));
break;
default:
buf[runetochar(buf, r)]='\0';
/***/ pl_clr(t->b, Rpt(*lp, addpt(*lp, stringsize(t->font, buf))));
ur=string(t->b, *lp, display->black, ZP, t->font, buf);
break;
}
if(lp[1].y!=lp[0].y)
/***/ pl_clr(t->b, Rpt(ur, Pt(t->r.max.x, ur.y+t->hgt)));
}
}
/*
* Hilight the characters with tops between ul and ur
*/
void tw_hilitep(Textwin *t, Point ul, Point ur){
Point swap;
int y;
if(tw_before(t, ur, ul)){ swap=ul; ul=ur; ur=swap;}
y=ul.y+t->hgt;
if(y>t->r.max.y) y=t->r.max.y;
if(ul.y==ur.y)
pl_highlight(t->b, Rpt(ul, Pt(ur.x, y)));
else{
pl_highlight(t->b, Rpt(ul, Pt(t->r.max.x, y)));
ul=Pt(t->r.min.x, y);
pl_highlight(t->b, Rpt(ul, Pt(t->r.max.x, ur.y)));
ul=Pt(t->r.min.x, ur.y);
y=ur.y+t->hgt;
if(y>t->r.max.y) y=t->r.max.y;
pl_highlight(t->b, Rpt(ul, Pt(ur.x, y)));
}
}
/*
* Hilite/unhilite the given range of characters
*/
void twhilite(Textwin *t, int sel0, int sel1, int on){
Point ul, ur;
int swap, y;
if(sel1<sel0){ swap=sel0; sel0=sel1; sel1=swap; }
if(sel1<t->top || t->bot<sel0) return;
if(sel0<t->top) sel0=t->top;
if(sel1>t->bot) sel1=t->bot;
if(!on){
if(sel1==sel0){
ul=t->loc[sel0-t->top];
y=ul.y+t->hgt;
if(y>t->r.max.y) y=t->r.max.y;
pl_clr(t->b, Rpt(ul, Pt(ul.x+1, y)));
}else
tw_draw(t, sel0, sel1);
return;
}
ul=t->loc[sel0-t->top];
if(sel1==sel0)
ur=addpt(ul, Pt(1, 0));
else
ur=t->loc[sel1-t->top];
tw_hilitep(t, ul, ur);
}
/*
* Set t->sel[01] from mouse input.
* Also hilites the selection.
* Caller should unhilite the previous
* selection before calling this.
*/
void twselect(Textwin *t, Mouse *m){
int sel0, sel1, newsel;
Point p0, p1, newp;
sel0=sel1=twpt2rune(t, m->xy);
p0=tw_rune2pt(t, sel0);
p1=addpt(p0, Pt(1, 0));
twhilite(t, sel0, sel1, 1);
for(;;){
if(display->bufp > display->buf)
flushimage(display, 1);
*m=emouse();
if((m->buttons&7)!=1) break;
newsel=twpt2rune(t, m->xy);
newp=tw_rune2pt(t, newsel);
if(eqpt(newp, p0)) newp=addpt(newp, Pt(1, 0));
if(!eqpt(newp, p1)){
if((sel0<=sel1 && sel1<newsel) || (newsel<sel1 && sel1<sel0))
tw_hilitep(t, p1, newp);
else if((sel0<=newsel && newsel<sel1) || (sel1<newsel && newsel<=sel0)){
twhilite(t, sel1, newsel, 0);
if(newsel==sel0)
tw_hilitep(t, p0, newp);
}else if((newsel<sel0 && sel0<=sel1) || (sel1<sel0 && sel0<=newsel)){
twhilite(t, sel0, sel1, 0);
tw_hilitep(t, p0, newp);
}
sel1=newsel;
p1=newp;
}
}
if(sel0<=sel1){
t->sel0=sel0;
t->sel1=sel1;
}
else{
t->sel0=sel1;
t->sel1=sel0;
}
}
/*
* Clear the area following the last displayed character
*/
void tw_clrend(Textwin *t){
Point ul;
int y;
ul=t->loc[t->bot-t->top];
y=ul.y+t->hgt;
if(y>t->r.max.y) y=t->r.max.y;
pl_clr(t->b, Rpt(ul, Pt(t->r.max.x, y)));
ul=Pt(t->r.min.x, y);
pl_clr(t->b, Rpt(ul, t->r.max));
}
/*
* Move part of a line of text, truncating the source or padding
* the destination on the right if necessary.
*/
void tw_moverect(Textwin *t, Point uld, Point urd, Point uls, Point urs){
int sw, dw, d;
if(urs.y!=uls.y) urs=Pt(t->r.max.x, uls.y);
if(urd.y!=uld.y) urd=Pt(t->r.max.x, uld.y);
sw=uls.x-urs.x;
dw=uld.x-urd.x;
if(dw>sw){
d=dw-sw;
pl_clr(t->b, Rect(urd.x-d, urd.y, urd.x, urd.y+t->hgt));
dw=sw;
}
pl_cpy(t->b, uld, Rpt(uls, Pt(uls.x+dw, uls.y+t->hgt)));
}
/*
* Move a block of characters up or to the left:
* Identify contiguous runs of characters whose width doesn't change, and
* move them in one bitblt per run.
* If we get to a point where source and destination are x-aligned,
* they will remain x-aligned for the rest of the block.
* Then, if they are y-aligned, they're already in the right place.
* Otherwise, we can move them in three bitblts; one if all the
* remaining characters are on one line.
*/
void tw_moveup(Textwin *t, Point *dp, Point *sp, Point *esp){
Point uld, uls; /* upper left of destination/source */
int y;
while(sp!=esp && sp->x!=dp->x){
uld=*dp;
uls=*sp;
while(sp!=esp && sp->y==uls.y && dp->y==uld.y && sp->x-uls.x==dp->x-uld.x){
sp++;
dp++;
}
tw_moverect(t, uld, *dp, uls, *sp);
}
if(sp==esp || esp->y==dp->y) return;
if(esp->y==sp->y){ /* one line only */
pl_cpy(t->b, *dp, Rpt(*sp, Pt(esp->x, sp->y+t->hgt)));
return;
}
y=sp->y+t->hgt;
pl_cpy(t->b, *dp, Rpt(*sp, Pt(t->r.max.x, y)));
pl_cpy(t->b, Pt(t->r.min.x, dp->y+t->hgt),
Rect(t->r.min.x, y, t->r.max.x, esp->y));
y=dp->y+esp->y-sp->y;
pl_cpy(t->b, Pt(t->r.min.x, y),
Rect(t->r.min.x, esp->y, esp->x, esp->y+t->hgt));
}
/*
* Same as above, but moving down and in reverse order, so as not to overwrite stuff
* not moved yet.
*/
void tw_movedn(Textwin *t, Point *dp, Point *bsp, Point *esp){
Point *sp, urs, urd;
int dy;
dp+=esp-bsp;
sp=esp;
dy=dp->y-sp->y;
while(sp!=bsp && dp[-1].x==sp[-1].x){
--dp;
--sp;
}
if(dy!=0){
if(sp->y==esp->y)
pl_cpy(t->b, *dp, Rect(sp->x, sp->y, esp->x, esp->y+t->hgt));
else{
pl_cpy(t->b, Pt(t->r.min.x, sp->x+dy),
Rect(t->r.min.x, sp->y, esp->x, esp->y+t->hgt));
pl_cpy(t->b, Pt(t->r.min.x, dp->y+t->hgt),
Rect(t->r.min.x, sp->y+t->hgt, t->r.max.x, esp->y));
pl_cpy(t->b, *dp,
Rect(sp->x, sp->y, t->r.max.x, sp->y+t->hgt));
}
}
while(sp!=bsp){
urd=*dp;
urs=*sp;
while(sp!=bsp && sp[-1].y==sp[0].y && dp[-1].y==dp[0].y
&& sp[-1].x-sp[0].x==dp[-1].x-dp[0].x){
--sp;
--dp;
}
tw_moverect(t, *dp, urd, *sp, urs);
}
}
/*
* Move the given range of characters, already drawn on
* the given textwin, to the given location.
* Start and end must both index characters that are initially on-screen.
*/
void tw_relocate(Textwin *t, int first, int last, Point dst){
Point *srcloc;
int nbyte;
if(first<t->top || last<first || t->bot<last) return;
nbyte=(last-first+1)*sizeof(Point);
srcloc=pl_emalloc(nbyte);
memmove(srcloc, &t->loc[first-t->top], nbyte);
tw_setloc(t, first, last, dst);
if(tw_before(t, dst, srcloc[0]))
tw_moveup(t, t->loc+first-t->top, srcloc, srcloc+(last-first));
else
tw_movedn(t, t->loc+first-t->top, srcloc, srcloc+(last-first));
}
/*
* Replace the runes with indices from r0 to r1-1 with the text
* pointed to by text, and with length ntext.
* Open up a hole in t->text, t->loc.
* Insert new text, calculate their locs (save the extra loc that's overwritten first)
* (swap saved & overwritten locs)
* move tail.
* calc locs and draw new text after tail, if necessary.
* draw new text, if necessary
*/
void twreplace(Textwin *t, int r0, int r1, Rune *ins, int nins){
int olen, nlen, tlen, dtop;
olen=t->etext-t->text;
nlen=olen+nins-(r1-r0);
tlen=t->eslack-t->text;
if(nlen>tlen){
tlen=nlen+SLACK;
t->text=pl_erealloc(t->text, tlen*sizeof(Rune));
t->eslack=t->text+tlen;
}
if(olen!=nlen)
memmove(t->text+r0+nins, t->text+r1, (olen-r1)*sizeof(Rune));
if(nins!=0) /* ins can be 0 if nins==0 */
memmove(t->text+r0, ins, nins*sizeof(Rune));
t->etext=t->text+nlen;
if(r0>t->bot) /* insertion is completely below visible text */
return;
if(r1<t->top){ /* insertion is completely above visible text */
dtop=nlen-olen;
t->top+=dtop;
t->bot+=dtop;
return;
}
if(1 || t->bot<=r0+nins){ /* no useful text on screen below r0 */
if(r0<=t->top) /* no useful text above, either */
t->top=r0;
t->bot=tw_setloc(t, r0, nlen, t->loc[r0-t->top]);
tw_draw(t, r0, t->bot);
tw_clrend(t);
return;
}
/*
* code for case where there is useful text below is missing (see `1 ||' above)
*/
}
/*
* This works but is stupid.
*/
void twscroll(Textwin *t, int top){
while(top!=0 && t->text[top-1]!='\n') --top;
t->top=top;
t->bot=tw_setloc(t, top, t->etext-t->text, t->r.min);
tw_draw(t, t->top, t->bot);
tw_clrend(t);
}
void twreshape(Textwin *t, Rectangle r){
t->r=r;
t->bot=tw_setloc(t, t->top, t->etext-t->text, t->r.min);
tw_draw(t, t->top, t->bot);
tw_clrend(t);
}
Textwin *twnew(Image *b, Font *f, Rune *text, int ntext){
Textwin *t;
t=pl_emalloc(sizeof(Textwin));
t->text=pl_emalloc((ntext+SLACK)*sizeof(Rune));
t->loc=pl_emalloc(SLACK*sizeof(Point));
t->eloc=t->loc+SLACK;
t->etext=t->text+ntext;
t->eslack=t->etext+SLACK;
if(ntext) memmove(t->text, text, ntext*sizeof(Rune));
t->top=0;
t->bot=0;
t->sel0=0;
t->sel1=0;
t->b=b;
t->font=f;
t->hgt=f->height;
t->mintab=stringwidth(f, "0");
t->tabstop=8*t->mintab;
return t;
}
void twfree(Textwin *t){
free(t->loc);
free(t->text);
free(t);
}
/*
* Correct the character locations in a textwin after the panel is moved.
* This horrid hack would not be necessary if loc values were relative
* to the panel, rather than absolute.
*/
void twmove(Textwin *t, Point d){
Point *lp;
t->r = rectaddpt(t->r, d);
for(lp=t->loc; lp<t->eloc; lp++)
*lp = addpt(*lp, d);
}

View file

@ -0,0 +1,30 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
/*
* This is the same definition that 8½ uses
*/
int pl_idchar(int c){
if(c<=' '
|| 0x7F<=c && c<=0xA0
|| utfrune("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))
return 0;
return 1;
}
int pl_rune1st(int c){
return (c&0xc0)!=0x80;
}
char *pl_nextrune(char *s){
do s++; while(!pl_rune1st(*s));
return s;
}
int pl_runewidth(Font *f, char *s){
char r[4], *t;
t=r;
do *t++=*s++; while(!pl_rune1st(*s));
*t='\0';
return stringwidth(f, r);
}

19
sys/src/cmd/gopher/mkfile Normal file
View file

@ -0,0 +1,19 @@
</$objtype/mkfile
TARG=gopher
LIB=libpanel/libpanel.$O.a
OFILES=gopher.$O
HFILES=dat.h libpanel/panel.h libpanel/rtext.h
BIN=/$objtype/bin/
</sys/src/cmd/mkone
CFLAGS=-FTVw -Ilibpanel
$LIB:V:
cd libpanel
mk
clean nuke:V:
@{ cd libpanel; mk $target }
rm -f *.[$OS] [$OS].out $TARG