ref: 856542c51fbe7a4d55e292ad91714f58907d6869
dir: /libgenenter.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include "genenter.h"
static void
sorttick(int *t1, int *t2)
{
int i;
if(*t1 <= *t2)
return;
i = *t1;
*t1 = *t2;
*t2 = i;
}
static Point
drawstring(Image *b, char *buf, Point p, int s, int e, Image *bg, int h)
{
sorttick(&s, &e);
p = stringn(b, p, display->black, ZP, font, buf, utfnlen(buf, s));
if(s == e){
draw(b, Rect(p.x-1, p.y, p.x+2, p.y+3), display->black, nil, ZP);
draw(b, Rect(p.x, p.y, p.x+1, p.y+h), display->black, nil, ZP);
draw(b, Rect(p.x-1, p.y+h-3, p.x+2, p.y+h), display->black, nil, ZP);
} else {
p = stringnbg(b, p, display->black, ZP, font, buf+s, utfnlen(buf+s, e-s), bg, ZP);
}
p = string(b, p, display->black, ZP, font, buf+e);
return p;
}
static void
enterselection(char *buf, int len, int s, int e, int *sp, int *ep)
{
int l, i;
Rune k;
sorttick(&s, &e);
*sp = *ep = -1;
for(i = 0; i < len; i += l){
l = chartorune(&k, buf+i);
if(*sp >= 0 && i >= e){
*ep = i;
break;
}
if(*sp < 0 && i >= s)
*sp = i;
}
if (*ep < 0)
*ep = len;
}
static int
delsubstring(char *buf, int len, int s, int e, int *nlen)
{
int sp, ep;
if(s == e)
return s;
if (s < 0)
s = 0;
enterselection(buf, len, s, e, &sp, &ep);
memmove(buf+sp, buf+ep, len - ep);
buf[len-ep+sp] = 0;
if (nlen)
*nlen = sp+len-ep;
return sp;
}
static int
entersnarf(char *buf, int len, int s, int e, int *nlen)
{
int fd, sp, ep;
fd = open("/dev/snarf", OWRITE|OTRUNC);
if(fd < 0){
fprint(2, "error: %r\n");
return s;
}
enterselection(buf, len, s, e, &sp, &ep);
if(sp < 0 || ep < 0){
close(fd);
return sp < 0 ? ep : sp;
}
pwrite(fd, &buf[sp], ep-sp, 0);
close(fd);
return delsubstring(buf, len, s, e, nlen);
}
static void
enterpaste(char *buf, int len, int max, int s, int e, int *nlen, int *ns, int *ne)
{
char *str;
int fd, sp, ep, n, newlen;
fd = open("/dev/snarf", OREAD);
if(fd < 0){
fprint(2, "error: %r\n");
return;
}
str = mallocz(max*sizeof(char), 1);
n = pread(fd, str, max-1, 0);
str[n] = 0;
close(fd);
newlen = len;
enterselection(buf, len, s, e, &sp, &ep);
s = entersnarf(buf, len, s, e, &newlen);
memmove(buf+n+s, buf+s, newlen-s);
memcpy(buf+s, str, n);
free(str);
if (nlen)
*nlen = newlen+n;
if (ns)
*ns = s;
if (ne)
*ne = s+n;
}
int
_genenter(char *ask, char *buf, int len, Enterparams *ps)
{
int done, down, tick, n, h, w, l, i;
int tick2, mb;
Image *backcol, *bordcol;
Point p, t;
Rune k;
Mouse m;
mb = 0;
if(!ptinrect(ps->o, screen->r))
ps->o = screen->r.min;
backcol = allocimagemix(display, DPurpleblue, DWhite);
bordcol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
if(backcol == nil || bordcol == nil)
return -1;
if(buf && len > 0)
n = strlen(buf);
else {
buf = nil;
len = 0;
n = 0;
}
ps->k = -1;
tick2 = tick = n;
ps->save = nil;
done = down = 0;
p = stringsize(font, " ");
h = p.y;
w = p.x;
while(!done){
p = stringsize(font, buf ? buf : "");
if(ask && ask[0]){
if(buf) p.x += w;
p.x += stringwidth(font, ask);
}
ps->r = rectaddpt(insetrect(Rpt(ZP, p), -4), ps->o);
p.x = 0;
ps->r = rectsubpt(ps->r, p);
p = ZP;
if(ps->r.min.x < screen->r.min.x)
p.x = screen->r.min.x - ps->r.min.x;
if(ps->r.min.y < screen->r.min.y)
p.y = screen->r.min.y - ps->r.min.y;
ps->r = rectaddpt(ps->r, p);
p = ZP;
if(ps->r.max.x > screen->r.max.x)
p.x = ps->r.max.x - screen->r.max.x;
if(ps->r.max.y > screen->r.max.y)
p.y = ps->r.max.y - screen->r.max.y;
ps->r = rectsubpt(ps->r, p);
ps->r = insetrect(ps->r, -2);
if(ps->initsave)
if(ps->initsave(ps)){
n = -1;
break;
}
draw(ps->b, ps->r, backcol, nil, ZP);
border(ps->b, ps->r, 2, bordcol, ZP);
p = addpt(ps->r.min, Pt(6, 6));
if(ask && ask[0]){
p = string(ps->b, p, bordcol, ZP, font, ask);
if(buf) p.x += w;
}
if(buf){
t = p;
p = drawstring(ps->b, buf, p, tick, tick2, bordcol, h);
}
flushimage(display, 1);
nodraw:
i = ps->getevent(ps);
switch(i){
default:
done = 1;
n = -1;
break;
case Gkeyboard:
k = ps->k;
if(buf == nil || k == Keof || k == '\n'){
done = 1;
break;
}
if(k == Knack || k == Kesc){
done = !n;
n = tick2 = tick = 0;
buf[n] = 0;
break;
}
if(k == Ksoh || k == Khome){
tick2 = tick = 0;
continue;
}
if(k == Kenq || k == Kend){
tick2 = tick = n;
continue;
}
if(k == Kright){
if(tick2 < n)
tick2 = tick += chartorune(&k, buf+tick);
continue;
}
if(k == Kleft){
for(i = 0; i < n; i += l){
l = chartorune(&k, buf+i);
if(i+l >= tick){
tick2 = tick = i;
break;
}
}
continue;
}
if(k == Ketb){
l = tick;
while(tick > 0){
tick--;
if(tick == 0 ||
strchr(" !\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", buf[tick-1]))
break;
}
memmove(buf+tick, buf+l, n-l);
buf[n -= l-tick] = 0;
break;
}
if(k == Kbs){
if(tick <= 0 && tick2 <= 0)
continue;
if (tick == tick2)
for(i = 0; i < n; i += l){
l = chartorune(&k, buf+i);
if(i+l >= tick){
memmove(buf+i, buf+i+l, n - (i+l));
buf[n -= l] = 0;
tick2 = tick -= l;
break;
}
}
else
tick = tick2 = delsubstring(buf, n, tick-1, tick2, &n);
break;
}
if(k < 0x20 || k == Kdel || (k & 0xFF00) == KF || (k & 0xFF00) == Spec)
continue;
if((len-n) <= (l = runelen(k)))
continue;
tick = delsubstring(buf, n, tick, tick2, &n);
memmove(buf+tick+l, buf+tick, n - tick);
runetochar(buf+tick, &k);
buf[n += l] = 0;
tick2 = tick += l;
break;
case Gmouse:
m = ps->m;
if(mb&1 && !m.buttons&1) {
sorttick(&tick, &tick2);
mb = m.buttons;
}
if(m.buttons&1 && mb&6){
if (m.buttons != mb)
goto Mchecks;
continue;
}
if(m.buttons&1 && mb&6){
continue;
}
if(!ptinrect(m.xy, ps->r)){
down = 0;
goto nodraw;
}
if(m.buttons&1){
down = 1;
if(buf && m.xy.x >= (t.x - w)){
down = 0;
for(i = 0; i < n; i += l){
l = chartorune(&k, buf+i);
t.x += stringnwidth(font, buf+i, 1);
if(t.x > m.xy.x)
break;
}
if(mb & 1){
tick2 = i;
}else
tick = tick2 = i;
}
if(!((m.buttons&2) || (m.buttons&4))){
mb = m.buttons;
continue;
}
}
Mchecks:
if(!(mb&2) && (m.buttons&3) == 3){
tick = tick2 = entersnarf(buf, n, tick, tick2, &n);
mb = m.buttons;
}
if(!(mb&4) && (m.buttons&5) == 5){
enterpaste(buf, n, len, tick, tick2, &n, &tick, &tick2);
mb = m.buttons;
}
done = down;
break;
}
if(ps->loopcleanup)
ps->loopcleanup(ps);
}
if(ps->cleanup)
ps->cleanup(ps);
freeimage(backcol);
freeimage(bordcol);
flushimage(display, 1);
return n;
}