ref: 20f2add592f8463ef6820afd07a342acb26da304
parent: b2c2d1ed2a0ce84f3ebe34065d35cec0789653cb
author: stanley lieber <stanley.lieber@gmail.com>
date: Sun Feb 8 08:19:47 EST 2015
mothra: add side scrolling, controlled by left and right buttons on the keyboard. if desired, x-scrollbar can be set visible via the visxbar variable in mothra.c. (thanks, jpm_)
--- a/sys/src/cmd/mothra/libpanel/draw.c
+++ b/sys/src/cmd/mothra/libpanel/draw.c
@@ -243,7 +243,7 @@
}
void pl_draw1(Panel *p, Image *b);
void pl_drawall(Panel *p, Image *b){
- if(p->flags&INVIS) return;
+ 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);
--- a/sys/src/cmd/mothra/libpanel/pack.c
+++ b/sys/src/cmd/mothra/libpanel/pack.c
@@ -97,6 +97,7 @@
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:
--- a/sys/src/cmd/mothra/libpanel/panel.h
+++ b/sys/src/cmd/mothra/libpanel/panel.h
@@ -86,6 +86,8 @@
#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 */
+/* pldefs.h flags 0x08000-0x40000 */
+#define IGNORE 0x080000 /* ignore this panel totally */
#define USERFL 0x100000 /* start of user flag */
/*
--- a/sys/src/cmd/mothra/libpanel/pldefs.h
+++ b/sys/src/cmd/mothra/libpanel/pldefs.h
@@ -5,10 +5,10 @@
* Variable-font text routines
* These could make a separate library.
*/
-int pl_rtfmt(Rtext *, int);
-void pl_rtdraw(Image *, Rectangle, Rtext *, int);
-void pl_rtredraw(Image *, Rectangle, Rtext *, int, int);
-Rtext *pl_rthit(Rtext *, int, Point, Point);
+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 */
--- a/sys/src/cmd/mothra/libpanel/rtext.c
+++ b/sys/src/cmd/mothra/libpanel/rtext.c
@@ -67,14 +67,16 @@
}
/*
* initialize rectangles & nextlines of text starting at t,
- * galley width is wid. Returns the total length of the text
+ * galley width is wid. Returns the total width/height of the text
*/
-int pl_rtfmt(Rtext *t, int wid){
+Point pl_rtfmt(Rtext *t, int wid){
Rtext *tp, *eline;
- int ascent, descent, x, space, a, d, w, topy, indent;
+ 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;
@@ -147,9 +149,10 @@
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 p.y;
+ return Pt(maxwid, p.y);
}
/*
@@ -163,9 +166,9 @@
pl_stuffbitmap(p, b);
}
-void pl_rtdraw(Image *b, Rectangle r, Rtext *t, int yoffs){
+void pl_rtdraw(Image *b, Rectangle r, Rtext *t, Point offs){
static Image *backup;
- Point offs, lp;
+ Point lp;
Rectangle dr;
Image *bb;
@@ -178,11 +181,13 @@
b=backup;
pl_clr(b, r);
lp=ZP;
- offs=subpt(r.min, Pt(0, yoffs));
+ 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.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);
@@ -232,30 +237,51 @@
* 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, int yoffs, int oldoffs){
- int dy, size;
- dy=oldoffs-yoffs;
- size=r.max.y-r.min.y;
- if(dy>=size || -dy>=size)
- pl_rtdraw(b, r, t, yoffs);
- else if(dy<0){
- pl_reposition(t, b, r.min,
- Rect(r.min.x, r.min.y-dy, r.max.x, r.max.y));
- pl_rtdraw(b, Rect(r.min.x, r.max.y+dy, r.max.x, r.max.y),
- t, yoffs+size+dy);
+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);
+ }
}
- else if(dy>0){
- pl_reposition(t, b, Pt(r.min.x, r.min.y+dy),
- Rect(r.min.x, r.min.y, r.max.x, r.max.y-dy));
- pl_rtdraw(b, Rect(r.min.x, r.min.y, r.max.x, r.min.y+dy), t, yoffs);
- }
}
-Rtext *pl_rthit(Rtext *t, int yoffs, Point p, Point ul){
+Rtext *pl_rthit(Rtext *t, Point offs, Point p, Point ul){
Rectangle r;
Point lp;
if(t==0) return 0;
- p.x-=ul.x;
- p.y+=yoffs-ul.y;
+ 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){
--- a/sys/src/cmd/mothra/libpanel/textview.c
+++ b/sys/src/cmd/mothra/libpanel/textview.c
@@ -15,11 +15,12 @@
struct Textview{
void (*hit)(Panel *, int, Rtext *); /* call back to user on hit */
Rtext *text; /* text */
- int yoffs; /* offset of top of screen */
+ Point offs; /* offset of left/top of screen */
Rtext *hitword; /* text to hilite */
Rtext *hitfirst; /* first word in range select */
- int twid; /* text width */
- int thgt; /* text height */
+ int twid; /* text width (visible) */
+ int thgt; /* text height (total) */
+ int maxwid; /* width of longest line */
Point minsize; /* smallest acceptible window size */
int buttons;
};
@@ -27,25 +28,35 @@
void pl_setscrpos(Panel *p, Textview *tp, Rectangle r){
Panel *sb;
int lo, hi;
- lo=tp->yoffs;
+
+ 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);
+ 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;
- tp->thgt=pl_rtfmt(tp->text, tp->twid);
- p->scr.size.y=tp->thgt;
+ 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.y=tp->yoffs;
- pl_rtdraw(p->b, r, tp->text, tp->yoffs);
+ p->scr.pos = tp->offs;
+ pl_rtdraw(p->b, r, tp->text, tp->offs);
pl_setscrpos(p, tp, r);
}
/*
@@ -62,7 +73,6 @@
Textview *tp;
tp=p->data;
-
hitme=0;
oldstate=p->state;
oldhitword=tp->hitword;
@@ -78,7 +88,7 @@
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->yoffs, m->xy, ul);
+ tp->hitword=pl_rthit(tp->text, tp->offs, m->xy, ul);
if(tp->hitword==0)
if(oldhitword!=0 && oldstate==DOWN)
tp->hitword=oldhitword;
@@ -108,38 +118,64 @@
return 0;
}
void pl_scrolltextview(Panel *p, int dir, int buttons, int num, int den){
- int yoffs;
+ int xoffs, yoffs;
Point ul, size;
Textview *tp;
Rectangle r;
- if(dir!=VERT) return;
tp=p->data;
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
- switch(buttons){
- default:
- SET(yoffs);
- break;
- case 1: /* left -- top moves to pointer */
- yoffs=(vlong)tp->yoffs-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->yoffs+(vlong)num*size.y/den;
- if(yoffs>tp->thgt) yoffs=tp->thgt;
- break;
+ 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);
+ }
}
- if(yoffs!=tp->yoffs){
- r=pl_outline(p->b, p->r, p->state);
- pl_rtredraw(p->b, r, tp->text, yoffs, tp->yoffs);
- p->scr.pos.y=tp->yoffs=yoffs;
- pl_setscrpos(p, tp, r);
- }
}
void pl_typetextview(Panel *g, Rune c){
USED(g, c);
@@ -162,7 +198,7 @@
ul=p->r.min;
size=subpt(p->r.max, p->r.min);
pl_interior(p->state, &ul, &size);
- h=pl_rthit(tp->text, tp->yoffs, xy, ul);
+ 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);
@@ -189,12 +225,13 @@
tp->hit=hit;
tp->minsize=minsize;
tp->text=t;
- tp->yoffs=0;
+ 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);
}
@@ -205,9 +242,9 @@
return v;
}
int plgetpostextview(Panel *p){
- return ((Textview *)p->data)->yoffs;
+ return ((Textview *)p->data)->offs.y;
}
void plsetpostextview(Panel *p, int yoffs){
- ((Textview *)p->data)->yoffs=yoffs;
+ ((Textview *)p->data)->offs.y=yoffs;
pldraw(p, p->b);
}
--- a/sys/src/cmd/mothra/mothra.c
+++ b/sys/src/cmd/mothra/mothra.c
@@ -15,6 +15,8 @@
int debug=0;
int verbose=0; /* -v flag causes html errors to be written to file-descriptor 2 */
int defdisplay=1; /* is the default (initial) display visible? */
+int visxbar=0; /* horizontal scrollbar visible? */
+int topxbar=0; /* horizontal scrollbar at top? */
Panel *root; /* the whole display */
Panel *alt; /* the alternate display */
Panel *alttext; /* the alternate text window */
@@ -152,16 +154,46 @@
s.pos.y = s.size.y+dy;
break;
}
- if(s.pos.y < 0)
- s.pos.y = 0;
if(s.pos.y > s.size.y)
s.pos.y = s.size.y;
+ if(s.pos.y < 0)
+ s.pos.y = 0;
plsetscroll(text, s);
}
+void sidescroll(int dx, int whence)
+{
+ Scroll s;
+
+ s = plgetscroll(text);
+ switch(whence){
+ case 0:
+ s.pos.x = dx;
+ break;
+ case 1:
+ s.pos.x += dx;
+ break;
+ case 2:
+ s.pos.x = s.size.x+dx;
+ break;
+ }
+ if(s.pos.x > s.size.x - text->size.x + 5)
+ s.pos.x = s.size.x - text->size.x + 5;
+ if(s.pos.x < 0)
+ s.pos.x = 0;
+ plsetscroll(text, s);
+}
+
void mkpanels(void){
- Panel *p, *bar, *swap;
+ Panel *p, *xbar, *ybar, *swap;
+ int xflags;
+ if(topxbar)
+ xflags=PACKN|USERFL;
+ else
+ xflags=PACKS|USERFL;
+ if(!visxbar)
+ xflags|=IGNORE;
menu3=plmenu(0, 0, buttons, PACKN|FILLX, hit3);
root=plpopup(root, EXPAND, 0, 0, menu3);
p=plgroup(root, PACKN|FILLX);
@@ -170,23 +202,24 @@
pllabel(p, PACKW, "Go:");
cmd=plentry(p, PACKN|FILLX, 0, "", docmd);
p=plgroup(root, PACKN|FILLX);
- bar=plscrollbar(p, PACKW);
+ ybar=plscrollbar(p, PACKW);
list=pllist(p, PACKN|FILLX, genwww, 8, doprev);
- plscroll(list, 0, bar);
+ plscroll(list, 0, ybar);
p=plgroup(root, PACKN|FILLX);
pllabel(p, PACKW, "Url:");
cururl=pllabel(p, PACKE|EXPAND, "---");
plplacelabel(cururl, PLACEW);
p=plgroup(root, PACKN|EXPAND);
- bar=plscrollbar(p, PACKW|USERFL);
+ ybar=plscrollbar(p, PACKW|USERFL);
+ xbar=plscrollbar(p, xflags);
text=pltextview(p, PACKE|EXPAND, Pt(0, 0), 0, dolink);
- plscroll(text, 0, bar);
+ plscroll(text, xbar, ybar);
plgrabkb(cmd);
alt=plpopup(0, PACKE|EXPAND, 0, 0, menu3);
- bar=plscrollbar(alt, PACKW|USERFL);
+ ybar=plscrollbar(alt, PACKW|USERFL);
+ xbar=plscrollbar(alt, xflags);
alttext=pltextview(alt, PACKE|EXPAND, Pt(0, 0), 0, dolink);
- plscroll(alttext, 0, bar);
-
+ plscroll(alttext, xbar, ybar);
if(!defdisplay){
swap=root;
root=alt;
@@ -318,11 +351,11 @@
plinit(screen->depth);
if(debug) notify(dienow);
getfonts();
- hrule=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
+ hrule=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
if(hrule==0)
sysfatal("can't allocimage!");
- draw(hrule, Rect(0,1,1280,3), display->black, 0, ZP);
- linespace=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
+ draw(hrule, Rect(0,1,1,3), display->black, 0, ZP);
+ linespace=allocimage(display, Rect(0, 0, 1, 5), screen->chan, 1, DWhite);
if(linespace==0)
sysfatal("can't allocimage!");
bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DWhite);
@@ -389,6 +422,12 @@
break;
case Kack:
search();
+ break;
+ case Kright:
+ sidescroll(text->size.x/4, 1);
+ break;
+ case Kleft:
+ sidescroll(-text->size.x/4, 1);
break;
}
break;
--
⑨