code: 9ferno

ref: 600bbfe4aaa9ad0f73d8d73eef1b7670e5f7d3a3
dir: /appl/lib/popup.b/

View raw version
implement Popup;
include "sys.m";
	sys: Sys;
include "draw.m";
	Point: import Draw;
include "tk.m";
	tk: Tk;
include "popup.m";

init()
{
	sys = load Sys Sys->PATH;
	tk = load Tk Tk->PATH;
}

post(win: ref Tk->Toplevel, p: Point, a: array of string, n: int): chan of int
{
	rc := chan of int;
	spawn postproc(win, p, a, n, rc);
	return rc;
}

postproc(win: ref Tk->Toplevel, p: Point, a: array of string, n: int, rc: chan of int)
{
	c := chan of string;
	tk->namechan(win, c, "c.popup");
	mkpopupmenu(win, a);
	cmd(win, ".popup entryconfigure " + string n + " -state active");
	cmd(win, "bind .popup <Unmap> {send c.popup unmap}");

	dy := ypos(win, n) - ypos(win, 0);
	p.y -= dy;
	cmd(win, ".popup post " + string p.x + " " + string p.y +
		";grab set .popup");
	n = -1;
	while ((e := <-c) != "unmap")
		n = int e;

	cmd(win, "destroy .popup");
	rc <-= n;
}

mkpopupmenu(win: ref Tk->Toplevel, a: array of string)
{
	cmd(win, "menu .popup");
	for (i := 0; i < len a; i++) {
		cmd(win, ".popup add command -command {send c.popup " + string i +
			"} -text '" + a[i]);
	}
}

Blank: con "-----";

# XXX what should we do about popups containing no items.
mkbutton(win: ref Tk->Toplevel, w: string, a: array of string, n: int): chan of string
{
	c := chan of string;
	if (len a == 0) {
		cmd(win, "label " + w + " -bd 2 -relief raised -text '" + Blank);
		return c;
	}
	tk->namechan(win, c, "c" + w);
	mkpopupmenu(win, a);
	cmd(win, "label " + w + " -bd 2 -relief raised -width [.popup cget -width] -text '" + a[n]);
	cmd(win, "bind " + w + " <Button-1> {send c" + w + " " + w + "}");
	cmd(win, "destroy .popup");
	return c;
}

changebutton(win: ref Tk->Toplevel, w: string, a: array of string, n: int)
{
	if (len a > 0) {
		mkpopupmenu(win, a);
		cmd(win, w + " configure -width [.popup cget -width] -text '" + a[n]);
		cmd(win, "bind " + w + " <Button-1> {send c" + w + " " + w + "}");
		cmd(win, "destroy .popup");
	} else {
		cmd(win, w + " configure -text '" + Blank);
		cmd(win, "bind " + w + " <Button-1> {}");
	}
}

add(a: array of string, s: string): (array of string, int)
{
	for (i := 0; i < len a; i++)
		if (s == a[i])
			return (a, i);
	na := array[len a + 1] of string;
	na[0:] = a;
	na[len a] = s;
	return (na, len a);
}

#event(win: ref Tk->Toplevel, e: string, a: array of string): int
#{
#	w := e;
#	p := Point(int cmd(win, w + " cget -actx"), int cmd(win, w + " cget -acty"));
#	s := cmd(win, w + " cget -text");
#	for (i := 0; i < len a; i++)
#		if (s == a[i])
#			break;
#	if (i == len a)
#		i = 0;
#		
#	n := post(win, p, a, i);
#	if (n != -1) {
#		cmd(win, w + " configure -text '" + a[n]);
#		i = n;
#	}
#	return i;
#}

ypos(win: ref Tk->Toplevel, n: int): int
{
	return int cmd(win, ".popup yposition " + string n);
}

cmd(win: ref Tk->Toplevel, s: string): string
{
	r := tk->cmd(win, s);
	if (len r > 0 && r[0] == '!')
		sys->print("error executing '%s': %s\n", s, r[1:]);
	return r;
}