240 lines · 4.5 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h>#include "kbd.h" intkbdenter(char *ask, char *buf, int len, Mousectl *mc, Kbdctl *kc, Screen *scr){	int done, down, tick, n, h, w, l, i;	Image *b, *save, *backcol, *bordcol;	Point p, o, t;	Rectangle r, sc;	Alt a[3];	Mouse m;	Key key;	Rune k; 	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; 	sc = screen->clipr;	replclipr(screen, 0, screen->r); 	n = 0;	if(kc){		while(nbrecv(kc->c, nil) == 1)			;		a[n].op = CHANRCV;		a[n].c = kc->c;		a[n].v = &key;		n++;	}	if(mc){		o = mc->xy;		a[n].op = CHANRCV;		a[n].c = mc->c;		a[n].v = &m;		n++;	}	a[n].op = CHANEND;	a[n].c = nil;	a[n].v = nil; 	if(buf && len > 0)		n = strlen(buf);	else {		buf = nil;		len = 0;		n = 0;	} 	k = -1;	b = nil;	tick = n;	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);		}		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(scr){			if(b == nil)				b = allocwindow(scr, r, Refbackup, DWhite);			if(b == nil)				scr = nil;		}		if(scr == nil && save == nil){			if(b == nil)				b = screen;			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 = stringn(b, p, display->black, ZP, font, buf, utfnlen(buf, tick));			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);			p = string(b, p, display->black, ZP, font, buf+tick);		}		flushimage(display, 1); nodraw:		switch(alt(a)){		case -1:			done = 1;			n = -1;			break;		case 0:			k = key.k;			if(buf == nil || k == Keof || k == '\n'){				done = 1;				break;			}			if(k == Knack || k == Kesc){				done = !n;				buf[n = tick = 0] = 0;				break;			}			if(k == Ksoh || k == Khome){				tick = 0;				continue;			}			if(k == Kenq || k == Kend){				tick = n;				continue;			}			if(k == Kright){				if(tick < n)					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){						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)					continue;				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;						tick -= l;						break;					}				}				break;			}			if(k < 0x20 || k == Kdel || (k & 0xFF00) == KF || (k & 0xFF00) == Spec)				continue;			if((len-n) <= (l = runelen(k)))				continue;			memmove(buf+tick+l, buf+tick, n - tick);			runetochar(buf+tick, &k);			buf[n += l] = 0;			tick += l;			break;		case 1:			if(!ptinrect(m.xy, r)){				down = 0;				goto nodraw;			}			if(m.buttons & 7){				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;					}					tick = i;				}				continue;			}			done = down;			break;		} 		if(b != screen) {			freeimage(b);			b = nil;		} else {			draw(b, save->r, save, nil, save->r.min);			freeimage(save);			save = nil;		}	} 	replclipr(screen, 0, sc); 	freeimage(backcol);	freeimage(bordcol);	flushimage(display, 1); 	return n;}