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