#!/usr/bin/wish proc get_fname {{dir .}} { global _fname set _fname "" catch {destroy .file} toplevel .file wm title .file {File Dialog} frame .file.file -border 6 -relief groove frame .file.dir -border 6 -relief groove frame .file.cmd -border 6 -relief groove label .file.file.l -text {File Name:} entry .file.file.name -width 20 -font 7x14 listbox .file.file.lb -height 10 -width 20 -selectmode browse -yscrollcommand {.file.file.sb set} scrollbar .file.file.sb -orient v -command {.file.file.lb yview} label .file.dir.l -text {Directory} button .file.cmd.ok -text {OK} -command { set tmp [.file.file.name get] if {$tmp==""} { set tmp [.file.file.lb curselection] if {$tmp==""} { bell return } set tmp [.file.file.lb get $tmp] } set _fname $tmp destroy .file } button .file.cmd.cancel -text {Cancel} -command { destroy .file } listbox .file.dir.up -height 0 -width 20 -selectmode browse label .file.dir.cur -text "Current" listbox .file.dir.dir pack .file.file -side left -fill y pack .file.dir -side left -fill y pack .file.cmd -side left -fill y pack .file.file.l -side top pack .file.file.name -side top pack .file.file.lb -side left -fill y pack .file.file.sb -side left -fill y pack .file.dir.l -side top pack .file.cmd.ok -side top -fill x pack .file.cmd.cancel -side top -fill x pack .file.dir.up .file.dir.cur -side top pack .file.dir.dir -side left foreach name [glob $dir/*] { if [file isdirectory $name] { .file.dir.dir insert end [file tail $name] } else { .file.file.lb insert end [file tail $name] } } bind .file.file.lb <1> { .file.file.name delete 0 end .file.file.name insert 0 [.file.file.lb get @%x,%y] } bind .file.file.lb { .file.cmd.ok invoke } grab .file tkwait window .file return $_fname } proc load fname { global edit_mode return [ catch { set file [open $fname r] .t delete 1.0 end .t insert end [read -nonewline $file] close $file .f.n configure -text $fname set_mode "flat" } ] } proc fi_new {} { catch {destroy .load } catch {destroy .save } set conf [tk_dialog .confirm "Confirmation" "Are you sure you want to wipe out the current document?" questhead {} NO! Yes] if {$conf == 1} { .t delete 1.0 end .f.n configure -text "untitled" } } proc fi_load {} { set fname [get_fname] if {$fname == ""} return load $fname } proc fi_save {} { chk_edit_mode flat catch { destroy .save } toplevel .save wm title .save "Save File" label .save.q -text {File to save:} entry .save.fname -font 7x14 .save.fname insert end [.f.n cget -text] button .save.confirm -text "Confirm" -command { catch { # Get file mode set fmod 644 catch { file stat [.save.fname get] stat set fmod [expr $stat(mode) & 0777] set fmod "[expr $fmod / 64][expr ($fmod/8) % 8][expr $fmod % 8]" } # Make backups catch {eval exec /bin/mv [.save.fname get]~ [.save.fname get]~~} catch {eval exec /bin/mv [.save.fname get] [.save.fname get]~} # Save the file set file [open [.save.fname get] w] puts -nonewline $file [.t get 1.0 end] close $file # Set the file permissions catch {eval exec /bin/chmod $fmod [.save.fname get]} # Clean up .f.n configure -text [.save.fname get] } destroy .save } pack .save.q .save.fname .save.confirm } proc ins stuff { .t insert insert $stuff } proc wcc name { global contlist catch {destroy .wcc} toplevel .wcc wm title .wcc [concat $name "Widget Code Creator"] frame .wcc.n label .wcc.n.cl -text "Container" eval tk_optionMenu .wcc.n.cont cont $contlist label .wcc.n.nl -text "Name" entry .wcc.n.name -width 30 -font 7x14 frame .wcc.a -relief raised -border 3 frame .wcc.p label .wcc.p.lside -text "Side" tk_optionMenu .wcc.p.side side top left right bottom label .wcc.p.lfill -text "Fill" tk_optionMenu .wcc.p.fill fill none x y both label .wcc.p.lanch -text "Anchor" tk_optionMenu .wcc.p.anch anchor center n s e w ne se sw nw checkbutton .wcc.p.expand -text "Expand" -variable expand frame .wcc.c frame .wcc.b -border 3 -relief sunken button .wcc.b.dismiss -text "Dismiss" -command { destroy .wcc } pack .wcc.n.cl .wcc.n.cont .wcc.n.nl .wcc.n.name -side left pack .wcc.n pack .wcc.a pack .wcc.p.lside .wcc.p.side .wcc.p.lfill .wcc.p.fill -side left pack .wcc.p.lanch .wcc.p.anch .wcc.p.expand -side left pack .wcc.p .wcc.c .wcc.b -side top -fill x pack .wcc.b -fill x } proc widpath {} { global cont return ${cont}[.wcc.n.name get] } proc packline {} { global side fill anchor expand widlist set tmp [widpath] ins "\npack $tmp -side $side -fill $fill" if {$anchor != "center"} {ins " -anchor $anchor"} if {$expand} {ins " -expand 1"} ins "\n" lappend widlist $tmp catch {.wl.lb insert end $tmp} } proc add_obj {} { global oarr obj widlist side fill anchor expand q_nid set obj(name) [widpath] set tmp "-side $side" if {$fill != "none"} {set tmp "$tmp -fill $fill"} if {$anchor != "center"} {set tmp "$tmp -anchor $anchor"} if {$expand} {set tmp "$tmp -expand 1"} set obj(pack) $tmp set enum $q_nid incr q_nid set oarr($enum) [array get obj] lappend widlist $enum catch { eval "$obj(type) .ex$obj(name) $obj(app)" eval "pack .ex$obj(name) $obj(pack)" } catch { .wl.lb insert end $obj(name) } } proc code_oarr root { global oarr widlist ins "\n" # Spout widget creation commands set max [array size oarr] foreach i $widlist { catch {unset obj} array set obj $oarr($i) ins "$obj(type) $root$obj(name) $obj(app) $obj(cfg)\n" } ins "\n" # Spout widget packing commands foreach i $widlist { catch {unset obj} array set obj $oarr($i) ins "pack $root$obj(name) $obj(pack)\n" } ins "\n" } proc put_oarr {} { global widlist oarr set f [open test w] puts $f "*** --- This is a generated file. Do not hand edit --- ***" puts $f $widlist puts $f [array get oarr] close $f } proc get_oarr {} { global widlist oarr set f [open test r] catch { gets $f gets $f widlist unset oarr array set oarr [read -nonewline $f] } close $f } proc setlang {} { global lang set_menu_bar cluehunt "" } proc cluehunt_sql clue { set cl {{select} {insert} {update} {delete} {where}} clue_offer $cl } proc cluehunt clue { global lang # First try to get some context # Then hit up a database to get guesses # One source of guesses is a markov-like chain # Can make one from a text file if can parse into words # Can maintain one in a few arrays # {{select} {insert} {update} {delete}} # {{from} {into} {where} {sort by} {group by}} switch $lang { sql {cluehunt_sql $clue} eng {cluehunt_english $clue} tk {cluehunt_tk $clue} } } proc cluehit hit { set tmp [.clue.b${hit} cget -text] ins $tmp cluehunt $tmp } proc mk_label {} { global contlist wcc {Label} label .wcc.a.cl -text "Label Contents:" entry .wcc.a.ce -width 60 -font 7x14 button .wcc.b.code -text "Write Code" -command { .t insert insert "\nlabel [widpath] -text \{[.wcc.a.ce get]\}\n" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "label" set obj(app) "-text \{[.wcc.a.ce get]\}" set obj(cfg) "" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.cl .wcc.a.ce -side top pack .wcc.b.code -side left pack .wcc.b.dismiss -side right } proc mk_entry {} { global contlist wcc {Entry} scale .wcc.a.width -orient h -label "Width" -from 4 -to 80 .wcc.a.width set 20 button .wcc.b.code -text "Write Code" -command { ins "\nentry [widpath] -width [.wcc.a.width get] -font 7x14\n" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "entry" set obj(app) "-width [.wcc.a.width get] -font 7x14" set obj(cfg) "" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.width -fill x -side top pack .wcc.b.code .wcc.b.dismiss -side left pack .wcc.b.dismiss -side right } proc mk_scale {} { global contlist wcc {Scale} label .wcc.a.cl -text "Label Contents:" entry .wcc.a.ce -width 60 -font 7x14 frame .wcc.a.f label .wcc.a.f.lfrom -text {From} entry .wcc.a.f.from -width 6 -font 7x14 label .wcc.a.f.lto -text {To} entry .wcc.a.f.to -width 6 -font 7x14 label .wcc.a.f.lres -text {Resolution} entry .wcc.a.f.res -width 6 -font 7x14 label .wcc.a.f.lori -text {Orientation} tk_optionMenu .wcc.a.f.ori orient h v button .wcc.b.code -text "Write Code" -command { ins "\nscale [widpath]" if { "" != [.wcc.a.f.from get]} {ins " -from [.wcc.a.f.from get]"} if { "" != [.wcc.a.f.to get]} {ins " -to [.wcc.a.f.to get]"} if { "" != [.wcc.a.f.res get]} {ins " -resolution [.wcc.a.f.res get]"} ins " -orient $orient" if { "" != [.wcc.a.ce get]} {ins " -label \{[.wcc.a.ce get]\}"} ins "\n" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "scale" set tmp "-orient $orient" if { "" != [.wcc.a.f.from get]} {set tmp "$tmp -from [.wcc.a.f.from get]"} if { "" != [.wcc.a.f.to get]} {set tmp "$tmp -to [.wcc.a.f.to get]"} if { "" != [.wcc.a.f.res get]} {set tmp "$tmp -resolution [.wcc.a.f.res get]"} if { "" != [.wcc.a.ce get]} {set tmp "$tmp -label \{[.wcc.a.ce get]\}"} set obj(app) $tmp set obj(cfg) "" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.f.lfrom .wcc.a.f.from .wcc.a.f.lto .wcc.a.f.to .wcc.a.f.lres .wcc.a.f.res .wcc.a.f.lori .wcc.a.f.ori -side left pack .wcc.a.cl .wcc.a.ce -side top pack .wcc.a.f -fill x -side top pack .wcc.b.code -side left pack .wcc.b.dismiss -side right } proc mk_scrollbar {} { global contlist wcc {Scrollbar} label .wcc.a.lori -text {Orientation} tk_optionMenu .wcc.a.ori orient h v label .wcc.c.l1 -text {Command:} entry .wcc.c.command -width 40 -font 7x14 button .wcc.b.code -text "Write Code" -command { ins "\nscrollbar [widpath] -orient $orient -command \{[.wcc.c.command get]\}" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "scrollbar" set obj(app) "-orient $orient" set obj(cfg) "-command \{[.wcc.c.command get]\}" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.lori .wcc.a.ori -side left pack .wcc.c.l1 -side left -fill none pack .wcc.c.command -side left -fill none pack .wcc.b.code -side left pack .wcc.b.dismiss -side right } proc mk_frame {} { global widlist contlist cont wcc "Frame" scale .wcc.a.border -to 25 -orient h -label {Border Size} label .wcc.a.lbev -text {Relief Type:} tk_optionMenu .wcc.a.rel relief flat groove raised ridge sunken button .wcc.b.code -text "Write Code" -command { set tmp [widpath] ins "\nframe $tmp" if [.wcc.a.border get] {ins " -border [.wcc.a.border get] -relief $relief"} ins "\n" packline lappend contlist ${tmp}. } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "frame" set obj(app) "-border [.wcc.a.border get] -relief $relief" set obj(cfg) "" add_obj lappend contlist [widpath]. } pack .wcc.b.al -side left -fill none pack .wcc.a.border .wcc.a.lbev .wcc.a.rel -side left pack .wcc.b.code .wcc.b.dismiss -side left pack .wcc.b.dismiss -side right } proc mk_button {} { global contlist wcc {Button} label .wcc.a.cl -text "Label Contents:" entry .wcc.a.ce -width 30 -font 7x14 button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "button" set obj(app) "-text {[.wcc.a.ce get]}" set obj(cfg) "-command \{[.wcc.c.comm get 1.0 end ]\}" add_obj } pack .wcc.b.al -side left -fill none label .wcc.c.lc -text {Button Command:} text .wcc.c.comm -font 7x14 -width 60 -height 5 scrollbar .wcc.c.sb -orient v -command ".wcc.c.comm yview" .wcc.c.comm configure -yscrollcommand ".wcc.c.sb set" pack .wcc.a.cl .wcc.a.ce -side top pack .wcc.c.lc -side top pack .wcc.c.comm .wcc.c.sb -side left -fill y pack .wcc.b.al -side left pack .wcc.b.dismiss -side right } proc mk_text {} { global contlist wcc {Text} scale .wcc.a.width -orient h -label "Width" -from 10 -to 120 -length 220 scale .wcc.a.height -orient v -label "Height" -from 2 -to 50 -length 100 checkbutton .wcc.a.sg -text "Set Grid" -variable setgrid checkbutton .wcc.a.font -text "7x14 Font" -variable tfont .wcc.a.width set 80 .wcc.a.height set 24 button .wcc.b.code -text "Write Code" -command { ins "\ntext [widpath] -width [.wcc.a.width get] -height [.wcc.a.height get]" if {$setgrid} {ins " -setgrid 1"} if {$tfont} {ins " -font 7x14"} ins "\n" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "text" set tmp "-width [.wcc.a.width get] -height [.wcc.a.height get]" if {$setgrid} {set tmp "$tmp -setgrid 1"} if {$tfont} {set tmp "$tmp -font 7x14"} set obj(app) $tmp set obj(cfg) "" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.width -side left -anchor n pack .wcc.a.height -side left pack .wcc.a.sg .wcc.a.font -side top pack .wcc.b.code -side left pack .wcc.b.dismiss -side right } proc mk_listbox {} { global contlist wcc {Listbox} scale .wcc.a.height -orient h -label "Height" -from 0 -to 35 -length 105 scale .wcc.a.width -orient h -label "Width" -from 10 -to 120 -length 220 label .wcc.a.l1 -text {Select Mode} tk_optionMenu .wcc.a.sm selmode single browse multiple extended .wcc.a.width set 20 .wcc.a.height set 10 button .wcc.b.code -text "Write Code" -command { ins "\nlistbox [widpath] -height [.wcc.a.height get] -width [.wcc.a.width get] -selectmode $selmode" packline } button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "listbox" set obj(app) "-height [.wcc.a.height get] -width [.wcc.a.width get] -selectmode $selmode" set obj(cfg) "" add_obj } pack .wcc.b.al -side left -fill none pack .wcc.a.height .wcc.a.width -side left pack .wcc.a.l1 .wcc.a.sm -side top -fill none pack .wcc.b.code -side left pack .wcc.b.dismiss -side right } proc mk_toplevel {} { global toplist contlist cont catch {destroy .wcc} toplevel .wcc wm title .wcc "Top Level Window Creator" label .wcc.l1 -text {Toplevel Widget Name (without the leading dot)} pack .wcc.l1 -side top -fill none entry .wcc.name -width 20 -font 7x14 pack .wcc.name -side top -fill none label .wcc.l2 -text {Window Title} pack .wcc.l2 -side top -fill none entry .wcc.title -width 40 -font 7x14 pack .wcc.title -side top -fill none button .wcc.code -text {Code} -command { set tmp .[.wcc.name get] # Put the actual lines in the file. ins "catch \{destroy $tmp\}\n" ins "toplevel $tmp\n" ins "wm title $tmp \{[.wcc.title get]\}\n" # From here down would need redone later on. lappend toplist ${tmp}. lappend contlist ${tmp}. # No longer do this: lappend widlist $tmp set cont ${tmp}. # The point of the below is to make sure the widget previewer works catch {destroy .ex} toplevel .ex wm title .ex [.wcc.title get] bind .ex <3> {widpop %X %Y %W} frame .ex.[.wcc.name get] -width 50 -height 50 pack .ex.[.wcc.name get] -side top -fill both -expand 1 } pack .wcc.code -side left -fill none } proc mk_combo {} { } proc mk_proc {} { catch {destroy .wcc} toplevel .wcc wm title .wcc {Procedure Template} label .wcc.l1 -text {Procedure Name} entry .wcc.name -width 20 -font 7x14 label .wcc.l2 -text {Arguments} pack .wcc.l1 -side top -fill none pack .wcc.name -side top -fill none pack .wcc.l2 -side top -fill none frame .wcc.a -border 3 -relief sunken pack .wcc.a -side top -fill both -expand 1 listbox .wcc.a.l -yscrollcommand {.wcc.a.sb set} scrollbar .wcc.a.sb -orient v -command {.wcc.a.l yview} pack .wcc.a.l -side left -fill both -expand 1 pack .wcc.a.sb -side left -fill y label .wcc.l3 -text {New Argument (and default)} pack .wcc.l3 -side top -fill none entry .wcc.arg -width 20 -font 7x14 pack .wcc.arg -side top -fill none button .wcc.add -text {Add Argument} -command { .wcc.a.l insert end [.wcc.arg get] } pack .wcc.add -side top -fill none button .wcc.code -text {Write Code} -command { ins "\nproc [.wcc.name get] " ins [list [.wcc.a.l get 0 end]] ins " \{\n\}\n" } pack .wcc.code -side top -fill none bind .wcc.arg { .wcc.add invoke } } proc wi_immediate {} { catch {destroy .im} toplevel .im wm title .im "immediate mode executor" frame .im.h label .im.h.l -text "History List" listbox .im.h.lb -width 60 -height 5 -font 7x14 -selectmode extended -yscrollcommand {.im.h.sb set} scrollbar .im.h.sb -orient v -command {.im.h.lb yview} frame .im.c label .im.c.l -text "Command Entry" text .im.c.line -height 4 -width 60 -font 7x14 -yscrollcommand {.im.c.sb set} scrollbar .im.c.sb -orient v -command {.im.c.line yview} button .im.eval -command { set tmp [eval [.im.c.line get 1.0 end]] if {""!=$tmp} {puts $tmp} } -text Evaluate button .im.clear -text Clear -command {.im.c.line delete 1.0 end} button .im.append -text Append -command {.im.h.lb insert end [.im.c.line get 1.0 end]} button .im.dismiss -text "Dismiss" -command {destroy .im} pack .im.h.l -side top pack .im.h.sb -side right -fill y pack .im.h.lb -side left -expand 1 -fill x pack .im.c.l -side top pack .im.c.sb -side right -fill y pack .im.c.line -side left -expand 1 -fill both pack .im.h -side top -fill x pack .im.c -side top -expand 1 -fill both pack .im.dismiss .im.clear .im.append .im.eval -side right } proc wi_widgetlist {} { global widlist oarr catch {destroy .wl} toplevel .wl wm title .wl {Widget List} listbox .wl.lb -height 0 -font 7x14 foreach w $widlist { array set obj $oarr($w) .wl.lb insert end $obj(name) } pack .wl.lb frame .wl.move pack .wl.move button .wl.move.up -text {Move up} -command { set num [.wl.lb curselection] if {""==$num} return if {$num==0} return widflip $num incr num -1 .wl.lb selection set $num .wl.lb see $num } pack .wl.move.up -side left -fill none button .wl.move.dn -text {Move down} -command { set num [.wl.lb curselection] if {""==$num} return incr num 1 if {$num==[.wl.lb index end]} return widflip $num .wl.lb selection set $num .wl.lb see $num } pack .wl.move.dn -side left -fill none frame .wl.rank frame .wl.edit pack .wl.rank .wl.edit button .wl.rank.pro -text "Promote" button .wl.rank.dem -text "Demote" pack .wl.rank.pro .wl.rank.dem -side left button .wl.edit.edit -text "Edit" -command { set num [.wl.lb curselection] if {""==$num} return widedit [lindex $widlist $num] } button .wl.edit.dele -text "Delete" -command { qtk_delwidget } pack .wl.edit.edit .wl.edit.dele -side left } proc wi_example {} { catch {destroy .ex} toplevel .ex wm title .ex "Example Dialog" bind .ex <3> {widpop %X %Y %W} qtk_inval_example } proc wi_toplist {} { global toplist catch {destroy .tl} toplevel .tl wm title .tl {Toplevel List} frame .tl.f -border 4 -relief groove listbox .tl.f.l -height 10 -yscrollcommand {.tl.f.sb set} scrollbar .tl.f.sb -orient v -command {.tl.f.l yview} pack .tl.f.l -side left -fill both -expand 1 pack .tl.f.sb -side left -fill y pack .tl.f -side top -fill both -expand 1 button .tl.prev -text {Preview} -command {toplev_preview} pack .tl.prev -side left -fill none button .tl.select -text {Select} -command {toplev_select} pack .tl.select -side left -fill none button .tl.code -text {Write Code} -command {toplev_code} pack .tl.code -side left -fill none button .tl.dismiss -text {Dismiss} -command {destroy .tl} pack .tl.dismiss -side right -fill none foreach b $toplist { .tl.f.l insert end $b } } proc qtk_manpage {} { catch {destroy .man} toplevel .man wm title .man {TCL/Tk Man Pages} label .man.l1 -text {Select a man page} frame .man.f -border 4 -relief ridge listbox .man.f.lb -height 20 -width 30 -selectmode browse -yscrollcommand {.man.f.sb set} scrollbar .man.f.sb -orient v -command {.man.f.lb yview} button .man.view -text {View} -command { catch { exec xterm -e man n [.man.f.lb get active] & } } frame .man.s label .man.s.l -text "Search:" entry .man.s.e -width 5 button .man.dis -text {Dismiss} -command {destroy .man} pack .man.l1 -side top pack .man.f -side top -fill both pack .man.f.lb -side left -fill both -expand 1 pack .man.f.sb -side left -fill y pack .man.view -side left pack .man.s -side left -fill x -expand 1 pack .man.s.l .man.s.e -side left pack .man.dis -side right set cmds "" foreach i [exec ls /usr/man/mann] { set sl [string first . $i] incr sl -1 if {$sl > 0} { set tmp [string range $i 0 $sl] .man.f.lb insert end $tmp lappend cmds $tmp } } bind .man.f.lb { .man.view invoke } bind .man.s.e [subst -nocommands {.man.f.lb yview [lsearch -glob {$cmds} [.man.s.e get]* ]} ] } proc qtk_invalidate_views {} { global q_curbuf set q_curbuf invalid qtk_inval_example qtk_inval_funclist } proc qtk_flush_buffer {} { global q_curbuf qtk q_func_args q_func_body set a [lindex $q_curbuf 0] if {$a=="invalid"} {return} if {$a=="func"} { set name [lindex $q_curbuf 1] set argys [.metabits.args get] set body [.t get 1.0 "end-1c"] set q_func_args($name) $argys set q_func_body($name) $body # set q_funcs([lindex $q_curbuf 1]) [.t get 1.0 "end-1c"] } else { set qtk($a) [.t get 1.0 "end-1c"] } } proc qtk_flush_all {} { qtk_flush_buffer } proc qtk_set_buffer {a b} { global q_curbuf qtk_flush_buffer .t delete 1.0 end .t insert 1.0 $a set q_curbuf $b .f.s config -text $b } proc qtk_load {} { global qtk q_func_args q_func_body edit_mode widlist oarr contlist q_nid set_mode qtk qtk_eraseproj set f [open "Project" "r"] catch { array set qtk [read $f] } close $f array set q_func_args $qtk(func_args) array set q_func_body $qtk(func_body) unset qtk(func_args) unset qtk(func_body) catch { ## try to extract graphical/interface information, where possible array set oarr $qtk(oarr) set widlist $qtk(widlist) set contlist $qtk(contlist) set q_nid $qtk(q_nid) unset qtk(widlist) unset qtk(oarr) unset qtk(contlist) unset qtk(q_nid) } qtk_invalidate_views .f.n config -text $qtk(name) catch {qtk_showfunc [lindex $qtk(rec_func) 0]} qtk_selfunc } proc qtk_newproj {} { global qtk q_func_body q_func_args qtk_eraseproj qtk_setname "tk.out" set q_func_body(__HEADER__) "#!/usr/bin/wish\n" set q_func_body(__MAIN__) "# A new QTK Project Begins Here\n" set q_func_args(__HEADER__) "" set q_func_args(__MAIN__) "" set qtk(funclist) {__HEADER__ __MAIN__} qtk_showfunc __MAIN__ qtk_selfunc } proc qtk_mk_func name { global qtk q_func_body q_func_args if {$name==""} {return 0} if {[lsearch -exact $qtk(funclist) $name] >= 0} {return 0} set p [llength $qtk(funclist)] incr p -1 set qtk(funclist) [linsert $qtk(funclist) $p $name] set q_func_body($name) "\n" set q_func_args($name) "" qtk_inval_funclist qtk_showfunc $name return 1 } proc qtk_newfunc {} { catch {destroy .newfunc} toplevel .newfunc wm title .newfunc {New Function} label .newfunc.l1 -text {New Function Name} entry .newfunc.name -width 20 -font 7x14 button .newfunc.create -text {Create} -command { if [qtk_mk_func [.newfunc.name get]] { destroy .newfunc } else { bell return } } button .newfunc.cancel -text {Cancel} -command {destroy .newfunc} pack .newfunc.l1 -side top pack .newfunc.name -side top pack .newfunc.create -side left pack .newfunc.cancel -side right focus .newfunc.name } proc qtk_save {} { global qtk q_func_args q_func_body widlist oarr contlist q_nid qtk_flush_all set qtk(func_args) [array get q_func_args] set qtk(func_body) [array get q_func_body] set f [open "Project" "w"] ## Also save graphical/interface information now. set qtk(widlist) $widlist set qtk(oarr) [array get oarr] set qtk(contlist) $contlist set qtk(q_nid) $q_nid ## Write out the file puts $f [array get qtk] close $f ## Clean up some unset qtk(widlist) unset qtk(oarr) unset qtk(contlist) unset qtk(q_nid) unset qtk(func_args) unset qtk(func_body) } proc qtk_compile {} { chk_edit_mode qtk global qtk q_func_args q_func_body qtk_flush_all set f [open $qtk(name) "w" 0755] puts -nonewline $f $q_func_body(__HEADER__) set n [llength $qtk(funclist)] set func [lrange $qtk(funclist) 1 [expr $n - 2]] foreach i $func { puts $f "[list proc $i $q_func_args($i)] {\n$q_func_body($i)}" } puts -nonewline $f $q_func_body(__MAIN__) close $f } proc qtk_run {} { chk_edit_mode qtk qtk_compile exec -keepnewline wish << tk.out & } proc qtk_notes {} { global qtk qtk_flush_buffer qtk_set_buffer $qtk(notes) notes } proc qtk_selfunc {} { global qtk edit_mode if {$edit_mode!="qtk"} { bell return } catch {destroy .fl} toplevel .fl wm title .fl {Functions} frame .fl.s label .fl.s.l -text "Search: " entry .fl.s.e -width 10 frame .fl.f -border 0 -relief flat listbox .fl.f.l -height 25 -width 30 -selectmode browse -yscrollcommand {.fl.f.s set} scrollbar .fl.f.s -orient v -command {.fl.f.l yview} button .fl.view -text {View} -command { set tmp [.fl.f.l curselection] if {[llength $tmp]} { qtk_showfunc [.fl.f.l get $tmp] .fl.s.e delete 0 end } else {bell} } button .fl.new -text {New} -command {qtk_newfunc} button .fl.del -text "Delete" -command { set tmp [.fl.f.l curselection] if {[llength $tmp]} { qtk_delfunc [.fl.f.l get $tmp] } else {bell} } button .fl.dis -text {Dismiss} -command {destroy .fl} pack .fl.s -side top -fill x pack .fl.s.l .fl.s.e -side left pack .fl.f -side top -fill both pack .fl.f.s -side right -fill y pack .fl.f.l -side left -fill both -expand 1 pack .fl.view .fl.new .fl.del -side left pack .fl.dis -side right qtk_inval_funclist bind .fl.f.l {.fl.view invoke} bind .fl.s.e { .fl.f.l yview [lsearch -glob [lsort $qtk(funclist)] [.fl.s.e get]*] } } proc ed_cut widget { global clipboard set range [$widget tag ranges sel] catch { set clipboard [eval $widget get $range] eval $widget delete $range } } proc ed_copy widget { global clipboard set range [$widget tag ranges sel] catch { set clipboard [eval $widget get $range] } } proc ed_paste widget { global clipboard $widget insert insert $clipboard } proc ed_search {} { catch {destroy .search} toplevel .search wm title .search "Search / Replace" frame .search.a label .search.a.l -text {Search For:} pack .search.a.l -side left -fill none entry .search.a.pat -width 30 -font 7x14 pack .search.a.pat -side left -fill none pack .search.a.pat pack .search.a -side top -fill none frame .search.b label .search.b.ldir -text {Direction} tk_optionMenu .search.b.dir sdir forward backward label .search.b.lt -text {Search Type:} tk_optionMenu .search.b.type stype nocase exact regexp pack .search.b.ldir .search.b.dir -side left -fill none pack .search.b.lt .search.b.type -side left -fill none pack .search.b -side top -fill none frame .search.c button .search.c.find -text "Find" button .search.c.dismiss -text "Dismiss" -command {destroy .search} pack .search.c.find .search.c.dismiss -side left pack .search.c -side top .search.c.find configure -command { set stmp [.t search -$sdir -$stype -count scount -- [.search.a.pat get] insert] if {$stmp != ""} { .t see $stmp .t mark set insert "$stmp + $scount chars" set acmd ".t tag delete hilite" after cancel $acmd catch $acmd .t tag add hilite $stmp "$stmp + $scount chars" .t tag configure hilite -background white after 1000 $acmd } } } proc ed_set {} { .t mark set book insert } proc ed_recall {} { .t see book .t mark set insert book } proc ed_indent {} { set interval [.t tag ranges sel] for {set i [lindex $interval 0]} {$i < [lindex $interval 1]} {set i [expr $i + 1]} { .t insert "$i linestart" " " } } proc ht_arbtag {} { global ht_closetag catch {destroy .html} toplevel .html wm title .html {HTML Tag} frame .html.t label .html.t.l1 -text {Tag} entry .html.t.tag -width 10 -font 7x14 label .html.t.l2 -text {Attributes} entry .html.t.att -width 20 -font 7x14 checkbutton .html.t.close -text "Close Tag" -variable ht_closetag pack .html.t -side top -fill none pack .html.t.l1 -side left -fill none pack .html.t.tag -side left -fill none pack .html.t.l2 -side left -fill none pack .html.t.att -side left -fill none pack .html.t.close -side left -fill none button .html.code -text {Code} -command { ins "<" ins [.html.t.tag get] if {""!=[.html.t.att get]} { ins " " ins [.html.t.att get] } ins ">" if {$ht_closetag} { set tmp [.t index insert] ins "" .t mark set index $tmp } } pack .html.code -side left -fill none button .html.dismiss -text {Dismiss} -command {destroy .html} pack .html.dismiss -side right -fill none } proc ht_skel {} { catch {destroy .html} toplevel .html wm title .html {HTML Skeleton Page} label .html.l1 -text {Title for your new page} entry .html.title -width 40 -font 7x14 button .html.code -text {Write Code} -command { ins "\n" ins [.html.title get] ins "\n\n\n\n\n\n" } button .html.dismiss -text Dismiss -command { destroy .html } pack .html.l1 -side top pack .html.title -side top pack .html.code -side left pack .html.dismiss -side right } proc ht_hr {} { catch {destroy .html} toplevel .html wm title .html {Horizontal Rule Maker} frame .html.f scale .html.f.width -orient h -from 0 -to 100 -label {Width} scale .html.f.size -orient h -from 1 -to 10 -label {Size} pack .html.f.width -side left pack .html.f.size -side left pack .html.f -side top button .html.code -text {Write} -command { ins "\n" } pack .html.code -side left -fill none button .html.dismiss -text "Dismiss" -command {destroy .html} pack .html.dismiss -side right .html.f.width set 100 .html.f.size set 1 } proc ht_link {} { global ht_targlist catch {destroy .link} toplevel .link wm title .link {Link} label .link.l1 -text {Link To:} entry .link.href -width 40 -font 7x14 label .link.l2 -text {Target Frame:} entry .link.target -width 20 -font 7x14 frame .link.f1 -border 0 -relief flat listbox .link.f1.lb -height 5 -width 20 -selectmode browse -yscrollcommand {.link.f1.sb set} scrollbar .link.f1.sb -orient v -command {.link.f1.lb yview} label .link.l3 -text {ToolTip/Title:} entry .link.title -width 40 -font 7x14 frame .link.f2 -border 0 -relief flat button .link.f2.code -text {Write Code} -command { set href [.link.href get] set target [.link.target get] set title [.link.title get] set attrs "href=\"$href\"" if {$title != ""} { set attrs "$attrs title=\"$title\"" } if {$target != ""} { set attrs "$attrs target=\"$target\"" } ht_tag "a" $attrs set target [string tolower $target] if {-1==[lsearch -exact $ht_targlist $target]} {lappend ht_targlist $target} destroy .link } button .link.f2.dismiss -text {Dismiss} -command {destroy .link} pack .link.l1 -side top pack .link.href -side top pack .link.l2 -side top pack .link.target -side top pack .link.f1 -side top pack .link.f1.lb -side left pack .link.f1.sb -side left -fill y pack .link.l3 -side top pack .link.title -side top pack .link.f2 -side bottom -fill x pack .link.f2.code -side left pack .link.f2.dismiss -side right foreach tmp $ht_targlist { .link.f1.lb insert end $tmp } .link.f1.lb see end bind .link.f1.lb { catch { .link.target delete 0 end .link.target insert 0 [.link.f1.lb get [.link.f1.lb curselection]] } } } proc ht_init {} { global ent_nums ent_names ent_longnames ht_closetag ht_targlist set ht_closetag 1 set ht_targlist {{} _self _blank _parent _top} set ent_nums { 34 38 60 62 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 } set ent_names { quot amp lt gt nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml } set ent_longnames { { Quote (") } { Ampersand (&) } { Less-than (<) } { Greater-than (>) } { Non-breaking Space } { Inverted exclamation } { Cent sign } { Pound sterling } { General currency sign } { Yen sign } { Broken vertical bar } { Section sign } { Umlaut (dieresis) } { Copyright } { Feminine ordinal } { Left angle quote, guillemotleft } { Not sign } { Soft hyphen } { Registered trademark } { Macron accent } { Degree sign } { Plus or minus } { Superscript two } { Superscript three } { Acute accent } { Micro sign } { Paragraph sign } { Middle dot } { Cedilla } { Superscript one } { Masculine ordinal } { Right angle quote, guillemotright } { Fraction one-fourth } { Fraction one-half } { Fraction three-fourths } { Inverted question mark } { Capital A, grave accent } { Capital A, acute accent } { Capital A, circumflex accent } { Capital A, tilde } { Capital A, dieresis or umlaut mark } { Capital A, ring } { Capital AE dipthong (ligature) } { Capital C, cedilla } { Capital E, grave accent } { Capital E, acute accent } { Capital E, circumflex accent } { Capital E, dieresis or umlaut mark } { Capital I, grave accent } { Capital I, acute accent } { Capital I, circumflex accent } { Capital I, dieresis or umlaut mark } { Capital Eth, Icelandic } { Capital N, tilde } { Capital O, grave accent } { Capital O, acute accent } { Capital O, circumflex accent } { Capital O, tilde } { Capital O, dieresis or umlaut mark } { Multiply sign } { Capital O, slash } { Capital U, grave accent } { Capital U, acute accent } { Capital U, circumflex accent } { Capital U, dieresis or umlaut mark } { Capital Y, acute accent } { Capital THORN, Icelandic } { Small sharp s, German (sz ligature) } { Small a, grave accent } { Small a, acute accent } { Small a, circumflex accent } { Small a, tilde } { Small a, dieresis or umlaut mark } { Small a, ring } { Small ae dipthong (ligature) } { Small c, cedilla } { Small e, grave accent } { Small e, acute accent } { Small e, circumflex accent } { Small e, dieresis or umlaut mark } { Small i, grave accent } { Small i, acute accent } { Small i, circumflex accent } { Small i, dieresis or umlaut mark } { Small eth, Icelandic } { Small n, tilde } { Small o, grave accent } { Small o, acute accent } { Small o, circumflex accent } { Small o, tilde } { Small o, dieresis or umlaut mark } { Division sign } { Small o, slash } { Small u, grave accent } { Small u, acute accent } { Small u, circumflex accent } { Small u, dieresis or umlaut mark } { Small y, acute accent } { Small thorn, Icelandic } { Small y, dieresis or umlaut mark } } } proc ht_charent {} { global ent_longnames catch {destroy .charent} toplevel .charent wm title .charent {HTML Character Entity} label .charent.l1 -text {Select Character Entity} frame .charent.f -border 0 -relief flat listbox .charent.f.lb -height 10 -width 30 -selectmode browse -yscrollcommand { .charent.f.sb set } scrollbar .charent.f.sb -orient v -command {.charent.f.lb yview} button .charent.paste -text {Paste} -command { catch { set tmp "&[lindex $ent_names [.charent.f.lb curselection]];" ins $tmp } } button .charent.pastenum -text {Paste Numeric} -command { catch { set tmp "&#[lindex $ent_nums [.charent.f.lb curselection]];" ins $tmp } } button .charent.dismiss -text {Dismiss} -command {destroy .charent} pack .charent.l1 -side top pack .charent.f -side top -fill both pack .charent.f.lb -side left -fill both -expand 1 pack .charent.f.sb -side left -fill y pack .charent.paste .charent.pastenum -side left pack .charent.dismiss -side right foreach name $ent_longnames { .charent.f.lb insert end $name } bind .charent.f.lb { .charent.paste invoke } } proc ht_tag {t {a ""}} { set r [.t tag ranges sel] if {$a==""} { set tagstart "<$t>" } else { set tagstart "<$t $a>" } if [string length $r] { .t insert [lindex $r 1] "" .t insert [lindex $r 0] $tagstart } else { .t insert insert $tagstart set tmp [.t index insert] .t insert insert "" .t mark set insert $tmp } } proc help jump { catch {destroy .help} toplevel .help wm title .help "About Quick-Tk" label .help.title -font "-*-*-bold-*-*-*-30-*-*-*-*-*-*-*" -text "Quick-Tk" set f .help.nav frame $f button $f.about -text "About" -command { .help.m.t config -state normal .help.m.t delete 1.0 end .help.m.t insert end \ {Quick-Tk aims first to be a relatively complete graphical Tk development environment which will work under Tk4.1 and above. Working features include: o Cut, Copy, and Paste o Right-Click menus in text boxes o Jump around from function to function o An immediate mode window with history o A moderate set of "widget wizards" o Preview of generated widgets o "Preview Compiler" o Project save capability Currently known bugs: o Parsing out a Tk project fails if last proc takes arguments. It seems that the parser gets confused and associates the body of the procedure with the __MAIN__ section. o "Project | Run" does not work o toplevel widget creator not yet integrated with new widget tree controls o some widget hierarchy controls not yet functional o several loose ends flying about Features under or awaiting construction: o Widget Editor - rapidly gaining features. o Better Help o Better Widget editing support o Context Sensitive Auto-Complete - Cluehunting o Syntax Highlighting - not essential. o HTML4, CSS, JavaScript support o PHP3/SQL supoprt Delusions of Granduer: o C/C++ support o English, Natural Language support o Mind Reading o The direct conversion of thought to results :) } .help.m.t config -state disabled } button $f.tips -text "Tips" -command { .help.m.t config -state normal .help.m.t delete 1.0 end .help.m.t insert end \ {Tips on using QTK: 1. Getting started painting a Tk Interface: Open the example dialog and widget list windows, then tear off the widget menu (select the menu and click the dotted line on top). Just make interface elements as you need them, and use the widget list to shove them into place. Go back and edit the widgets to reflect new decisions for pack options. 2. Q: What do the buttons on the Widget List do? A: Assuming you have selected a widget by name, then you can move that widget earlier or later in the pack order by choosing "move up" or "move down". Promote will move a widget out of its innermost containing frame, and demote lets you select a frame within the same scope to push a widget into. Edit lets you change the properties of a given widget, and delete removes the widget entirely. 3. Q: What do I do when I'm happy with my layout? A: From the "Widget" menu, choose Code, then Code Widget List. This will paste interface creation code into your editor at the cursor. It is your responsibility to do something inteligent with that code afterwards. 4. Q: What if I want to modify existing interface code? A: Take advantage of the GPL. At the moment, QTK does not have a reverse-compiler function for interface code. You might code one up and send me patches. As a side note, there is some work on saving and restoring interface definitions. This could be useful in conjunction with a recursive pack-tree scanner function. 5. Canvases, text-embeds, Place, and other geometry managers: There is no support here YET. I'm having enough fun trying to get the other parts of this program working to put off support for other geometry managers until later. You want sooner? Send me patches. 6. HTML editing: From the Options menu, choose language, then HTML. The menu will change to be relevant to HTML. This area is not as advanced as the Tk interface editor, and mostly amounts to a collection of typing aids, but clearly this can be greatly expanded on with little work. Send me patches for anything interesting you do. Please. 7. Other features, like syntax highlighting: Coming soon. } .help.m.t config -state disabled } button $f.license -text "License" -command { .help.m.t config -state normal .help.m.t delete 1.0 end .help.m.t insert end \ {This program is distributed under the terms of the Gnu General Public License (GPL). You can find a copy of this license at http://www.gnu.org/copyleft/gpl.html } .help.m.t config -state disabled } button $f.credits -text "Credits" -command { .help.m.t config -state normal .help.m.t delete 1.0 end .help.m.t insert end \ {Quick-Tk was written from scratch by Ian Kjos. You can send him e-mail at: brooke@jump.net } .help.m.t config -state disabled } pack $f.about $f.tips $f.license $f.credits -side top frame .help.m -border 4 -relief ridge text .help.m.t -width 50 -height 12 -setgrid 1 -font 7x14 -yscrollcommand {.help.m.s set} -wrap word scrollbar .help.m.s -orient v -command {.help.m.t yview} pack .help.m.t -side left -fill both -expand 1 pack .help.m.s -side left -fill y button .help.dismiss -text "Dismiss" -command {destroy .help} pack .help.title -side top pack .help.nav -side left -anchor n pack .help.m -side top -expand 1 -fill both pack .help.dismiss -side top .help.nav.$jump invoke } proc menu_file {} { ####### File Menu set m .menu.file.m menubutton .menu.file -text "File" -menu $m -underline 0 menu $m $m add command -label "Run" -command {exec -keepnewline wish << [.t get 1.0 end ] &} -underline 0 $m add command -label "New" -command {fi_new} -underline 0 $m add command -label "Load" -command {fi_load} -underline 0 $m add command -label "Save" -command {fi_save} -underline 0 -accelerator "Ctrl-S" $m add command -label "Quit" -command {destroy .} -underline 0 } proc menu_edit {} { ####### Edit Menu set m .menu.edit.m menubutton .menu.edit -text "Edit" -menu $m -underline 0 menu $m $m add command -label "Copy" -command {ed_copy .t} -underline 0 -accelerator "Ctrl-Ins" $m add command -label "Cut" -command {ed_cut .t} -underline 2 -accelerator "Shift-Del" $m add command -label "Paste" -command {ed_paste .t} -underline 0 -accelerator "Shift-Ins" $m add separator $m add command -label "Search" -command {ed_search} -underline 0 $m add separator $m add command -label "Set Bookmark" -command {ed_set} -underline 1 $m add command -label "Go to Bookmark" -command {ed_recall} -underline 6 $m add separator $m add command -label "Indent Selection" -command {ed_indent} -underline 0 $m add separator $m add cascade -label "Font" -menu .menu.edit.m.font set m .menu.edit.m.font menu $m -tearoff 0 $m add command -label "7x14" -command {.t config -font 7x14} -underline 0 $m add command -label "8x16" -command {.t config -font 8x16} -underline 0 $m add command -label "10x20" -command {.t config -font 10x20} -underline 0 } proc menu_widget {} { ####### Widget Menu set m .menu.widget.m menubutton .menu.widget -text "Widget" -menu $m -underline 0 menu $m $m add command -label "Label" -command {mk_label} -underline 0 $m add command -label "Entry" -command {mk_entry} -underline 0 $m add command -label "Scale" -command {mk_scale} -underline 2 $m add cascade -label "Buttons" -menu $m.buttons -underline 0 $m add command -label "Listbox" -command {mk_listbox} -underline 1 $m add command -label "Text" -command {mk_text} -underline 0 $m add command -label "Scrollbar" -command {mk_scrollbar} -underline 2 $m add separator $m add command -label "Frame" -command {mk_frame} -underline 0 $m add command -label "Toplevel" -command {mk_toplevel} -underline 0 $m add separator $m add command -label "Combo Gallery" -command {mk_combo} -underline 6 $m add separator $m add cascade -menu .menu.widget.m.code -label "Code" -underline 2 set m .menu.widget.m.code menu $m -tearoff 0 $m add command -label "Code widget list" -command {code_widlist} -underline 0 $m add command -label "Empty widget list" -command {empty_widlist} -underline 0 set m .menu.widget.m.buttons menu $m -tearoff 0 $m add command -label "Push Button" -command {mk_button} -underline 0 $m add command -label "Check Button" -command {mk_checkbutton} -underline 0 $m add command -label "Radio Button" -command {mk_radiobutton} -underline 0 $m add command -label "Menu Button" -command {mk_menubutton} -underline 0 $m add command -label "OptionMenu Button" -command {mk_optmenubutton} -underline 0 } proc menu_tcl {} { ####### TCL Menu set m .menu.tcl.m menubutton .menu.tcl -text "TCL" -menu $m -underline 0 menu $m $m add command -label "New Procedure" -command {qtk_newfunc} $m add separator $m add cascade -menu .menu.tcl.m.string -label "String" -underline 0 $m add cascade -menu .menu.tcl.m.array -label "Array" -underline 0 $m add cascade -menu .menu.tcl.m.list -label "List" -underline 0 $m add cascade -menu .menu.tcl.m.file -label "File" -underline 0 $m add separator $m add command -label "Man Pages" -command {qtk_manpage} set m .menu.tcl.m.string menu $m foreach i { compare first index last length match range tolower toupper trim trimleft trimright wordend wordstart } { $m add command -label $i -command [subst {ins "string $i "}] } $m add separator $m add command -label "Manual Page" -command {exec xterm -e man n string &} set m .menu.tcl.m.array menu $m foreach {i u} { anymore 0 donesearch 0 exists 0 get 0 names 0 nextelement 0 set 0 size 1 startsearch 1 } { $m add command -label $i -command [subst {ins "array $i "}] -underline $u } $m add separator $m add command -label "Manual Page" -command {exec xterm -e man n array &} set m .menu.tcl.m.list menu $m foreach i {concat lappend lindex linsert list llength lrange lreplace lsearch lsort} { $m add command -label $i -command [subst {ins "$i "}] } set m .menu.tcl.m.file menu $m foreach {i u} { atime 0 dirname 0 executable 4 exists 0 extension 1 isdirectory 0 isfile 2 join 0 lstat 0 mtime 0 owned 0 pathtype 3 readable 0 readlink 7 rootname 4 size 2 split 1 stat 0 tail 0 type 1 writable 0 } { $m add command -label $i -command [subst {ins "file $i "}] -underline $u } $m add separator $m add command -label "Manual Page" -command {exec xterm -e man n file &} } proc menu_tk_proj {} { set m .menu.tk_proj.m menubutton .menu.tk_proj -text "Project" -menu $m -underline 0 menu $m $m add command -label "Compile Project" -command {qtk_compile} -underline 0 $m add command -label "Run Project" -command {qtk_run} $m add command -label "Set Target Name" -command {qtk_name} $m add separator $m add command -label "Load Project" -command {qtk_load} $m add command -label "Save Project" -command {qtk_save} -underline 0 $m add command -label "New Project" -command {qtk_newproj} $m add command -label "Parse TK to Project" -command {qtk_decompose} } proc menu_window {} { ####### Window Menu set m .menu.window.m menubutton .menu.window -text "Window" -menu $m -underline 2 menu $m $m add command -label "Function List" -command {qtk_selfunc} $m add command -label "Project Notes" -command {qtk_notes} $m add separator $m add command -label "Immediate Mode" -command {wi_immediate} $m add command -label "Widget List" -command {wi_widgetlist} $m add command -label "Example Dialog" -command {wi_example} $m add command -label "Toplevel List" -command {wi_toplist} } proc menu_html {} { ####### HTML Menu set m .menu.html.m menubutton .menu.html -text "HTML" -menu $m -underline 2 menu $m $m add command -label "Horizontal Rule" -command {ht_hr} -underline 11 $m add command -label "Link" -command {ht_link} -underline 0 $m add command -label "Character Entity" -command {ht_charent} -underline 11 $m add command -label "Table" -command {ht_table_create} -underline 0 $m add separator $m add cascade -menu $m.spells -label "Spells" -underline 0 $m add separator $m add command -label "Arbitrary Tag" -command {ht_arbtag} -underline 0 $m add command -label "HTML Skeleton File" -command {ht_skel} -underline 6 $m add separator $m add command -label "Highlight Now" -command {html_highlight} -underline 1 set m .menu.html.m.spells menu $m $m add command -label "Refresh" -command {ht_spell_refresh} -underline 0 $m add command -label "Import Style Sheet" -command {ht_spell_style_import} -underline 0 } proc menu_options {} { set m .menu.options.m menubutton .menu.options -text "Options" -menu $m -underline 0 menu $m $m add check -label "AutoIndent" -variable autoindent -underline 4 $m add cascade -label "Word Wrap" -menu .menu.options.m.wrap -underline 0 $m add cascade -label "Language" -menu .menu.options.m.lang -underline 0 set m .menu.options.m.wrap menu $m $m add command -label "char" -underline 0 -command {.t config -wrap char} $m add command -label "none" -underline 0 -command {.t config -wrap none} $m add command -label "word" -underline 0 -command {.t config -wrap word} set m .menu.options.m.lang menu $m $m add radio -label "Tk" -command setlang -var lang -value tk -underline 0 $m add radio -label "HTML" -command setlang -var lang -value html -underline 0 $m add radio -label "C++" -command setlang -var lang -value c++ -underline 0 $m add radio -label "PHP" -command setlang -var lang -value php -underline 0 $m add radio -label "SQL" -command setlang -var lang -value sql -underline 0 $m add radio -label "English" -command setlang -var lang -value eng -underline 0 $m add radio -label "Text" -command setlang -var lang -value text -underline 2 } proc menu_help {} { ####### Help Menu set m .menu.help.m menubutton .menu.help -text "Help" -menu $m -underline 0 menu $m -tearoff 0 $m add command -label "About Quick-Tk" -command {help about} $m add command -label "Tips on Quick-Tk" -command {help tips} $m add command -label "License" -command {help license} $m add command -label "Credits" -command {help credits} } proc pos {} { .f.p config -text [.t index insert] } proc main {} { ######################### # # Main Interface Setup # ######################### wm title . "Quick Tk" frame .menu -relief raised -bd 2 frame .clue -relief sunken -bd 2 frame .f label .f.n -text {untitled} -bd 2 -relief ridge label .f.s -text {} -bd 2 -relief ridge label .f.p -text {1.0} -bd 2 -relief ridge # A place to put (changable) info regarding the current view frame .metabits text .t -font 7x14 -setgrid 1 scrollbar .sy -orient v -command ".t yview" .t configure -yscrollcommand ".sy set" focus .t # Eliminate some undesired bindings bind Text {} # Make the clipboard work right bind Text {ed_paste %W} bind Text {ed_cut %W} bind Text {ed_copy %W} bind Text <3> {rt_menu %W %X %Y} # Make the accelerator bindings bind .t {fi_save} bind .t { pos } bind .t <1> { .f.p config -text [.t index insert] } # Other cool bindings bind Text { if {$autoindent} { set str [%W get "insert linestart" "insert lineend"] set indent [expr [string length $str] - [string length [string trimleft $str ]]] tkTextInsert %W \n for {set i 0} {$i < $indent} {incr i} {%W insert insert " "} } else { tkTextInsert %W \n } } # Some Clue-hunting Bindings #bindtags .t {Text .t . all} foreach k {space Return dollar} { bind .t { cluehunt %K pos } } pack .menu -side top -fill x -anchor n pack .f -side top pack .f.n .f.s .f.p -side left pack .metabits -fill x pack .clue -side bottom -fill x -anchor s pack .sy -side right -fill y pack .t -side left -expand 1 -fill both # Create Menus set_menu_bar # Create Cluehunt button bar (with bindings) foreach i {1 2 3 4 5} { label .clue.l$i -text "F${i}:" button .clue.b$i -text {} -command "cluehit $i" pack .clue.l$i -side left pack .clue.b$i -side left bind .t "cluehit $i" } } proc develop {} { bind all <3> {set clipboard %W} bind .metabits.name <2> { set tmp [lindex $q_curbuf 1] set clipboard "[list proc $tmp $q_func_args($tmp)] {\n$q_func_body($tmp)}" } } proc qtk_init {} { global widlist contlist toplist cont selmode orient curtop global q_nid qtk # for dialog editor set widlist {} set contlist {.} set toplist {.} set q_nid 0 # This is the current container we work within. set cont {.} # Set some defaults set selmode browse set orient v set curtop . catch {unset obj} set qtk(rec_func) {} } proc qtk_showfunc name { global q_func_args q_func_body #qtk_flush_buffer qtk_set_buffer $q_func_body($name) [list func $name] .metabits.name config -text $name do_recent_funcs $name .metabits.args delete 0 end .metabits.args insert 0 $q_func_args($name) } proc qtk_inval_funclist {} { # The general idea is to refresh the function list IFF it is present and # visible, otherwise do nothing. global qtk catch { .fl.f.l delete 0 end foreach i [lsort $qtk(funclist)] { .fl.f.l insert end $i } } } proc qtk_delfunc name { global q_func_body q_func_args qtk q_curbuf set resp [tk_dialog .confirm "Confirmation" "Are you sure you want to utterly anhilate ${name}?" questhead -1 "I mean it" "Ooops - don't do that"] if {$resp==0} { set num [lsearch -exact $qtk(funclist) $name] if {($num <1) || ($num == [llength $qtk(funclist)]-1)} { tk_dialog .confirm "Affirmation" "Function $name cannot be deleted. It's vital." exclamation 0 "Whatever" return } set qtk(funclist) [lreplace $qtk(funclist) $num $num] unset q_func_args($name) unset q_func_body($name) qtk_inval_funclist if {$q_curbuf==[list func $name]} { set q_curbuf invalid qtk_notes } } } proc qtk_eraseproj {} { global qtk q_func_args q_func_body edit_mode set_mode qtk catch {unset qtk} catch {unset q_func_args} catch {unset q_func_body} foreach i {notes funclist funcs globals widgets menus settings rec_func} { set qtk($i) {} } qtk_invalidate_views qtk_notes } proc qtk_setname name { global qtk set qtk(name) $name .f.n config -text $name } proc qtk_name {} { catch {destroy .name} toplevel .name wm title .name {Set Target Name} entry .name.name -width 32 -font 7x14 button .name.ok -text {OK} -command {set tmp [.name.name get] if {$tmp != ""} { qtk_setname $tmp destroy .name } else {bell} } button .name.cancel -text {Cancel} -command {destroy .name } pack .name.name -side top pack .name.ok -side left pack .name.cancel -side right focus .name.name } proc history_box {w l} { # History Box takes a widget name and a list of recent entries. # It will create a frame containing an entry widget $w.e and # a menubutton $w.m. The menubutton will be bound to a menu of # recent entries (given by list $l) and selection of any of those # menu options will replace the contents of the entry box by the # label in the menu option. # # It is up to the user of the function to pack the frame widget. frame $w entry $w.e -font 7x14 menubutton $w.m -menu $w.m.m -text "-V-" -relief raised menu $w.m.m -tearoff no foreach i $l { $w.m.m add command -label $i -command [subst {$w.e delete 0 end; $w.e insert 0 $i}] } pack $w.e $w.m -side left } proc mk_checkbutton {} { # To make a checkbutton global contlist qtk wcc {CheckButton} label .wcc.a.cl -text "Label Contents:" entry .wcc.a.ce -width 30 -font 7x14 button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "checkbutton" set obj(app) "-text {[.wcc.a.ce get]}" set obj(cfg) "-variable \{[.wcc.c.var.e get]\}" add_obj } pack .wcc.b.al -side left -fill none label .wcc.c.lv -text {Associated Global Variable:} history_box .wcc.c.var $qtk(globals) pack .wcc.a.cl .wcc.a.ce -side top pack .wcc.c.lv .wcc.c.var -side top pack .wcc.b.al -side left pack .wcc.b.dismiss -side right } proc set_menu_bar {} { global lang foreach bob [pack slaves .menu] { destroy $bob } if {$lang == "tk"} { set ml {widget tcl window tk_proj} } if {$lang == "html"} { set ml {font htlists forms html} } menu_file menu_edit pack .menu.file .menu.edit -side left lappend ml options foreach bob $ml { menu_${bob} pack .menu.$bob -side left } menu_help pack .menu.help -side right } proc menu_font {} { set m .menu.font.m menubutton .menu.font -text "Font" -menu $m -underline 2 menu $m $m add cascade -label "Heading" -menu $m.head -underline 0 $m add cascade -label "Size" -menu $m.size -underline 2 $m add separator foreach {i u} {strong 0 em 0 code 0 pre 0 cite 2 address 0 var 0} { $m add command -label $i -command [subst {ht_tag "$i"}] -underline $u } $m add separator foreach {name tag u} {Bold b 0 Italic i 0 Typewriter tt 1} { $m add command -label $name -command [subst {ht_tag "$tag"}] -underline $u } set m .menu.font.m.head menu $m -tearoff 0 foreach i {1 2 3 4 5 6} { $m add command -label "Heading $i" -command "ht_tag h$i" -underline 8 } set m .menu.font.m.size menu $m -tearoff 0 foreach i {+4 +3 +2 +1 +0 -1 -2 -3} { $m add command -label "size $i" -command "ht_tag font size=$i" } } proc menu_htlists {} { set m .menu.htlists.m menubutton .menu.htlists -text "Lists" -menu $m -underline 0 menu $m $m add command -label {List Element} -command {ins "
  • "} -underline 0 $m add command -label {Ordered List} -command {ins "
      \n
    \n"} -underline 0 $m add command -label {Unordered List} -command {ins "
      \n
    \n"} -underline 0 $m add separator $m add command -label "Quick List" -command html_quicklist $m add command -label "Listify" -command html_listify } proc html_quicklist {} { catch {destroy .ql} toplevel .ql wm title .ql {Quick List} tk_optionMenu .ql.type ht_listtype ordered 1 I A i a unordered disc square circle pack .ql.type -side top button .ql.code -text {Code} -command { if {[lsearch -exact {1 I A i a} $ht_listtype] != -1} { ins [subst {
      \n
    \n}] } if {[lsearch -exact {disc square circle} $ht_listtype] != -1} { ins [subst {
      \n
    \n}] } if {$ht_listtype == "ordered"} {ins "
      \n
    \n"} if {$ht_listtype == "unordered"} {ins "
      \n
    \n"} destroy .ql } button .ql.cancel -text {Cancel} -command { destroy .ql } pack .ql.code -side top pack .ql.cancel -side top } proc html_listify {} { set interval [.t tag ranges sel] for {set i [lindex $interval 0]} {$i < [lindex $interval 1]} {set i [expr $i + 1]} { .t insert "$i linestart" "
  • " } } proc code_widlist {} { catch {destroy .cw} toplevel .cw wm title .cw {Code Widgets} label .cw.l1 -text {Enter Parent Name (Without trailing dot)} entry .cw.root -width 25 -font 7x14 button .cw.ok -text {OK} -command { set tmp [.cw.root get] code_oarr $tmp destroy .cw } button .cw.cancel -text {Cancel} -command {destroy .cw} pack .cw.l1 -side top pack .cw.root -side top pack .cw.ok -side left pack .cw.cancel -side right } proc widpop {x y w} { catch {destroy .popup} menu .popup -tearoff no set m .popup set widname [string range $w 3 end] set tmp $widname if {$tmp == ""} {set tmp .} while {$widname != ""} { $m add command -label $widname -command "widedit [widlookup $widname]" set widname [string range $widname 1 [expr [string last . $widname] -1]] } $m add command -label "Root Window" -command {puts UNIMPLEMENTED} $m add separator $m add command -label "Copy Widget Name" -command "set clipboard $tmp" tk_popup .popup $x $y } proc widedit w { } proc widflip n { # Flip elements n and n-1 global widlist .wl.lb selection clear 0 end set above [expr $n - 1] set tmp [.wl.lb get $n] .wl.lb insert $above $tmp .wl.lb delete [expr $n + 1] set tmp [concat [lrange $widlist 0 [expr $n-2]] \ [lindex $widlist $n] [lindex $widlist $above] \ [lrange $widlist [expr $n+1] end] ] set widlist $tmp qtk_inval_example } proc qtk_inval_example {} { # Redraw the example dialog box where available. global oarr widlist catch { foreach w [pack slaves .ex] {destroy $w} foreach w $widlist { array set obj $oarr($w) eval $obj(type) .ex$obj(name) $obj(app) eval pack .ex$obj(name) $obj(pack) } } } proc empty_widlist {} { global widlist contlist toplist oarr catch {unset oarr} set widlist "" set contlist {.} set toplist {.} qtk_inval_example catch {.wl.lb delete 0 end} } proc widlookup w { global widlist oarr foreach n $widlist { array set obj $oarr($n) if {$obj(name) == $w} {return $n} } return "" } proc cluehunt_english clue { if {$clue == " "} { # Look for a word to play the Markov Game with. # Basically a two step process: # Get the two most recent words and add the pair to the Markov array. # Set the clue bar to the Markov array point for the most recent word. } # For now, I'm playing real simple games. set index [.t index insert] set curlin [.t get "$index linestart" "$index lineend"] set cw [.t get "$index wordstart" "$index wordend"] .clue.b1 config -text $cw .clue.b2 config -text $curlin } proc mk_radiobutton {} { # To make a radiobutton global contlist qtk wcc {RadioButton} label .wcc.a.cl -text "Label Contents:" entry .wcc.a.ce -width 30 -font 7x14 button .wcc.b.al -text {Add to List} -command { catch {unset obj} set obj(type) "radiobutton" set obj(app) "-text {[.wcc.a.ce get]}" set obj(cfg) "-variable \{[.wcc.c.var.h.e get]\} -value \{[.wcc.c.val.e get]\}" add_obj } pack .wcc.b.al -side left -fill none frame .wcc.c.var frame .wcc.c.val label .wcc.c.var.l -text {Associated Global Variable:} history_box .wcc.c.var.h $qtk(globals) label .wcc.c.val.l -text "Value for this choice:" entry .wcc.c.val.e pack .wcc.a.cl .wcc.a.ce -side top pack .wcc.c.var .wcc.c.val -side left -fill y -expand 1 pack .wcc.c.var.l .wcc.c.var.h -side top pack .wcc.c.val.l .wcc.c.val.e -side top pack .wcc.b.al -side left pack .wcc.b.dismiss -side right } proc chk_edit_mode mode { global edit_mode if {$edit_mode != $mode} { bell return -code return } } proc deduce_lang filename { global lang # Should give correct language mode id given file name set ext [file extension $filename] set lang text foreach {id el} { tk {.tk .tcl} html {.html .htm .phtml .php .php3} c++ {.c .cc .C .cpp .cxx .c++ .C++} sql {.sql} } { if {[lsearch -exact $el $ext] >= 0} {set lang $id} } setlang } proc cluehunt_tk clue { if {$clue == "dollar"} { set l [lrange [lindex [.t get 1.0 "1.0 lineend"] 2] 0 4] clue_offer $l } } proc clue_offer cl { set i 1 foreach try $cl { .clue.b$i config -text "$try " incr i if {$i == 6} {return} } } proc html_highlight {} { # This should highlight the syntax of an entire page. # Essentially, I will scan through the page reading HTML and maintaining a small # amount of state which enables me to tell what color the current character # should be. This, combined with a knowledge of state changes, should let me # sprinkle tags appropriately. # First, clean out the tags: .t tag delete htext htag hcomment hquote hres hdubious # Initialize data # States are text, tag, comment, quote, dubious set state text set lastloc 1.0 set laststate text # Loop across all lines set maxy [lindex [split [.t index end] .] 0] for {set y 1} {$y < $maxy} {incr y} { # Loop across all characters set maxx [lindex [split [.t index "$y.0 lineend"] .] 1] for {set x 0} {$x < $maxx} {incr x} { set consume 0 set ch [.t get $y.$x] switch $state { text { if {$ch == "\<"} {set state tag} } tag { if {$ch == "\""} {set state quote} if {$ch == "\>"} { set state text set consume 1 } } comment { } quote { if {$ch == "\""} { set state tag set consume 1 } if {$ch == "\>"} { set state dubious set consume 1 } } dubious { } } # Set the character to be part of the tag. if {$state != $laststate} { set pt $y.[expr $x + $consume] .t tag add h${laststate} $lastloc $pt set laststate $state set lastloc $y.$x } } # X if {$state == "dubious"} { set state text set pt $y.[expr $x + $consume] .t tag add hdubious $lastloc $pt set laststate text set lastloc $y.$x } } # Y .t tag add h${laststate} $lastloc end set laststate $state set lastloc $y.$x .t tag config htag -foreground blue .t tag config hquote -foreground darkgreen } proc qtk_delwidget {} { # This function relies on being able to see the widget list. # Perhaps better would be to take an argument as an index into the widget list. global widlist oarr # get index into widget array to delete set wn [.wl.lb curselection] if {[llength $wn] != 1} { bell return } #remove it from the viewer. .wl.lb delete $wn # Get widget id to delete set wid [lindex $widlist $wn] # remove widget from list set prefix [lrange $widlist 0 [expr $wn - 1]] set suffix [lrange $widlist [expr $wn + 1] end] set widlist [concat $prefix $suffix] # delete the widget unset oarr($wid) # Invalidate the widget list and/or the example dialog qtk_inval_example } proc ht_table_create {} { catch {destroy .httc} toplevel .httc wm title .httc {Table Creatrix} label .httc.l -text {Table Creatrix} frame .httc.ali -border 0 -relief flat frame .httc.clr -border 0 -relief flat frame .httc.row -border 0 -relief flat frame .httc.col -border 0 -relief flat frame .httc.wid -border 0 -relief flat frame .httc.hei -border 0 -relief flat frame .httc.cap -border 0 -relief flat frame .httc.cmd -border 0 -relief flat label .httc.ali.l -text {Align} label .httc.clr.l -text {BgColor} label .httc.row.l -text {Rows} label .httc.col.l -text {Columns} label .httc.wid.l -text {Width} label .httc.hei.l -text {Height} label .httc.cap.l -text {Caption} entry .httc.ali.e -width 20 -font 7x14 entry .httc.clr.e -width 20 -font 7x14 entry .httc.row.e -width 20 -font 7x14 entry .httc.col.e -width 20 -font 7x14 entry .httc.wid.e -width 20 -font 7x14 entry .httc.hei.e -width 20 -font 7x14 entry .httc.cap.e -width 20 -font 7x14 button .httc.cmd.ok -text {Write Code} -command { ht_table_write destroy .httc } button .httc.cmd.dis -text {Dismiss} -command { destroy .httc } pack .httc.l -side top pack .httc.ali -side top -fill x pack .httc.clr -side top -fill x pack .httc.row -side top -fill x pack .httc.col -side top -fill x pack .httc.wid -side top -fill x pack .httc.hei -side top -fill x pack .httc.cap -side top -fill x pack .httc.cmd -side top -fill x pack .httc.ali.l -side left -anchor e pack .httc.clr.l -side left -anchor e pack .httc.row.l -side left -anchor e pack .httc.col.l -side left -anchor e pack .httc.wid.l -side left -anchor e pack .httc.hei.l -side left -anchor e pack .httc.cap.l -side left -anchor e pack .httc.ali.e -side left -anchor e pack .httc.clr.e -side left -anchor e pack .httc.row.e -side left -anchor e pack .httc.col.e -side left -anchor e pack .httc.wid.e -side left -anchor e pack .httc.hei.e -side left -anchor e pack .httc.cap.e -side left -anchor e pack .httc.cmd.ok -side left -expand 1 pack .httc.cmd.dis -side left -expand 1 } proc ht_table_write {} { set ali [.httc.ali.e get] set clr [.httc.clr.e get] set row [.httc.row.e get] set col [.httc.col.e get] set wid [.httc.wid.e get] set hei [.httc.hei.e get] set cap [.httc.cap.e get] ins "\n" if {$cap!=""} { ins "\n" ins $cap ins "\n" } for {set y 0} {$y<$row} {incr y} { ins "" for {set x 0} {$x<$col} {incr x} { ins " " } ins "\n" } ins "\n" } proc ht_spell_refresh {} { catch {destroy .spell} toplevel .spell wm title .spell {HTML Spells} label .spell.l -text {Refresh Spell} frame .spell.delay -border 0 -relief flat frame .spell.url -border 0 -relief flat frame .spell.cmd -border 0 -relief flat label .spell.delay.l -text {Delay} label .spell.url.l -text {URL} entry .spell.delay.e -width 10 -font 7x14 entry .spell.url.e -width 19 -font 7x14 button .spell.cmd.ok -text {Code} -command { ins {} ins \n destroy .spell } button .spell.cmd.dis -text {Cancel} -command {destroy .spell} pack .spell.l -side top pack .spell.delay -side top -fill x pack .spell.url -side top -fill x pack .spell.cmd -side top -fill x pack .spell.delay.l -side left -fill x pack .spell.url.l -side left -fill x pack .spell.delay.e -side left pack .spell.url.e -side left pack .spell.cmd.ok -side left -expand 1 pack .spell.cmd.dis -side left -expand 1 } proc ht_spell_style_import {} { catch {destroy .spell} toplevel .spell wm title .spell {HTML Spells} label .spell.l -text {Style Sheet Spell} frame .spell.url -border 0 -relief flat frame .spell.cmd -border 0 -relief flat label .spell.url.l -text {css url} entry .spell.url.e -width 20 -font 7x14 button .spell.cmd.ok -text {Code} -command { ins {} ins \n destroy .spell } button .spell.cmd.dis -text {Cancel} -command {destroy .spell} pack .spell.l -side top pack .spell.url -side top -fill x pack .spell.cmd -side top -fill x pack .spell.url.l -side left -fill x pack .spell.url.e -side right -fill x pack .spell.cmd.ok -side left -expand 1 pack .spell.cmd.dis -side left -expand 1 } proc menu_forms {} { set m .menu.forms.m menubutton .menu.forms -text "Forms" -menu $m -underline 2 menu $m $m add command -label "Form" -command {ins "
    \n
    "} -underline 0 $m add cascade -label "Input" -menu $m.input -underline 0 $m add cascade -label "Textarea" -menu $m.textarea -underline 0 # Input types set inputs {text password button submit reset checkbox radio} set m .menu.forms.m.input menu $m foreach type $inputs { set cmd [subst {ins ""}] $m add command -label $type -command $cmd -underline 0 } set m .menu.forms.m.textarea menu $m foreach {label cols rows} {Small 30 3 Medium 45 5 Large 60 7} { set cmd [subst {ins ""}] $m add command -label $label -command $cmd -underline 0 } $m add command -label "Generic" -command {ins ""} -underline 0 } proc qtk_decompose {} { #global qtk q_funcs q_curbuf edit_mode global qtk q_func_args q_func_body set fname [get_fname] if {$fname==""} return set_mode qtk qtk_eraseproj # Intention of this function: Take a file of tcl/tk code and # apply string functions to tear such file apart into syntactic blocks. # Should be robust against most forms of badly written or quirky code. # First read file into string. # Prepare initial strings set main "" set header "" set qtk(funclist) "__HEADER__" # Use precalculated knowledge of where procedures start (pass 1) to speed # parsing by avoiding manipulating too much text at once. set cluehelper {$1=="proc" {print NR}} set lineclues [exec awk $cluehelper $fname] # Create a loop, reading sections of a file until it's all used up. # Should reduce time used from O(n^2) to O(n log n) -- Much Faster set f [open $fname r] set test [read $f] close $f while {[string length $test]} { # Next start picking apart lines. set linelen [string first \n $test] set line [string range $test 0 $linelen] set cmd [lindex $line 0] if {$cmd == "proc"} { # Do we need to twiddle header? # Stuff before first procedure should be in header. if {$header == ""} { set header $main set main "" } # Parse procedure set lproc [lrange $test 0 3] set name [lindex $lproc 1] set argys [lindex $lproc 2] set body [lindex $lproc 3] # Clean things up a bit if {[string index $body 0] == "\n"} {set body [string range $body 1 end]} # Stick it in data structure lappend qtk(funclist) $name set q_func_args($name) $argys set q_func_body($name) $body # Now have to figure out how to pluck the right number of lines from $test. # Turns out that inter-element white space is preserved in list operations. set test [string range $test [string length $lproc] end] # Now remove the last bits on the end of the line closing the procedure. set linelen [string first \n $test] set test [string range $test [expr $linelen + 1] end] # Let people know it's been parsed puts [list $cmd $name $argys] } else { # add line to "__MAIN__" set main "$main$line" set test [string range $test [expr $linelen + 1] end] } } lappend qtk(funclist) "__MAIN__" set q_func_body(__HEADER__) $header set q_func_args(__HEADER__) "" set q_func_body(__MAIN__) $main set q_func_args(__MAIN__) "" qtk_invalidate_views qtk_setname $fname qtk_selfunc } proc rt_menu {wid x y} { set m .rt_menu catch {destroy $m} menu $m -tearoff 0 $m add command -label "Copy" -command "ed_copy $wid" -underline 0 -accelerator "Ctrl-Ins" $m add command -label "Cut" -command "ed_cut $wid" -underline 2 -accelerator "Shift-Del" $m add command -label "Paste" -command "ed_paste $wid" -underline 0 -accelerator "Shift-Ins" tk_popup .rt_menu $x $y } proc set_mode mode { global edit_mode set edit_mode $mode foreach widget [pack slaves .metabits] { destroy $widget } if {$mode == "qtk"} { label .metabits.l1 -text "proc" menubutton .metabits.name -text {$name} -relief raised entry .metabits.args -width 30 -font 7x14 pack .metabits.l1 -side left pack .metabits.name -side left -anchor w -ipady 2 -ipadx 4 pack .metabits.args -side left -anchor w } } proc do_recent_funcs name { global qtk set index [lsearch -exact $qtk(rec_func) $name] if {$index == -1} { set qtk(rec_func) [lrange [concat $name $qtk(rec_func)] 0 4 ] } else { set first [lrange $qtk(rec_func) 0 [expr $index - 1]] set mid [lindex $qtk(rec_func) $index] set last [lrange $qtk(rec_func) [expr $index + 1] end] set qtk(rec_func) [concat $mid $first $last] } ## By this time qtk(rec_func) is in a state where we can make a menu. set m .metabits.name.m catch { destroy $m } menu $m -tearoff 0 foreach f $qtk(rec_func) { $m add command -label $f -command "qtk_showfunc $f" } $m add separator $m add command -label "Project Notes" -command {qtk_notes} $m add command -label "All Functions" -command {qtk_selfunc} .metabits.name configure -menu $m } proc hl_annoying {} { # This should highlight an entire page in alternating colors. # Its purpose is to discover the issues behind syntax highlighting. # It will decide what is whitespace, punctuation, or a word. # Whitespace no longer gets a green background. # Punctuation turns brown. # Words turn blue. # Numbers turn green. # First, clean out the tags: hl_unhighlight # The basic algorithm is to keep track of state transitions. # I.E. what point the scanner moves from one lexical object to the next. # This means we need to store the "mark", "point", and "scan" positions. # Presumably when we come to a conclusion about the extent of a lexical object, # we tag that object according to the scheme in place. We may also set some # other state information about how future scanning should take place. # Presumably scanners could be stacked.... # Initialize data set mark 1.0 set point 1.0 set collecting ws set wants 1 set terminal 0 # Options: WhiteSpace, Number, Punctuation, Alnum # Loop across all lines set maxy [lindex [split [.t index end] .] 0] for {set y 1} {$y < $maxy} {incr y} { # In real life, we need a list of continuation options for each recognizer # state so we can run through the recognizer (possibly multiple ones in # parallel) as a (multiple) state graph transition algorithm. # This is simple to think about but nontrivial to program. # The compromise here is to presume that the "recognizer" degenerates to a # single case for the first character. # There are two cases: a recognizer "wants" the character, or it doesn't. # The recognizer may optionally advise that it is finished. (in a terminal # state) # Loop across all characters set maxx [lindex [split [.t index "$y.0 lineend"] .] 1] set x 0 while {$x < $maxx} { set ch [.t get "$y.$x"] # Classify this character: set ct [ctype $ch] switch $collecting { ws { if {$ct != "ws"} { set terminal 1 set wants 0 } else { set wants 1 } } punc { if {$ct != "punc"} { set terminal 1 set wants 0 } else { set wants 1 } } num { if {$ct != "digit"} { set terminal 1 set wants 0 } else { set wants 1 } } alnum { if {($ct == "punc") || ($ct == "ws")} { set terminal 1 set wants 0 } else { set wants 1 } } } # switch # Now process the "wants" variable if $wants { incr x } # Now check for a terminal state. if {$terminal == 1} { # set the point: set point "$y.$x" # add the tag: (maybe generalize to a function returning the tag name?) switch $collecting { ws {.t tag add ws $mark $point} punc {.t tag add punc $mark $point} num {.t tag add num $mark $point} alnum {.t tag add alnum $mark $point} } # reset the "terminal" state. set terminal 0 # set the mark: set mark $point # Read ahead a character so we can make the appropriate # collector transition. set ra [.t get $point] set ct [ctype $ra] switch $ct { ws {set collecting ws} punc {set collecting punc} digit {set collecting num} lcase - ucase {set collecting alnum} } # switch $ct } # if $terminal } # while x # In real life, each recognizer would return the terminal state ID and # we could color appropriately. For this excercise, the color is according # to which recognizer turned up its nose at further input. # It would be good to update things regularly. Do it after every line. update } # for y # The last thing to do is color the final (unfinished?) string. # This amounts to re-running the $terminal routine on the last bit of text # but not performing the associated read-ahead (which really should be # separate...) # The below is a copy from above. Presumably it will be proceduralized # when enough details of the general case are known. set point "$y.$x" # add the tag: (maybe generalize to a function returning the tag name?) switch $collecting { ws {.t tag add ws $mark $point} punc {.t tag add punc $mark $point} num {.t tag add num $mark $point} alnum {.t tag add alnum $mark $point} } # The only thing left is to actually CONFIGURE the tags we've been sprinkling # so liberally throughout the text. .t tag config alnum -foreground blue .t tag config num -foreground darkgreen .t tag config punc -foreground brown #.t tag config ws -background green } proc hl_unhighlight {} { foreach victim [.t tag names] { .t tag delete $victim } } proc ctype ch { # Return a code indicating the type of the character # Do this by making some key comparisons. # Outputs: lcase ucase digit punc ws if {( "a" <= $ch) && ("z" >= $ch)} { return lcase } if {" " >= $ch} { return ws } if {("0" <= $ch) && ("9" >= $ch)} { return digit } if {("A" <= $ch) && ("Z" >= $ch)} { return ucase } return punc } proc hl_php {} { } proc hl_generic {} { global hl_def_state hl_context_other hl_term hl_other hl_cmd hl_context # Initialize tables: hl_init # Set initial context and stack. set hl_context "php" set cstack {} # Initialize data set mark 1.0 set point 1.0 set state $hl_def_state($hl_context) set wants 1 # Clean out the old tags: hl_unhighlight # # What we need to do here is the state transition function. # This entails getting the S-T list for the current state, then # making key comparisons to find the "NEXT STATE". # Afterwards we check the "terminal" array to find if the given # next state is a terminal box, and if so, color the lexical # unit appropriately. # If we can't find a "next state" based on the S-T list, then # we try the "hl_other" array. If that has a value, we use it. # Should the "other" entry lead to a terminal state, the # character is not gobbled. (If you want it gobbled, insert an # extra state.) # Otherwise we assume that this character can't be used by the # state graph and that we have matched an invalid lexical unit. # This ONLY gobbles the character IF the current state is the # default state for the context. # Next it applies the coloring for the context's "other" tag # and sets the state back to the default for the context. # # Terminal states are also checked for context push/pull status. # If the state number appears in the hl_cmd array, then the # value therein is used to determine whether to push or pull, # and if push, then which context to switch to. # Stack code takes place after coloring. # # Loop across all lines set maxy [lindex [split [.t index end] .] 0] for {set y 1} {$y < $maxy} {incr y} { # Loop across all characters set maxx [lindex [split [.t index "$y.0 lineend"] .] 1] set x 0 while {$x < $maxx} { set ch [.t get "$y.$x"] set wants [hl_trans state $ch] # Now process the "wants" variable incr x $wants # Now check for a terminal state. if {$hl_term($state)} { # Do the highlighting set point "$y.$x" hl_do_terminal $mark $point $state set mark $point # Perform any context commands catch { set cmd $hl_cmd($state) switch [lindex $cmd 0] { pop { set hl_context [lindex $cstack 0] set cstack [lrange $cstack 1 end] } push { set cstack [concat $context $cstack] set hl_context [lindex $cmd 1] } } } # Reset the state. set state $hl_def_state($hl_context) } # if $hl_term($state) } # while x # Need to pass the "eol" character through the state graph. hl_trans state \n if {$hl_term($state)} { # Do the highlighting set point [expr $y + 1 ] set point "$point.0" hl_do_terminal $mark $point $state set mark $point } # It would be good to update things regularly. Do it after every line. update } # for y # Now we have to "terminate" whatever token we've been collecting. # Presumably this is done with "EOF" which is "other" than any character. # Thus we state-transition to the "context-other" entry for where we are, then color. # Some things (e.g. Quotes) may want to color set point "$y.$x" hl_do_terminal $mark $point $hl_def_state($hl_context) # The only thing left is to actually CONFIGURE the tags we've been sprinkling # so liberally throughout the text. .t tag config 103 -background red -foreground black foreach {ts color} { 4 purple 9 grey37 13 grey37 18 #ddf38fd30000 37 brown 41 darkgreen 42 darkgreen 30 darkgreen 35 darkgreen 59 grey37 61 blue 62 darkgreen 66 brown 70 blue 72 darkgreen 74 darkgreen 101 #00006b169ba5 105 #00006b169ba5 108 #00006b169ba5 112 #00006b169ba5 113 #00006b169ba5 117 #00006b169ba5 } { .t tag config $ts -foreground $color } } proc hl_do_terminal {mark point state} { # This needs to consult a terminal highlight table and apply the appropriate tag. # Perhaps one easy thing is to name the tag after the terminal state number, then # use the coloring table to configure the tags. .t tag add $state $mark $point # This should maybe see about context push/pull? Or maybe that should be done # outside this framework?} proc hl_init {} { global hl_def_state hl_x hl_context_other hl_term hl_other hl_cmd hl_lists hl_chars # The general idea here is to initialize the state transition graph # and related parameters. # There will be much static data here.... array set hl_def_state { html 50 php 0 tag 75 dquote 39 squote 40 } array set hl_context_other { html 50 php 0 tag 75 dquote 39 squote 40 } array set hl_x { 0 { a z 19 A Z 19 "\0" " " 1 1 9 109 } 1 { "\0" " " 1 } 15 { a z 16 A Z 16 } 16 { a z 16 A Z 16 } 17 { a z 17 A Z 17 0 9 17 } 19 { a z 20 A Z 20 0 9 20 } 20 { a z 20 A Z 20 0 9 20 } 100 { 0 7 104 } 100 { 8 9 102 } 104 { 0 7 104 } 106 { 0 9 107 a f 107 A F 107 } 109 { 0 9 110 } 110 { 0 9 110 } 111 { 0 9 114 } 115 { 0 9 116 } 116 { 0 9 116 } } array set hl_chars { 0 { _ 19 $ 15 0 100 ? 22 / 3 \" 25 \' 31 # 14} 3 { * 5 / 10 } 5 { * 7 } 6 { * 7 } 7 { / 8 } 10 { \n 12 } 11 { \n 12 } 14 { \n 12 } 15 { _ 16 $ 15 } 16 { _ 16 } 17 { _ 17 } 19 { _ 20 } 20 { _ 20 } 22 { > 24 } 26 { \\ 27 \" 29 } 33 { \\ 32 \' 34 } 39 { \\ 27 \" 29 } 40 { \\ 32 \' 34 } 50 { < 51 & 63 } 51 { ! 52 ? 60 } 52 { - 53 } 53 { - 54 } 54 { - 56 } 55 { - 56 } 56 { - 57 } 57 { > 58 } 64 { ; 65 } 67 { \" 69 } 68 { \" 69 } 75 { \" 67 > 71 } 109 { . 111 } 110 { . 111 } } array set hl_lists { 0 { "()[]{}" 37 } 100 { xX 106 } 109 { eE 115 } 110 { eE 115 } 111 { eE 115 } } array set hl_other { 0 38 1 2 3 4 5 6 6 6 7 6 8 9 10 11 11 11 12 13 14 11 16 18 17 18 19 21 20 21 22 4 24 23 25 41 26 26 27 26 31 42 32 33 33 33 34 35 38 4 39 26 40 33 51 62 52 62 53 62 54 55 55 55 56 55 57 66 58 59 60 61 63 64 64 64 65 66 67 68 69 70 71 72 75 73 73 74 100 101 102 103 104 105 107 108 109 112 110 112 114 113 116 117 } array set hl_cmd { 41 {push dquote} 42 {push squote} 30 pop 35 pop 23 pop 61 {push php} 62 {push tag} 72 pop } set term_states { 2 4 9 13 18 21 23 30 35 37 41 42 59 61 62 66 70 72 74 101 103 105 108 112 113 117 } # Automatically populate hl_term array. foreach a [concat [ array names hl_x ] [ array names hl_chars ] [ array names hl_lists ] [ array names hl_other ] ] { set hl_term($a) 0 } foreach a $term_states { set hl_term($a) 1 } } proc hl_trans {state_v ch} { global hl_x hl_term hl_lists hl_chars hl_context hl_def_state hl_other hl_context_other upvar $state_v state set xl {} catch {set xl $hl_x($state)} # Try to match against the hl_x (transition) array foreach {first last dest} $xl { if {("$first" <= "$ch") && ("$ch" <= "$last")} { set state $dest; return 1 } } # Try the state->chars strategy set xl {} catch { set xl $hl_chars($state) } foreach {char dest} $xl { if {"$char" == "$ch"} { set state $dest; return 1 } } # Try the "state->lists" strategy set xl {} catch { set xl $hl_lists($state) } foreach {ch_list dest} $xl { if {-1 != [lsearch -exact $ch_list]} { set state $dest; return 1 } } # Try the "state->other" strategy set next_state {} if {$next_state == {}} { catch { set next_state $hl_other($state) set wants 1 # Have a next state. Is it terminal? if {$hl_term($next_state)} { set wants 0 } } } # Try the "context->other" strategy if {$next_state == {}} { set next_state $hl_context_other($hl_context) if {$state == $hl_def_state($hl_context)} { set wants 1 } else { set wants 0 } } set state $next_state return $wants } # For the HTML module ht_init # For the QTK module qtk_init ################## # # Global Variables # ################## # for editor set clipboard {} set autoindent 1 set lang tk set edit_mode flat # Set up main interface window: main; ######################### # # # Read Command Line # # # ######################### if {$argv != ""} { if [load $argv] { set tmp [tk_dialog .confirm "Information" "Unable to read a file by the name \"$argv\". Would you like to create a new file?" info 0 "OK" "Nope." ] if {$tmp == 0} { .f.n config -text $argv } } deduce_lang $argv } if {($argv == "") && ([glob -nocomplain Project] != "")} { if {[tk_dialog .lp "Load Project?" "There's a project file in this directory. Do you want to load it?" question 0 "Yep" "Not Now"] == 0} { qtk_load } }