diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/demo/camera/tkinterface.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/demo/camera/tkinterface.b')
| -rw-r--r-- | appl/demo/camera/tkinterface.b | 2508 |
1 files changed, 2508 insertions, 0 deletions
diff --git a/appl/demo/camera/tkinterface.b b/appl/demo/camera/tkinterface.b new file mode 100644 index 00000000..69be88e9 --- /dev/null +++ b/appl/demo/camera/tkinterface.b @@ -0,0 +1,2508 @@ +# Sort out timing with taking photo & getting jpg/thumbnail - make sure it gets the right one when 2photos have been taken & sort out 'cannot communicate with camera' error + +implement tkinterface; + +include "tk.m"; + tk: Tk; +include "tkclient.m"; + tkclient: Tkclient; +include "sys.m"; + sys : Sys; +include "daytime.m"; + daytime: Daytime; +include "readdir.m"; + readdir: Readdir; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "selectfile.m"; + selectfile: Selectfile; + +include "string.m"; + str : String; +include "draw.m"; + draw: Draw; + Context, Display, Point, Rect, Image, Screen, Font: import draw; +include "grid/readjpg.m"; + readjpg: Readjpg; + +display : ref draw->Display; +context : ref draw->Context; +camerapath := ""; +savepath := ""; +tmppath := "/tmp/"; +usecache := 1; +working := 0; +processing := 0; +coords: draw->Rect; +DONE : con 1; +KILLED : con 2; +font: ref Draw->Font; +tkfont := ""; +tkfontb := ""; +tkfontf := ""; +ssize := 3; +maxsize : Point; +nilrect := Draw->Rect((0,0),(0,0)); +runwithoutcam := 0; +toplevels : list of (ref Tk->Toplevel, string, list of int, int) = nil; +procimg : ref Draw->Image; +loadimg: ref Draw->Image; + +tkinterface : module { + init : fn (ctxt : ref Draw->Context, argv : list of string); +}; + +init(ctxt : ref Draw->Context, argv : list of string) +{ + display = ctxt.display; + context = ctxt; + + sys = load Sys Sys->PATH; +# sys->pctl(Sys->NEWPGRP, nil); +# sys->pctl(Sys->FORKNS, nil); + + str = load String String->PATH; + readdir = load Readdir Readdir->PATH; + daytime = load Daytime Daytime->PATH; + bufio = load Bufio Bufio->PATH; + + str = load String String->PATH; + draw = load Draw Draw->PATH; + + tk = load Tk Tk->PATH; + tkclient = load Tkclient Tkclient->PATH; + tkclient->init(); + selectfile = load Selectfile Selectfile->PATH; + selectfile->init(); + readjpg = load Readjpg Readjpg->PATH; + readjpg->init(display); + font = draw->Font.open(display, "/fonts/charon/plain.small.font"); + runfrom := hd argv; + p := isat2(runfrom,"/"); + savepath = runfrom[:p+1]; + argv = tl argv; + while (argv != nil) { + if (camerapath == "" && (hd argv)[0] == '/') camerapath = hd argv; + if (hd argv == "nocache") usecache = 0; + argv = tl argv; + } + if (camerapath == "") + camerapath = "./"; + if (camerapath != "" && camerapath[len camerapath - 1] != '/') + camerapath[len camerapath] = '/'; + + r := display.image.r; +# if (r.dx() < 800 || r.dy() < 600) ssize = 2; + if (r.dx() < 400 || r.dy() < 300) ssize = 1; + maxsize = (r.dx(), r.dy()); + + if (ssize == 1) { + tkfont = "/fonts/charon/plain.tiny.font"; + tkfontb = "/fonts/charon/bold.tiny.font"; + tkfontf = "/fonts/pelm/unicode.8.font"; + } + else if (ssize == 2) { + tkfont = "/fonts/charon/plain.small.font"; + tkfontb = "/fonts/charon/bold.small.font"; + tkfontf = "/fonts/pelm/unicode.8.font"; + } + else { + tkfont = "/fonts/charon/plain.normal.font"; + tkfontb = "/fonts/charon/bold.normal.font"; + tkfontf = "/fonts/pelm/unicode.8.font"; + } + if ((sys->stat(tkfont)).t0 == -1) + tkfont = ""; + else tkfont = " -font " + tkfont; + if ((sys->stat(tkfontb)).t0 == -1) + tkfontb = ""; + else tkfontb = " -font " + tkfontb; + if ((sys->stat(tkfontf)).t0 == -1) + tkfontf = ""; + else tkfontf = " -font " + tkfontf; + + procimg = display.open("camproc.bit"); + loadimg = display.open("camload.bit"); + + spawn tkstuff(); +} + +# Tk stuff + +thumbscr := array[] of { + "frame .f", + "frame .fthumb -bg white", + "frame .f.finfo", + "frame .f.fsnap", + "menubutton .f.fsnap.fsettings.mb2 -text {Selected\n(0 files)} -menu .m2 @", + "menu .m2 @", + ".m2 add command -text {Select All} -command {send butchan selectall 1}", + ".m2 add command -text {Select None} -command {send butchan selectall 0}", + ".m2 add command -text {Invert Selection} -command {send butchan invert}", + ".m2 add command -text {Refresh Files} -command {send butchan refresh}", + "menu .m @", + + "frame .f.fsnap.fsettings -borderwidth 1 -relief raised", + "menubutton .f.fsnap.fsettings.mb -text {Settings} -menu .m &", + "button .f.fsnap.fsettings.b -text {Information} -command {send butchan info} &", + "grid .f.fsnap.fsettings.b -row 0 -column 0 -sticky ew", + "grid .f.fsnap.fsettings.mb -row 1 -column 0 -sticky ew", + "grid .f.fsnap.fsettings.mb2 -row 2 -column 0 -sticky ew", + + "frame .f.fsnap.fstore -borderwidth 1 -relief raised", + "label .f.fsnap.fstore.l1 -text { Photos taken: } @", + "label .f.fsnap.fstore.l2 -text { Remaining: } @", + "label .f.fsnap.fstore.l3 -text { } @", + "label .f.fsnap.fstore.l4 -text { } @", + "grid .f.fsnap.fstore.l1 -row 0 -column 0 -sticky w", + "grid .f.fsnap.fstore.l2 -row 1 -column 0 -sticky w", + "grid .f.fsnap.fstore.l3 -row 0 -column 1 -sticky w", + "grid .f.fsnap.fstore.l4 -row 1 -column 1 -sticky w", + + "frame .f.fsnap.ftime -borderwidth 1 -relief raised", + "label .f.fsnap.ftime.l1 -text {Local: } @", + "label .f.fsnap.ftime.l2 -text {Camera: } @", + "label .f.fsnap.ftime.l3", + "label .f.fsnap.ftime.l4", + "checkbutton .f.fsnap.ftime.cb -text {Set camera to local time} -variable time &", + "button .f.fsnap.ftime.b -text {refresh} -command {send butchan gettime} &", + "grid .f.fsnap.ftime.l1 -row 0 -column 0 -sticky w", + "grid .f.fsnap.ftime.l2 -row 1 -column 0 -sticky w", + "grid .f.fsnap.ftime.l3 -row 0 -column 1 -sticky w", + "grid .f.fsnap.ftime.l4 -row 1 -column 1 -sticky w", + "grid .f.fsnap.ftime.cb -row 2 -column 0 -columnspan 2", + "grid .f.fsnap.ftime.b -row 3 -column 0 -columnspan 2", + + "button .f.fsnap.b -text {Take Photo} -command {send butchan snap} &", + "grid columnconfigure .f.fsnap 2 -minsize 150", + "frame .f.fcom", + "frame .f.f1 -background #0d0d0d1a", + "canvas .f.f1.c1 -yscrollcommand {.f.f1.sb1 set} -height 255 -width 542 -bg white", + ".f.f1.c1 create window 0 0 -window .fthumb -anchor nw", + "scrollbar .f.f1.sb1 -command {.f.f1.c1 yview}", + +# "frame .f.f2", +# "canvas .f.f2.c1 -width 556 -height 304", +# ".f.f2.c1 create window 0 0 -window .f.fsnap -anchor nw", + + "grid .f.fsnap -column 0 -row 0", + "grid .f.f1 -column 0 -row 1", + "grid .f.f1.c1 -column 0 -row 0", + "grid .f.f1.sb1 -column 1 -row 0 -sticky ns", +# "grid .f.f2 -column 0 -row 0", +# "grid .f.f2.c1 -column 0 -row 0 -sticky ew", + "bind .Wm_t <ButtonPress-1> +{focus .}", + "bind .Wm_t.title <ButtonPress-1> +{focus .}", +}; + +lastpath := ""; + +Aitem: adt { + pname,desc: string; + dtype,factory: int; + read, location: string; + data: list of (string, int); +}; +LIST: con 0; +MINMAX: con 1; +OTHER: con 2; + +noabilities := 0; +abilities : array of Aitem; + +getdesc(l : list of string): list of string +{ + s := ""; + while(hd l != "min" && hd l != "items" && tl l != nil) { + s += hd l + " "; + l = tl l; + } + while (s[len s - 1] == ' ' || s[len s - 1] == '\n') + s = s[:len s -1]; + l = s :: l; + return l; +} + +inflist : list of (string, string); +ablmenu : array of string; + +getabilities() +{ + inflist = nil; + abilities = array[200] of Aitem; + fd := bufio->open(camerapath+"abilities", bufio->OREAD); + if (runwithoutcam) + fd = bufio->open("/usr/danny/camera/abls", bufio->OREAD); + i := 0; + for (;;) { + take := 0; + s := fd.gets('\n'); + if (s == "") break; + (n, lst) := sys->tokenize(s," ,:\t\n"); + abilities[i].data = nil; + abilities[i].read = ""; + if (lst != nil && len hd lst == 4) { + abilities[i].pname = hd lst; + lst = getdesc(tl lst); + abilities[i].desc = hd lst; + if (hd tl lst == "items") { + abilities[i].dtype = LIST; + abilities[i].factory = int hd tl tl tl tl lst; + noitems := int hd tl tl lst; + for (k := 0; k < noitems; k++) { + s = fd.gets('\n'); + (n2, lst2) := sys->tokenize(s,",:\t\n"); + name := hd lst2; + val := int hd tl lst2; + if (k == 0) { + if (abilities[i].pname == "ssiz") + abilities[i].factory = val; + else if (abilities[i].pname == "scpn") + abilities[i].factory = val; + } + if (val == abilities[i].factory && noitems > 1) name += " *"; + abilities[i].data = (name, val) :: abilities[i].data; + } + if (noitems < 2) { + inflist = (abilities[i].desc, (hd abilities[i].data).t0) :: inflist; + take = 1; + } + } + else if (hd tl lst == "min") { + abilities[i].dtype = MINMAX; + abilities[i].factory = int hd tl tl tl tl tl tl lst; + min := int hd tl tl lst; + max := int hd tl tl tl tl lst; + mul := 1; + while (max > 200000) { + min /= 10; + max /= 10; + mul *= 10; + } + abilities[i].data = ("min", min) :: abilities[i].data; + abilities[i].data = ("max", max) :: abilities[i].data; + abilities[i].data = ("mul", mul) :: abilities[i].data; + } + else { + inflist = (abilities[i].desc,list2string(tl lst)) :: inflist; + take = 1; + } + if (take || + abilities[i].desc == "Time Format" || + abilities[i].desc == "Date Format" || + abilities[i].desc == "File Type" || + contains(abilities[i].desc,"Video") || + contains(abilities[i].desc,"Media") || + contains(abilities[i].desc,"Sound") || + contains(abilities[i].desc,"Volume") || + contains(abilities[i].desc,"Slide") || + contains(abilities[i].desc,"Timelapse") || + contains(abilities[i].desc,"Burst") || + contains(abilities[i].desc,"Power") || + contains(abilities[i].desc,"Sleep")) + i--; + i++; + } + } + noabilities = i; +} + +isat(s: string, test: string): int +{ + num := -1; + if (len test > len s) return -1; + for (i := 0; i < (1 + (len s) - (len test)); i++) { + if (num == -1 && test == s[i:i+len test]) num = i; + } + return num; +} + +isat2(s: string, test: string): int +{ + num := -1; + if (len test > len s) return -1; + for (i := len s - len test; i >= 0; i--) { + if (num == -1 && test == s[i:i+len test]) num = i; + } + return num; +} + + +nomatches(s: string): int +{ + n := 0; + for (i := 0; i < noabilities; i++) { + test := abilities[i].desc; + if (len s <= len test && test[:len s] == s) n++; + } + return n; +} + +matches(s1,s2: string): int +{ + if (len s1 < len s2) return 0; + if (s1[:len s2] == s2) return 1; + return 0; +} + +biggestmatch(nm: int, s: string, l: int): string +{ + bigmatch := s; + match := s[:l]; + for (;;) { + if (bigmatch == match) break; + if (nomatches(bigmatch) == nm) return bigmatch; + p := isat2(bigmatch," "); + if (p < len match) break; + bigmatch = bigmatch[:p]; + } + return match; +} + +getabllist(): array of string +{ + los : list of string; + los = nil; + for (i := 0; i < noabilities; i++) { + p := 0; + p2 := 0; + nm : int; + for (;;) { + nm = -1; + tmpl := los; + while (tmpl != nil) { + if (matches(abilities[i].desc, hd tmpl)) nm = 0; + tmpl = tl tmpl; + } + if (nm == 0) break; + p += p2; + tmp := abilities[i].desc[p:]; + p2 = isat(tmp, " "); + if (p2 == -1) p2 = len tmp; + else p2++; + nm = nomatches(abilities[i].desc[:p+p2]); + if (nm <= 5) break; + } + if (nm > 0) { + listitem := biggestmatch(nm, abilities[i].desc,p+p2); + los = listitem :: los; + } + } + ar := array[len los] of string; + for (i = len ar - 1; i >= 0; i--) { + ar[i] = hd los; + los = tl los; + } + return ar; +} + +buildabilitiesframes(top: ref Tk->Toplevel) +{ + ablmenu = getabllist(); + tkcmd(top, ".m add command -text {Refresh Main Screen} -command {send butchan refreshstate}"); + tkcmd(top, ".m add command -text {Reset Camera} -command {send butchan reset}"); + for (k := 0; k < len ablmenu; k++) { + if (len ablmenu[k] > 4 && (ablmenu[k][:4] == "Zoom" || ablmenu[k][:5] == "Still")) + buildabilitiesframe(top,k,"butchan"); + else + tkcmd(top, ".m add command -text {"+ablmenu[k]+ + "} -command {send butchan abls "+string k+"}"); + } + tkcmd(top, "menu .mthumb "+tkfont); + tkcmd(top, ".mthumb add command -label {Selection (88 files)}"); + tkcmd(top, ".mthumb add separator"); + for (k = nothumbs; k < len menu; k++) + tkcmd(top, ".mthumb add command -text {"+menu[k].text+"} " + + "-command {send butchan}"); + +} + +buildabilitiesframe(top: ref Tk->Toplevel,k: int, chanout: string) +{ + nm := string nomatches(ablmenu[k]); + count2 := 0; + for (i := 0; i < noabilities; i++) { + if (matches(abilities[i].desc,ablmenu[k])) { + + frame : string; + case abilities[i].pname { + "scpn" or "ssiz" or "zpos" => + frame = ".f.fsnap.f"+abilities[i].pname; + tkcmd(top, "frame "+frame+" -borderwidth 1 -relief raised"); + * => + frame = ".f"; + if (count2 == 0) { + tkcmd(top, "frame "+frame); + tkcmd(top, "label "+frame+".l -text {"+ablmenu[k]+"}"+tkfontb); + tkcmd(top, "grid "+frame+".l -row 0 -column 0 -columnspan "+nm); + } + frame = frame + ".f"+string count2; + tkcmd(top, "frame "+frame+" -borderwidth 1 -relief raised"); + tkcmd(top, "grid "+frame+" -row 1 -column "+string count2+ " -sticky nsew"); + mul := getval(abilities[i].data,"mul"); + s := abilities[i].desc[len ablmenu[k]:]; + if (mul != 1 && abilities[i].dtype == MINMAX) + s += " (x"+string mul+")"; + tkcmd(top, "label "+frame+".l -text {"+s+"}"+tkfont); + tkcmd(top, "grid "+frame+".l -row 0 -column 0 -sticky nw"); + } + + if (abilities[i].dtype == MINMAX) { + abilities[i].location = frame+".sc"; + min := getval(abilities[i].data,"min"); + max := getval(abilities[i].data,"max"); + tkcmd(top, sys->sprint("scale %s.sc -to %d -from %d %s", frame,min,max,tkfont)); + tkcmd(top, "bind "+frame+".sc <ButtonPress-3> {send " + + chanout + " scaleval " + string i + " %X %Y}"); + tkcmd(top, "grid "+frame+".sc -row 1 -column 0"); + } + else if (abilities[i].dtype == LIST) { + tkcmd(top, "frame "+frame+".frb"); + tkcmd(top, "grid "+frame+".frb -row 1 -column 0"); + tmp := abilities[i].data; + row := 0; + while (tmp != nil) { + (name, val) := hd tmp; + s := sys->sprint("radiobutton %s.frb.rb%d -text {%s} -value %d -variable %s -height %d %s",frame,row,name,val,abilities[i].pname,24 - (3*(3-ssize)), tkfont); + tkcmd(top,s); + tkcmd(top, sys->sprint("grid %s.frb.rb%d -row %d -column 0 -sticky w", + frame,row,row)); + tmp = tl tmp; + row++; + } + } + tkcmd(top, "button "+frame+".bs -text {Set} -command "+ + "{send "+chanout+" set "+string i+"}"+butheight+tkfont); + tkcmd(top, "grid "+frame+".bs -row 2 -column 0 -sticky ew"); + if (abilities[i].dtype == MINMAX) { + tkcmd(top, "button "+frame+".bf -text {Default} -command "+ + "{send "+chanout+" setdef "+string i+"}"+butheight+tkfont); + tkcmd(top, "grid "+frame+".bf -row 3 -column 0 -sticky ew"); + } + count2++; + } + } +} + +getvaluescr := array[] of { + "frame .f -height 84 -width 114 -borderwidth 2 -relief raised", + "label .f.l1 -text {Enter Value:} @", + "entry .f.e1 -width 100 -bg white @", + "button .f.b1 -text { ok } -command {send chanin ok} &", + "button .f.b2 -text cancel -command {send chanin cancel} &", + "grid .f.l1 -column 1 -row 0 -columnspan 2 -padx 0 -sticky w", + "grid .f.e1 -column 1 -row 1 -columnspan 2 -padx 0 -pady 5", + "grid .f.b1 -column 1 -row 2 -padx 0", + "grid .f.b2 -column 2 -row 2 -padx 0", + "grid columnconfigure .f 1 -minsize 20", + "grid columnconfigure .f 2 -minsize 20", + "grid columnconfigure .f 3 -minsize 5", + "grid rowconfigure .f 0 -minsize 20", + "grid rowconfigure .f 1 -minsize 20", + "grid rowconfigure .f 2 -minsize 20", + "grid columnconfigure .f 0 -minsize 5", + "bind .f.e1 <Key> {send chanin key %s}", + "focus .f.e1", + "pack .f", + "update", +}; + +getvaluescreen(x,y: string): int +{ + x = string ((int x) - 55); + y = string ((int y) - 30); + (top, nil) := tkclient->toplevel(context, "-x "+x+" -y "+y, nil, tkclient->Plain); + chanin := chan of string; + tk->namechan(top, chanin, "chanin"); + for (tk1 := 0; tk1 < len getvaluescr; tk1++) + tkcmd(top, getvaluescr[tk1]); + tkclient->onscreen(top, "exact"); + tkclient->startinput(top, "kbd"::"ptr"::nil); + for(;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + inp := <- chanin => + if (inp == "ok") return int tkcmd(top, ".f.e1 get"); + else if (inp == "cancel") return -1; + else if (inp[:3] == "key") { + s := " "; + s[0] = int inp[4:]; + if (s[0] == '\n') return int tkcmd(top, ".f.e1 get"); + if (s[0] >= '0' && s[0] <= '9') { + tkcmd(top, ".f.e1 delete sel.first sel.last"); + tkcmd(top, ".f.e1 insert insert {"+s+"}; update"); + } + } + } + } +} + +infoscreen() +{ + (top, titlebar) := tkclient->toplevel(context, "", "Information", Tkclient->Hide); + tmp := inflist; + tkcmd(top, "frame .f"); + tkcmd(top, "label .f.l -text {Information}"); + tkcmd(top, "grid .f.l -row 0 -column 0 -columnspan 2"); + tkcmd(top, "frame .f.finfo -borderwidth 1 -relief raised"); + tkcmd(top, "grid .f.finfo"); + infrow := 0; + while (tmp != nil) { + infrow++; + s := string infrow; + (d1,d2) := hd tmp; + tkcmd(top, "label .f.finfo.l"+s+"1 -text {"+d1+"}"); + tkcmd(top, "label .f.finfo.l"+s+"2 -text {"+d2+"}"); + tkcmd(top, "grid .f.finfo.l"+s+"1 -row "+s+" -column 0 -sticky w"); + tkcmd(top, "grid .f.finfo.l"+s+"2 -row "+s+" -column 1 -sticky e"); + tmp = tl tmp; + } + tkcmd(top, "pack .f; update"); + tkclient->onscreen(top, nil); + tkclient->startinput(top, "kbd"::"ptr"::nil); + main: for(;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + title := <-top.ctxt.ctl or + title = <-top.wreq or + title = <- titlebar => + if (title == "exit") break main; + tkclient->wmctl(top, title); + } + } +} + +settingsscreen(k: int, ctlchan: chan of int) +{ + low := toplevels; + for (;low != nil; low = tl low) { + (tplvl, name, nil,nil) := hd low; + if (name == ablmenu[k]) { + tkcmd(tplvl, "raise .; focus .; update"); + ctlchan <-= DONE; + return; + } + } + pid := sys->pctl(0, nil); + (top, titlebar) := tkclient->toplevel(context, "", "Config", Tkclient->Appl); + chanin := chan of string; + tk->namechan(top,chanin, "chanin"); + buildabilitiesframe(top,k, "chanin"); + tkcmd(top,"bind .Wm_t <ButtonPress-1> +{focus .}"); + tkcmd(top,"bind .Wm_t.title <ButtonPress-1> +{focus .}"); + tkcmd(top, "pack .f; update"); + err := 0; + allread := 1; + l : list of int = nil; + for (i := 0; i < noabilities; i++) { + if (matches(abilities[i].desc, ablmenu[k])) { + l = i :: l; + if (abilities[i].read != "") + setmystate(top,i,abilities[i].read); + else + allread = 0; + } + } + tkclient->onscreen(top, nil); + tkclient->startinput(top, "kbd"::"ptr"::nil); + if (!allread) { + spawn workingscreen2(getcoords(top),pid, ctlchan,0); + ltmp := l; + for (;ltmp != nil; ltmp = tl ltmp) { + if (abilities[hd ltmp].read == "" && getstate(top, hd ltmp) == -1) { + err = 1; + break; + } + } + } + if (!err) + spawn settingsloop(top,chanin,titlebar,k,l); + ctlchan <-= DONE; +} + +settingsloop(top: ref Tk->Toplevel, chanin,titlebar: chan of string, k: int, abls: list of int) +{ + tkcmd(top, "focus .Wm_t"); + pid := sys->pctl(0,nil); + addtoplevel(top,ablmenu[k], abls, pid); + ctlchan := chan of int; + main: for(;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + inp := <- chanin => + tkcmd(top, "focus ."); + (n, lst) := sys->tokenize(inp, " \t\n"); + case hd lst { + "scaleval" => + i := int hd tl lst; + val := getvaluescreen(hd tl tl lst, hd tl tl tl lst); + if (val != -1) tkcmd(top, abilities[i].location+" set "+string val+";update"); + "set" or "setdef" => + if (working) + dialog(" Camera is busy! ", 2,-1,getcoords(top)); + else { + spawn set(top, int hd tl lst, hd lst, ctlchan); + <-ctlchan; + working = 0; + } + } + clearbuffer(chanin); + title := <-top.ctxt.ctl or + title = <-top.wreq or + title = <- titlebar => + if (title == "exit") break main; + tkclient->wmctl(top, title); + } + } + deltoplevel(top); +} + +clearbuffer(c: chan of string) +{ + tc := chan of int; + spawn timer(tc); + main: for (;;) alt { + del := <-c => ; + tick := <-tc => + break main; + } +} + +timer(tick: chan of int) +{ + sys->sleep(100); + tick <- = 1; +} + +getval(l: list of (string,int), s: string): int +{ + while (l != nil) { + (name,val) := hd l; + if (name == s) return val; + l = tl l; + } + return -2; +} + +list2string(l : list of string): string +{ + s := ""; + while (l != nil) { + s += " " + hd l; + l = tl l; + } + if (s != "") return s[1:]; + return s; +} + +JPG: con 0; +THUMB: con 1; + +Imgloaded: adt { + name: string; + imgtype: int; +}; + +nofiles := 0; +filelist := array[200] of string; +thumbimg := array[200] of ref draw->Image; +selected := array[200] of { * => 0 }; +noselected := 0; +fnew : list of int; +imgloaded : list of Imgloaded; +maxwidth, maxheight: int; +nothumbs := 0; + +nocamera(): int +{ + (n,dir) := sys->stat(camerapath+"ctl"); + if (n != -1) return 0; + return 1; +} + +startuptkstuff(top: ref Tk->Toplevel, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,1); + getabilities(); + (dirs,n) := readdir->init(camerapath+"thumb", readdir->NAME); + if (n == -1) nothumbs = 1; + buildabilitiesframes(top); + refreshfilelist(top,0); + ctlchan <-= DONE; +} + +tibuild := 0; +butheight := ""; + +tkstuff() +{ + if (!runwithoutcam && nocamera()) { + dialog("Cannot find camera!",0,-1,nilrect); + exit; + } + (win, titlebar) := tkclient->toplevel(context, "", "Camera", Tkclient->Appl); + tkcmd(win, "frame .test"); + if (tkcmd(win, ".test cget -bg") == "#ffffffff") + tibuild = 1; + tkcmd(win, "destroy .test"); + butheight = " -height "+string (16 + (5*tibuild) - (3*(3-ssize))); + butchan := chan of string; + tk->namechan(win, butchan, "butchan"); + for (tk1 := 0; tk1 < len thumbscr; tk1++) + tkcmd(win, thumbscr[tk1]); + coords = display.image.r; + ctlchan := chan of int; + imgloaded = nil; + + spawn startuptkstuff(win, ctlchan); + e := <- ctlchan; + if (e == KILLED) { + dialog("Cancel during load!",0,-1,coords); + exit; + } + working = 0; + spawn mainscreen(win, 1, ctlchan); + <- ctlchan; + working = 0; + + processing = 0; + tkcmd(win, "pack propagate . 0"); + resizemain(win,1); + tkcmd(win, "pack .f; update; focus ."); + coords = getcoords(win); + loadimg = nil; + tkclient->onscreen(win, nil); + tkclient->startinput(win, "kbd"::"ptr"::nil); + main: for (;;) { + alt { + s := <-win.ctxt.kbd => + tk->keyboard(win, s); + s := <-win.ctxt.ptr => + tk->pointer(win, *s); + inp := <-butchan => + tkcmd(win, "focus ."); + (n, lst) := sys->tokenize(inp, "\t\n "); + case hd lst { + + # Communicates internally + + "scaleval" => + i := int hd tl lst; + val := getvaluescreen(hd tl tl lst, hd tl tl tl lst); + if (val != -1) tkcmd(win, abilities[i].location+" set "+string val); + "info" => + spawn infoscreen(); + "unload" => + i := int hd tl lst; + for (k := 0; k < nofiles; k++) { + if (i == k || (i == -1 && selected[k])) { + delloaded(filelist[k],JPG); + delloaded(filelist[k],THUMB); + } + } + "invert" => + nf := 0; + for (i := 0; i < nofiles; i++) + selected[i] = 1 - selected[i]; + doselect(win); + "selectall" => + val := int hd tl lst; + for (i := 0; i < nofiles; i++) + selected[i] = val; + doselect(win); + "select" => + i := int hd tl lst; + selected[i] = 1 - selected[i]; + doselect(win); + "selectonly" => + i := int hd tl lst; + val := selected[i]; + for (k := 0; k < nofiles; k++) + selected[k] = 0; + if (noselected - val == 0) selected[i] = 1 - val; + else selected[i] = 1; + doselect(win); + "menu" => + i := int hd tl lst; + if (selected[i] && noselected > 1) i = -1; + title := "Selection ("+string noselected+" files)"; + if (i != -1) title = filelist[i]+".jpg"; + si := string i; + tkcmd(win, ".mthumb entryconfigure 0 -text {"+title+"}"); + for (k := nothumbs; k < len menu; k++) + tkcmd(win, ".mthumb entryconfigure "+string (2+k-nothumbs)+ + " -command {send butchan "+ menu[k].com+" "+si+"}"); + tkcmd(win, ".mthumb post "+hd tl tl lst+" "+hd tl tl tl lst); + * => + if (!processing) + spawn dealwithcamera(win, lst); + } + tkcmd(win, "update"); + clearbuffer(butchan); + title := <-win.ctxt.ctl or + title = <-win.wreq or + title = <-titlebar => + if (title == "exit") + break main; + err := tkclient->wmctl(win, title); + if (err == nil && title == "!size") { + (n, lst) := sys->tokenize(title, " "); + if (hd tl lst == ".") + resizemain(win,0); + } + coords = getcoords(win); + } + } + for (; toplevels != nil; toplevels = tl toplevels) { + (nil, nil, nil, pid) := hd toplevels; + if (pid != -1) + kill(pid); + } + while (imgloaded != nil) { + (fname, ftype) := hd imgloaded; + sys->remove(tmppath+fname+"."+string ftype+"~"); + imgloaded = tl imgloaded; + } + tkcmd(win, "destroy ."); + exit; +} + +dealwithcamera(win: ref Tk->Toplevel, lst: list of string) +{ + ctlchan := chan of int; + processing = 1; + case hd lst { + "gettime" => + spawn refreshtime(win, ctlchan); + <- ctlchan; + "show" => + spawn loadthumb(win,int hd tl lst,ctlchan); + <- ctlchan; + "snap" => + selected[nofiles+1] = 0; + spawn takephoto(win, ctlchan); + <- ctlchan; + working = 0; + if (fnew == nil) + break; + spawn waittilready(camerapath+"jpg/"+filelist[hd fnew]+".jpg", ctlchan); + e := <- ctlchan; + working = 0; + if (e == DONE) { + spawn loadnewthumb(win, ctlchan); + <- ctlchan; + working = 0; + } + "abls" => + spawn settingsscreen(int hd tl lst, ctlchan); + <- ctlchan; + "set" or "setdef" => + spawn set(win, int hd tl lst, hd lst, ctlchan); + <- ctlchan; + "del" => + spawn delete(win, int hd tl lst, ctlchan); + <- ctlchan; + "view" => + i := int hd tl lst; + unnew(win, i); + if (i == -1) multiview(); + else vw(i); + "refresh" => + spawn refresh(win, ctlchan); + <- ctlchan; + "refreshstate" => + spawn mainscreen(win, 0, ctlchan); + <- ctlchan; + "dnld" => + i := int hd tl lst; + unnew(win, i); + if (i == -1) multidownload(); + else dnld(i, ""); + "reset" => + if (dialog("reset camera to default settings?",1,-1,coords)) { + spawn resetcam(win,1, ctlchan); + <- ctlchan; + } + } + processing = 0; + working = 0; +} + +refresh(top: ref Tk->Toplevel, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,0); + refreshfilelist(top,1); + ctlchan <-= DONE; +} + +delete(top: ref Tk->Toplevel, i: int, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + ok : int; + s := ""; + loi : list of int; + loi = nil; + if (i == -1) { + for (k := 0; k < nofiles; k++) + if (selected[k]) s+= filelist[k]+".jpg\n"; + if (!dialog("Delete Selected files?\n\n"+s,1,-1,coords)) { + ctlchan <-= DONE; + return; + } + } + else if (!dialog("Delete "+filelist[i]+".jpg?",1,i,coords)) { + ctlchan <-= DONE; + return; + } + spawn workingscreen2(coords,pid, ctlchan,0); + s = ""; + for (k := 0; k < nofiles; k++) { + if ((i == -1 && selected[k]) || k == i) { + s += filelist[k]+".jpg "; + ok = sys->remove(camerapath+ + "jpg/"+filelist[k]+".jpg"); + if (ok == -1) s+="failed\n"; + else { + s+="ok\n"; + loi = k :: loi; + } + } + } + if (loi == nil && i != -1) { + dialog("cannot remove "+filelist[i]+".jpg?",0,i,coords); + ctlchan <-= DONE; + return; + } + while (loi != nil) { + delloaded(filelist[hd loi],JPG); + delloaded(filelist[hd loi],THUMB); + delselect(hd loi); + loi = tl loi; + } + refreshfilelist(top,0); + getstore(top); + if (i == -1) dialog("Files deleted:\n\n"+s,0,-1,coords); + ctlchan <-= DONE; +} + +delselect(n: int) +{ + for (i := n; i < nofiles - 1; i++) + selected[i] = selected[i+1]; + selected[nofiles - 1] = 0; +} + +doselect(top: ref Tk->Toplevel) +{ + n := 0; + for (i := 0; i < nofiles; i++) { + col := "white"; + if (selected[i]) { + col = "blue"; + n++; + } + tkcmd(top,".fthumb.p"+string i+" configure -bg "+col); + } + noselected = n; + s := " files"; + if (n == 1) s = " file"; + tkcmd(top, ".f.fsnap.fsettings.mb2 configure -text {Selected\n("+string n+s+")}"); +} + +takephoto(top: ref Tk->Toplevel, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,0); + fd := sys->open(camerapath+"ctl",sys->OWRITE); + if (fd != nil) { + e := sys->fprint(fd, "snap"); + if (e < 0) { + dialog("Could not take photo",0,-1,coords); + getstore(top); + } + else { + getstore(top); + n := nofiles; + for (i := 0; i < 5; i++) { + refreshfilelist(top,1); + sys->sleep(1000); + if (nofiles > n) + break; + } + } + } + ctlchan <-= DONE; +} + +unnew(top: ref Tk->Toplevel, i: int) +{ + if (fnew == nil) + return; + tmp : list of int = nil; + for (;fnew != nil; fnew = tl fnew) { + if (i == -1 && selected[hd fnew]) + i = hd fnew; + if (hd fnew == i) + tkcmd(top, ".fthumb.mb"+string hd fnew+" configure -fg black; update"); + else + tmp = hd fnew :: tmp; + } + fnew = tmp; +} + +refreshtime(top: ref Tk->Toplevel, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,0); + if (!samedate(top) && tkcmd(top, "variable time") == "1") settime(); + gettime(top); + ctlchan <-= DONE; +} + +addtoplevel(top: ref Tk->Toplevel, name: string, abls: list of int, pid: int) +{ + ltmp := toplevels; + isin := 0; + for (;ltmp != nil; ltmp = tl ltmp) { + (tplvl, nil, nil, nil) := hd ltmp; + if (tplvl == top) isin = 1; + } + if (!isin) + toplevels = (top, name, abls, pid) :: toplevels; +} + +deltoplevel(top: ref Tk->Toplevel) +{ + ltmp : list of (ref Tk->Toplevel, string, list of int, int) = nil;; + for (;toplevels != nil; toplevels = tl toplevels) { + (tplvl, nm, loi, p) := hd toplevels; + if (tplvl != top) + ltmp = (tplvl, nm, loi, p) :: ltmp; + } + toplevels = ltmp; +} + +resetcam(top: ref Tk->Toplevel, show: int, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,0); + for (i := 0; i < noabilities; i++) + setstate(i, string abilities[i].factory); + if (show) { + ltmp := toplevels; + for (;ltmp != nil; ltmp = tl ltmp) { + (tplvl, nm, loi, p) := hd ltmp; + for (; loi != nil; loi = tl loi) + setmystate(tplvl, hd loi, string abilities[hd loi].factory); + } + if (top != nil) + getstore(top); + } + ctlchan <-= DONE; +} + +set(top: ref Tk->Toplevel, i: int, s: string, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(getcoords(top),pid, ctlchan,0); + + val : string; + if (s == "setdef") { + val = string abilities[i].factory; + setmystate(top,i,val); + } + else { + if (abilities[i].dtype == MINMAX) { + val = tkcmd(top, abilities[i].location+" get"); + mul := getval(abilities[i].data, "mul"); + val = string (int val * mul); + } + else { + val = tkcmd(top, "variable "+abilities[i].pname); + } + } + + e := setstate(i,val); + if (e == 2) getstore(top); + else if (e == 0) + dialog("cannot communicate with camera",0,-1,coords); + ctlchan <-= DONE; +} + +setstate(i: int, val: string): int +{ + fd := sys->open(camerapath+"ctl",sys->OWRITE); + if (fd != nil) { + sys->fprint(fd, "%s %s",abilities[i].pname,val); + abilities[i].read = val; + if (abilities[i].pname == "ssiz" || abilities[i].pname == "scpn") return 2; + return 1; + } + else return 0; +} + +getfirst(s: string): string +{ + (n, lst) := sys->tokenize(s," \n\t"); + if (lst == nil) return ""; + return hd lst; +} + +getabl(pname: string): int +{ + for (i := 0; i < noabilities; i++) + if (abilities[i].pname == pname) return i; + return -1; +} + +getstate(top: ref Tk->Toplevel, i: int): int +{ + fd := sys->open(camerapath+"state", sys->OWRITE); + if (fd != nil) { + sys->fprint(fd ,"%s", abilities[i].pname); + sys->sleep(500); + fdi := bufio->open(camerapath+"state",sys->OREAD); + if (fdi != nil) { + s := fdi.gets('\n'); + if (s != nil) { + (n,lst) := sys->tokenize(s,":\n"); + val := hd tl lst; + setmystate(top,i,val); + } + return 0; + } + } + dialog("cannot communicate with camera",0,-1,coords); + return -1; +} + +setmystate(top: ref Tk->Toplevel, i: int, val: string) +{ + abilities[i].read = val; + if (abilities[i].dtype == LIST) + tkcmd(top, "variable "+abilities[i].pname+" "+val); + else if (abilities[i].dtype == MINMAX) { + mul := getval(abilities[i].data, "mul"); + tkcmd(top, abilities[i].location+" set "+string((int val)/mul)); + } + tkcmd(top, "update"); +} + +max(a,b: int): int +{ + if (a > b) return a; + return b; +} + +refreshfilelist(win: ref Tk->Toplevel, refresh: int): int +{ + if (refresh) { + fd := sys->open(camerapath+"ctl",sys->OWRITE); + if (fd == nil) { + dialog("cannot communicate with camera",0,-1,coords); + return -1; + } + else + sys->fprint(fd, "refresh"); + } + oldlist := filelist[:nofiles]; + for (i := 0; i < nofiles; i++) { + si := string i; + tk->cmd(win, "grid forget .fthumb.mb"+si+" .fthumb.p"+si); + tk->cmd(win, "destroy .fthumb.mb"+si+" .fthumb.p"+si+" .mthumb"+si); + } + (dirs,n) := readdir->init(camerapath+"jpg", readdir->NAME); + if (n == -1) + return -1; + nofiles = n; + row := 0; + col := 0; + nocols := -1; + w1 := int tkcmd(win, ".f.f1.c1 cget -width"); + w := 0; + fnew = nil; + for (i = 0; i < nofiles; i++) { + filelist[i] = dirs[i].name; + if (len filelist[i] > 3 && filelist[i][len filelist[i] - 4] == '.') + filelist[i] = filelist[i][:len filelist[i]-4]; + + isnew := 1; + for (k := 0; k < len oldlist; k++) { + if (filelist[i] == oldlist[k]) { + isnew = 0; + break; + } + } + si := string i; + tkcmd(win, "menubutton .fthumb.mb"+si+" -bg white " + + "-text {"+filelist[i]+".jpg} -menu .mthumb"+si+tkfontf); + if (isnew && refresh) { + fnew = i :: fnew; + tkcmd(win, ".fthumb.mb"+si+" configure -fg red"); + } + thumbimg[i] = display.newimage(Rect((0,0),(90,90)),draw->RGB24,0,int 16rffcc00ff); + e := tkcmd(win,"panel .fthumb.p"+si+" -borderwidth 2 -bg white"+ + " -height 90 -width 90 -relief raised"); + tk->putimage(win,".fthumb.p"+si, thumbimg[i],nil); + tkcmd(win, "bind .fthumb.p"+si+" <Double-Button-1> {send butchan view "+si+"}"); + tkcmd(win, "bind .fthumb.p"+si+" <ButtonPress-1> {send butchan selectonly "+si+"}"); + tkcmd(win, "bind .fthumb.p"+si+" <ButtonPress-2> {send butchan select "+si+"}"); + tkcmd(win, "bind .fthumb.p"+si+" <ButtonPress-3> {send butchan menu "+si+" %X %Y}"); + thisw := int tkcmd(win, ".fthumb.mb"+si+" cget -width"); + w += max(94, thisw); + if ((nocols == -1 && w >= w1-(col*2)) || col == nocols) { + nocols = col; + col = 0; + row+=2; + w = thisw; + } + if (col == 0) + tkcmd(win, "grid rowconfigure .fthumb "+string (row+1)+ + " -minsize "+string (105 - 2*(3-ssize))); + + tkcmd(win, "grid .fthumb.mb"+si+" -row "+string row+" -column "+string col); + tkcmd(win, "grid .fthumb.p"+si+" -row "+string (row+1)+" -column "+string col+" -sticky n"); + + tkcmd(win, "menu .mthumb"+si+tkfont); + for (k = nothumbs; k < len menu; k++) + tkcmd(win, ".mthumb"+si+" add command -text {"+menu[k].text+"} " + + "-command {send butchan "+menu[k].com+" "+si+"}"); + + if (isloaded(filelist[i],THUMB) && usecache) + loadthumbnail(win,i); + col++; + } + if (row == 0) + nocols = col; + doselect(win); + size := tkcmd(win, "grid size .fthumb"); + csize := int size[:isat(size, " ")]; + rsize := int size[isat(size, " ")+1:]; + if (csize > nocols) + tkcmd(win, "grid columndelete .fthumb "+string nocols+" "+string csize); + if (rsize > row+1) + tkcmd(win, "grid rowdelete .fthumb "+string (row+2)+" "+string rsize); + height := string (2 + int tkcmd(win, ".fthumb cget -height")); + width := tkcmd(win, ".f.f1.c1 cget -width"); + colsize : int; + if (nocols > 0) colsize = int width / nocols; + else colsize = int width; + for (i = 0; i < nocols; i++) + tkcmd(win, "grid columnconfigure .fthumb "+string i+" -minsize "+string colsize); + + tkcmd(win, ".f.f1.c1 configure -scrollregion { 0 0 "+width+" "+height+"}"); + tkcmd(win, "update"); + return 0; +} + +Mtype: adt { + text, com: string; +}; + +menu := array[] of { + Mtype ("Show Thumbnail", "show"), + Mtype ("Download", "dnld"), + Mtype ("View", "view"), + Mtype ("Delete", "del"), + Mtype ("Clear Cache", "unload"), + Mtype ("Refresh Files", "refresh"), +}; + +tkcmd(top: ref Tk->Toplevel, cmd: string): string +{ + if (cmd[len cmd - 1] == '$') + cmd = cmd[:len cmd - 1] + tkfontb; + else if (cmd[len cmd - 1] == '@') + cmd = cmd[:len cmd - 1] + tkfont; + if (cmd[len cmd - 1] == '&') + cmd = cmd[:len cmd - 1] + butheight+tkfont; + + e := tk->cmd(top, cmd); + if (e != "" && e[0] == '!') sys->print("tk error: '%s': %s\n",cmd,e); + return e; +} + +loadnewthumb(top: ref Tk->Toplevel, ctlchan: chan of int) +{ + pid := sys->pctl(0,nil); + spawn workingscreen2(coords,pid, ctlchan,0); + getstore(top); + for (tmp := fnew; tmp != nil; tmp = tl tmp) + loadthumbnail(top,hd tmp); + ctlchan <-= DONE; +} + +loadthumb(top: ref Tk->Toplevel, i: int, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid, ctlchan,0); + if (i == -1) { + for (k := 0; k < nofiles; k++) + if (selected[k]) + if (loadthumbnail(top, k) != 0) break; + } + else loadthumbnail(top, i); + ctlchan <-= DONE; +} + +loadthumbnail(top: ref Tk->Toplevel, i: int): int +{ + fd : ref sys->FD; + if (usecache && isloaded(filelist[i],THUMB)) + fd = sys->open(tmppath+filelist[i]+"."+string THUMB+"~",sys->OREAD); + else fd = sys->open(camerapath+"thumb/"+filelist[i]+".bit",sys->OREAD); + if (fd == nil) { + if (usecache && isloaded(filelist[i],THUMB)) { + delloaded(filelist[i],THUMB); + return loadthumbnail(top,i); + } + else dialog("cannot open "+filelist[i]+".bit",0,-1,coords); + return -2; + } + image := display.readimage(fd); + if (image == nil) { + if (usecache && isloaded(filelist[i],THUMB)) { + delloaded(filelist[i],THUMB); + return loadthumbnail(top,i); + } + else dialog("Could not load thumbnail: "+filelist[i]+".jpg",0,-1,coords); + return -1; + } + else { + p := Point((90-image.r.max.x)/2,(90-image.r.max.y)/2); + thumbimg[i].draw(image.r.addpt(p), image,nil,(0,0)); + si := string i; + tkcmd(top,".fthumb.p"+si+" dirty"); + fd = nil; + n := -1; + if (usecache) { + fd = sys->create(tmppath+filelist[i]+"."+string THUMB+"~",sys->OWRITE,8r666); + n = display.writeimage(fd, image); + } + x := int tkcmd(top, ".fthumb.mb"+string i+" cget -actx"); + y := int tkcmd(top, ".fthumb.mb"+string i+" cget -acty"); + h := int tkcmd(top, ".fthumb.mb"+string i+" cget -height"); + x1 := int tkcmd(top, ".fthumb cget -actx"); + y1 := int tkcmd(top, ".fthumb cget -acty"); + tkcmd(top, ".f.f1.c1 see "+string (x-x1)+" " +string (y-y1)+ + " "+string (x-x1+90)+" " +string (y-y1+h+102)+"; update"); + if (!usecache || n == 0) imgloaded = (filelist[i],THUMB) :: imgloaded; + } + return 0; +} + +isloaded(name: string, ftype: int): int +{ + tmp := imgloaded; + while (tmp != nil) { + ic := hd tmp; + if (ic.name == name && ic.imgtype == ftype) return 1; + tmp = tl tmp; + } + return 0; +} + +delloaded(name: string, ftype: int) +{ + tmp : list of Imgloaded; + tmp = nil; + while (imgloaded != nil) { + ic := hd imgloaded; + if (ic.name != name || ic.imgtype != ftype) + tmp = ic :: tmp; + else sys->remove(tmppath+ic.name+"."+string ic.imgtype+"~"); + imgloaded = tl imgloaded; + } + imgloaded = tmp; +} + +dialog(msg: string, diagtype, img: int, r: Rect): int +{ + if (diagtype == 2) + diagtype = 0; + else + working = 0; + tmpimg : ref draw->Image; + out := 0; + title := "Dialog"; + if (diagtype == 0) title = "Alert!"; + (win, titlebar) := tkclient->toplevel(context, "" , title, Tkclient->Appl); + diagchan := chan of string; + tk->namechan(win, diagchan, "diagchan"); + tkcmd(win, "frame .f"); + tkcmd(win, "label .f.l -text {"+msg+"}"+tkfont); + tkcmd(win, "button .f.bo -text { ok } -command {send diagchan ok} "+butheight+tkfont); + tkcmd(win, "button .f.bc -text {cancel} -command {send diagchan cancel}"+butheight+tkfont); + if (img >= 0 && isloaded(filelist[img], THUMB) && usecache) { + fd := sys->open(tmppath+filelist[img]+"."+string THUMB+"~", sys->OREAD); + if (fd != nil) { + tmpimg = display.readimage(fd); + tkcmd(win,"panel .f.p -height "+string tmpimg.r.max.y+ + " -width "+string tmpimg.r.max.x+" -borderwidth 2 -relief raised"); + tk->putimage(win,".f.p", tmpimg, nil); + tkcmd(win, "grid .f.p -row 1 -column 0 -columnspan 2 -padx 5 -pady 5"); + } + } + tkcmd(win, "grid .f.l -row 0 -column 0 -columnspan 2 -padx 10 -pady 5"); + if (diagtype == 1) { + tkcmd(win, "grid .f.bo -row 2 -column 0 -padx 5 -pady 5"); + tkcmd(win, "grid .f.bc -row 2 -column 1 -padx 5 -pady 5"); + } + else tkcmd(win, "grid .f.bo -row 2 -column 0 -columnspan 2 -padx 5 -pady 5"); + if (!r.eq(nilrect)) + centrewin(win, r, 1); + else + tkcmd(win, "pack .f; focus .; update"); + tkclient->onscreen(win, "exact"); + tkclient->startinput(win, "kbd"::"ptr"::nil); + main: for (;;) { + alt { + s := <-win.ctxt.kbd => + tk->keyboard(win, s); + s := <-win.ctxt.ptr => + tk->pointer(win, *s); + inp := <-diagchan => + if (inp == "ok") { + out = 1; + break main; + } + if (inp == "cancel") + break main; + + title = <-win.ctxt.ctl or + title = <-win.wreq or + title = <-titlebar => + if (title == "exit") + break main; + else + tkclient->wmctl(win, title); + } + } + return out; +} + +snapscr := array[] of { + "label .f.fsnap.ltime -text {Date and Time} $", + "label .f.fsnap.lstore -text {Memory Status} $", + "label .f.fsnap.lzpos -text {Zoom} $", + "label .f.fsnap.lssiz -text {Resolution} $", + "label .f.fsnap.lscpn -text {Compression} $", + "grid .f.fsnap.ltime -row 0 -column 0 -sticky sw", + "grid .f.fsnap.lstore -row 0 -column 1 -sticky sw", + "grid .f.fsnap.lscpn -row 2 -column 0 -sticky sw", + "grid .f.fsnap.lssiz -row 2 -column 1 -sticky sw", + "grid .f.fsnap.lzpos -row 2 -column 2 -sticky sw", + + "grid .f.fsnap.ftime -row 1 -column 0 -sticky nsew", + "grid .f.fsnap.fstore -row 1 -column 1 -sticky nsew", + "grid .f.fsnap.fsettings -row 1 -column 2 -sticky nsew", + "grid .f.fsnap.fscpn -row 3 -column 0 -sticky nsew", + "grid .f.fsnap.fssiz -row 3 -column 1 -sticky nsew", + "grid .f.fsnap.fzpos -row 3 -column 2 -sticky nsew", + "grid .f.fsnap.b -row 4 -column 0 -columnspan 3", + "grid rowconfigure .f.fsnap 0 -minsize 30", + "grid rowconfigure .f.fsnap 2 -minsize 30", + "grid rowconfigure .f.fsnap 4 -minsize 30", + + "update", +}; + +mainscreen(win: ref Tk->Toplevel, opt: int, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords, pid, ctlchan, opt); + if (opt == 1) { + for (tk1 := 0; tk1 < len snapscr; tk1++) + tkcmd(win, snapscr[tk1]); + + gettime(win); + if (samedate(win)) tkcmd(win, "variable time 1; update"); + } + getstore(win); + lst := getabl("scpn") :: getabl("ssiz") :: getabl("zpos") :: nil; + if (getstate(win, hd tl tl lst) == 0); + if (getstate(win, hd tl lst) == 0); + getstate(win, hd lst); + if (opt == 1) { + addtoplevel(win, "", lst, -1); + height := tkcmd(win, ".f.fsnap cget -height"); + width := tkcmd(win, ".f.fsnap cget -width"); +# tkcmd(win, ".f.f2.c1 configure -scrollregion { 0 0 "+width+" "+height+"}"); +# tkcmd(win, ".f.f2.c1 configure -height "+height+"}"); + } + ctlchan <-= DONE; +} + +kill(pid: int) +{ + pctl := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE); + if (pctl != nil) + sys->write(pctl, array of byte "kill", len "kill"); +} + +gettime(win: ref Tk->Toplevel) +{ + tkcmd(win,".f.fsnap.ftime.l3 configure -text {}"+tkfont); + tkcmd(win,".f.fsnap.ftime.l4 configure -text {}"+tkfont); + fdi := bufio->open(camerapath+"date",sys->OREAD); + if (fdi != nil) { + s := fdi.gets('\n'); + if (s != nil) { + if (s[len s - 1] == '\n') s = s[:len s - 1]; + tm := daytime->local(daytime->now()); + time := sys->sprint("%d/%d/%d %d:%d:%d", tm.mon+1, tm.mday, tm.year-100, + tm.hour,tm.min,tm.sec); + ltime = addzeros(time); + ctime = addzeros(s[len "date is ":]); + tk->cmd(win,".f.fsnap.ftime.l3 configure -text {"+ltime+"}"); + tk->cmd(win,".f.fsnap.ftime.l4 configure -text {"+ctime+"}"); + } + } + if (len ltime < 16) + ltime = "??/??/?? ??:??:??"; + if (len ctime < 16) + ctime = "??/??/?? ??:??:??"; + tkcmd(win, "update"); +} + +addzeros(s: string): string +{ + s[len s] = ' '; + rs := ""; + start := 0; + isnum := 0; + for (i := 0; i < len s; i++) { + if (s[i] < '0' || s[i] > '9') { + if (isnum && i - start < 2) rs[len rs] = '0'; + rs += s[start:i+1]; + start = i+1; + isnum = 0; + } + else isnum = 1; + } + i = len rs - 1; + while (i >= 0 && rs[i] == ' ') i--; + return rs[:i+1]; +} + +samedate(win: ref Tk->Toplevel): int +{ + s1 := tkcmd(win, ".f.fsnap.ftime.l3 cget -text"); + s2 := tkcmd(win, ".f.fsnap.ftime.l4 cget -text"); + if (s1 == "" || s1 == "") return 0; + if (s1[:len s1 - 3] == s2[:len s2 - 3]) return 1; + return 0; +} + +settime() +{ + tm := daytime->local(daytime->now()); + fd := sys->open(camerapath+"date", sys->OWRITE); + if (fd != nil) { + sys->fprint(fd, "%s", addzeros(sys->sprint("%d/%d/%d %d:%d:%d" + ,tm.mon+1, tm.mday, tm.year-100, tm.hour,tm.min,tm.sec))); + } +} + +getstore(win: ref Tk->Toplevel) +{ + fdi := bufio->open(camerapath+"storage",sys->OREAD); + if (fdi != nil) { + for(i := 0; i < 3; i++) { + s := fdi.gets('\n'); + if (s == nil) break; + if (i > 0) { + (n,lst) := sys->tokenize(s,"\t\n:"); + val := string int hd tl lst; + if (i == 2 && val == "0") + tkcmd(win, ".f.fsnap.b configure -state disabled"); + else tkcmd(win, ".f.fsnap.b configure -state normal"); + tkcmd(win,".f.fsnap.fstore.l"+string (2+i)+" configure -text {"+val+" }"); + } + } + tkcmd(win, "update"); + } +} + +contains(s: string, test: string): int +{ + num :=0; + if (len test > len s) return 0; + for (i := 0; i < (1 + (len s) - (len test)); i++) { + if (test == s[i:i+len test]) num++; + } + return num; +} + +multidownload() +{ + getpath := selectfile->filename(context, + display.image, + "Multiple download to directory...", + nil, + lastpath); + if (getpath == "" || getpath[0] != '/' || getpath[len getpath - 1] != '/') + return; + s := ""; + for (k := 0; k < nofiles; k++) { + if (selected[k]) { + e := dnld(k,getpath); + if (e != 1) + s += filelist[k]+".jpg "; + if (e == 3) { + s += "cancelled\n"; + break; + } + else if (e == 0) + s += "failed\n"; + working = 0; + } + } + if (s != "") s = ":\n\n"+s; + dialog("Multiple download complete"+s,0,-1,coords); +} + +downloading := ""; + +dnld(i: int, path: string): int +{ + ctlchan := chan of int; + ctlchans := chan of string; + chanout := chan of string; + spawn downloadscreen(coords, i, ctlchans, chanout); + spawn download(i,path,ctlchan, ctlchans, chanout); + pid := <-ctlchan; + alt { + s := <-ctlchans => + chanout <-= "!done!"; + if (s == "kill") { + if (downloading != "") { + (n,lst) := sys->tokenize(downloading, " \t\n"); + for(;lst != nil; lst = tl lst) + sys->remove(hd lst); + } + kill(pid); + return 3; + } + else return dnld(i, "!"+s); + e := <-ctlchan => + chanout <-= "!show!"; + chanout <-= "!done!"; + return e; + } + return 0; +} + +filelenrefresh(filename: string): int +{ + fd := sys->open(camerapath+"ctl",sys->OWRITE); + if (fd != nil) { + sys->fprint(fd, "refresh"); + (n, dir) := sys->stat(filename); + if (n == -1) + return -1; + return int dir.length; + } + return -1; +} + +testfilesize(filename: string): int +{ + e := filelenrefresh(filename); + if (e == 0) { + e2 := dialog("Camera is still processing image\nwait until ready?",1,-1,coords); + if (e2 == 0) + return 0; + ctlchan := chan of int; + spawn waittilready(filename, ctlchan); + e3 := <- ctlchan; + working = 0; + if (e3 == KILLED) + return 0; + return testfilesize(filename); + } + else return e; +} + +waittilready(filename: string, ctlchan: chan of int) +{ + pid := sys->pctl(0, nil); + spawn workingscreen2(coords,pid,ctlchan,0); + for (;;) { + if (filelenrefresh(filename) != 0) + break; + sys->sleep(2000); + } + ctlchan <-= DONE; +} + +download(i: int, path: string, ctlchan: chan of int, ctlchans, chanout: chan of string) +{ + ctlchan <-= sys->pctl(0, nil); + downloading = ""; + savename : string; + if (path == "") { + savename = selectfile->filename(context, + display.image, + "Save "+filelist[i]+".jpg to directory...", + "*.jpg" :: "*.jpeg" :: nil, + lastpath); + if (savename == "" || savename[0] != '/') { + ctlchan <-= 0; + return; + } + } + else savename = path; + + # Used when retrying due to cache copy failing + if (savename[0] == '!') { + delloaded(filelist[i],JPG); + savename = savename[1:]; + path = ""; + } + confirm := 1; + # Don't confirm overwrite + if (savename[0] == '$') { + confirm = 0; + savename = savename[1:]; + } + + if (savename[len savename - 1] == '/') + savename += filelist[i]+".jpg"; + + if (!hasext(savename, ".jpg")) + savename += ".jpg"; + + p := isat2(savename,"/"); + lastpath = savename[:p+1]; + + filename := camerapath+"jpg/"+filelist[i]+".jpg"; + filesize := testfilesize(filename); + cached := 0; + if (filesize > 0 && isloaded(filelist[i],JPG) && usecache) { + cachefilename := tmppath+filelist[i]+"."+string JPG+"~"; + if (testfilesize(cachefilename) == filesize) { + cached = 1; + filename = cachefilename; + } + else delloaded(filelist[i],JPG); + } + fd := sys->open(filename, sys->OREAD); + if (filesize < 1 || fd == nil) { + ctlchan <-= -1; + return; + } + + read := 0; + cancel : int; + buf : array of byte; + fd2, fd3 : ref sys->FD = nil; + cachename := tmppath+filelist[i]+"."+string JPG+"~"; + if (confirm) (fd2, cancel) = create(savename, coords); + else fd2 = sys->create(savename,sys->OWRITE, 8r666); + if (fd2 == nil) { + ctlchan <-= cancel; + return; + } + if (usecache && !cached) + fd3 = sys->create(cachename,sys->OWRITE,8r666); + chanout <-= "!show!"; + chanout <-= "l2 Downloading..."; + chanout <-= "pc 0"; + n : int; + downloading = savename; + if (fd3 != nil) + downloading += " "+cachename; + loop: for(;;) { + rlen := 8192; + if (read + rlen >= filesize) rlen = filesize - read; + buf = array[rlen] of byte; + n = sys->read(fd,buf,len buf); + read += n; + sout := "pc "+string ( (100*read)/filesize); + chanout <-= sout; + if (n < 1) break loop; + written := 0; + while (written < n) { + n2 := sys->write(fd2,buf,n); + if (n2 < 1) break loop; + if (fd3 != nil) sys->write(fd3,buf,n); + written += n2; + } + } + chanout <-= "pc 100"; + downloading = ""; + fd = nil; + fd2 = nil; + if (read < filesize || n == -1) { + if (cached) { + ctlchans <-= savename; + return; + } + sys->remove(savename); + sys->remove(cachename); + if (path == "") + dialog(sys->sprint("Download Failed: %s.jpg\nread %d of %d bytes\n", + filelist[i],read,filesize), 0, i,coords); + ctlchan <-= 0; + return; + } + + # save it in cache + if (usecache) + imgloaded = (filelist[i],JPG) :: imgloaded; + if (path == "") dialog(filelist[i]+".jpg downloaded",0,i,coords); + ctlchan <-= 1; +} + +downloadscr := array[] of { + "frame .f -borderwidth 2 -relief raised", + "label .f.l1 -text { } @", + "label .f.l2 -text {Waiting...} @", + "button .f.b -text {Cancel} -command {send ctlchans kill} &", + "grid .f.l1 -row 0 -column 0 -columnspan 2 -pady 5", + "grid .f.l2 -row 2 -column 1 -sticky w -padx 10", + "grid .f.p -row 3 -column 1 -columnspan 1 -padx 10", + "grid .f.b -row 4 -column 0 -pady 5 -columnspan 2", +}; + +downloadscreen(r: Rect, i: int, ctlchans, chanin: chan of string) +{ + working = 1; + <- chanin; + (top, nil) := tkclient->toplevel(context,"", nil, tkclient->Plain); + progr := Rect((0,0),(100,15)); + imgbg := display.newimage(progr,draw->CMAP8,1,draw->Black); + black := display.newimage(progr,draw->CMAP8,1,draw->Black); + white := display.newimage(progr,draw->CMAP8,1,draw->White); + imgfg := display.newimage(progr,draw->CMAP8,1,draw->Blue); + tkcmd(top, "panel .f.p -width 100 -height 15 -bg white -borderwidth 2 - relief raised"); + tk->putimage(top, ".f.p",imgbg,nil); + tk->namechan(top, ctlchans, "ctlchans"); + for (tk1 := 0; tk1 < len downloadscr; tk1++) + tkcmd(top, downloadscr[tk1]); + tmpimg : ref Image = nil; + if (i >= 0 && isloaded(filelist[i], THUMB) && usecache) + tmpimg = display.open(tmppath+filelist[i]+"."+string THUMB+"~"); + if (tmpimg == nil) + tmpimg = procimg; + if (tmpimg != nil) { + w := tmpimg.r.dx(); + h := tmpimg.r.dy(); + tkcmd(top, "panel .f.p2 -width "+string w+" -height "+string h+ + " -borderwidth 2 -relief raised"); + tk->putimage(top, ".f.p2", tmpimg, nil); + tkcmd(top, "grid .f.p2 -row 2 -column 0 -rowspan 2 -sticky e"); + tkcmd(top, "grid columnconfigure .f 0 -minsize "+string (w + 14)); + } + + tkcmd(top, ".f.l1 configure -text {"+filelist[i]+".jpg}"); + centrewin(top,r,1); + oldcoords := coords; + tkclient->onscreen(top, "exact"); + tkclient->startinput(top, "kbd"::"ptr"::nil); + + main: for (;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + text := <-chanin => + if (!oldcoords.eq(coords)) { + centrewin(top,coords,0); + oldcoords = coords; + } + if (text == "!done!") break main; + if (text[:2] == "pc") { + val := int text[3:]; + imgbg.draw(((0,0),(val,15)), imgfg,nil,(0,0)); + if (val != 100) + imgbg.draw(((val+1,0),(100,15)), black,nil,(0,0)); + imgbg.text((42,1),white,(0,0),font, text[3:]+"%"); + tkcmd(top,".f.p dirty; update"); + } + else if (text[:2] == "l2") + tkcmd(top, ".f.l2 configure -text {"+text[3:]+"}; update"); + } + } + working = 0; +} + +centrewin(top: ref Tk->Toplevel, r: Rect, first: int) +{ + s := ""; + if (first) + s = "pack .f;"; + w := int tkcmd(top, ".f cget -width"); + h := int tkcmd(top, ".f cget -height"); + tmp := tk->cmd(top, ".Wm_t cget -height"); + if (tmp != "" && tmp[0] != '!') { + h += int tmp; + s += "focus .;"; + } + px := r.min.x + ((r.max.x - r.min.x - w) / 2); + py := r.min.y + ((r.max.y - r.min.y - h) / 2); + tkcmd(top, ". configure -x "+string px+" -y "+string py); + tkcmd(top, s+"raise .; update"); +} + +workingscr2 := array[] of { + "frame .f -borderwidth 2 -relief raised", + "label .f.l3 -text { } -width 220 -height 2", + "label .f.l -text {Please Wait} @", + "label .f.l2 -text {|} -width 20 @", + "button .f.b -text {Cancel} -command {send chanin kill} &", + "grid .f.l -row 1 -column 0 -sticky e", + "grid .f.l2 -row 1 -column 1 -sticky w", + "grid .f.b -pady 5 -row 3 -column 0 -columnspan 2", + "grid .f.l3 -row 4 -column 0 -columnspan 2", + "grid rowconfigure .f 1 -minsize 80", +}; + +workingscreen2(r : Rect, pid: int, ctlchan: chan of int, loading: int) +{ + (top, nil) := tkclient->toplevel(context,"",nil, tkclient->Plain); + chanin := chan of string; + tk->namechan(top, chanin, "chanin"); + for (tk1 := 0; tk1 < len workingscr2; tk1++) + tkcmd(top, workingscr2[tk1]); + + if (loading) { +# loadimg := display.open("camload.bit"); + if (loadimg != nil) { + w := loadimg.r.dx(); + h := loadimg.r.dy(); + tkcmd(top, "panel .f.p -width "+string w+" -height "+string h+ + " -borderwidth 2 -relief raised"); + tk->putimage(top, ".f.p", loadimg, nil); + tkcmd(top, "grid .f.p -row 2 -column 0 -columnspan 2 -pady 5 -padx 20"); + tkcmd(top, "grid forget .f.l .f.l2; grid rowconfigure .f 1 -minsize 20"); + } + } + else { + if (procimg != nil) { + w := procimg.r.dx(); + h := procimg.r.dy(); + tkcmd(top, "panel .f.p -width "+string w+" -height "+string h+ + " -borderwidth 2 -relief raised"); + tk->putimage(top, ".f.p", procimg, nil); + tkcmd(top, "grid .f.p -row 2 -column 0 -columnspan 2"); + tkcmd(top, "grid rowconfigure .f 1 -minsize 30"); + tkcmd(top, "grid rowconfigure .f 2 -minsize 50"); + } + } + + centrewin(top,r,1); + spawn workingupdate(top,chanin); + tkclient->onscreen(top, "exact"); + tkclient->startinput(top, "kbd"::"ptr"::nil); + + main: for (;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + inp := <-chanin => + if (inp == "done") break main; + if (inp == "kill") { + working = 0; + if (pid != -1) kill(pid); + ctlchan <-= KILLED; + <-chanin; + break main; + } + } + } +} + +workingupdate(top: ref Tk->Toplevel, chanout: chan of string) +{ + show := array[] of { "/", "-", "\\\\", "|", }; + if (working) { + chanout <-= "done"; + return; + } + working = 1; + oldcoords := coords; + hidden := 0; + loop: for(;;) { + for (i := 0; i < 4; i++) { + sys->sleep(100); + tkcmd(top, ".f.l2 configure -text {"+show[i]+"}; update"); + if (!working) break loop; + if (!oldcoords.eq(coords)) { + centrewin(top, coords,0); + oldcoords = coords; + } + } + } + chanout <-= "done"; +} + +scrollx := 0; +scrolly := 0; + +resizemain(top: ref Tk->Toplevel, init: int) +{ + h, w: int; + if (init) { + growheight(top, 4000); + h = int tkcmd(top, ".f.fsnap cget -height") + + int tkcmd(top, ".Wm_t cget -height") + + 2 * (124 - (5*(3-ssize))); + if (h > display.image.r.dy()) + h = display.image.r.dy(); + w = display.image.r.dx(); + } + else { + r := tk->rect(top, ".", 0); + h = r.dy(); + w = r.dx(); + } + + ht := int tkcmd(top, ".Wm_t cget -height"); + + hf := int tkcmd(top, ".f cget -height"); + wf := int tkcmd(top, ".f cget -width"); + wsb := int tkcmd(top, ".f.f1.sb1 cget -width"); + + growwidth(top, w - 4); + ws := int tkcmd(top, ".f.fsnap cget -width"); + if (w > ws + 4) + w = ws + 4; + shrinkwidth(top,w - 4); + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (w < ws || init) + w = ws + 4; + + hmax := ((3*(h - ht))/5) - 4; + growheight(top, hmax); + shrinkheight(top, hmax); + hs := int tkcmd(top, ".f.fsnap cget -height"); + + hmb := int tkcmd(top, ".f.fsnap.fsettings.mb cget -height"); + if (h < ht+hs + 107 + hmb) h = ht+hs+107 + hmb; + +# hc2 = int tkcmd(top, ".f.fsnap cget -height"); + wc2 := int tkcmd(top, ".f.fsnap cget -width"); + + hc1 := h - ht - hs - 4; + wc1 := w-wsb-4; +# wc1 = wc2 - wsb; + tkcmd(top, ".f.f1.c1 configure -height "+string hc1+" -width "+string wc1); +# tkcmd(top, ".f.f2.c1 configure -height "+string hc2+" -width "+string wc2); + if (w < wc2 + 4) + w = wc2 + 4; + ws = int tkcmd(top, ".f.fsnap cget -width"); + hs = int tkcmd(top, ".f.fsnap cget -height"); + + tkcmd(top, ". configure -height "+string h+" -width "+string w+"; update"); + refreshfilelist(top, 0); +} + +growwidth(top: ref Tk->Toplevel, wc2: int) +{ + ws := int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 > ws && reducew[2]) { + tkcmd(top, ".f.fsnap.ftime.l1 configure -text {Local:}"); + tkcmd(top, ".f.fsnap.ftime.l2 configure -text {Camera:}"); + tkcmd(top, ".f.fsnap.ftime.cb configure -text {Set to local time}"); + reducew[2] = 0; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 > ws && reducew[1]) { + tkcmd(top, ".f.fsnap.ftime.l3 configure -text {"+ltime+"}"); + tkcmd(top, ".f.fsnap.ftime.l4 configure -text {"+ctime+"}"); + tkcmd(top, ".f.fsnap.ftime.cb configure -text {Set camera to local time}"); + reducew[1] = 0; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 > ws && reducew[0]) { + tkcmd(top, ".f.fsnap.fstore.l1 configure -text { Photos taken:}"); + reducew[0] = 0; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 > ws) { + wfs += wc2 - ws; + if (wfs > 125-(20*(3-ssize))) wfs = 125-(20*(3-ssize)); + tkcmd(top, "grid columnconfigure .f.fsnap 2 -minsize "+string wfs); + } +} + +growheight(top: ref Tk->Toplevel, hc2: int) +{ + hs := int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 > hs) { + tk->cmd(top, "grid .f.fsnap.fsettings.mb2 -row 2 -column 0 -sticky ew"); + tk->cmd(top, "grid .f.fsnap.ftime.cb -row 2 -column 0 -columnspan 2"); + tk->cmd(top, "grid .f.fsnap.ftime.b -row 3 -column 0 -columnspan 2"); + } + hs = int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 > hs) { + hsc := int tkcmd(top, ".f.fsnap.fzpos.sc cget -height"); + hsc += hc2 - hs; + if (hsc > 88-(10*(3-ssize))) hsc = 88-(10*(3-ssize)); + tkcmd(top, ".f.fsnap.fzpos.sc configure -height "+string hsc); + } + hs = int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 > hs) { + hfs += hc2 - hs; + if (hfs > 30 - (5*(3-ssize))) hfs = 30- (5*(3-ssize)); + tkcmd(top, "grid rowconfigure .f.fsnap 0 -minsize "+string hfs); + tkcmd(top, "grid rowconfigure .f.fsnap 2 -minsize "+string hfs); + tkcmd(top, "grid rowconfigure .f.fsnap 4 -minsize "+string hfs); + } +} + +shrinkheight(top: ref Tk->Toplevel, hc2: int) +{ + hs := int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 < hs) { + hfs -= hs - hc2; + if (hfs < 15) hfs = 15; + tkcmd(top, "grid rowconfigure .f.fsnap 0 -minsize "+string hfs); + tkcmd(top, "grid rowconfigure .f.fsnap 2 -minsize "+string hfs); + tkcmd(top, "grid rowconfigure .f.fsnap 4 -minsize "+string hfs); + } + hs = int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 < hs) { + hsc := int tkcmd(top, ".f.fsnap.fzpos.sc cget -height"); + hsc -= hs - hc2; + if (hsc < 55-(5*(3-ssize))) hsc = 55-(5*(3-ssize)); + tkcmd(top, ".f.fsnap.fzpos.sc configure -height "+string hsc); + } + hs = int tkcmd(top, ".f.fsnap cget -height"); + if (hc2 < hs) { + tk->cmd(top, "grid forget .f.fsnap.fsettings.mb2"); + tk->cmd(top, "grid forget .f.fsnap.ftime.cb"); + tk->cmd(top, "grid forget .f.fsnap.ftime.b"); + } +} + +shrinkwidth(top: ref Tk->Toplevel, wc2: int) +{ + ws := int tkcmd(top, ".f.fsnap cget -width"); + wib := int tkcmd(top, ".f.fsnap.fsettings.b cget -width"); + if (wc2 < ws) { + diff := ws - wc2; + wfs -= diff; + if (wfs < wib) wfs = wib; + tkcmd(top, "grid columnconfigure .f.fsnap 2 -minsize "+string wfs); + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 < ws) { + tkcmd(top, ".f.fsnap.fstore.l1 configure -text { Taken:}"); + reducew[0] = 1; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 < ws) { + tkcmd(top, ".f.fsnap.ftime.l3 configure -text {"+ltime[len ltime - 8:]+"}"); + tkcmd(top, ".f.fsnap.ftime.l4 configure -text {"+ctime[len ctime - 8:]+"}"); + tkcmd(top, ".f.fsnap.ftime.cb configure -text {Set to local time}"); + reducew[1] = 1; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 < ws) { + tkcmd(top, ".f.fsnap.ftime.l1 configure -text {C:}"); + tkcmd(top, ".f.fsnap.ftime.l2 configure -text {}"); + tkcmd(top, ".f.fsnap.ftime.l3 configure -text {"+ctime[len ctime - 17:len ctime - 8]+"}"); + tkcmd(top, ".f.fsnap.ftime.cb configure -text {Set local}"); + reducew[2] = 1; + } + ws = int tkcmd(top, ".f.fsnap cget -width"); + if (wc2 > ws) { + wfs = 125-(20*(3-ssize)); + tkcmd(top, "grid columnconfigure .f.fsnap 2 -minsize "+string wfs); + } +} + +ltime, ctime: string; +wfs := 150; +hfs := 30; +reducew := array[10] of { * => 0 }; + +getcoords(top: ref Tk->Toplevel): Rect +{ + h := int tkcmd(top, ". cget -height"); + w := int tkcmd(top, ". cget -width"); + x := int tkcmd(top, ". cget -actx"); + y := int tkcmd(top, ". cget -acty"); + r := Rect((x,y),(x+w,y+h)); + return r; +} + +viewscr := array[] of { + "frame .f -bg", + "canvas .f.c -yscrollcommand {.f.sy set} -xscrollcommand {.f.sx set} -height 300 -width 500", + "scrollbar .f.sx -command {.f.c xview} -orient horizontal", + "scrollbar .f.sy -command {.f.c yview}", + "grid .f.c -row 0 -column 0", + "grid .f.sy -row 0 -column 1 -sticky ns", + "grid .f.sx -row 1 -column 0 -sticky ew", + "bind .Wm_t <ButtonPress-1> +{focus .}", + "bind .Wm_t.title <ButtonPress-1> +{focus .}", + "pack propagate . 0", + "menu .m @", + ".m add command -text {Save As...}", + ".m add separator", + ".m add command -text {bit} -command {send butchan save bit}", + ".m add command -text {jpeg} -command {send butchan save jpg}", + +}; + +resizeview(top: ref Tk->Toplevel, wp,hp: int) +{ + w := int tkcmd(top, ". cget -width"); + h := int tkcmd(top, ". cget -height"); + hs := int tkcmd(top, ".f.sx cget -height"); + ws := int tkcmd(top, ".f.sy cget -width"); + ht := int tkcmd(top, ".Wm_t cget -height"); + wc := w - ws - 4; + hc := h - hs - ht - 6; + wpc := wc - wp; + hpc := hc - hp; + if (wpc > 0) { + wc -= wpc; + w -= wpc; + } + if (hpc > 0) { + hc -= hpc; + h -= hpc; + } + tkcmd(top, ". configure -height "+string h+" -width "+string w); + tkcmd(top, ".f.c configure -height "+string hc+" -width "+string wc); + tkcmd(top, "update"); +} + +multiview() +{ + s := ""; + for (k := 0; k < nofiles; k++) { + if (selected[k]) { + e := vw(k); + if (e != 0) + s += filelist[k]+".jpg "; + if (e == 3) { + s += "cancelled\n"; + break; + } + else if (e == -1) + s += "failed\n"; + } + } + if (s != "") + dialog("Multiple view complete:\n\n"+s,0,-1,coords); +} + +vw(i: int): int +{ + # raise window if it is already open + low := toplevels; + for(; low != nil; low = tl low) { + (tplvl, name, nil, nil) := hd low; + if (filelist[i]+".jpg" == name) { + tkcmd(tplvl, "raise .; focus .; update"); + return 0; + } + } + + ctlchan := chan of int; + ctlchans := chan of string; + chanout := chan of string; + chanin := chan of string; + spawn downloadscreen(coords, i, ctlchans, chanout); + chanout <-= "!show!"; + spawn view(i,ctlchan, chanin, chanout); + pid := <-ctlchan; + killed := 0; + for (;;) alt { + s := <-ctlchans => + if (s == "kill") { + chanin <-= "kill"; + killed = 1; + } + e := <-ctlchan => + chanout <-= "!done!"; + if (killed) + return 3; + if (e == -1) + dialog(sys->sprint("Cannot read file: %s.jpg\n%r",filelist[i]),0,i,coords); + if (e == -2) return vw(i); + else return e; + } + return 0; +} + +view(i: int, ctlchan: chan of int, chanin, chanout: chan of string) +{ + ctlchan <-= sys->pctl(0, nil); + titlename := filelist[i]+".jpg"; + + filename := camerapath+"jpg/"+filelist[i]+".jpg"; + filesize := testfilesize(filename); + cached := 0; + if (filesize > 0 && isloaded(filelist[i],JPG) && usecache) { + cachefilename := tmppath+filelist[i]+"."+string JPG+"~"; + if (testfilesize(cachefilename) == filesize) { + cached = 1; + filename = cachefilename; + } + else delloaded(filelist[i],JPG); + } + if (filesize < 1) { + ctlchan <-= -1; + return; + } + + img: ref Image; + cachepath := ""; + if (!cached && usecache) + cachepath = tmppath+filelist[i]+"."+string JPG+"~"; + img = readjpg->jpg2img(filename, cachepath, chanin, chanout); + if(img == nil) { + if (cachepath != nil) + sys->remove(cachepath); + if (!cached) + ctlchan <-= -1; + else { + delloaded(filelist[i], JPG); + ctlchan <-= -2; + } + return; + } + else { + chanout <-= "l2 Displaying"; + if (cachepath != "") + imgloaded = (filelist[i], JPG) :: imgloaded; + (t, titlechan) := tkclient->toplevel(context, "", titlename, Tkclient->Appl); + butchan := chan of string; + tk->namechan(t, butchan, "butchan"); + tkcmd(t, "focus .Wm_t; update"); + for (tk1 := 0; tk1 < len viewscr; tk1++) + tkcmd(t, viewscr[tk1]); + w := img.r.dx(); + h := img.r.dy(); + tkcmd(t, "panel .p -width "+string w+" -height "+string h); + tk->putimage(t, ".p",img,nil); + tkcmd(t, "bind .p <ButtonPress-2> {send butchan move %X %Y}"); + tkcmd(t, "bind .p <ButtonRelease-2> {send butchan release}"); + tkcmd(t, "bind .p <ButtonPress-3> {send butchan menu %X %Y}"); + tkcmd(t, ".f.c create window 0 0 -window .p -anchor nw"); + tkcmd(t, ".f.c configure -scrollregion {0 0 "+string w+" "+string h+"}"); + ctlchan <-= 0; + addtoplevel(t,titlename,nil, sys->pctl(0,nil)); + + h1 := 300; + w1 := 500; + ht := int tkcmd(t, ".Wm_t cget -height"); + if (h1 > display.image.r.dy() - ht) h1 = display.image.r.dy() - ht; + if (w1 > display.image.r.dx()) w1 = display.image.r.dx(); + tkcmd(t, ". configure -width "+string w1+" -height "+string h1); + resizeview(t,w,h); + tkcmd(t, "pack .f; update"); + scrolling := 0; + origin := Point (0,0); + tkclient->onscreen(t, nil); + tkclient->startinput(t, "kbd"::"ptr"::nil); + + loop: for(;;) alt{ + s := <-t.ctxt.kbd => + tk->keyboard(t, s); + s := <-t.ctxt.ptr => + tk->pointer(t, *s); + inp := <- butchan => + (n, lst) := sys->tokenize(inp, " \t\n"); + case hd lst { + "save" => + ftype := "."+hd tl lst; + savename := selectfile->filename(context, + display.image, + "Save "+filelist[i]+ftype+" to directory...", + "*"+ftype :: nil, + lastpath); + if (savename != "" && savename[0] == '/') { + lastpath = savename[:isat2(savename,"/")+1]; + if (savename[len savename - 1] == '/') + savename += filelist[i]+ftype; + + if (!hasext(savename, ftype)) + savename += ftype; + (fd, cancel) := create(savename, getcoords(t)); + if (fd != nil) { + n2 := -1; + if (ftype == ".bit") + n2 = display.writeimage(fd,img); + if (ftype == ".jpg") + n2 = 1 - dnld(i, "$"+savename); + if (n2 == 0) { + dialog(filelist[i]+ftype+" saved",0,i,getcoords(t)); + break; + } + dialog("Could not save: "+filelist[i]+ftype,0,i,getcoords(t)); + } + if (!cancel) + dialog("Could not save: "+filelist[i]+ftype,0,i,getcoords(t)); + break; + } + + "menu" => + tkcmd(t, ".m post "+hd tl lst+" "+hd tl tl lst); + "release" => + scrolling = 0; + "move" => + newpoint := Point (int hd tl lst, int hd tl tl lst); + + if (scrolling) { + diff := (origin.sub(newpoint)).mul(2); + tkcmd(t, ".f.c xview scroll "+string diff.x+" units"); + tkcmd(t, ".f.c yview scroll "+string diff.y+" units"); + origin = newpoint; + # clearbuffer(butchan); + } + else { + origin = newpoint; + scrolling = 1; + } + } + + s := <-t.ctxt.ctl or + s = <-t.wreq or + s = <-titlechan => + if (s == "exit") + break loop; + e := tkclient->wmctl(t, s); + if (e == nil && s[0] == '!') + resizeview(t,w,h); + } + deltoplevel(t); + } +} + +create(filename: string, co: Rect): (ref sys->FD, int) +{ + (n,dir) := sys->stat(filename); + if (n != -1 && !dialog("overwrite "+filename+"?",1,-1,co)) + return (nil,1); + return (sys->create(filename,sys->OWRITE,8r666), 0); +} + +hasext(name,ext: string): int +{ + if (len name >= len ext && name[len name - len ext:] == ext) + return 1; + return 0; +} |
