diff options
author | Sigrid <ftrvxmtrx@gmail.com> | 2021-02-16 22:04:50 +0100 |
---|---|---|
committer | Sigrid <ftrvxmtrx@gmail.com> | 2021-02-16 22:04:50 +0100 |
commit | 79cf39c53ab311f61fd3a3826cefeaead6342601 (patch) | |
tree | db486c0a6e837cbea743d601e6d78c3a796f350a | |
parent | 04bf70d344698014f9c85ef3c1ae8215223cdb45 (diff) | |
download | plan9front-79cf39c53ab311f61fd3a3826cefeaead6342601.tar.xz |
mothra: tune up entry control logic for easier text editing
-rw-r--r-- | sys/src/cmd/mothra/libpanel/draw.c | 15 | ||||
-rw-r--r-- | sys/src/cmd/mothra/libpanel/entry.c | 231 | ||||
-rw-r--r-- | sys/src/cmd/mothra/libpanel/event.c | 5 | ||||
-rw-r--r-- | sys/src/cmd/mothra/libpanel/pldefs.h | 4 | ||||
-rw-r--r-- | sys/src/cmd/mothra/mothra.c | 7 | ||||
-rw-r--r-- | sys/src/cmd/mothra/rdhtml.c | 8 |
6 files changed, 200 insertions, 70 deletions
diff --git a/sys/src/cmd/mothra/libpanel/draw.c b/sys/src/cmd/mothra/libpanel/draw.c index 41ac936bf..f8e9d72ae 100644 --- a/sys/src/cmd/mothra/libpanel/draw.c +++ b/sys/src/cmd/mothra/libpanel/draw.c @@ -13,8 +13,8 @@ #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 Image *pl_white, *pl_light, *pl_dark, *pl_black, *pl_hilit; -Image *pl_blue; +static Image *pl_light, *pl_dark, *pl_tick, *pl_hilit; +Image *pl_blue, *pl_white, *pl_black; int pl_drawinit(void){ pl_white=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFFFFFFF); pl_light=allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFFFFFFF); @@ -22,7 +22,13 @@ int pl_drawinit(void){ 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); pl_blue=allocimage(display, Rect(0,0,1,1), RGB24, 1, 0x0000FFFF); - if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0 || pl_blue==0) sysfatal("allocimage: %r"); + if((pl_tick = allocimage(display, Rect(0, 0, TICKW, font->height), screen->chan, 0, DNofill)) != nil){ + draw(pl_tick, pl_tick->r, pl_white, nil, ZP); + draw(pl_tick, Rect(TICKW/2, 0, TICKW/2+1, font->height), pl_black, nil, ZP); + draw(pl_tick, Rect(0, 0, TICKW, TICKW), pl_black, nil, ZP); + draw(pl_tick, Rect(0, font->height-TICKW, TICKW, font->height), pl_black, nil, ZP); + } + if(pl_white==0 || pl_light==0 || pl_black==0 || pl_dark==0 || pl_blue==0 || pl_tick==0) sysfatal("allocimage: %r"); return 1; } Rectangle pl_boxoutline(Image *b, Rectangle r, int style, int fill){ @@ -227,6 +233,9 @@ Point pl_iconsize(int flags, Icon *p){ void pl_highlight(Image *b, Rectangle r){ draw(b, r, pl_dark, pl_hilit, ZP); } +void pl_drawtick(Image *b, Rectangle r){ + draw(b, r, pl_tick, nil, ZP); +} void pl_clr(Image *b, Rectangle r){ draw(b, r, display->white, 0, ZP); } diff --git a/sys/src/cmd/mothra/libpanel/entry.c b/sys/src/cmd/mothra/libpanel/entry.c index ccf4d5e1c..1dd2fc0d0 100644 --- a/sys/src/cmd/mothra/libpanel/entry.c +++ b/sys/src/cmd/mothra/libpanel/entry.c @@ -8,13 +8,25 @@ typedef struct Entry Entry; struct Entry{ - char *entry; - char *entp; - char *eent; + Rectangle lastr; + Rune *entry; + char *sentry; + int sz, n; + int a, b; + Point text; void (*hit)(Panel *, char *); Point minsize; }; #define SLACK 7 /* enough for one extra rune and ◀ and a nul */ +void pl_cutentry(Panel *p){ + Entry *ep; + + ep=p->data; + memmove(ep->entry+ep->a, ep->entry+ep->b, (ep->n-ep->b)*sizeof(Rune)); + ep->n -= ep->b-ep->a; + ep->entry[ep->n]=0; + ep->b=ep->a; +} char *pl_snarfentry(Panel *p){ Entry *ep; int n; @@ -22,72 +34,144 @@ char *pl_snarfentry(Panel *p){ if(p->flags&USERFL) /* no snarfing from password entry */ return nil; ep=p->data; - n=utfnlen(ep->entry, ep->entp-ep->entry); + n=ep->b-ep->a; if(n<1) return nil; - return smprint("%.*s", n, ep->entry); + return smprint("%.*S", n, ep->entry+ep->a); } void pl_pasteentry(Panel *p, char *s){ Entry *ep; - char *e; - int n, m; + int 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; + m=utflen(s); + ep->sz=ep->n+m+100+SLACK; + ep->entry=pl_erealloc(ep->entry,ep->sz*sizeof(Rune)); + memmove(ep->entry+ep->a+m, ep->entry+ep->b, (ep->n-ep->b)*sizeof(Rune)); + ep->n+=m-(ep->b-ep->a); + while(m-- > 0) + s += chartorune(&ep->entry[ep->a++], s); + ep->b=ep->a; + ep->entry[ep->n]=0; pldraw(p, p->b); } +static void drawentry(Panel *p, Rectangle r, Rune *s){ + Rectangle save; + Point tick; + Entry *ep; + Image *b; + int d; + + ep = p->data; + b = p->b; + + if(Dx(r) != Dx(ep->lastr)){ + ep->text = r.min; + ep->lastr = r; + } + tick = ep->text; + tick.x += runestringnwidth(font, s, ep->a); + + if(plkbfocus == p) + r.max.x -= TICKW; + ep->text.y = r.min.y; + if(!ptinrect(tick, r)){ + d = 0; + if(tick.x < r.min.x) + d = r.min.x - tick.x; + else if(tick.x > r.max.x) + d = r.max.x - tick.x; + tick.x += d; + ep->text.x += d; + } + if(plkbfocus == p) + r.max.x += TICKW; + + save = b->clipr; + if(!rectclip(&r, save)) + return; + replclipr(b, b->repl, r); + runestring(b, ep->text, pl_black, ZP, font, s); + if(plkbfocus == p){ + r.min = tick; + if(ep->a != ep->b){ + r.max.x = ep->text.x+runestringnwidth(font, s, ep->b); + if(r.max.x < r.min.x){ + d = r.min.x; + r.min.x = r.max.x; + r.max.x = d; + } + pl_highlight(b, r); + }else + pl_drawtick(b, r); + } + replclipr(b, b->repl, save); +} void pl_drawentry(Panel *p){ Rectangle r; Entry *ep; - char *s; + Rune *s; ep=p->data; r=pl_box(p->b, p->r, p->state|BORDER); s=ep->entry; if(p->flags & USERFL){ - char *p; - s=strdup(s); + Rune *p; + s=runestrdup(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); + drawentry(p, r, s); if(s != ep->entry) free(s); } int pl_hitentry(Panel *p, Mouse *m){ + Entry *ep; + int i, n, selecting; if((m->buttons&7)==1){ + if(plkbfocus != p) + p->state=DOWN; plgrabkb(p); - - p->state=DOWN; + ep = p->data; + for(i = 1; i <= ep->n; i++) + if(runestringnwidth(font, ep->entry, i) > m->xy.x-ep->text.x) + break; + n = i-1; + ep->a = ep->b = n; pldraw(p, p->b); + selecting = 1; while(m->buttons&1){ int old; old=m->buttons; if(display->bufp > display->buf) flushimage(display, 1); *m=emouse(); + p->state=UP; if((old&7)==1){ if((m->buttons&7)==3){ - Entry *ep; - plsnarf(p); - - /* cut */ - ep=p->data; - ep->entp=ep->entry; - *ep->entp='\0'; + pl_cutentry(p); pldraw(p, p->b); + ep->b = n = ep->a; } + if(selecting && (m->buttons&7)==1){ + p->state=UP; + for(i = 0; i < ep->n; i++) + if(runestringnwidth(font, ep->entry, i)+TICKW > m->xy.x-ep->text.x) + break; + /* + * tick is moved towards the mouse pointer dragging the selection + * after drawing it has to be set so that (a <= b), since + * the rest of the logic assumes that's always the case + */ + ep->a = i; + ep->b = n; + pldraw(p, p->b); + if(ep->a > ep->b){ + ep->a = n; + ep->b = i; + } + }else + selecting = 0; if((m->buttons&7)==5) plpaste(p); } @@ -98,45 +182,67 @@ int pl_hitentry(Panel *p, Mouse *m){ 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); + if(ep->hit) ep->hit(p, plentryval(p)); return; + case Kleft: + if(ep->a > 0) + ep->a--; + ep->b=ep->a; + break; + case Kright: + if(ep->a<ep->n) + ep->a++; + ep->b = ep->a; + break; + case Ksoh: + ep->a=ep->b=0; + break; + case Kenq: + ep->a=ep->b=ep->n; + break; case Kesc: + ep->a=0; + ep->b=ep->n; plsnarf(p); /* no break */ case Kdel: /* clear */ + ep->a = ep->b = ep->n = 0; + *ep->entry = 0; + break; case Knack: /* ^U: erase line */ - ep->entp=ep->entry; - *ep->entp='\0'; + ep->a = 0; + pl_cutentry(p); 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; + if(ep->a > 0 && ep->a == ep->b) + ep->a--; + /* wet floor */ + if(0){ 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'; + while(ep->a>0 && !pl_idchar(ep->entry[ep->a-1])) + --ep->a; + while(ep->a>0 && pl_idchar(ep->entry[ep->a-1])) + --ep->a; + } + pl_cutentry(p); 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; + memmove(ep->entry+ep->a+1, ep->entry+ep->b, (ep->n-ep->b)*sizeof(Rune)); + ep->n -= ep->b - ep->a - 1; + ep->entry[ep->a++] = c; + ep->b = ep->a; + if(ep->n>ep->sz){ + ep->sz = ep->n+100; + ep->entry=pl_erealloc(ep->entry, (ep->sz+SLACK)*sizeof(Rune)); } - *ep->entp='\0'; + ep->entry[ep->n]=0; break; } pldraw(p, p->b); @@ -152,10 +258,11 @@ void pl_freeentry(Panel *p){ Entry *ep; ep = p->data; free(ep->entry); - ep->entry = ep->eent = ep->entp = 0; + free(ep->sentry); + ep->entry = nil; + ep->sentry = nil; } 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; @@ -169,12 +276,11 @@ void plinitentry(Panel *v, int flags, int wid, char *str, void (*hit)(Panel *, c 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->a = ep->b = 0; + ep->n = str ? utflen(str) : 0; + ep->sz = ep->n + 100; + ep->entry=pl_erealloc(ep->entry, (ep->sz+SLACK)*sizeof(Rune)); + runesnprint(ep->entry, ep->sz, "%s", str ? str : ""); ep->hit=hit; v->kind="entry"; } @@ -187,6 +293,7 @@ Panel *plentry(Panel *parent, int flags, int wid, char *str, void (*hit)(Panel * char *plentryval(Panel *p){ Entry *ep; ep=p->data; - *ep->entp='\0'; - return ep->entry; + free(ep->sentry); + ep->sentry = smprint("%S", ep->entry); + return ep->sentry; } diff --git a/sys/src/cmd/mothra/libpanel/event.c b/sys/src/cmd/mothra/libpanel/event.c index 4a9355d58..0a4ee943b 100644 --- a/sys/src/cmd/mothra/libpanel/event.c +++ b/sys/src/cmd/mothra/libpanel/event.c @@ -6,6 +6,11 @@ #include "pldefs.h" void plgrabkb(Panel *g){ + Panel *o; + o=plkbfocus; + plkbfocus=nil; + if(o && o!=g) /* redraw if lost focus */ + pldraw(o, o->b); plkbfocus=g; } void plkeyboard(Rune c){ diff --git a/sys/src/cmd/mothra/libpanel/pldefs.h b/sys/src/cmd/mothra/libpanel/pldefs.h index b2ccbee81..be5537120 100644 --- a/sys/src/cmd/mothra/libpanel/pldefs.h +++ b/sys/src/cmd/mothra/libpanel/pldefs.h @@ -13,6 +13,7 @@ Rtext *pl_rthit(Rtext *, Point, Point, Point); #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 */ +#define TICKW 3 /* tick width */ /* * States, also styles */ @@ -40,7 +41,7 @@ enum{ SCROLLABSX, }; -extern Image *pl_blue; +extern Image *pl_blue, *pl_white, *pl_black; /* * Scrollbar, slider orientations @@ -70,6 +71,7 @@ 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_drawtick(Image *, Rectangle); void pl_clr(Image *, Rectangle); void pl_fill(Image *, Rectangle); void pl_cpy(Image *, Point, Rectangle); diff --git a/sys/src/cmd/mothra/mothra.c b/sys/src/cmd/mothra/mothra.c index 8eab20806..84d3fbced 100644 --- a/sys/src/cmd/mothra/mothra.c +++ b/sys/src/cmd/mothra/mothra.c @@ -399,6 +399,7 @@ void main(int argc, char *argv[]){ case Ekeyboard: switch(e.kbdc){ default: +Plkey: adjkb(); plkeyboard(e.kbdc); break; @@ -424,9 +425,13 @@ void main(int argc, char *argv[]){ search(); break; case Kright: + if(plkbfocus) + goto Plkey; sidescroll(text->size.x/4, 1); break; case Kleft: + if(plkbfocus) + goto Plkey; sidescroll(-text->size.x/4, 1); break; } @@ -441,6 +446,8 @@ void main(int argc, char *argv[]){ break; } plmouse(root, &mouse); + if(mouse.buttons == 1 && root->lastmouse == root) + plgrabkb(nil); break; case Eplumb: pm=e.v; diff --git a/sys/src/cmd/mothra/rdhtml.c b/sys/src/cmd/mothra/rdhtml.c index 7a36b83b8..1197b33a0 100644 --- a/sys/src/cmd/mothra/rdhtml.c +++ b/sys/src/cmd/mothra/rdhtml.c @@ -374,7 +374,7 @@ void pl_rmentities(Hglob *, char *s){ /* * Skip over white space */ -char *pl_white(char *s){ +char *pl_whitespace(char *s){ while(*s==' ' || *s=='\t' || *s=='\n' || *s=='\r') s++; return s; } @@ -431,19 +431,19 @@ void pl_tagparse(Hglob *g, char *str){ g->tag=tagp-tag; if(g->tag==Tag_end) htmlerror(g->name, g->lineno, "no tag %s", name); for(;;){ - s=pl_white(s); + s=pl_whitespace(s); if(*s=='\0'){ ap->name=0; return; } ap->name=s; s=pl_word(s); - t=pl_white(s); + t=pl_whitespace(s); c=*t; *s='\0'; for(s=ap->name;*s;s++) if('A'<=*s && *s<='Z') *s+='a'-'A'; if(c=='='){ - s=pl_white(t+1); + s=pl_whitespace(t+1); if(*s=='\'' || *s=='"'){ ap->value=s+1; s=pl_quote(s); |