chiark / gitweb /
wip fixes to show-thing for reorg
[ypp-sc-tools.db-live.git] / pctb / show-thing.tcl
1 #!/usr/bin/wish
2
3 # usage:
4 #  run show-thing without args
5 #  then on stdin write
6 #     one line which is a Tcl list for foolist
7 #     the xpm in the format expected
8 #  then expect child to raise SIGSTOP or exit 0 or exit nonzero
9 #  if child raised SIGSTOP, check database was updated
10
11 proc manyset {list args} {
12     foreach val $list var $args {
13         upvar 1 $var my
14         set my $val
15     }
16 }
17
18 set mul 6
19 set inter 1
20
21 set gotsh 20
22 set csrh 20
23
24 proc read_xpm {f} {
25     global foolist mul inter rhsmost_max unk_l unk_r gotsh csrh
26     global cols rows wordmap
27     
28     set o {}
29     set y -3
30     while 1 {
31         if {[gets $f l] < 0} { error "huh? "}
32         if {![regexp {^"(.*)",$} $l dummy l]} {
33             append o "$l\n"
34             if {[regexp {^\}\;$} $l]} break
35             continue
36         }
37         if {$y==-3} {
38             manyset $l cols rows colours cpp
39             #assert {$colours==2}
40             #assert {$cpp==1}
41             set mulcols [expr {$cols*$mul+$inter}]
42             set mulrows [expr {$rows*$mul+$inter}]
43             append o "\"$mulcols $mulrows 9 1\",\n"
44             for {set x 0} {$x<$cols} {incr x} { set wordmap($x) 0 }
45         } elseif {$y==-2} { # first pixel
46             append o \
47 "\"+ c #111\",
48 \"a c #800\",
49 \"A c #fcc\",
50 \"b c #00c\",
51 \"B c #fff\",
52 \"u c #000\",
53 \"U c #ff0\",
54 \"q c #000\",
55 \"Q c #ff0\",\n"
56         } elseif {$y==-1} { # 2nd pixel but we've already printed ours
57         } else {
58             set ybit [expr {1<<$y}]
59             set x 0
60             set ol "\"+"
61             set olh $ol
62             foreach c [split $l ""] {
63                 set how "u"
64                 if {$x >= $unk_l && $x <= $unk_r} {
65                     set how q
66                 } else {
67                     set ab 0
68                     foreach {min max context got} $foolist {
69                         set rhsmost_max $max
70                         if {$x >= $min && $x <= $max} {
71                             set how [lindex {a b} $ab]
72                             break
73                         }
74                         set ab [expr {!$ab}]
75                     }
76                 }
77                 switch -exact $c {
78                     " " { set p $how }
79                     "o" {
80                         set p [string toupper $how]
81                         incr wordmap($x) $ybit
82                     }
83                     default { error "$c ?" }
84                 }
85                 append ol "[string repeat $p [expr {$mul-$inter}]][
86                          string repeat + $inter]"
87                 append olh [string repeat + $mul]
88                 incr x
89             }
90             set ole "\",\n"
91             append ol $ole
92             append olh $ole
93             set olhn [string repeat $olh $inter]
94             if {!$y} { append o $olhn }
95             append o [string repeat $ol [expr {$mul-1}]]
96             append o $olhn
97         }
98         incr y
99     }
100     set data [exec xpmtoppm << $o]
101     image create photo main_image -data $data
102     
103     foreach w {.d .d.csr .d.got} {
104         $w configure -width $mulcols
105     }
106     .d configure -height [expr {$csrh+$mulrows+$gotsh}]
107     foreach w {0 1} {
108         .d.csr_$w configure -height $mulrows
109     }
110     place .d.got -x 0 -y [expr {$csrh+$mulrows}]
111 }
112
113 #puts $o
114
115 frame .d
116
117 set mi main_image
118 image create bitmap main_image
119 label .d.mi -image $mi -borderwidth 0
120
121 frame .d.csr -bg black -height $csrh
122 frame .d.got -bg black -height $gotsh
123
124 proc draw_foolist {} {
125     global foolist mul inter
126     eval destroy [winfo children .d.got]
127     foreach {min max context got} $foolist {
128         frame .d.got.m$min -bd 0 -background \#888
129         label .d.got.m$min.l -text "$got" -fg white -bg black -bd 0
130         pack .d.got.m$min.l -padx 1 -pady 1
131         place .d.got.m$min -x [expr {$min*$mul+$inter}] -y 0
132     }
133 }
134
135 set imcsr [image create bitmap -data \
136 {#define csr_width 11
137 #define csr_height 11
138 static unsigned char csr_bits[] = {
139    0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x21, 0x04, 0x22, 0x02, 0x25, 0x05,
140    0xaa, 0x02, 0x74, 0x01, 0xa8, 0x00, 0x70, 0x00, 0x20, 0x00};
141 }]
142
143 frame .d.csr.csr
144 label .d.csr.csr.l -image $imcsr -compound left
145 entry .d.csr.csr.e -bd 0
146 pack .d.csr.csr.l -side left
147
148 frame .d.csr_0 -bg white -width 1
149 frame .d.csr_1 -bg white -width 1
150
151 place .d.csr -x 0 -y 0
152 place .d.mi -x 0 -y $csrh
153 pack .d
154
155 frame .help
156 pack .help
157
158 proc startup_cursor {} {
159     global cur_already cur_mode cur_0 cur_1 last_ht
160     global foolist unk_l unk_r
161     
162     set cur_already [expr {[llength $foolist]/4-1}]
163     set cur_mode 1 ;# one of:   0 1 already text
164
165     set cur_0 $unk_l
166     set cur_1 [expr {$unk_r+1}]
167     set last_ht {}
168 }
169
170 proc helptext {t} {
171     global last_ht
172     if {![string compare $t $last_ht]} return
173     eval destroy [grid slaves .help]
174     set y 0; foreach l $t {
175         set x 0; foreach c $l {
176             set w .help.at${x}x${y}
177             label $w -text $c
178             grid $w -row $y -column $x -padx 5
179             incr x
180         }
181         incr y
182     }
183     set last_ht $t
184 }
185
186 proc recursor/0 {} { recursor//01 0 }
187 proc recursor/1 {} { recursor//01 1 }
188 proc recursor//01 {z1} {
189     global mul rhsmost_max cols foolist
190     upvar #0 cur_$z1 cur
191     .d.csr.csr.l configure -text {adjust}
192     place .d.csr.csr -x [expr {$cur*$mul - 7}]
193     bind_key space { othercursor }
194     bind_leftright cur_$z1 0 [expr {$cols-1}]
195     if {[llength $foolist]} {
196         bind_key Tab { set cur_mode already; recursor }
197     } else {
198         bind_key Tab {}
199     }
200     bind_key Return {
201         if {$cur_0 != $cur_1} {
202             set cur_mode text
203             recursor
204         }
205     }
206     helptext {
207         {{<- ->}   {move cursor, adjusting area to define}}
208         {Space     {switch to moving other cursor}}
209         {Return    {confirm location, enter letter(s)}}
210         {Tab       {switch to correcting earlier ocr}}
211     }
212 }
213 proc othercursor {} {
214     global cur_mode
215     set cur_mode [expr {!$cur_mode}]
216     recursor
217 }
218
219 proc recursor/text {} {
220     helptext {
221         {Return   {confirm entry of new glyph}}
222         {Escape   {abandon entry}}
223     }
224     unbind_all_keys
225     .d.csr.csr.l configure -text {define:}
226     pack .d.csr.csr.e -side left
227     focus .d.csr.csr.e
228     bind_key Return {
229         binary scan [.d.csr.csr.e get] h* hex
230         if {[string length $hex]} {
231             RETURN_RESULT DEFINE "$cur_0 $cur_1 $hex"
232         }
233     }
234     bind_key Escape {
235         bind_key Escape {}
236         pack forget .d.csr.csr.e
237         set cur_mode 1
238         recursor
239     }
240 }
241
242 proc recursor/already {} {
243     global mul
244     global foolist
245     global cur_already mul
246     global foolist cur_already mul
247     .d.csr.csr.l configure -text {correct}
248     set rmax [lindex $foolist [expr {$cur_already*4}]]
249     place .d.csr.csr -x [expr {$rmax*$mul-3}]
250     bind_key Return {}
251     bind_key space {}
252     bind_leftright cur_already 0 [expr {[llength $foolist]/4-1}]
253     bind_key Tab { bind_key Delete {}; set cur_mode 1; recursor }
254     bind_key Delete {
255         RETURN_RESULT DELETE [lrange $foolist \
256                                   [expr $cur_already*4] \
257                                   [expr $cur_already*4+1]]
258     }
259     helptext {
260         {{<- ->}   {move cursor, selecting glyph to correct}}
261         {Del       {clear this glyph from the recognition database}}
262         {Tab       {switch to selecting area to define as new glyph}}
263     }
264 }
265
266 proc bind_key {k proc} {
267     global keybindings
268     bind . <Key-$k> $proc
269     set keybindings($k) [expr {!![string length $proc]}]
270 }
271 proc unbind_all_keys {} {
272     global keybindings
273     foreach k [array names keybindings] { bind_key $k {} }
274 }
275
276 proc bind_leftright {var min max} {
277     bind_key Left  [list leftright $var $min $max -1]
278     bind_key Right [list leftright $var $min $max +1]
279 }
280 proc leftright {var min max inc} {
281     upvar #0 $var v
282     set vnew $v
283     incr vnew $inc
284     if {$vnew < $min || $vnew > $max} return
285     set v $vnew
286     recursor
287 }
288
289 proc recursor {} {
290     global csrh cur_mode cur_0 cur_1 mul
291     foreach z1 {0 1} {
292         place .d.csr_$z1 -y $csrh -x [expr {[set cur_$z1] * $mul}]
293     }
294     recursor/$cur_mode
295 }
296
297
298 # database format:
299 # series of glyphs:
300 #   <context> <ncharacters> <hex>...
301 #   width
302 #   <hex-bitmap>
303
304 # $database($context 0x<bits> 0x<bits>...) = $hex
305
306 proc read_database {} {
307     global database
308     set f [open database r]
309     while {[gets $f l] >= 0} {
310         if {![regexp {^(\w+) (\d+) ((?:[0-9a-f]{2})+)$} $l \
311                   dummy context strl strh]} {
312             error "bad syntax"
313         }
314         if {[string length $strh] != $strl*2} { error "$strh $strl" }
315         gets $f l; set width [format %d $l]
316         set bm $context
317         for {set x 0} {$x < $width} {incr x} {
318             gets $f l; lappend bm [format %x 0x$l]
319         }
320         set database($bm) $strh
321     }
322     close $f
323 }
324
325 proc write_database {} {
326     global database
327     set ol {}
328     foreach bm [array names database] {
329         set strh $database($bm)
330         set strs [binary format h* $strh]
331         set strdo [format "%d %s" [expr {[string length $strh]/2}] $strh]
332         set o "[lindex $bm 0] $strdo\n"
333         append o [format "%d\n" [expr {[llength $bm]-1}]]
334         foreach x [lrange $bm 1 end] { append o "$x\n" }
335         lappend ol $o
336     }
337     set f [open database.new w]
338     foreach o [lsort $ol] {
339         puts -nonewline $f $o
340     }
341     close $f
342     file rename -force database.new database
343 }
344
345 proc update_database/DEFINE {c0 c1 strh} {
346     global foolist unk_l unk_context wordmap database
347     if {$c0 > $c1} { manyset [list $c0 $c1] c1 c0 }
348     if {$c0 == $unk_l} {
349         set ncontext $unk_context
350     } else {
351         foreach {l r context got} $foolist {
352             if {$l==$c0} { set ncontext $context; break }
353         }
354         if {![exists ncontext]} {
355             puts stderr "must start at letter LHS!"
356             return
357         }
358     }
359     set bm $ncontext
360     for {set x $c0} {$x < $c1} {incr x} {
361         lappend bm [format %x $wordmap($x)]
362     }
363     set database($bm) $strh
364     write_database
365 }
366     
367
368 proc RETURN_RESULT {how what} {
369     place forget .d.csr.csr
370     pack forget .d.csr.csr.e
371     helptext {{{ Processing }}}
372     unbind_all_keys
373     update idletasks
374     puts "$how $what"
375     eval update_database/$how $what
376 }
377
378 #    bind . <Key-space> {}
379
380 proc test_main {} {
381     global foolist unk_l unk_r unk_context
382     
383     set foolist {
384         7 11 1 M
385         13 17 0 a
386         19 23 0 n
387     }
388     set unk_l 25
389     set unk_r 29
390     set unk_context 0
391
392     set f [open text.xpm]
393     read_xpm $f
394     close $f
395
396     draw_foolist
397     startup_cursor
398     
399     read_database
400     recursor
401 }
402
403 test_main