shithub: gopher

ref: d2dd69c31884b642d5efc11cf1b95b677243d4bd
dir: /libpanel/entry.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
#include <keyboard.h>

typedef struct Entry Entry;
struct Entry{
	char *entry;
	char *entp;
	char *eent;
	void (*hit)(Panel *, char *);
	Point minsize;
};
#define	SLACK	7	/* enough for one extra rune and ◀ and a nul */
char *pl_snarfentry(Panel *p){
	Entry *ep;
	int n;

	if(p->flags&USERFL)	/* no snarfing from password entry */
		return nil;
	ep=p->data;
	n=utfnlen(ep->entry, ep->entp-ep->entry);
	if(n<1) return nil;
	return smprint("%.*s", n, ep->entry);
}
void pl_pasteentry(Panel *p, char *s){
	Entry *ep;
	char *e;
	int n, 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;
	pldraw(p, p->b);
}
void pl_drawentry(Panel *p){
	Rectangle r;
	Entry *ep;
	char *s;

	ep=p->data;
	r=pl_box(p->b, p->r, p->state);
	s=ep->entry;
	if(p->flags & USERFL){
		char *p;
		s=strdup(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);
	if(s != ep->entry)
		free(s);
}
int pl_hitentry(Panel *p, Mouse *m){
	if((m->buttons&7)==1){
		plgrabkb(p);

		p->state=DOWN;
		pldraw(p, p->b);
		while(m->buttons&1){
			int old;
			old=m->buttons;
			if(display->bufp > display->buf)
				flushimage(display, 1);
			*m=emouse();
			if((old&7)==1){
				if((m->buttons&7)==3){
					Entry *ep;

					plsnarf(p);

					/* cut */
					ep=p->data;
					ep->entp=ep->entry;
					*ep->entp='\0';
					pldraw(p, p->b);
				}
				if((m->buttons&7)==5)
					plpaste(p);
			}
		}
		p->state=UP;
		pldraw(p, p->b);
	}
	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);
		return;
	case Kesc:
		plsnarf(p);
		/* no break */
	case Kdel:	/* clear */
	case Knack:	/* ^U: erase line */
		ep->entp=ep->entry;
		*ep->entp='\0';
		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;
	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';
		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;
		}
		*ep->entp='\0';
		break;
	}
	pldraw(p, p->b);
}
Point pl_getsizeentry(Panel *p, Point children){
	USED(children);
	return pl_boxsize(((Entry *)p->data)->minsize, p->state);
}
void pl_childspaceentry(Panel *p, Point *ul, Point *size){
	USED(p, ul, size);
}
void pl_freeentry(Panel *p){
	Entry *ep;
	ep = p->data;
	free(ep->entry);
	ep->entry = ep->eent = ep->entp = 0;
}
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;
	v->state=UP;
	v->draw=pl_drawentry;
	v->hit=pl_hitentry;
	v->type=pl_typeentry;
	v->getsize=pl_getsizeentry;
	v->childspace=pl_childspaceentry;
	ep->minsize=Pt(wid, font->height);
	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->hit=hit;
	v->kind="entry";
}
Panel *plentry(Panel *parent, int flags, int wid, char *str, void (*hit)(Panel *, char *)){
	Panel *v;
	v=pl_newpanel(parent, sizeof(Entry));
	plinitentry(v, flags, wid, str, hit);
	return v;
}
char *plentryval(Panel *p){
	Entry *ep;
	ep=p->data;
	*ep->entp='\0';
	return ep->entry;
}