proc ::toxy::kbout {path target remote oldchord newchord} { foreach key $oldchord { pd [concat $target _cb [lindex $key 0] 0 \;] if {$remote != "."} { pd [concat $remote [lindex $key 0] 0 \;] } } foreach key $newchord { pd [concat $target _cb [lindex $key 0] [lindex $key 1] \;] if {$remote != "."} { pd [concat $remote [lindex $key 0] [lindex $key 1] \;] } } } proc ::toxy::kbput {path target remote keys appendmode doout} { set oldchord {} set newchord {} if {$appendmode} { foreach key $keys { set ndx [lindex $key 0] # FIXME upper limit if {$ndx >= 0} { if {$appendmode == 1} { set found \ [lsearch $::toxy::kbchord($target) [concat $ndx *]] } else { set found -1 } if {$found < 0} { $path itemconfig $path.$ndx -fill grey lappend newchord $key lappend ::toxy::kbchord($target) $key } else { $path itemconfig $path.$ndx \ -fill [lindex [$path gettags $path.$ndx] 2] lappend oldchord $key set ::toxy::kbchord($target) \ [lreplace $::toxy::kbchord($target) $found $found] } } } # FIXME oldchord set ::toxy::kbchord($target) \ [lsort -unique -integer -index 0 $::toxy::kbchord($target)] } else { set oldchord $::toxy::kbchord($target) foreach key $::toxy::kbchord($target) { set ndx [lindex $key 0] $path itemconfig $path.$ndx \ -fill [lindex [$path gettags $path.$ndx] 2] } foreach key $keys { set ndx [lindex $key 0] # FIXME upper limit if {$ndx >= 0} { $path itemconfig $path.$ndx -fill grey lappend newchord $key } } set ::toxy::kbchord($target) [lsort -unique -integer -index 0 $newchord] } if {$doout} { ::toxy::kbout $path $target $remote $oldchord $newchord } } proc ::toxy::kb {path target remote noctaves size} { # guard against BadAlloc crashes if {$size > 10} {set size 10} set lft [expr {round(5 * $size)}] set top [expr {round(5 * $size)}] set bot [expr {round(100 * $size)}] set dx [expr {round(17 * $size)}] set wid [expr {round($dx - $size * .5)}] set blbot [expr {round($bot * .65)}] $path config -height [expr {$bot + $top}] \ -width [expr {$dx * ($noctaves * 7 + 1) + $lft * 2 - 1}] bind $path +[concat ::toxy::kbenter $path $target] bind $path +[concat ::toxy::kbleave $path $target] bind $path \ +[concat ::toxy::kbdrag $path $target $remote %X %Y 0] bind $path \ +[concat ::toxy::kbdrag $path $target $remote %X %Y 1] bind $path \ +[concat ::toxy::kbdrag $path $target $remote %X %Y 2] for {set octave 0} {$octave <= $noctaves} {incr octave} { set prevkey 0 foreach key {0 2 4 5 7 9 11} { set ndx [expr $octave * 12 + $key] set id [$path create rect $lft $top [expr {$lft + $wid}] $bot \ -fill white -tags "$ndx $path.$ndx white"] $path bind $id <1> \ [concat ::toxy::kbpress $path $target $remote $ndx %y 0] $path bind $id \ [concat ::toxy::kbpress $path $target $remote $ndx %y 1] $path bind $id \ [concat ::toxy::kbcontrolon $path $target $remote $ndx %y] $path bind $id \ [concat ::toxy::kbcontroloff $path $target $remote $ndx] if {$key - $prevkey > 1} { incr ndx -1 set x [expr {$lft - $wid * .22}] set id [$path create rect $x $top [expr {$x + $wid * .44}] \ $blbot -fill black -tags "$ndx $path.$ndx black"] $path bind $id <1> \ [concat ::toxy::kbpress $path $target $remote $ndx %y 0] $path bind $id \ [concat ::toxy::kbpress $path $target $remote $ndx %y 1] $path bind $id \ [concat ::toxy::kbcontrolon $path $target $remote $ndx %y] $path bind $id \ [concat ::toxy::kbcontroloff $path $target $remote $ndx] } set prevkey $key incr lft $dx if {$octave == $noctaves && $key == 0} break } } set ::toxy::kbisinside($target) 0 set chord $::toxy::kbchord($target) set ::toxy::kbchord($target) {} ::toxy::kbput $path $target $remote $chord 0 0 } proc ::toxy::kbgetvel {path ndx y} { set g [$path coords $path.$ndx] set top [lindex $g 1] set bot [lindex $g 3] set vel [expr 100.0 - 99.0 * ($top - $y) / ($top - $bot)] if {$vel < 1.0} {set vel 1.0} elseif {$vel > 100.0} {set vel 100.0} return $vel } proc ::toxy::kbcontrolon {path target remote ndx y} { if {[$path cget -state] == "normal"} { $path itemconfig $path.$ndx -fill red ::toxy::kbout $path $target $remote {} \ [list [concat $ndx [::toxy::kbgetvel $path $ndx $y]]] } } proc ::toxy::kbcontroloff {path target remote ndx} { if {[$path cget -state] == "normal"} { if {[lsearch $::toxy::kbchord($target) [concat $ndx *]] < 0} { $path itemconfig $path.$ndx \ -fill [lindex [$path gettags $path.$ndx] 2] } else { $path itemconfig $path.$ndx -fill grey } ::toxy::kbout $path $target $remote [list [concat $ndx 0]] {} } } proc ::toxy::kbpress {path target remote ndx y shift} { if {[$path cget -state] == "normal"} { ::toxy::kbput $path $target $remote \ [list [concat $ndx [::toxy::kbgetvel $path $ndx $y]]] $shift 1 } } proc ::toxy::kbdrag {path target remote rx ry shift} { if {$shift <= 1 && $::toxy::kbisinside($target) && \ [$path cget -state] == "normal"} { set x [expr $rx - [winfo rootx $path]] set y [expr $ry - [winfo rooty $path]] set ndx [lindex [$path gettags [$path find closest $x $y]] 0] if {[lsearch $::toxy::kbchord($target) [concat $ndx *]] < 0} { ::toxy::kbput $path $target $remote \ [list [concat $ndx [::toxy::kbgetvel $path $ndx $y]]] $shift 1 } } } proc ::toxy::kbenter {path target} { set ::toxy::kbisinside($target) 1 } proc ::toxy::kbleave {path target} { set ::toxy::kbisinside($target) 0 } proc ::toxy::kbbang {path target remote} { ::toxy::kbout $path $target $remote {} $::toxy::kbchord($target) } proc ::toxy::kbfloat {path target remote ndx} { ::toxy::kbput $path $target $remote [list [concat $ndx 50.0]] 0 1 } proc ::toxy::kblist {path target remote args} { # LATER (::toxy::kbput ... 1) } proc ::toxy::kbset {path target remote args} { # LATER (::toxy::kbput ... 0) } #> kb canvas #. -bg yellow -cursor hand1 #. #oct 4 #size .75 #. @bang ::toxy::kbbang .- .| . #. @float ::toxy::kbfloat .- .| . .#1 #. @list ::toxy::kblist .- .| . .#args #. @set ::toxy::kbset .- .| . .#args #. @clear ::toxy::kbput .- .| . {} 0 1 ::toxy::kb .- .| . .#oct .#size # undo the "bind Canvas <1> {+focus %W}" from the setup.wid bind .- {focus .^.c} #@ new set ::toxy::kbchord(.|) {} #@ free unset ::toxy::kbchord(.|)