henesyinit from p9fd787fda5 years agoHistory
431 lines · 8.8 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;	int		lastbut;	CFont	*font;	CImage	*image;	CImage	*textcolor;	CImage	*bordercolor;	CImage	*selectcolor;	Rune		**line;	int		selectmode;	uchar	*selected;	int		nline;	int		align;}; enum{	Selsingle,	Selmulti,}; enum{	EAccumulate,	EAdd,	EAlign,	EBorder,	EBordercolor,	EClear,	EDelete,	EFocus,	EFont,	EHide,	EImage,	ERect,	EReplace,	EReveal,	EScroll,	ESelect,	ESelectcolor,	ESelectmode,	EShow,	ESize,	ETextcolor,	ETopline,	EValue,}; static char *cmds[] = {	[EAccumulate] =	"accumulate",	[EAdd] =			"add",	[EAlign] =			"align",	[EBorder] =		"border",	[EBordercolor] =	"bordercolor",	[EClear] =			"clear",	[EDelete] =		"delete",	[EFocus] = 		"focus",	[EFont] =			"font",	[EHide] =			"hide",	[EImage] =		"image",	[ERect] =			"rect",	[EReplace] =		"replace",	[EReveal] =		"reveal",	[EScroll] =			"scroll",	[ESelect] =		"select",	[ESelectcolor] =	"selectcolor",	[ESelectmode] =	"selectmode",	[EShow] =			"show",	[ESize] =			"size",	[ETextcolor] =		"textcolor",	[ETopline] =		"topline",	[EValue] =			"value",	nil}; static void	textshow(Text*);static void	texttogglei(Text*, int);static int	texttoggle(Text*, Point); static voidtextmouse(Control *c, Mouse *m){	Text *t;	int sel; 	t = (Text*)c;	if(t->lastbut != (m->buttons&7)){		if(m->buttons & 7){			sel = texttoggle(t, m->xy);			if(sel >= 0)				chanprint(t->event, "%q: select %d %d",					t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);		}		t->lastbut = m->buttons & 7;	}} static voidtextfree(Control *c){	int i;	Text *t; 	t = (Text*)c;	_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; 	if (t->hidden)		return;	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)/f->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, CParse *cp){	int cmd, i, n;	Rectangle r;	Text *t;	Rune *rp; 	t = (Text*)c;	cmd = _ctllookup(cp->args[0], cmds, nelem(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 EHide:		_ctlargcount(t, cp, 1);		t->hidden = 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)/t->font->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 EReveal:		_ctlargcount(t, cp, 1);		t->hidden = 0;		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 ESize:		if (cp->nargs == 3)			r.max = Pt(10000, 10000);		else{			_ctlargcount(t, cp, 5);			r.max.x = cp->iargs[3];			r.max.y = cp->iargs[4];		}		r.min.x = cp->iargs[1];		r.min.y = cp->iargs[2];		if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)			ctlerror("%q: bad sizes: %s", t->name, cp->str);		t->size.min = r.min;		t->size.max = r.max;		break;	case ETextcolor:		_ctlargcount(t, cp, 2);		_setctlimage(t, &t->textcolor, cp->args[1]);		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 EAccumulate:	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 && cmd!=EAccumulate);		t->nline++;		if(t->scroll) {			if(n > t->topline + (t->nvis - 1)){				t->topline = n - (t->nvis - 1);				if(t->topline < 0)					t->topline = 0;			}			if(n < t->topline)				t->topline = n;		}		if(cmd != EAccumulate)			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)/t->font->font->height;	i += t->topline;	if(i >= t->nline)		return -1;	texttogglei(t, i);	return i;} Control*createtext(Controlset *cs, char *name){	Text *t; 	t = (Text*)_createctl(cs, "text", sizeof(Text), name);	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;	t->lastbut = 0;	t->mouse = textmouse;	t->ctl = textctl;	t->exit = textfree;	return (Control *)t;}