forsyth20100821-1800749be1916 years agoHistory
1368 lines · 26.5 KB · C
RawDownload
#include <lib9.h>#include <kernel.h>#include "draw.h"#include "keyboard.h"#include "tk.h" /* Widget Commands (+ means implemented)	+bbox	+cget	+configure	+delete	+get	+icursor	+index	 scan	+selection	+xview	+see*/ #define	O(t, e)		((long)(&((t*)0)->e)) #define CNTL(c) ((c)&0x1f)#define DEL 0x7f /* Layout constants */enum {	Entrypady	= 0,	Entrypadx	= 0,	Inswidth = 2, 	Ecursoron = 1<<0,	Ecenter = 1<<1,	Eright = 1<<2,	Eleft = 1<<3,	Ewordsel = 1<<4, 	Ejustify = Ecenter|Eleft|Eright}; static TkStab tkjust[] ={	"left",	Eleft,	"right",	Eright,	"center",	Ecenter,	nil}; staticTkEbind b[] = {	{TkKey,			"%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},	{TkKey|CNTL('a'),	"%W icursor 0;%W see insert;%W selection clear"},	{TkKey|Home,		"%W icursor 0;%W see insert;%W selection clear"},	{TkKey|CNTL('d'),	"%W delete insert; %W see insert"},	{TkKey|CNTL('e'),    "%W icursor end; %W see insert;%W selection clear"},	{TkKey|End,	     "%W icursor end; %W see insert;%W selection clear"},	{TkKey|CNTL('h'),	"%W tkEntryBS;%W see insert"},	{TkKey|CNTL('k'),	"%W delete insert end;%W see insert"},	{TkKey|CNTL('u'),	"%W delete 0 end;%W see insert"},	{TkKey|CNTL('w'),	"%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},	{TkKey|DEL,		"%W tkEntryBS 1;%W see insert"},	{TkKey|CNTL('\\'),	"%W selection clear"},	{TkKey|CNTL('/'),	"%W selection range 0 end"},	{TkKey|Left,	"%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},	{TkKey|Right,	"%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},	{TkButton1P,		"focus %W; %W tkEntryB1P %X"},	{TkButton1P|TkMotion, 	"%W tkEntryB1M %X"},	{TkButton1R,		"%W tkEntryB1R"},	{TkButton1P|TkDouble,	"%W tkEntryB1P %X;%W selection word @%x"},	{TkButton2P,			"%W tkEntryB2P %x"},	{TkButton2P|TkMotion,	"%W xview scroll %x scr"},	{TkFocusin,		"%W tkEntryFocus in"},	{TkFocusout,		"%W tkEntryFocus out"},	{TkKey|APP|'\t',	""},	{TkKey|BackTab,		""},}; typedef struct TkEntry TkEntry;struct TkEntry{	Rune*	text;	int		textlen; 	char*	xscroll;	char*	show;	int		flag;	int		oldx; 	int		icursor;		/* index of insertion cursor */	int		anchor;		/* selection anchor point */	int		sel0;			/* index of start of selection */	int		sel1;			/* index of end of selection */ 	int		x0;			/* x-offset of visible area */ 	/* derived values */	int		v0;			/* index of first visible character */	int		v1;			/* index of last visible character + 1 */	int		xlen;			/* length of text in pixels*/	int		xv0;			/* position of first visible character */	int		xsel0;		/* position of start of selection */	int		xsel1;		/* position of end of selection */	int		xicursor;		/* position of insertion cursor */}; static void blinkreset(Tk*); staticTkOption opts[] ={	"xscrollcommand",	OPTtext,	O(TkEntry, xscroll),	nil,	"justify",		OPTstab,	O(TkEntry, flag),	tkjust,	"show",			OPTtext,	O(TkEntry, show),	nil,	nil}; static intxinset(Tk *tk){	return Entrypadx + tk->highlightwidth;} static intyinset(Tk *tk){	return Entrypady + tk->highlightwidth;} static voidtksizeentry(Tk *tk){	if((tk->flag & Tksetwidth) == 0)		tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;	if((tk->flag & Tksetheight) == 0)		tk->req.height = tk->env->font->height+ 2*yinset(tk);} intentrytextwidth(Tk *tk, int n){	TkEntry *tke = TKobj(TkEntry, tk);	Rune c;	Font *f; 	f = tk->env->font;	if (tke->show != nil) {		chartorune(&c, tke->show);		return n * runestringnwidth(f, &c, 1);	}	return runestringnwidth(f, tke->text, n);} static intx2index(Tk *tk,  int x, int *xc){	TkEntry *tke = TKobj(TkEntry, tk);	int t0, t1, r, q; 	t0 = 0;	t1 = tke->textlen;	while (t0 <= t1) {		r = (t0 + t1) / 2;		q = entrytextwidth(tk, r);		if (q == x) {			if (xc != nil)				*xc = q;			return r;		}		if (q < x)			t0 = r + 1;		else			t1 = r - 1;	}	if (xc != nil)		*xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;	if (t1 < 0)		t1 = 0;	return t1;} /* * recalculate derived values */static voidrecalcentry(Tk *tk){	TkEntry *tke = TKobj(TkEntry, tk);	int x, avail, locked; 	locked = lockdisplay(tk->env->top->display); 	tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth; 	avail = tk->act.width - 2*xinset(tk);	if (tke->xlen < avail) {		switch(tke->flag & Ejustify) {		default:			tke->x0 = 0;			break;		case Eright:			tke->x0 = -(avail - tke->xlen);			break;		case Ecenter:			tke->x0 = -(avail - tke->xlen) / 2;			break;		}	} 	tke->v0 = x2index(tk, tke->x0, &tke->xv0);	tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);	/* perhaps include partial last character */	if (tke->v1 < tke->textlen && x < avail + tke->x0)		tke->v1++;	tke->xsel0 = entrytextwidth(tk, tke->sel0);	tke->xsel1 = entrytextwidth(tk, tke->sel1);	tke->xicursor = entrytextwidth(tk, tke->icursor); 	if (locked)		unlockdisplay(tk->env->top->display);} char*tkentry(TkTop *t, char *arg, char **ret){	Tk *tk;	char *e;	TkName *names;	TkEntry *tke;	TkOptab tko[3]; 	tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));	if(tk == nil)		return TkNomem; 	tk->relief = TKsunken;	tk->borderwidth = 1;	tk->flag |= Tktakefocus;	tk->highlightwidth = 1; 	tke = TKobj(TkEntry, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tke;	tko[1].optab = opts;	tko[2].ptr = nil; 	names = nil;	e = tkparse(t, arg, tko, &names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));	tksizeentry(tk);	e = tkbindings(t, tk, b, nelem(b)); 	if(e != nil) {		tkfreeobj(tk);		return e;	} 	e = tkaddchild(t, tk, &names);	tkfreename(names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tk->name->link = nil;	recalcentry(tk); 	return tkvalue(ret, "%s", tk->name->name);} static char*tkentrycget(Tk *tk, char *arg, char **val){	TkOptab tko[3];	TkEntry *tke = TKobj(TkEntry, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tke;	tko[1].optab = opts;	tko[2].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} voidtkfreeentry(Tk *tk){	TkEntry *tke = TKobj(TkEntry, tk); 	free(tke->xscroll);	free(tke->text);	free(tke->show);} static voidtkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env){	TkEntry *tke = TKobj(TkEntry, tk);	Point dp;	int s0, s1, xs0, xs1, j;	Rectangle r;	Rune showr, *text; 	dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);	if (tke->show) {		chartorune(&showr, tke->show);		text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);		if (text == nil)			return;		for (j = 0; j < tke->textlen; j++)			text[j] = showr;	} else		text = tke->text; 	runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,				text+tke->v0, tke->v1-tke->v0); 	if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {		if (tke->sel0 < tke->v0) {			s0 = tke->v0;			xs0 = tke->xv0 - tke->x0;		} else {			s0 = tke->sel0;			xs0 = tke->xsel0 - tke->x0;		} 		if (tke->sel1 > tke->v1) {			s1 = tke->v1;			xs1 = s.max.x;		} else {			s1 = tke->sel1;			xs1 = tke->xsel1 - tke->x0;		} 		r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);		tktextsdraw(i, r, env, 1);		runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,				text+s0, s1-s0);	} 	if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {		r = Rect(			tke->xicursor - tke->x0, 0, 			tke->xicursor - tke->x0 + Inswidth, env->font->height		);		draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);	}	if (tke->show)		free(text);} char*tkdrawentry(Tk *tk, Point orig){	Point p;	TkEnv *env;	Rectangle r, s;	Image *i;	int xp, yp; 	env = tk->env; 	r.min = ZP;	r.max.x = tk->act.width + 2*tk->borderwidth;	r.max.y = tk->act.height + 2*tk->borderwidth;	i = tkitmp(env, r.max, TkCbackgnd);	if(i == nil)		return nil; 	xp = tk->borderwidth + xinset(tk);	yp = tk->borderwidth + yinset(tk);	s = r;	s.min.x += xp;	s.max.x -= xp;	s.min.y += yp;	s.max.y -= yp;	tkentrytext(i, s, tk, env); 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); 	if (tkhaskeyfocus(tk))		tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd)); 	p.x = tk->act.x + orig.x;	p.y = tk->act.y + orig.y;	r = rectaddpt(r, p);	draw(tkimageof(tk), r, i, nil, ZP); 	return nil;}	char*tkentrysh(Tk *tk){	TkEntry *tke = TKobj(TkEntry, tk);	int dx, top, bot;	char *val, *cmd, *v, *e; 	if(tke->xscroll == nil)		return nil; 	bot = 0;	top = Tkfpscalar; 	if(tke->text != 0 && tke->textlen != 0) {		dx = tk->act.width - 2*xinset(tk); 		if (tke->xlen > dx) {			bot = TKI2F(tke->x0) / tke->xlen;			top = TKI2F(tke->x0 + dx) / tke->xlen;		}	} 	val = mallocz(Tkminitem, 0);	if(val == nil)		return TkNomem;	v = tkfprint(val, bot);	*v++ = ' ';	tkfprint(v, top);	cmd = mallocz(Tkminitem, 0);	if(cmd == nil) {		free(val);		return TkNomem;	}	sprint(cmd, "%s %s", tke->xscroll, val);	e = tkexec(tk->env->top, cmd, nil);	free(cmd);	free(val);	return e;} voidtkentrygeom(Tk *tk){	char *e;	e = tkentrysh(tk);	if ((e != nil) &&	/* XXX - Tad: should propagate not print */             (tk->name != nil))		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);	recalcentry(tk);} static char*tkentryconf(Tk *tk, char *arg, char **val){	char *e;	TkGeom g;	int bd;	TkOptab tko[3];	TkEntry *tke = TKobj(TkEntry, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tke;	tko[1].optab = opts;	tko[2].ptr = nil; 	if(*arg == '\0')		return tkconflist(tko, val); 	bd = tk->borderwidth;	g = tk->req;	e = tkparse(tk->env->top, arg, tko, nil);	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));	tksizeentry(tk);	tkgeomchg(tk, &g, bd);	recalcentry(tk);	tk->dirty = tkrect(tk, 1);	return e;} static char*tkentryparseindex(Tk *tk, char *buf, int *index){	TkEntry *tke = TKobj(TkEntry, tk);	TkEnv *env;	char *mod;	int i, x, locked, modstart; 	modstart = 0;	for(mod = buf; *mod != '\0'; mod++)		if(*mod == '-' || *mod == '+') {			modstart = *mod;			*mod = '\0';			break;		}	if(strcmp(buf, "end") == 0)		i = tke->textlen;	else	if(strcmp(buf, "anchor") == 0)		i = tke->anchor;	else	if(strcmp(buf, "insert") == 0)		i = tke->icursor;

Lines 1–500 of 1368.