ref: f94021cad309874252753f9ac7b49b9efe9b04be
dir: /libeenter.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <event.h> #include <keyboard.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; } } static int delsubstring(char *buf, int len, int s, int e, int *nlen) { int l, i, sp, ep; Rune k; 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 eenter(char *ask, char *buf, int len, Mouse *m) { int done, down, tick, n, h, w, l, i; int tick2, mb, ti; Image *b, *save, *backcol, *bordcol; Point p, o, t; Rectangle r, sc; Event ev; Rune k; mb = 0; 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; while(ecankbd()) ekbd(); if(m) o = m->xy; if(buf && len > 0) n = strlen(buf); else { buf = nil; len = 0; n = 0; } k = -1; tick2 = tick = n; save = nil; done = down = 0; p = stringsize(font, " "); h = p.y; w = p.x; b = screen; sc = b->clipr; replclipr(b, 0, b->r); while(!done){ p = stringsize(font, buf ? buf : ""); if(ask && ask[0]){ if(buf) p.x += w; p.x += stringwidth(font, ask); } r = rectaddpt(insetrect(Rpt(ZP, p), -4), o); p.x = 0; r = rectsubpt(r, p); p = ZP; if(r.min.x < screen->r.min.x) p.x = screen->r.min.x - r.min.x; if(r.min.y < screen->r.min.y) p.y = screen->r.min.y - r.min.y; r = rectaddpt(r, p); p = ZP; if(r.max.x > screen->r.max.x) p.x = r.max.x - screen->r.max.x; if(r.max.y > screen->r.max.y) p.y = r.max.y - screen->r.max.y; r = rectsubpt(r, p); r = insetrect(r, -2); if(save == nil){ save = allocimage(display, r, b->chan, 0, DNofill); if(save == nil){ n = -1; break; } draw(save, r, b, nil, r.min); } draw(b, r, backcol, nil, ZP); border(b, r, 2, bordcol, ZP); p = addpt(r.min, Pt(6, 6)); if(ask && ask[0]){ p = string(b, p, bordcol, ZP, font, ask); if(buf) p.x += w; } if(buf){ t = p; p = drawstring(b, buf, p, tick, tick2, bordcol, h); } flushimage(display, 1); nodraw: i = Ekeyboard; if(m != nil) i |= Emouse; replclipr(b, 0, sc); i = eread(i, &ev); /* screen might have been resized */ if(b != screen || !eqrect(screen->clipr, sc)){ freeimage(save); save = nil; } b = screen; sc = b->clipr; replclipr(b, 0, b->r); switch(i){ default: done = 1; n = -1; break; case Ekeyboard: k = ev.kbdc; 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 Emouse: *m = ev.mouse; 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, 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(save){ draw(b, save->r, save, nil, save->r.min); freeimage(save); save = nil; } } replclipr(b, 0, sc); freeimage(backcol); freeimage(bordcol); flushimage(display, 1); return n; }