henesyinit from p9f0ed2a895 years agoHistory
415 lines · 8.3 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h>#include <control.h> typedef struct Text Text; struct Text{	Control;	int		border;	int		topline;	int		scroll;	int		nvis;	CFont	*font;	CImage	*image;	CImage	*textcolor;	CImage	*bordercolor;	CImage	*selectcolor;	Rune		**line;	int		selectmode;	uchar	*selected;	int		nline;	int		align;}; enum{	Selsingle,	Selmulti,}; enum{	EAdd,	EAlign,	EBorder,	EBordercolor,	EClear,	EDelete,	EFocus,	EFont,	EImage,	ERect,	EReplace,	EScroll,	ESelect,	ESelectcolor,	ESelectmode,	EShow,	ETextcolor,	ETopline,	EValue,}; static char *cmds[] = {	[EAdd] =			"add",	[EAlign] =			"align",	[EBorder] =		"border",	[EBordercolor] =	"bordercolor",	[EClear] =			"clear",	[EDelete] =		"delete",	[EFocus] = 		"focus",	[EFont] =			"font",	[EImage] =		"image",	[ERect] =			"rect",	[EReplace] =		"replace",	[EScroll] =			"scroll",	[ESelect] =		"select",	[ESelectcolor] =	"selectcolor",	[ESelectmode] =	"selectmode",	[EShow] =			"show",	[ETextcolor] =		"textcolor",	[ETopline] =		"topline",	[EValue] =			"value",	nil}; static void	textctl(Control*, char*);static void	textshow(Text*);static void	texttogglei(Text*, int);static void	textfree(Text*);static int	texttoggle(Text*, Point); static voidtextthread(void *v){	char buf[32];	Text *t;	int lastbut, sel; 	t = v; 	snprint(buf, sizeof buf, "text-%s-0x%p", t->name, t);	threadsetname(buf); 	t->line = ctlmalloc(sizeof(Rune*));	t->selected = ctlmalloc(1);	t->nline = 0;	t->image = _getctlimage("white");	t->textcolor = _getctlimage("black");	t->bordercolor = _getctlimage("black");	t->selectcolor = _getctlimage("yellow");	t->font = _getctlfont("font");	t->selectmode = Selsingle;	lastbut = 0; 	for(;;){		switch(alt(t->alts)){		default:			ctlerror("%q: unknown message", t->name);		case AKey:			/* ignore keystrokes */			break;		case AMouse:			if(lastbut != (t->m.buttons&1)){				if(t->m.buttons & 1){					sel = texttoggle(t, t->m.xy);					if(sel >= 0)						printctl(t->event, "%q: select %d %d",							t->name, sel, t->selected[sel]);				}				lastbut = t->m.buttons & 1;			}			break;		case ACtl:			_ctlcontrol(t, t->str, textctl);			free(t->str);			break;		case AWire:			_ctlrewire(t);			break;		case AExit:			textfree(t);			sendul(t->exit, 0);			return;		}	}} Control*createtext(Controlset *cs, char *name){	return _createctl(cs, "text", sizeof(Text), name, textthread, 0);} static voidtextfree(Text *t){	int i; 	_putctlfont(t->font);	_putctlimage(t->image);	_putctlimage(t->textcolor);	_putctlimage(t->bordercolor);	_putctlimage(t->selectcolor);	for(i=0; i<t->nline; i++)		free(t->line[i]);	free(t->line);	free(t->selected);} static voidtextshow(Text *t){	Rectangle r, tr;	Point p;	int i, ntext;	Font *f;	Rune *text; 	r = t->rect;	f = t->font->font;	draw(t->screen, r, t->image->image, nil, t->image->image->r.min);	if(t->border > 0){		border(t->screen, r, t->border, t->bordercolor->image, t->bordercolor->image->r.min);		r = insetrect(r, t->border);	}	tr = r;	t->nvis = Dy(r)/font->height;	for(i=t->topline; i<t->nline && i<t->topline+t->nvis; i++){		text = t->line[i];		ntext = runestrlen(text);		r.max.y = r.min.y+f->height;		if(t->selected[i])			draw(t->screen, r, t->selectcolor->image, nil, ZP);		p = _ctlalignpoint(r,			runestringnwidth(f, text, ntext),			f->height, t->align);		_string(t->screen, p, t->textcolor->image,			ZP, f, nil, text, ntext, tr,			nil, ZP);		r.min.y += f->height;	}	flushimage(display, 1);} static voidtextctl(Control *c, char *str){	int cmd, i, n;	CParse cp;	Rectangle r;	Text *t;	Rune *rp; 	t = (Text*)c;	cmd = _ctlparse(&cp, str, cmds);	switch(cmd){	default:		ctlerror("%q: unrecognized message '%s'", t->name, cp.str);		break;	case EAlign:		_ctlargcount(t, &cp, 2);		t->align = _ctlalignment(cp.args[1]);		break;	case EBorder:		_ctlargcount(t, &cp, 2);		if(cp.iargs[1] < 0)			ctlerror("%q: bad border: %c", t->name, cp.str);		t->border = cp.iargs[1];		break;	case EBordercolor:		_ctlargcount(t, &cp, 2);		_setctlimage(t, &t->bordercolor, cp.args[1]);		break;	case EClear:		_ctlargcount(t, &cp, 1);		for(i=0; i<t->nline; i++)			free(t->line[i]);		free(t->line);		free(t->selected);		t->line = ctlmalloc(sizeof(Rune*));		t->selected = ctlmalloc(1);		t->nline = 0;		textshow(t);		break;	case EDelete:		_ctlargcount(t, &cp, 2);		i = cp.iargs[1];		if(i<0 || i>=t->nline)			ctlerror("%q: line number out of range: %s", t->name, cp.str);		free(t->line[i]);		memmove(t->line+i, t->line+i+1, (t->nline-(i+1))*sizeof(Rune*));		memmove(t->selected+i, t->selected+i+1, t->nline-(i+1));		t->nline--;		textshow(t);		break;	case EFocus:		break;	case EFont:		_ctlargcount(t, &cp, 2);		_setctlfont(t, &t->font, cp.args[1]);		break;	case EImage:		_ctlargcount(t, &cp, 2);		_setctlimage(t, &t->image, cp.args[1]);		break;	case ERect:		_ctlargcount(t, &cp, 5);		r.min.x = cp.iargs[1];		r.min.y = cp.iargs[2];		r.max.x = cp.iargs[3];		r.max.y = cp.iargs[4];		if(Dx(r)<=0 || Dy(r)<=0)			ctlerror("%q: bad rectangle: %s", t->name, cp.str);		t->rect = r;		t->nvis = (Dy(r)-2*t->border)/font->height;		break;	case EReplace:		_ctlargcount(t, &cp, 3);		i = cp.iargs[1];		if(i<0 || i>=t->nline)			ctlerror("%q: line number out of range: %s", t->name, cp.str);		free(t->line[i]);		t->line[i] = _ctlrunestr(cp.args[2]);		textshow(t);		break;	case EScroll:		_ctlargcount(t, &cp, 2);		t->scroll = cp.iargs[1];		break;	case ESelect:		if(cp.nargs!=2 && cp.nargs!=3)	badselect:			ctlerror("%q: bad select message: %s", t->name, cp.str);		if(cp.nargs == 2){			if(strcmp(cp.args[1], "all") == 0){				memset(t->selected, 1, t->nline);				break;			}			if(strcmp(cp.args[1], "none") == 0){				memset(t->selected, 0, t->nline);				break;			}			if(cp.args[1][0]<'0' && '9'<cp.args[1][0])				goto badselect;			texttogglei(t, cp.iargs[1]);			break;		}		if(cp.iargs[1]<0 || cp.iargs[1]>=t->nline)			ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp.str);		if(t->selected[cp.iargs[1]] != (cp.iargs[2]!=0))			texttogglei(t, cp.iargs[1]);		break;	case ESelectcolor:		_ctlargcount(t, &cp, 2);		_setctlimage(t, &t->selectcolor, cp.args[1]);		break;	case ESelectmode:		_ctlargcount(t, &cp, 2);		if(strcmp(cp.args[1], "single") == 0)			t->selectmode = Selsingle;		else if(strncmp(cp.args[1], "multi", 5) == 0)			t->selectmode = Selmulti;		break;	case EShow:		_ctlargcount(t, &cp, 1);		textshow(t);		break;	case ETextcolor:		_ctlargcount(t, &cp, 2);		_setctlimage(t, &t->textcolor, cp.args[1]);		break;		break;	case ETopline:		_ctlargcount(t, &cp, 2);		i = cp.iargs[1];		if(i < 0)			i = 0;		if(i > t->nline)			i = t->nline;		if(t->topline != i){			t->topline = i;			textshow(t);		}		break;	case EValue:		/* set contents to single line */		/* free existing text and fall through to add */		for(i=0; i<t->nline; i++){			free(t->line[i]);			t->line[i] = nil;		}		t->nline = 0;		t->topline = 0;		/* fall through */	case EAdd:		switch (cp.nargs) {		default:			ctlerror("%q: wrong argument count in '%s'", t->name, cp.str);		case 2:			n = t->nline;			break;		case 3:			n = cp.iargs[1];			if(n<0 || n>t->nline)				ctlerror("%q: line number out of range: %s", t->name, cp.str);			break;		}		rp = _ctlrunestr(cp.args[cp.nargs-1]);		t->line = ctlrealloc(t->line, (t->nline+1)*sizeof(Rune*));		memmove(t->line+n+1, t->line+n, (t->nline-n)*sizeof(Rune*));		t->line[n] = rp;		t->selected = ctlrealloc(t->selected, t->nline+1);		memmove(t->selected+n+1, t->selected+n, t->nline-n);		t->selected[n] = (t->selectmode == Selmulti);		t->nline++;		if(t->scroll) {			if (n > t->topline + t->nvis)				t->topline = n - t->nvis;			if (n < t->topline)				t->topline = n;		}		if(t->scroll || t->nline<=t->topline+t->nvis)			textshow(t);		break;	}} static voidtexttogglei(Text *t, int i){	int prev; 	if(t->selectmode == Selsingle){		/* clear the others */		prev = t->selected[i];		memset(t->selected, 0, t->nline);		t->selected[i] = prev;	}	t->selected[i] ^= 1;	textshow(t);} static inttexttoggle(Text *t, Point p){	Rectangle r;	int i; 	r = t->rect;	if(t->border > 0)		r = insetrect(r, t->border);	if(!ptinrect(p, r))		return -1;	i = (p.y-r.min.y)/font->height;	i += t->topline;	if(i >= t->nline)		return -1;	texttogglei(t, i);	return i;}