summaryrefslogtreecommitdiff
path: root/appl/wm/coffee.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/wm/coffee.b')
-rw-r--r--appl/wm/coffee.b227
1 files changed, 227 insertions, 0 deletions
diff --git a/appl/wm/coffee.b b/appl/wm/coffee.b
new file mode 100644
index 00000000..09369bc9
--- /dev/null
+++ b/appl/wm/coffee.b
@@ -0,0 +1,227 @@
+implement Coffee;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+ Context, Display, Point, Rect, Image, Screen: import draw;
+
+include "tk.m";
+ tk: Tk;
+ Toplevel: import tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+Coffee: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+display: ref Display;
+t: ref Toplevel;
+
+NC: con 6;
+
+task_cfg := array[] of {
+ "frame .f",
+ "frame .b",
+ "button .b.Stop -text Stop -command {send cmd stop}",
+ "scale .b.Rate -from 1 -to 10 -orient horizontal"+
+ " -showvalue 0 -command {send cmd rate}",
+ "scale .b.Jitter -from 0 -to 5 -orient horizontal"+
+ " -showvalue 0 -command {send cmd jitter}",
+ "scale .b.Skip -from 0 -to 25 -orient horizontal"+
+ " -showvalue 0 -command {send cmd skip}",
+ ".b.Rate set 3",
+ ".b.Jitter set 2",
+ ".b.Skip set 5",
+ "pack .b.Stop .b.Rate .b.Jitter .b.Skip -side left",
+ "pack .b -anchor w",
+ "pack .f -side bottom -fill both -expand 1",
+};
+
+init(ctxt: ref Context, nil: list of string)
+{
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ tk = load Tk Tk->PATH;
+ tkclient = load Tkclient Tkclient->PATH;
+
+ sys->pctl(Sys->NEWPGRP, nil);
+
+ tkclient->init();
+ if(ctxt == nil)
+ ctxt = tkclient->makedrawcontext();
+ display = ctxt.display;
+
+ menubut: chan of string;
+ (t, menubut) = tkclient->toplevel(ctxt, "", "Infernal Coffee", 0);
+
+ cmdch := chan of string;
+ tk->namechan(t, cmdch, "cmd");
+
+ for (i := 0; i < len task_cfg; i++)
+ cmd(t, task_cfg[i]);
+
+ tk->cmd(t, "update");
+ tkclient->startinput(t, "ptr"::"kbd"::nil);
+ tkclient->onscreen(t, nil);
+
+ ctl := chan of (string, int, int);
+ spawn animate(ctl);
+
+ for(;;) alt {
+ s := <-t.ctxt.kbd =>
+ tk->keyboard(t, s);
+ s := <-t.ctxt.ptr =>
+ tk->pointer(t, *s);
+ s := <-t.ctxt.ctl or
+ s = <-t.wreq or
+ s = <-menubut =>
+ tkclient->wmctl(t, s);
+ press := <-cmdch =>
+ (nil, word) := sys->tokenize(press, " ");
+ case hd word {
+ "stop" or "go" =>
+ ctl <-= (hd word, 0, 0);
+ "rate" or "jitter" or "skip" =>
+ ctl <-= (hd word, int hd tl word, 0);
+ }
+ }
+
+}
+
+animate(ctl: chan of (string, int, int))
+{
+ stopped := 0;
+
+ fill := display.open("/icons/bigdelight.bit");
+ if (fill == nil) {
+ sys->fprint(sys->fildes(2), "coffee: failed to allocate image\n");
+ exit;
+ }
+
+ c := array[NC] of ref Image;
+ m := array[NC] of ref Image;
+
+ for(i:=0; i<NC; i++){
+ c[i] = display.open("/icons/coffee"+string i+".bit");
+ m[i] = display.open("/icons/coffee"+string i+".mask");
+ if (c[i] == nil || m[i] == nil) {
+ sys->fprint(sys->fildes(2), "coffee: failed to allocate image\n");
+ exit;
+ }
+ }
+
+ r := Rect((0, 0), (400, 300));
+ buffer := display.newimage(r, t.image.chans, 0, Draw->Black);
+ if (buffer == nil) {
+ sys->fprint(sys->fildes(2), "coffee: failed to allocate image\n");
+ exit;
+ }
+ cmd(t, "panel .f.p -bd 3 -relief flat");
+ cmd(t, "pack .f.p -fill both -expand 1");
+ cmd(t, "update");
+ # org := buffer.r.min;
+ tk->putimage(t, ".f.p", buffer, nil);
+
+ rate := 3;
+ jitter := 2;
+ skip := 5;
+
+ i = 0;
+ for(k:=0; ; k++){
+ sys->sleep(1);
+ if(k%25 > 25-skip)
+ i -= rate;
+ else
+ i += rate;
+ buffer.draw(buffer.clipr, fill, nil, fill.r.min);
+ center := buffer.r.max.div(2);
+ for(j:=0; j<NC; j++){
+ (sin, cos) := sincos(i+j*(360/NC));
+ x := (sin*150)/1000 + jitter*(k%5);
+ y := (cos*100)/1000 + jitter*(k%5);
+ p0 := center.add((x-c[j].r.dx()/2, y-c[j].r.dy()/2));
+ buffer.draw(c[j].r.addpt(p0), c[j], m[j], (0,0));
+ if(j & 1) # be nice from time to time
+ sys->sleep(0);
+ }
+ tk->cmd(t, ".f.p dirty; update");
+ sys->sleep(5);
+ alt{
+ (cmd, i0, i1) := <-ctl =>
+ Pause:
+ for(;;){
+ case cmd{
+ "go" =>
+ if(stopped){
+ tk->cmd(t, ".b.Stop configure -text Stop -command {send cmd stop}");
+ tk->cmd(t, "update");
+ stopped = 0;
+ }
+ break Pause;
+ "stop" =>
+ if(!stopped){
+ tk->cmd(t, ".b.Stop configure -text { Go } -command {send cmd go}");
+ tk->cmd(t, "update");
+ stopped = 1;
+ }
+ "rate" =>
+ rate = i0;
+ if(stopped == 0)
+ break Pause;
+ "jitter" =>
+ jitter = i0;
+ if(stopped == 0)
+ break Pause;
+ "skip" =>
+ skip = i0;
+ if(stopped == 0)
+ break Pause;
+ }
+ (cmd, i0, i1) = <-ctl;
+ }
+ * =>
+ ;
+ }
+ }
+}
+
+sintab := array[] of {
+ 0000, 0017, 0035, 0052, 0070, 0087, 0105, 0122, 0139, 0156,
+ 0174, 0191, 0208, 0225, 0242, 0259, 0276, 0292, 0309, 0326,
+ 0342, 0358, 0375, 0391, 0407, 0423, 0438, 0454, 0469, 0485,
+ 0500, 0515, 0530, 0545, 0559, 0574, 0588, 0602, 0616, 0629,
+ 0643, 0656, 0669, 0682, 0695, 0707, 0719, 0731, 0743, 0755,
+ 0766, 0777, 0788, 0799, 0809, 0819, 0829, 0839, 0848, 0857,
+ 0866, 0875, 0883, 0891, 0899, 0906, 0914, 0921, 0927, 0934,
+ 0940, 0946, 0951, 0956, 0961, 0966, 0970, 0974, 0978, 0982,
+ 0985, 0988, 0990, 0993, 0995, 0996, 0998, 0999, 0999, 1000,
+ 1000, };
+
+sincos(a: int): (int, int)
+{
+ a %= 360;
+ if(a < 0)
+ a += 360;
+
+ if(a <= 90)
+ return (sintab[a], sintab[90-a]);
+ if(a <= 180)
+ return (sintab[180-a], -sintab[a-90]);
+ if(a <= 270)
+ return (-sintab[a-180], -sintab[270-a]);
+ return (-sintab[360-a], sintab[a-270]);
+}
+
+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;
+}