ref: f664f9d3a8d305e088f259a23cb6e86e664a7b36
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; }