TkTwig - GUI frontend to [Twig] Directions to find it at [Stu] [Stu] 2008-10-30 Created this page. ---- **SOURCE** ====== #! /bin/sh # \ exec tclsh "$0" ${1+"$@"} # TkTwig # # Stuart Cassoff # # May 2008 # October 2008 # # Version 0.1 # # namespace eval tktwig {} # #------------------------------------------------------------------- # Info #------------------------------------------------------------------- # # # proc tktwig::readme {} { return { GUI frontend to Twig run view reset (sum) exit Menus do things Basic Twigging -------------- * Twig->New * Type in page# * Query (adjust lines to taste) * Adjust blocks if necessary * View (does not compute checksum - careful!) * Examine (not a button - use your eyes and brain) * Run (careful!) * Acquire * Keep * Bundle->(Save|Save as...) } } ### # # # proc tktwig::usage {} { variable cfg append usage $cfg(name) " " $cfg(version) \n usage: " " append usage [string tolower $cfg(name)] " " {[-b bundleFile] [-z configFile]} return $usage } ### # # # proc tktwig::about {} { variable cfg variable gui lappend vd [wm title $gui(W)] lappend vd $cfg(author) lappend vd {} {Fall 2008} return [join $vd \n] } ### # # # proc tktwig::license {} { return { Copyright 2008 Stuart Cassoff. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. } } ### # # # proc tktwig::messages {} { variable cfg return [join $cfg(messages) \n] } ### #------------------------------------------------------------------- # TkTwig #------------------------------------------------------------------- # # # proc tktwig::checkTwig {twig} { variable cfg if {[catch {llength $twig} l] || $l < [llength $cfg(twigFields)]} { return 0 } return 1 } ### # # # proc tktwig::rovosTwig {rovos} { variable cfg variable gui set sel [$gui(lb) curselection] if {[llength $sel] == 0} { return } set idx [lindex $sel 0] lassign [lindex $cfg(twigs) $idx] page blocks sum url name if {[catch { switch -exact -- $rovos { run { if {$cfg(runPipe)} { exec $cfg(tclsh) $cfg(twig) -s $sum $page $blocks | $cfg(run) & } else { exec $cfg(run) <<[twiggit $page $blocks $sum] & } } view { view [twiggit $page $blocks $sum] $name } sum { twiggit $page $blocks $sum $gui(lb) itemconfigure [lindex $sel 0] \ -background green -selectbackground lightgreen } default { huh? } }} err]} { $gui(lb) itemconfigure [lindex $sel 0] \ -background red -selectbackground pink lappend cfg(messages) $err view $err ERROR } } ### # # # proc tktwig::newTwig {} { variable cfg set editData {} foreach n $cfg(twigFields) { lappend editData $n {} } editSomething $cfg(NS)::newTwigSaveCallback {} $editData New\ Twig true } ### # # # proc tktwig::newTwigSaveCallback {clientData editData} { variable cfg set twig {} foreach {n v} $editData { lappend twig $v } lappend cfg(twigs) $twig refreshTwiglist return 1 } ### # # # proc tktwig::editTwig {{twig {}}} { variable cfg if {![checkTwig $twig]} { variable gui set sel [$gui(lb) curselection] if {[llength $sel] == 0} { return } set idx [lindex $sel 0] set twig [lindex $cfg(twigs) $idx] } else { set idx -1 } if {![checkTwig $twig]} { return } set editData {} foreach n $cfg(twigFields) v $twig { lappend editData $n $v } editSomething $cfg(NS)::editTwigSaveCallback $idx $editData Edit\ Twig\ $idx:\ [lindex $editData end] true } ### # # # proc tktwig::editTwigSaveCallback {clientData editData} { variable cfg set twig {} foreach {n v} $editData { lappend twig $v } set cfg(twigs) [lreplace $cfg(twigs) $clientData $clientData $twig] refreshTwiglist return 1 } ### # # # proc tktwig::deleteTwig {{idx -1}} { variable cfg if {$idx == -1} { variable gui set sel [$gui(lb) curselection] if {[llength $sel] == 0} { return } set idx [lindex $sel 0] } set cfg(twigs) [lreplace $cfg(twigs) $idx $idx] refreshTwiglist } ### #------------------------------------------------------------------- # Bundle #------------------------------------------------------------------- # # # proc tktwig::loadBundle {{fn {?}} {append false}} { variable cfg if {$fn eq {}} { set fn $cfg(bundleFile) } lassign [loadListFile $fn [list $cfg(filetypes,bundle)]] fn data if {$fn eq ""} { return 0 } if {!$append} { set cfg(twigs) {} } foreach t $data { if {[checkTwig $t]} { lappend cfg(twigs) $t }} set cfg(bundleFile) $fn refreshTwiglist return 1 } ### # # # proc tktwig::saveBundle {{fn {}}} { variable cfg if {$fn eq {}} { set fn $cfg(bundleFile) } set cfg(bundleFile) [saveFile $fn [join $cfg(twigs) \n] [list $cfg(filetypes,bundle)]] refreshGUI } ### #------------------------------------------------------------------- # Config #------------------------------------------------------------------- # # # proc tktwig::loadConfig {{fn {?}}} { variable cfg if {$fn eq {}} { set fn $cfg(configFile) } lassign [loadListFile $fn [list $cfg(filetypes,config)]] fn data if {$fn eq ""} { return 0 } array set cfg [processNv $data $cfg(configFileFields)] set cfg(configFile) $fn adjustConfig refreshGUI return 1 } ### # # # proc tktwig::saveConfig {{fn {}}} { variable cfg if {$fn eq {}} { set fn $cfg(configFile) } set l {} foreach n $cfg(configFileFields) { lappend l [list $n $cfg($n)] } set fn [saveFile $fn [join $l \n] [list $cfg(filetypes,config)]] if {$fn eq ""} { return 0 } set cfg(configFile) $fn adjustConfig refreshGUI return 1 } ### # # # proc tktwig::autoloadConfig {} { variable cfg adjustConfig if {[info exists cfg(pConfigFile)]} { set cfg(configFile) $cfg(pConfigFile) } adjustConfig if {$cfg(autoloadConfigFile)} { loadConfig {} } if {[info exists cfg(pBundleFile)]} { set cfg(bundleFile) $cfg(pBundleFile) } adjustConfig if {$cfg(autoloadBundleFile)} { loadBundle $cfg(bundleFile) } adjustConfig } ### # # # proc tktwig::editConfig {} { variable cfg set editData {} foreach n $cfg(configFileFields) { lappend editData $n $cfg($n) } editSomething $cfg(NS)::editConfigSaveCallback {} $editData Edit\ Config } ### # # # proc tktwig::editConfigSaveCallback {clientData editData} { variable cfg foreach {n v} $editData { set cfg($n) $v } adjustConfig refreshGUI return 1 } ### # # # proc tktwig::adjustConfig {} { variable cfg #set cfg(configFile) [file normalize $cfg(configFile)] #set cfg(bundleFile) [file normalize $cfg(bundleFile)] } ### #------------------------------------------------------------------- # File #------------------------------------------------------------------- # # # proc tktwig::loadFile {{fn {}} {filetypes {}} } { variable cfg variable gui if {$fn eq {} || $fn eq {?}} { lappend filetypes $cfg(filetypes,all) set fn [tk_getOpenFile -filetypes $filetypes -parent $gui(W)] } if {$fn eq {}} { return {} } if {[catch { if {$fn eq "-"} { set data [read -nonewline stdin] } else { set f [open $fn r] set data [read -nonewline $f] close $f } } err]} { lappend cfg(messages) $err return {} } return [list $fn $data] } ### # # # proc tktwig::saveFile {{fn {}} data {filetypes {}}} { variable cfg if {$fn eq {?}} { lappend filetypes $cfg(filetypes,all) set fn [tk_getSaveFile -filetypes $filetypes] } if {$fn eq {}} { return $fn } if {$fn eq "-"} { puts -nonewline stdout $data; return $fn } set f [open $fn w] puts -nonewline $f $data close $f return $fn } ### # # # proc tktwig::loadListFile {{fn {}} {filetypes {}} } { set res {} lassign [loadFile $fn $filetypes] fn data foreach l [split $data \n] { set l [string trim $l] if {$l eq {} || [string index $l 0] eq {#}} { continue } if {[catch {set len [llength $l]}] || $len < 1} { continue } lappend res $l } return [list $fn $res] } ### #------------------------------------------------------------------- # Twig #------------------------------------------------------------------- # # # proc tktwig::run {code} { variable cfg exec $cfg(run) <<$code & } ### # # # proc tktwig::twiggit {page {blocks 0} {sum {flipper}}} { variable cfg return [exec $cfg(tclsh) $cfg(twig) -s $sum $page $blocks] } ### # # # proc tktwig::query {editInfo} { variable cfg variable gui array set ei $editInfo set page [$ei(page) get] if {$page eq ""} { return } set name [$ei(name) get] if {[catch { set data [exec $cfg(tclsh) $cfg(twig) -q $gui(query) $page] } err]} { lappend cfg(messages) $err view $err ERROR return } view $data "Query ($gui(query)): $page $name" } ### # # # proc tktwig::acquire {editInfo} { variable cfg variable gui array set ei $editInfo set page [$ei(page) get] if {$page eq ""} { return } set blocks [$ei(blocks) get] if {$blocks eq ""} { $ei(blocks) insert end [set blocks 0] } if {[catch { set twig [exec $cfg(tclsh) $cfg(twig) -g $page $blocks] set name [exec $cfg(tclsh) $cfg(twig) -u http://wiki.tcl.tk -t title $page] } err]} { lappend cfg(messages) $err view $err ERROR return } $ei(sum) delete 0 end $ei(name) delete 0 end $ei(sum) insert 0 [lindex $twig 2] $ei(name) insert 0 $name } ### # # # proc tktwig::eView {editInfo} { variable cfg variable gui array set ei $editInfo set page [$ei(page) get] if {$page eq ""} { return } set blocks [$ei(blocks) get] if {$blocks eq ""} { $ei(blocks) insert end [set blocks 0] } set sum DO-NOT-VERIFY-SUM if {[catch { set data [twiggit $page $blocks $sum] } err]} { lappend cfg(messages) $err view $err ERROR return } view $data $page:$blocks\ [$ei(name) get] } ### #------------------------------------------------------------------- # Misc #------------------------------------------------------------------- # # # proc tktwig::processNv {data flds} { set res {} foreach l $data { if {[lsearch -exact $flds [lindex $l 0]] == -1} { continue } lappend res {*}$l } return $res } ### # # # proc tktwig::viewFile {} { if {[lindex [set what [loadFile]] 0] ne ""} { view {*}[lreverse $what] } } ### # # # proc tktwig::viewIt {what} { view [[string tolower $what]] $what } ### # # # proc tktwig::alias {this that args} { variable cfg interp alias {} $cfg(NS)::$this {} $cfg(NS)::$that {*}$args } ### #------------------------------------------------------------------- # GUI #------------------------------------------------------------------- # # # proc tktwig::toggle {button} { variable gui set gui($button,full) [expr {!$gui($button,full)}] refreshGUI } ### # # # proc tktwig::reset {w} { variable gui set sel [$w curselection] if {[llength $sel] == 0} { return } $w itemconfigure [lindex $sel 0] -background $gui(defBackground) \ -selectbackground $gui(defSelectbackground) } ### # # # proc tktwig::refreshGUI {} { variable cfg if {!$cfg(guiCreated)} { return } variable gui foreach what [list bundle config] { set t [file normalize $cfg($what\File)] if {!$gui($what,full)} { set t [file tail $t] } $gui($what) configure -text $t } if {$gui(ntwigs,full)} { set lb \[; set rb \] } else { set lb (; set rb ) } $gui(ntwigs) configure -text "$lb[llength $cfg(twigs)]$rb" } ### # # # proc tktwig::refreshTwiglist {} { variable cfg if {!$cfg(guiCreated)} { return } variable gui $gui(lb) delete 0 end foreach t $cfg(twigs) { $gui(lb) insert end [lindex $t 4] } set ntwigs [llength $cfg(twigs)] if {$ntwigs > 0} { $gui(lb) configure -width 0 -height 20 } else { $gui(lb) configure -width 0 -height 0 } refreshGUI } ### # # # proc tktwig::refreshQueryButton {{incr 0}} { variable gui incr gui(query) $incr if {$gui(query) < 0} { set gui(query) 0 } $gui(queryButton) configure -text "Query ($gui(query))" } ### # # # proc tktwig::newToplevelName {} { variable cfg variable gui return $gui(w).[string tolower $cfg(name)][regsub -all {\.} $cfg(version) {}]_[subst [string repeat {[format %c [expr {65 + int(rand() * 26)}]]} 10]] } ### # # # proc tktwig::view {{what {}} {title {}}} { variable cfg variable gui toplevel [set dlg [newToplevelName]] wm group $dlg $gui(W) set w $dlg set tf [ttk::frame $w.tf] text $tf.text -wrap none -yscroll [list $tf.vsb set] -xscroll [list $tf.hsb set] ttk::scrollbar $tf.vsb -orient vertical -command [list $tf.text yview] ttk::scrollbar $tf.hsb -orient horizontal -command [list $tf.text xview] set bf [ttk::frame $w.bf] ttk::button $bf.br -text Run -width -12 -command "$cfg(NS)::run \[$tf.text get 1.0 end\]" ttk::button $bf.bc -text Clear -width -12 -command "$tf.text delete 1.0 end" ttk::button $bf.bs -text Save -width -12 -command "$cfg(NS)::saveFile ? \[$tf.text get 1.0 end\]" ttk::button $bf.bd -text Dismiss -width -12 -command [list destroy $dlg] grid $tf.text $tf.vsb -sticky news grid $tf.hsb -sticky ew grid $bf.br -sticky e -padx 4 grid ^ $bf.bc -sticky e grid ^ ^ $bf.bs -sticky e -padx 4 grid ^ ^ ^ $bf.bd -sticky e grid $tf -sticky news grid $bf -sticky ew grid rowconfigure $tf 0 -weight 1 grid columnconfigure $tf 0 -weight 1 grid rowconfigure $bf 0 -weight 1 grid columnconfigure $bf 0 -weight 1 grid rowconfigure $w 0 -weight 1 grid columnconfigure $w 0 -weight 1 bind $dlg [list $bf.bd invoke] bind $dlg [list $bf.bd invoke] wm title $dlg [wm title $gui(W)]\ -\ $title $tf.text delete 1.0 end $tf.text insert end $what focus $dlg ::tk::PlaceWindow $dlg widget $gui(W) } ### # # # proc tktwig::editSomething {saveCallback clientData editData {title {Edit}} {tool false}} { variable cfg variable gui toplevel [set dlg [newToplevelName]] wm group $dlg $gui(W) set w $dlg set ef [ttk::frame $w.ef] foreach {n v} $editData { set nt [string totitle $n] grid [ttk::label $ef.l$nt -text $n -justify left] -sticky ew grid ^ [ttk::entry $ef.e$nt -width 40] -sticky ew $ef.e$nt insert end $v lappend editInfo $n $ef.e$nt } set bf [ttk::frame $w.bf] if {$tool} { set bqp [ttk::button $bf.bqp -text + -width -1 -command [list $cfg(NS)::refreshQueryButton 1]] set bqm [ttk::button $bf.bqm -text - -width -1 -command [list $cfg(NS)::refreshQueryButton -1]] set bq [ttk::button $bf.bq -width -12 -command [list $cfg(NS)::query $editInfo]] set ba [ttk::button $bf.ba -text Acquire -width -12 -command [list $cfg(NS)::acquire $editInfo]] set bv [ttk::button $bf.bv -text View -width -12 -command [list $cfg(NS)::eView $editInfo]] set gui(query) 1 set gui(queryButton) $bq refreshQueryButton } ttk::button $bf.bk -text Keep -width -12 -command [list $cfg(NS)::editSomethingSaveCallback $dlg $editInfo $saveCallback $clientData] ttk::button $bf.bd -text Discard -width -12 -command [list destroy $dlg] if {$tool} { grid $bqp $bqm $bq $ba $bv -sticky e; set push x } else { set push "" } grid {*}$push {*}$push {*}$push $bf.bk $bf.bd -sticky e grid $ef -sticky nsew -padx 1 -pady 1 grid $bf -sticky ew -padx 1 -pady 1 grid columnconfigure $ef 1 -weight 1 grid columnconfigure $bf 0 -weight 1 grid rowconfigure $bf 1 -weight 1 grid rowconfigure $w 0 -weight 1 grid columnconfigure $w 0 -weight 1 bind $dlg [list $bf.bd invoke] bind $dlg [list $bf.bd invoke] wm title $dlg [wm title $gui(W)]\ -\ $title focus $ef.e[string totitle [lindex $editData 0 0]] ::tk::PlaceWindow $dlg widget $gui(W) } ### # # # proc tktwig::editSomethingSaveCallback {w editInfo saveCallback clientData} { set editData {} foreach {n e} $editInfo { lappend editData $n [$e get] } if {[$saveCallback $clientData $editData]} { destroy $w } } ### #------------------------------------------------------------------- # Setup #------------------------------------------------------------------- # # # proc tktwig::setupGUI {{W {.}}} { variable cfg variable gui set gui(W) $W set gui(w) [string trimright $gui(W) .] set w $gui(w) ttk::style theme use clam set M [menu $w.m -tearoff 0] foreach {menu items} [list \ File [list New View Exit] \ Twig [list Run View Sum Edit New Delete] \ Bundle [list Load Append Reload Save "Save As..."] \ Config [list Edit Load Save "Save As..."] \ Help [set helps [list About Readme Usage Messages License]]] { $M add cascade -label $menu -menu [set menuw [menu $M.[string tolower $menu] -tearoff 0]] -underline 0 foreach item $items { $menuw add command -label $item -command [list $cfg(NS)::[string tolower $item]$menu] -underline 0 } } set bf [ttk::frame $w.bf] foreach button [list bundle ntwigs config] { set b [string index $button 0] set gui($button) [set btn$b [ttk::button $bf.btn$b -command [list $cfg(NS)::toggle $button]]] set gui($button,full) false } set gui(lb) [listbox $w.lb -selectmode browse -exportselection 0 -yscrollcommand [list $w.vsb set] -xscrollcommand [list $w.hsb set]] ttk::scrollbar $w.vsb -orient vertical -command [list $gui(lb) yview] ttk::scrollbar $w.hsb -orient horizontal -command [list $gui(lb) xview] grid $btnb -sticky we grid ^ $btnn -sticky we grid ^ ^ $btnc -sticky ew grid $bf -sticky ew grid $gui(lb) $w.vsb -sticky nsew grid $w.hsb -sticky ew grid columnconfigure $bf 0 -weight 1 grid columnconfigure $bf 2 -weight 1 grid rowconfigure $W 1 -weight 1 grid columnconfigure $W 0 -weight 1 $W configure -menu $M wm title $W $cfg(name)\ $cfg(version) bind $gui(W) exit bind $gui(W) exit bind $gui(lb) [list $cfg(NS)::rovosTwig run] bind $gui(lb) [list $cfg(NS)::rovosTwig view] bind $gui(lb) [list $cfg(NS)::reset %W] alias newFile view {} "New file" alias exitFile exit interp alias {} $cfg(NS)::exit {} ::exit foreach a $helps { alias [string tolower $a]Help viewIt $a } foreach a [list run view sum] { alias $a\Twig rovosTwig $a } set gui(defBackground) [$gui(lb) cget -background] set gui(defSelectbackground) [$gui(lb) cget -selectbackground] set cfg(guiCreated) true } ### # # # proc tktwig::args {} { if {$::argc == 0} { return } variable cfg set state opt foreach arg $::argv { switch -exact -- $state { opt { switch -exact -- $arg { -b - -z { set state $arg } -h - -? - -help - --help { puts stderr [usage]; exit 0 } default { puts stderr "Huh? Try -?"; exit 1 } } } -b { set state opt; set cfg(pBundleFile) $arg } -z { set state opt; set cfg(pConfigFile) $arg } } } } ### # # # proc tktwig::setup {} { variable cfg set cfg(NS) [namespace current] set cfg(name) TkTwig set cfg(version) 0.1 set cfg(author) {Stuart Cassoff} set cfg(tclsh) tclsh set cfg(wish) wish set cfg(twig) ~/tcl/twig/twig.tcl set cfg(run) $cfg(wish) set cfg(runPipe) 0 set cfg(configFile) tktwig.conf set cfg(autoloadConfigFile) 1 set cfg(configFileFields) [list tclsh wish twig run bundleFile runPipe autoloadBundleFile] set cfg(bundleFile) mytwigs.twig set cfg(autoloadBundleFile) 1 set cfg(twigs) {} set cfg(twigFields) {page blocks sum url name} set cfg(filetypes,config) {{Twig Configuration Files} .*.conf} set cfg(filetypes,bundle) {{Twig Bundles} .twig} set cfg(filetypes,all) {{All Files} *} set cfg(messages) {} set cfg(guiCreated) false alias reloadBundle loadBundle "" alias appendBundle loadBundle ? true alias save\ as...Bundle saveBundle ? alias save\ as...Config saveConfig ? } ### # # # proc tktwig::depend {} { package require Tcl 8.5- package require Tk 8.5- } ### # namespace eval tktwig { depend; setup; args autoloadConfig setupGUI refreshTwiglist } # # EOF ====== ---- !!!!!! %| [Category Application] | [Category Tcler's Wiki] |% !!!!!!