# ngcgui_ttt.tcl: a LinuxCNC [DISPLAY]TKAPP for using truetype-tracer and ngcgui #----------------------------------------------------------------------- # Copyright: 2010-2012 # Author: Dewey Garrett # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #----------------------------------------------------------------------- # $ truetype-tracer -? # v3: [-?] [-u] [-s subdist] [-f font.ttf] 'Text to trace' # v4: [-?] [-s subdiv] [-u] [-c scale] [-l linescale] [-f /some/file.ttf] 'The Text' # ttt.c -l 0 or if speciied, 24 min # ttt.c -s --> dsteps default: 200 #note: to use quotes in text, express as \" seems to work namespace eval ::ttt {namespace export ttt ;# public interface} proc ::ttt::trimsuffix {s {sfx .ttf} } { set idx [string last $sfx $s] if {$idx <0} {return $s} return [string range $s 0 [expr -1 + $idx]] } ;# trimsuffix proc ::ttt::setfont {} { if {"$::ttt(font)" == ""} { set idir "/usr/share/fonts/truetype/freefont" } else { set idir [file dirname $::ttt(font)] } set filename [tk_getOpenFile \ -title "[_ "Set Font"]"\ -defaultextension .ttf \ -initialfile "" \ -initialdir "$idir" \ ] set ::ttt(font) $filename } ;# setfont proc ::ttt::checkttt {} { # 101127 ttt.c doesn't hava a --version option and returns 99 for -? #future: set ans -1 #future: if [catch {set ans [eval exec -ignorestderr $::ttt(exe) -v]} msg] { #future: puts check:<$msg> #future: } #future: test ans here # hack follows: catch {set ans1 [eval exec $::ttt(exe) -? 2>/tmp/ttt.q]} catch {set ans2 [eval exec grep -c subdiv /tmp/ttt.q]} catch {file delete /tmp/ttt.q} if {[info exists ans2] && $ans2 == 1} { set ::ttt(msg) "::ttt::embedinit [_ "found truetype-tracer v4 -OK"]" return 1 } else { puts stderr "::ttt::embedinit:[_ "Note truetype-tracer v4 is required"]" set ::ttt(msg) "[_ "Note: truetype-tracer v4 is required"]" return 0 } } ;# checkttt proc ::ttt::embedinit {} { package require Ngcgui if [info exists ::ttt(instance)] return ;# for testing convenience set ::ttt(this) ngcgui_ttt.tcl if {[info procs ::ngcgui::parent] == ""} { return -code error "\n\n[_ "ngcgui_app.tcl must be loaded before"] $::ttt(this)" } # alternate behaviors set ::ttt(multiplepages) 1 ;# 1:most flexible set ::ttt(use_program_prefix) 0 ;# 0:no clutter set ::ttt(info) \ "[_ "Create a subroutine file from truetype-tracer (V4 reqd)"]" set ::ttt(instance) 0 set ::ttt(color,ok) green4 set ::ttt(color,black) black set ::ttt(color,error) red set ::ttt(datefmt) "%d %b %Y" lappend ::ttt(embed,options) noiframe ;# no image and user needs controls lappend ::ttt(embed,options) nonew ;# lappend ::ttt(embed,options) nopathcheck ;# SUBROUTINE_PATH not checked set ::ttt(exe) [inifindall DISPLAY TTT] if {[llength $::ttt(exe)] >1} { return -code error "[_ "problem with"] \[DISPLAY\]TTT <$::ttt(exe)>" } if {"$::ttt(exe)" == ""} { set ::ttt(exe) [file join /usr/local/bin truetype-tracer] puts stderr "::ttt::embedinit:[_ "No entry for"] \[DISPLAY\]TTT, trying $::ttt(exe)" } if ![checkttt] { puts stderr "::ttt::embedinit:[_ "wrong version of truetype-tracer"]" return } set preamble [inifindall DISPLAY TTT_PREAMBLE] if {([llength $preamble] >1)} { return -code error "[_ "problem with"] \[DISPLAY\]TTT_PREAMBLE <$preamble>" } set ::ttt(preamble) $preamble if $::ttt(use_program_prefix) { set ::ttt(dir) [inifindall DISPLAY PROGRAM_PREFIX] if ![file writable $::ttt(dir)] { set d $::ttt(dir) set ::ttt(dir) /tmp puts stderr \ "::ttt::embedinit: <$d> [_ "not writable, using"] $::ttt(dir) [_ "and setting expandsub"]" lappend ::ttt(embed,options) expandsub ;# needed if no PROGRAM_PREFIX } } else { set ::ttt(dir) /tmp lappend ::ttt(embed,options) expandsub ;# using /tmp so need to expand } set ::ttt(filebase) ttt set ::ttt(text) truetype-tracer if [info exists ::env(USERNAME)] { set ::ttt(text) $::env(USERNAME) } # hardcoded in ttt.c: set ::ttt(font) "/usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf" set ::ttt(default,scale) 0.0003 ;# hardcoded in ttt.c: set ::ttt(pagename) ttt set ::ttt(topf) [::ngcgui::getngcgui_frame $::ttt(pagename)] if {[info procs ::ngcgui::tabmanage] == "::ngcgui::tabmanage"} { ::ngcgui::tabmanage $::ttt(pagename) $::ttt(topf) \ "truetype-tracer-ngcgui"\ ::ttt(info) } set w [frame $::ttt(topf).t] pack $w -fill both -expand 1 -anchor nw -side top set lw 8 ;# labelwidth set ew 6 ;# entrywidth set rw 8 ;# radiobutton width # f1 Text set f [frame $w.f1 -bd 1 -relief ridge] pack $f -fill both -side top -anchor nw -expand 0 pack [label $f.l -text "[_ "Text"]" \ -anchor e -relief ridge \ -width $lw \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(text)\ -justify left -width 40 -relief sunken] -side left -fill x -expand 1 # f2 linescale set f [frame $w.f2 -bd 1 -relief ridge] pack $f -side top -anchor nw -fill x -expand 0 pack [label $f.l -text "[_ "Linescale"]" -width $lw \ -anchor e -relief ridge \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(linescale) \ -justify right -width $ew\ ] -side left -fill none -expand 0 set dummy "[_ "none"]" ;# for i18n foreach value {none 25 50 100} { pack [radiobutton $f.ls$value \ -width $rw \ -text "[_ "$value"]" \ -value "[_ "$value"]" \ -variable ::ttt(linescale)\ -relief sunken\ ] -side left -fill none -expand 0 } set ::ttt(linescale) "none" # f3 subdiv set f [frame $w.f3 -bd 1 -relief ridge] pack $f -side top -anchor nw -fill x -expand 0 pack [label $f.l -text "[_ "Subdiv"]" \ -width $lw \ -anchor e -relief ridge \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(subdiv) \ -justify right -width $ew\ ] -side left -fill none -expand 0 set dummy "[_ "default"]" ;# for i18n foreach value {default 100 200 400} { pack [radiobutton $f.ls$value \ -width $rw \ -text "[_ "$value"]" \ -value "[_ "$value"]" \ -variable ::ttt(subdiv)\ -relief sunken\ ] -side left -fill none -expand 0 } set ::ttt(subdiv) "default" # f4 scale set f [frame $w.f4 -bd 1 -relief ridge] pack $f -side top -anchor nw -fill x -expand 0 pack [label $f.l -text "[_ "Scale"]" \ -width $lw \ -anchor e -relief ridge \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(scale) \ -justify right -width $ew\ ] -side left -fill none -expand 0 set svalues "default" set ct 0 foreach m {.5 2 5} { lappend svalues [format %.4g [expr $::ttt(default,scale) * $m]] } foreach value $svalues { incr ct pack [radiobutton $f.x$ct \ -width $rw \ -text $value -value "$value" -variable ::ttt(scale)\ -relief sunken\ ] -side left -fill none -expand 0 } set ::ttt(scale) default # f5 mode set f [frame $w.f5 -bd 1 -relief ridge] pack $f -side top -anchor nw -fill x -expand 0 pack [label $f.m -text "[_ "Mode"]" \ -width $lw \ -anchor e -relief ridge \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(test) \ -justify right -width $ew\ -state readonly \ ] -side left -fill none -expand 0 set dummy "[_ "normal"]" ;# i18n set dummy "[_ "date"]" ;# i18n set dummy "[_ "fontname"]" ;# i18n foreach value {normal date AaBb123 fontname} { pack [radiobutton $f.x$value \ -width $rw \ -text $value -value "$value" -variable ::ttt(test)\ -relief sunken\ ] -side left -fill none -expand 0 } set ::ttt(test) "normal" # f6 check buttons set f [frame $w.f6 -bd 1 -relief ridge] pack $f -side top -anchor nw -fill x -expand 0 pack [label $f.m -text "[_ "Switches"]" \ -width $lw \ -anchor e -relief ridge \ ] -side left -fill none -expand 0 pack $f -side top -anchor nw -fill x -expand 0 set ::ttt(unicode) 0 pack [checkbutton $f.unicode -text "[_ "Unicode"]" \ -var ::ttt(unicode)\ ] -side left -fill none -expand 0 set ::ttt(allowrotation) 0 pack [checkbutton $f.rotation -text "[_ "Allow Rotation"]" \ -var ::ttt(allowrotation)\ ] -side left -fill none -expand 0 # f7 font set f [frame $w.f7 -bd 1 -relief ridge] pack $f -fill both -side top -anchor nw -expand 0 pack [button $f.b -text "[_ "Font"]" \ -width $lw -padx 0 -pady 0\ -command ::ttt::setfont \ ] -side left -fill none -expand 0 pack [entry $f.e -textvariable ::ttt(font)\ -justify left -width 40 -relief sunken\ ] -side left -fill x -expand 1 # f8 Make set f [frame $w.f8 -relief ridge] pack $f -fill both -anchor nw -expand 0 pack [button $f.b \ -text "[_ "Make ngcgui-compatible subfile and new tab page"]" \ -padx 0 -pady 0 \ -command ::ttt::runttt\ ] -side top -fill x -expand 1 # f9 msg set f [frame $w.f9 -bd 1 -relief ridge] pack $f -fill both -side top -anchor nw -expand 0 set l [entry $f.msg -relief flat \ -state readonly \ -justify left -textvariable ::ttt(msg)] pack $l -anchor nw -fill x -expand 0 set ::ttt(msg,widget) $l $::ttt(msg,widget) configure -fg $::ttt(color,ok) ::ttt::bindings setup } ;# init proc ::ttt::bindings {mode} { switch $mode { setup { ::ngcgui::bind_for_axis $::ttt(topf) bindtags $::ttt(topf) $::ttt(topf) ::ngcgui::entry_mend $::ttt(topf) bind $::ttt(topf) [list ::ttt::bindings enter] bind $::ttt(topf) [list ::ttt::bindings leave] set ::ttt(restore,focus) [focus -lastfor $::ttt(topf)] } enter { set ::ttt(restore,focus) [focus -lastfor $::ttt(topf)] focus $::ttt(topf) } leave { focus -force $::ttt(restore,focus) } } } ;# bindings proc ::ttt::runttt {} { set sname $::ttt(filebase) # if you make a separate tab for each MakeTTT, # then need different subname and filename if $::ttt(multiplepages) { set sname $::ttt(filebase)-$::ttt(instance) } set ofile [file join $::ttt(dir) $sname.ngc] # switch -nocase not avail tcl8.4 switch [string tolower $::ttt(test)] { date {set thetext [clock format [clock seconds] \ -format $::ttt(datefmt)] } normal {set thetext "$::ttt(text)"} fontname {set thetext [trimsuffix [file tail $::ttt(font)]]} default {set thetext "$::ttt(test)"} } if {[string trim $thetext] == ""} { set ::ttt(msg) "[_ "Null text"]" $::ttt(msg,widget) configure -fg $::ttt(color,error) return } set ::ttt(msg) "" # tricky to get pipeline tokens correct: if {"$::ttt(linescale)" == "none"} { set lopt ""; set lval "" } else { set lopt "-l"; set lval $::ttt(linescale) } if {"$::ttt(subdiv)" == "default"} { set sopt ""; set sval "" } else { set sopt "-s"; set sval $::ttt(subdiv) } if {"$::ttt(scale)" == "default"} { set copt ""; set cval "" set ::ttt(scale) $::ttt(default,scale) ;# hack to agree with ttt.c } else { set copt "-c"; set cval "$::ttt(scale)" } switch $::ttt(unicode) { 1 {set uopt "-u"} default {set uopt ""} } if {$::ttt(font) == ""} { set fopt ""; set fval "" set ::ttt(msg) "[_ "Using truetype-tracer default font"]" $::ttt(msg,widget) configure -fg $::ttt(color,black) } else { if ![file exists $::ttt(font)] { set ::ttt(msg) "[_ "no such file"] : $::ttt(font)" $::ttt(msg,widget) configure -fg $::ttt(color,error) return } if ![file readable $::ttt(font)] { set ::ttt(msg) "[_ "file not readable"] :$::ttt(font)" $::ttt(msg,widget) configure -fg $::ttt(color,error) return } set fopt "-f"; set fval "$::ttt(font)" } set eline "$::ttt(exe) >>$ofile \ $lopt $lval \ $sopt $sval \ $copt $cval \ $uopt \ $fopt $fval \ \"$thetext\" \ | grep -Evi m02\|m2\|= \ " #puts eline=$eline set showopt "$lopt $lval $sopt $sval $copt $cval $uopt" #omitted for space: $fopt $fval # set pno 6; set gno 59; set gno(1) G54 set gno(2) G55 set gno(3) G56 set gno(4) G57 set gno(5) G58 set gno(6) G59 set gno(7) G59.1 set gno(8) G59.2 set gno(9) G59.3 set fd [open $ofile w] ;# truncate set txt \ "(cmd: [file tail $::ttt(exe)] $showopt) (info: TEXT: $thetext) ($::ttt(this) created this file using truetype-tracer) ( exe = $::ttt(exe)) ( font = $::ttt(font)) (linescale = $::ttt(linescale)) ( scale = $::ttt(scale)) ( subdiv = $::ttt(subdiv)) o<$sname> sub # = #1 (=0.1 Safe Height) # = #2 (=0.01 Depth of Cut) # = #3 (=$::ttt(scale) XY Scale) # = #4 (=10.0 Feed) # = #5 (=0.0 X offset) # = #6 (=0.0 Y offset)" puts $fd $txt if $:::ttt(allowrotation) { set txt \ "# = #7 (=1 coordsystem to rotate 1==g54) # = #8 (=0 rotate angle) o if \[# LT 0.0\] (debug, Illegal system #) m2 o endif o if \[# GT 9.0\] (debug, Illegal system #) m2 o endif " foreach s {1 2 3 4 5 6 7 8 9} { set txt "$txt o if \[# EQ $s\] o if \[# NE 0.0\] g10l2p$s r# ;system $s $gno($s) rotate (debug,system $s $gno($s) rotated #) o endif $gno($s) o endif " } puts $fd $txt } close $fd if [catch {eval exec >>$ofile $eline} msg] { set ::ttt(msg) "$msg" $::ttt(msg,widget) configure -fg $::ttt(color,error) return } set fd [open $ofile a] ;# append if $::ttt(allowrotation) { set txt "" foreach s {1 2 3 4 5 6 7 8 9} { set txt "$txt o if \[# EQ $s\] o if \[# NE 0.0\] g10l2p$s r0 ;reset $s rotation (debug,$gno($s) UNrotated) o endif o endif " } set txt "$txt o if \[# NE 1\] (debug, m2 restores g54) o endif " puts $fd $txt } puts $fd "o<$sname> endsub" close $fd if !$::ttt(multiplepages) { if [info exists ::ttt(hdl)] { # user may have already deleted it: if [::ngcgui::pageexists $:::ttt(hdl)] { ::ngcgui::deletepage $::ttt(pagename) } unset ::ttt(hdl) } } set ::ttt(msg) "[_ "Creating new tab page"]" $::ttt(msg,widget) configure -fg $::ttt(color,black) update after 200 # NB: using option expandsub lets the ofile be located anywhere set ::ttt(hdl) [::ngcgui::embed_in_axis_tab \ [::ngcgui::getngcgui_frame ttt-$::ttt(instance)] \ subfile=$ofile \ preamble=$::ttt(preamble) \ options=$::ttt(embed,options) \ ] ::ngcgui::raiselastpage incr ::ttt(instance) } ;# runttt package provide Ngcguittt 1.0 ::ttt::embedinit