<> [JOB] 2016-07-08 Playing with TclOO... The following source implements a TclOO megawidget based on [tablelist] with some extended features to manipulate the tablelist content. [WikiDBImage xtablelist_demo.png] **Features** The following additional commands are implemented: * Move selected items up or down, * reverse the list order, * delete selected items, * delete all, but just keep selected items (exceptional delete), * undo previous operations (restore content to it's original state), * save listbox to file, * restore content from file **Source Code** The megawidget source is divided into various files to keep public and private interface separated. As always, the purpose of the code is to gain some more experience in coding with TclOO. ***pkgIndex.tcl*** ====== # Tcl package index file package ifneeded xtablelist 0.3 \ " [list source [file join $dir xtablelist.tcl]]; \ [list source [file join $dir xtablelist_public.tcl]]; \ [list source [file join $dir xtablelist_private.tcl]]; \ [list source [file join $dir xtablelist_readwrite.tcl]]; \ [list source [file join $dir xtablelist_filesel.tcl]]; \ [list source [file join $dir xtablelist_popupmenu.tcl]]; \ " ====== ***xtablelist.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist.tcl --- # ----------------------------------------------------------------------------- # (c) 2016, Johann Oberdorfer - Engineering Support | CAD | Software # johann.oberdorfer [at] gmail.com # www.johann-oberdorfer.eu # ----------------------------------------------------------------------------- # This source file is distributed under the BSD license. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the BSD License for more details. # ----------------------------------------------------------------------------- # Purpose: # A TclOO class template to extend tablelist functionality. # Might be usefull as a starting point. # ----------------------------------------------------------------------------- # TclOO naming conventions: # public methods - starts with lower case declaration names, whereas # private methods - starts with uppercase naming, so we use CamelCase ... # ----------------------------------------------------------------------------- # Credits: # tablelist widget: Copyright (c) 2000-2015 Csaba Nemethi # tooltip: Copyright (c) 1996-2007 Jeffrey Hobbs # autoscroll: Copyright (c) 2003 Kevin B Kenny # icons used from: Open Icon Library # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # widget commands: # xtablelist::xtablelist # xtablelist::configure # xtablelist::cget # # xtablelist::... + all commands from original tablelist # for more sub-command refer as well to the # public class interface # # ----------------------------------------------------------------------------- # widget options # # -xhideoption boolean "yes",1 / "no",0 (default: "yes"), # hide/show popup-menu # to manipulate tablelist column display # default is "yes": show relev. menu items # # -xshowbuttons boolean (default: "yes"), # show sidebar action buttons to manipulate tablelist content # -xsortoption boolean (default: "yes"), # hide/show popup-menu to modify tablelist column sort order # # -xfileread boolean (default: "no"), # allows reading in a previously stored file, # # -xfilesave boolean (default: "no") # allows to saving tablelist data to a file # # -xfilereadpostcmd # file read post command (default: ""), # if defined, allows to e.g. set widget state of depending # action buttons in the caller program # # -xdeletepostcmd # table entry delete post command (default: "") # # -xrefreshpostcmd # executed after a delete / refresh action takes place # # -xselectpostcmd # specify a command to be executed after selecting # an item in the tablelist (default: "") # # -xmoveovereffect # boolean (default: "no"), # enable visual "move over" effect # # virtual events: # # <> - delete, modified or sort action took place # <> - undo, nothing changed so far! # ----------------------------------------------------------------------------- # Hint: # some of the options need to be specified when creating the widget # and are not fully configureable later on once the widget has been # created (open issue to be implemented later on...) # ----------------------------------------------------------------------------- # for development: try to find autoscroll, etc ... set this_file [file normalize [file dirname [info script]]] # where to find required packages... # set auto_path [linsert $auto_path 0 [file join $this_file ".." "contrib" ]] package require Tk package require TclOO package require tablelist_tile package require tooltip package require autoscroll package provide xtablelist 0.3 # workaround for aqua if { [tk windowingsystem] eq "aqua" } { interp alias {} ttk::scrollbar {} ::scrollbar } namespace eval xtablelist { # the widget's interface declaration namespace export \ addValues \ deleteAllItems set this_dir [file dirname [info script]] set image_dir [file join $this_dir "images"] set image_file [file join $this_dir "ImageLib.tcl"] proc LoadImages {image_dir {patterns {*.gif}}} { foreach p $patterns { foreach file [glob -nocomplain -directory $image_dir $p] { set img [file tail [file rootname $file]] if { ![info exists images($img)] } { set images($img) [image create photo -file $file] } }} return [array get images] } proc xtablelist {path args} { # this is a tk-like wrapper around my... class so that # object creation works like other tk widgets set obj [XTableList create tmp $path {*}$args] # rename oldName newName rename $obj ::$path return $path } } # ----------------------------------------------------------------------------- # Tk widget 'a like interface declaration # ----------------------------------------------------------------------------- oo::class create XTableList { variable tblwidget variable widgetOptions variable widgetCompounds constructor {path args} { # --------------------------------------------------------------- # read images from library file or alternatively one by one # --------------------------------------------------------------- set image_file $::xtablelist::image_file set image_dir $::xtablelist::image_dir if { [file exists $image_file] } { source $image_file array set widgetCompounds [array get images] } else { array set widgetCompounds [::tablelistbrowser::LoadImages \ [file join $image_dir] {"*.gif" "*.png"}] } # --------------------------------------------------------------- array set widgetCompounds { undo_flag 0 sortby -1 undoList {} DELIM "@" default_dir "" } # declaration of additional (configureable) widget options array set widgetOptions { -xtabheader {} -xmoveovereffect 1 -xhideoption 1 -xsortoption 1 -xshowbuttons 1 -xfileread 1 -xfilesave 1 -xfilereadpostcmd "" -xdeletepostcmd "" -xrefreshpostcmd "" -xselectpostcmd "" } switch -- $::tcl_platform(platform) { "windows" { set widgetCompounds(default_dir) $::env(TEMP) } "unix" - default { set widgetCompounds(default_dir) $::env(HOME) } } # we use a frame for this specific widget class set f [ttk::frame $path -class xtablelist] # we must rename the widget command # since it clashes with the object being created set widget ${path}_ my Build $f rename $path $widget my configure {*}$args } destructor { # add a destructor to clean up the widget set w [namespace tail [self]] catch {bind $w {}} catch {destroy $w} } method cget { {opt "" } } { my variable tblwidget my variable widgetOptions if { [string length $opt] == 0 } { return [array get widgetOptions] } if { [info exists widgetOptions($opt) ] } { return $widgetOptions($opt) } return [$tblwidget cget $opt] } method configure { args } { my variable tblwidget my variable widgetOptions if {[llength $args] == 0} { # return all tablelist options set opt_list [$tblwidget configure] # as well as all custom options foreach xopt [array get widgetOptions] { lappend opt_list $xopt } return $opt_list } elseif {[llength $args] == 1} { # return configuration value for this option set opt $args if { [info exists widgetOptions($opt) ] } { return $widgetOptions($opt) } return [$tblwidget cget $opt] } # error checking if {[expr {[llength $args]%2}] == 1} { return -code error "value for \"[lindex $args end]\" missing" } # process the new configuration options... array set opts $args foreach opt_name [array names opts] { set opt_value $opts($opt_name) # overwrite with new value if { [info exists widgetOptions($opt_name)] } { set widgetOptions($opt_name) $opt_value } # some options need action from the widgets side switch -- $opt_name { -labelcommand { # replace sortcolumn command by our own method... if { [my GetBoolean $widgetOptions(-xsortoption)] } { $tblwidget configure \ -labelcommand "[namespace code {my SortByColumnCmd}]" } else { $tblwidget configure -labelcommand $opt_value } } -xtabheader { my InitializeTabHeader $opt_value } -xmoveovereffect { if { [my GetBoolean $widgetOptions(-xmoveovereffect)] } { my EnableMoveover } else { $tblwidget configure -activestyle none } } -xhideoption {} -xsortoption {} -xshowbuttons {} -xfileread {} -xfilesave {} -xfilereadpostcmd {} -xdeletepostcmd {} -xrefreshpostcmd {} -xselectpostcmd {} default { # ------------------------------------------------------- # if the configure option wasn't one of our special one's, # pass control over to the original tablelist widget # ------------------------------------------------------- if {[catch {$tblwidget configure $opt_name $opt_value} result]} { return -code error $result } } } } } method insert {method args} { # overloaded tablelist method my variable tblwidget my variable widgetCompounds # maintain undo list + button states... lappend widgetCompounds(undoList) {*}$args # hand over to tablelist widget... if {[catch {$tblwidget insert $method {*}$args} result]} { return -code error $result } my UpdateStatusInfo [$tblwidget get 0 end] } method insertlist {method args} { # overloaded tablelist method my variable tblwidget # maintain undo list + button states... lappend widgetCompounds(undoList) {*}$args if {[catch {$tblwidget insertlist $method {*}$args} result]} { return -code error $result } my UpdateStatusInfo [$tblwidget get 0 end] } method unknown {method args} { # if the command wasn't one of our special one's, # pass control over to the original tablelist widget my variable tblwidget if {[catch {$tblwidget $method {*}$args} result]} { return -code error $result } } } # ----------------------------------------------------------------------------- # Private interface methods # ----------------------------------------------------------------------------- oo::define XTableList { method SortByColumnCmd {args} { my variable tblwidget my variable widgetCompounds # set tbl [lindex $args 0] set idx [lindex $args 1] set widgetCompounds(sortby) $idx ::tablelist::sortByColumn $tblwidget $idx } method InitBindings {} { my variable tblwidget bind [$tblwidget bodypath] { set t [winfo parent %W] set x [expr {%x + [winfo x %W]}] set y [expr {%y + [winfo y %W]}] set oo_my [winfo parent $t] # move up hierachy until our own class is reached: # notes: # - maybe there is a more convinient way to adress a class member function ? # - pls note that the member function needs to start with lowercase char # otherwise it's hidden in global namespace while { [winfo exists $oo_my] } { # puts "--> $oo_my : [winfo class $oo_my]" if { [winfo class $oo_my] == "xtablelist" } { break } set oo_my [winfo parent $oo_my] } $oo_my showContextMenu \ [$t nearestcolumn $x] [$t nearest $y] %X %Y } } method Build {frm} { # build the (mega-) widget # frm - parent frame widget path my variable tblwidget my variable widgetOptions my variable widgetCompounds # status line # ----------- set f [ttk::frame $frm.flabel] pack $f -side bottom -fill both ttk::label $f.lbl -text "" pack $f.lbl -side bottom -fill x -anchor w set widgetCompounds(label) $f.lbl # listbox and two scrollbars embedded into a frame set f [ttk::frame $frm.f] pack $f -side left -fill both -expand true # a.) right set fright [ttk::frame $f.fright] pack $fright -side right -fill y ttk::scrollbar $fright.scrolly -orient vertical pack $fright.scrolly -side top -fill y -expand true ttk::frame $fright.spacery -height 15 pack $fright.spacery -side bottom # b.) left set fleft [ttk::frame $f.fleft] pack $fleft -side left -fill both -expand true # left/top frame set fltop [ttk::frame $fleft.fltop] # left/bottom x scrollbar ttk::scrollbar $fleft.scrollx -orient horizontal # pack scrollbar 1st, so that it won't disappear while panning pack $fleft.scrollx -side bottom -fill x pack $fltop -side top -fill both -expand true # another frame for the tablelist object set fxx [ttk::frame $fltop.fleft] pack $fxx -side top -fill both -expand true ::tablelist::tablelist $fxx.tlist \ -selectmode extended \ -takefocus 0 \ -activestyle none \ -xscrollcommand "$fleft.scrollx set" \ -yscrollcommand "$fright.scrolly set" pack $fxx.tlist -side bottom -fill both -expand true set tblwidget $fxx.tlist bind $tblwidget <> \ "+ [namespace code {my SelectionCallback}]" bind $tblwidget <> \ "+ event generate $tblwidget <>" $fleft.scrollx configure -command "$fxx.tlist xview" $fright.scrolly configure -command "$fxx.tlist yview" # enable auto scrolling... autoscroll::autoscroll $fleft.scrollx autoscroll::autoscroll $fright.scrolly # icon-box for list manipulation ... # ---------------------------------- set f1 [ttk::frame $frm.f1] pack $f1 -side right -fill both if { [my GetBoolean $widgetOptions(-xshowbuttons)] } { ttk::button $f1.b1 -image $widgetCompounds(up) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 1" ::tooltip::tooltip $f1.b1 "Move-Up" pack $f1.b1 -pady 1 set widgetCompounds(b1) $f1.b1 ttk::button $f1.b1i -image $widgetCompounds(reverselist) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 10" ::tooltip::tooltip $f1.b1i "Reverse the list order" pack $f1.b1i -pady 1 set widgetCompounds(b1i) $f1.b1i ttk::button $f1.b2 -image $widgetCompounds(down) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 2" ::tooltip::tooltip $f1.b2 "Move-Down" pack $f1.b2 -pady 1 set widgetCompounds(b2) $f1.b2 ttk::button $f1.b3 -image $widgetCompounds(delete) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 3" ::tooltip::tooltip $f1.b3 "Remove item(s) from the list" pack $f1.b3 -pady 1 set widgetCompounds(b3) $f1.b3 ttk::button $f1.b3i -image $widgetCompounds(delete_reverse) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 5" ::tooltip::tooltip $f1.b3i "Remove All item(s)- except selected" pack $f1.b3i -pady 1 set widgetCompounds(b3i) $f1.b3i ttk::button $f1.b4 -image $widgetCompounds(reload) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 4" ::tooltip::tooltip $f1.b4 "Undo previous operation" pack $f1.b4 -pady 1 set widgetCompounds(b4) $f1.b4 } elseif {$widgetOptions(-xshowbuttons) == "arrows"} { ttk::button $f1.b1 -image $widgetCompounds(up) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 1" ::tooltip::tooltip $f1.b1 "Move-Up" pack $f1.b1 -pady 1 set widgetCompounds(b1) $f1.b1 ttk::button $f1.b2 -image $widgetCompounds(down) \ -style Toolbutton \ -command "[namespace code {my ToolbuttonCallback}] 2" ::tooltip::tooltip $f1.b2 "Move-Down" pack $f1.b2 -pady 1 set widgetCompounds(b2) $f1.b2 } if { [my GetBoolean $widgetOptions(-xfileread)] } { ttk::button $f1.b8 -image $widgetCompounds(folder) \ -style Toolbutton \ -command "[namespace code {my OpenFromFile}]" ::tooltip::tooltip $f1.b8 "Open Listbox content from file" pack $f1.b8 -pady 1 -side bottom set widgetCompounds(b8) $f1.b8 } if { [my GetBoolean $widgetOptions(-xfilesave)] } { ttk::button $f1.b5 -image $widgetCompounds(filesaveas) \ -style Toolbutton \ -command "[namespace code {my Save2File}]" ::tooltip::tooltip $f1.b5 "Save Listbox to file" pack $f1.b5 -pady 1 -side bottom set widgetCompounds(b7) $f1.b5 } # disabled by default: if { [my GetBoolean $widgetOptions(-xshowbuttons)] } { $widgetCompounds(b1) configure -state disabled $widgetCompounds(b2) configure -state disabled $widgetCompounds(b3) configure -state disabled $widgetCompounds(b3i) configure -state disabled $widgetCompounds(b4) configure -state disabled } elseif {$widgetOptions(-xshowbuttons) == "arrows"} { $widgetCompounds(b1) configure -state disabled $widgetCompounds(b2) configure -state disabled } #$tlist($w,b6) configure -state disabled if { [my GetBoolean $widgetOptions(-xfilesave)] } { $widgetCompounds(b7) configure -state disabled } # note: There is also a popup-menu, which corresponds with # the button box. So, if you do any changes here, # do not forget to maintain there as well! set widgetCompounds(mstate) disabled my InitBindings } } ====== ***xtablelist_public.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist_public.tcl --- # ----------------------------------------------------------------------------- # Purpose: # A TclOO class template to extend tablelist functionality. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Public interface # ----------------------------------------------------------------------------- oo::define XTableList { method info {} { puts [self class] } method selectArrowCallback {} { # this function is called every time an up-down arrow is selected # by default, it's empty, but can be predefined to suit the needs # in the caller application set dummy 0 } # unused method deleteAllItems {} { my variable tblwidget my variable widgetCompounds $tblwidget delete 0 end my UpdateStatusInfo {} # "Undo" button also needs to be disabled if { [winfo exists widgetCompounds(b4)] } { $widgetCompounds(b4) configure -state disabled } } method addValues {lst {mode ""}} { my variable tblwidget my variable widgetCompounds if {![info exists widgetCompounds(undoList)]} { set widgetCompounds(undoList) {} } # re-initialize variable (if necessary) if {$mode == ""} { $tblwidget delete 0 end set widgetCompounds(undoList) {} } # populate columns with information ... # ------------------------------------- set cnt 0 foreach sublist $lst { $tblwidget insert end $sublist lappend widgetCompounds(undoList) $sublist incr cnt } # update status text my UpdateStatusInfo $lst } } ====== ***xtablelist_private.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist_private.tcl --- # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # Private interface methods # ----------------------------------------------------------------------------- oo::define XTableList { method GetBoolean {value {errorValue 1}} { # returns the value of a (presumably) boolean string (ie: it should # do the right thing if the string is "yes", "no", "true", 1, etc # # value - value to be converted # errorValue - a default value to be returned in case of an error # # Returns: # a 1 or zero, or the value of errorValue if the string isn't # a proper boolean value if {[catch {expr {([string trim $value])?1:0}} res]} { return $errorValue } else { return $res } } method GetTblColumnNames {} { # retrieve all column names, regardless if they are hidden or not my variable tblwidget set col_names {} foreach {with name pos} [$tblwidget cget -columns] { lappend col_names $name } return $col_names } method GetOnlyVisibleTblColumnNames {} { # retrieve only column names which are not hidden my variable tblwidget set cnt 0 set col_names {} foreach {with name pos} [$tblwidget cget -columns] { if { ! [$tblwidget columncget $cnt -hide] } { lappend col_names $name } incr cnt } return $col_names } method InitializeTabHeader {kword_list} { my variable tblwidget set cols "" set cnt 0 foreach i $kword_list { set descr [lindex $i 0] set visual [lindex $i 1] set orient [lindex $i 2] if {[string length $orient] == 0} { set orient "left" } regsub -all " " $descr "_" descr if {$descr != "..." && [string range $descr end end] != ":"} { set descr "${descr}:" } # could be either a string or an integer: if {$visual == "hidden"} { set width 20 } else { set width $visual } append cols "$width $descr $orient " incr cnt } $tblwidget configure -columns $cols # hide specific columns as indicated with "hidden" in declaration array set cnt 0 foreach i $kword_list { if {[set width [lindex $i 1]] == "hidden"} { $tblwidget columnconfigure $cnt -hide yes } incr cnt } # expand last *visible* column # ---------------------------- set cnt 0 set lastcol 0 # tablelist -columns option are always 3 attributes each... foreach {w col pos} [$tblwidget cget -columns] { if {[$tblwidget columncget $cnt -hide] == 0} {set lastcol $cnt} incr cnt } if {$lastcol > 0} { $tblwidget configure -stretch $lastcol } } method SelectionCallback {} { my variable tblwidget my variable widgetCompounds my variable widgetOptions if { ![my GetBoolean $widgetOptions(-xshowbuttons)] } { return } # manage visualisation mode of toolboxes set csel [$tblwidget curselection] if {$widgetOptions(-xshowbuttons) == "arrows"} { if {$csel == {}} { $widgetCompounds(b1) configure -state disabled $widgetCompounds(b2) configure -state disabled } else { $widgetCompounds(b1) configure -state normal $widgetCompounds(b2) configure -state normal } } else { if {$csel == {}} { $widgetCompounds(b1) configure -state disabled $widgetCompounds(b2) configure -state disabled $widgetCompounds(b3) configure -state disabled $widgetCompounds(b3i) configure -state disabled } else { $widgetCompounds(b1) configure -state normal $widgetCompounds(b2) configure -state normal $widgetCompounds(b3) configure -state normal $widgetCompounds(b3i) configure -state normal } } # does it make sense to enable undo button: if {$widgetCompounds(undo_flag) == 1} { $widgetCompounds(b4) configure -state normal event generate $tblwidget <> } else { $widgetCompounds(b4) configure -state disabled event generate $tblwidget <> } # move-up if {[lsearch $csel 0] != -1} { $widgetCompounds(b1) configure -state disabled } # move-down set data [$tblwidget get 0 end] set len [expr [llength $data] -1] if {[lsearch $csel $len] != -1} { $widgetCompounds(b2) configure -state disabled } # evaluate post command in parent namespace... if {$widgetOptions(-xselectpostcmd) != ""} { catch {uplevel $widgetOptions(-xselectpostcmd)} } } method UpdateStatusInfo {lst} { # method to maintain additional status information my variable tblwidget my variable widgetCompounds my variable widgetOptions set msg "" switch -- [set cnt [llength $lst]] { 0 { $widgetCompounds(label) configure -text "Tablelist is empty." if { [my GetBoolean $widgetOptions(-xfilesave)] } { $widgetCompounds(b7) configure -state disabled } # required to manage state, when the widget is popping up! set widgetCompounds(mstate) disabled # maintain pop-up menu # note: catch is required if the pop-up is not "pinned" on # the screen (which is most likely the case!) if { [my GetBoolean $widgetOptions(-xhideoption)] } { set idx_list {8 9 10} } else { set idx_list {5 6 7} } $widgetCompounds(b1i) configure -state disabled return } 1 { $widgetCompounds(b1i) configure -state disabled $widgetCompounds(label) configure -text "1 item in tablelist. $msg" } default { $widgetCompounds(b1i) configure -state normal $widgetCompounds(label) configure -text "$cnt items in tablelist. $msg" } } if { [my GetBoolean $widgetOptions(-xfilesave)] } { $widgetCompounds(b7) configure -state normal } set widgetCompounds(mstate) normal if { [my GetBoolean $widgetOptions(-xhideoption)] } { set idx_list {8 9 10} } else { set idx_list {5 6 7} } catch { # @@@ foreach idx $idx_list { $widgetCompounds(m_$tblwidget) entryconfigure $idx -state normal } } } method ToolbuttonCallback {nr} { my variable tblwidget my variable widgetCompounds my variable widgetOptions # refresh if {$nr == 4} { $tblwidget delete 0 end eval $tblwidget insert end $widgetCompounds(undoList) set widgetCompounds(sortby) -1 set widgetCompounds(undo_flag) 0 my UpdateStatusInfo $widgetCompounds(undoList) # evaluate post command in parent namespace... if {$widgetOptions(-xrefreshpostcmd) != ""} { catch {uplevel $widgetOptions(-xrefreshpostcmd)} } my SelectionCallback return } # reverse the list if {$nr == 10} { set data [$tblwidget get 0 end] set data_len [llength $data] set csel [$tblwidget curselection] set reversed_data {} set reversed_csel {} for {set cnt [expr {$data_len -1}]} {$cnt >= 0} {incr cnt -1} { lappend reversed_data [lindex $data $cnt] } foreach idx $csel { lappend reversed_csel [expr {$data_len - $idx }] } $tblwidget delete 0 end eval $tblwidget insert end $reversed_data # highlight again ... foreach idx $reversed_csel { set idx1 [expr {$idx -1}] $tblwidget selection set $idx1 $idx1 } # re-position listbox acc. to current selection set csel [$tblwidget curselection] $tblwidget see [lindex $csel 0] my selectArrowCallback set widgetCompounds(undo_flag) 1 } set csel [$tblwidget curselection] if {$csel == {}} { # call get's important, if more than one widgets exists # at the same time, and the focus get's lost/shiftet: # action buttons are still enabled, but # the following call 'll disable them accordingly my SelectionCallback return } switch -- $nr { 1 { # move-up if {[lsearch $csel 0] != -1} { return } set data [$tblwidget get 0 end] for {set cnt 0} {$cnt < [llength $data]} {incr cnt} { set cnt0 [expr $cnt -1] set tmp0 [lindex [lrange $data $cnt0 $cnt0] 0] set tmp [lindex [lrange $data $cnt $cnt] 0] if {[lsearch $csel $cnt] != -1} { set data [lreplace $data $cnt0 $cnt0 $tmp] set data [lreplace $data $cnt $cnt $tmp0] } } $tblwidget delete 0 end eval $tblwidget insert end $data # highlight again ... foreach idx $csel { set idx0 [expr $idx -1] $tblwidget selection set $idx0 $idx0 } # 06.06.05: and (!) position listbox as it was before! $tblwidget see [lindex $csel 0] my selectArrowCallback set widgetCompounds(undo_flag) 1 } 2 { # move-down set data [$tblwidget get 0 end] set len [expr [llength $data] -1] if {[lsearch $csel $len] != -1} { return } set cnt 0 for {set cnt [llength $data]} {$cnt >= 0} {incr cnt -1} { set cnt1 [expr $cnt +1] set tmp1 [lindex [lrange $data $cnt1 $cnt1] 0] set tmp [lindex [lrange $data $cnt $cnt] 0] if {[lsearch $csel $cnt] != -1} { set data [lreplace $data $cnt $cnt $tmp1] set data [lreplace $data $cnt1 $cnt1 $tmp] } } $tblwidget delete 0 end eval $tblwidget insert end $data # highlight again ... foreach idx $csel { set idx1 [expr $idx +1] $tblwidget selection set $idx1 $idx1 } # set visual region as it was before... $tblwidget see [lindex $csel 0] my selectArrowCallback set widgetCompounds(undo_flag) 1 } 3 { # does not work with empty lines: # foreach i [lsort -decreasing $csel] { $w delete $i $i } set data [$tblwidget get 0 end] set cnt 0 for {set cnt [llength $data]} {$cnt >= 0} {incr cnt -1} { # check if index is within current selection # if true - remove list item ! if {[lsearch $csel $cnt] != -1} { set data [lreplace $data $cnt $cnt] } } $tblwidget delete 0 end eval $tblwidget insert end $data my UpdateStatusInfo $data # evaluate post command in parent namespace... if {$widgetOptions(-xdeletepostcmd) != ""} { catch {uplevel $widgetOptions(-xdeletepostcmd)} } set widgetCompounds(undo_flag) 1 } 5 { # inverse delete = delete all, except selected set data [$tblwidget get 0 end] set new_data {} for {set cnt 0} {$cnt < [llength $data]} {incr cnt 1} { # check if the current index is *not* part of the selection ... if {[lsearch $csel $cnt] != -1} { lappend new_data [lindex $data $cnt] # puts "--> [lindex $data $cnt]" } } $tblwidget delete 0 end eval $tblwidget insert end $new_data my UpdateStatusInfo $new_data # evaluate post command in parent namespace... if {$widgetOptions(-xdeletepostcmd) != ""} { catch {uplevel $widgetOptions(-xdeletepostcmd)} } set widgetCompounds(undo_flag) 1 } } my SelectionCallback } method EnableMoveover {} { my variable tblwidget # move-over effect: bind [$tblwidget bodypath] {+ set t [winfo parent %W] set x [expr {%x + [winfo x %W]}] set y [expr {%y + [winfo y %W]}] # set cell [$t nearestcell $x $y] # puts "Clicked on cell: $cell " # set rownum [lindex [split $cell ","] 0] focus $t $t configure -activestyle frame $t activate "@$x,$y" } bind [$tblwidget bodypath] {+ set t [winfo parent %W] $t configure -activestyle none } } } ====== ***xtablelist_popupmenu.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist_popupmenu.tcl --- # ----------------------------------------------------------------------------- oo::define XTableList { # unused method showColumnByIndex {idx} { my variable tblwidget my variable widgetCompounds set cnt 0 foreach column [my GetTblColumnNames] { if {$cnt == $idx} { $tblwidget columnconfigure $cnt -hide false set widgetCompounds(hide_column,$cnt) 0 } incr cnt } } # sort the list based on a particular column method SortCmd {index} { my variable tblwidget my variable widgetCompounds $tblwidget sortbycolumn $index set widgetCompounds(sortby) $index } method HideColumnCmd {index} { my variable tblwidget my variable widgetCompounds # hiding all columns doesn't make sense ... if {[llength [my GetOnlyVisibleTblColumnNames]] == 1} { tk_messageBox \ -parent $tblwidget \ -title "Warning" \ -icon "warning" \ -message "Cannot hide all columns!" \ -type ok return } if { $widgetCompounds(hide_column,$index) } { $tblwidget columnconfigure $index -hide true } else { $tblwidget columnconfigure $index -hide false } } method ShowAllColumnsCmd {} { my variable tblwidget my variable widgetCompounds set cnt 0 foreach column [my GetTblColumnNames] { $tblwidget columnconfigure $cnt -hide false set widgetCompounds(hide_column,$cnt) 0 incr cnt } } method showContextMenu {colx coly rootx rooty} { # x,y are the coordinates relative to the upper-left corner of the # listbox; rootx,rooty are screen coordinates (for knowing where # to place the menu). w is the name of the mclistbox widget that was # clicked on. my variable tblwidget my variable widgetOptions my variable widgetCompounds # re-create widget all the time: set contextMenu $tblwidget.tblContextMenu catch {destroy $contextMenu} set columnLabel [$tblwidget columncget $colx -title] set colIndex $colx set column $columnLabel set m [menu $contextMenu -tearoff 1] if { [my GetBoolean $widgetOptions(-xsortoption)] } { menu $m.sort_by -tearoff 1 $m add cascade \ -label "Sort by ..." \ -menu $m.sort_by set cnt 0 set cbrk_cnt 0 set col_names [my GetOnlyVisibleTblColumnNames] foreach i $col_names { # manage multi column menu, otherwise the menu limits # would exceed screen dimensions # --------------------------------------------------- if {[llength $col_names] > 39} { if {$cbrk_cnt < 10} { incr cbrk_cnt set cbrk 0 } else { set cbrk_cnt 1 set cbrk 1 } } else {set cbrk 0} # --------------------------------------------------- $m.sort_by add radiobutton \ -variable "[namespace current]::widgetCompounds(sortby)" \ -value $cnt \ -label $i \ -command "[namespace code {my SortCmd}] $cnt" \ -columnbreak $cbrk incr cnt } $m add command \ -label "Sort by: $columnLabel" \ -command "[namespace code {my SortCmd}] $colIndex" $m add separator } # -------------------------------------------------- # *only* show context-menu if specified by argument: # -------------------------------------------------- if { [my GetBoolean $widgetOptions(-xhideoption)] } { menu $m.hide_column -tearoff 1 $m add cascade \ -label "Hide column..." \ -menu $m.hide_column # $m.hide_column add command \ # -label "Hide column:" -state disabled set cnt 0 set cbrk_cnt 0 set col_names [my GetOnlyVisibleTblColumnNames] foreach i $col_names { # manage multi column menu, otherwise the menu limits # would exceed screen dimensions # --------------------------------------------------- if {[llength $col_names] > 39} { if {$cbrk_cnt < 10} { incr cbrk_cnt set cbrk 0 } else { set cbrk_cnt 1 set cbrk 1 } } else {set cbrk 0} # --------------------------------------------------- set colLabel [$tblwidget columncget $cnt -title] $m.hide_column add checkbutton \ -variable "[namespace current]::widgetCompounds(hide_column,$cnt)" \ -label $colLabel \ -command "[namespace code {my HideColumnCmd}] $cnt" \ -columnbreak $cbrk incr cnt } $m add command \ -label "Hide column: $columnLabel" \ -command "\ set [namespace current]::widgetCompounds(hide_column,$colIndex) 1; [namespace code {my HideColumnCmd}] $colIndex" # separator doesn't work in column mode if {[llength $col_names] <= 39} { $m.hide_column add separator } foreach m_item [list $m $m.hide_column] { $m_item add command \ -label "Show All" \ -command "[namespace code {my ShowAllColumnsCmd}]" } $m add separator } # manage visualisation mode # [$w get 0 end] is too slow if the listbox is pretty full... if {[info exists widgetCompounds(mstate)]} { set st $widgetCompounds(mstate) } else { set st disabled } $m add command \ -label "File Operations:" -state disabled if { [my GetBoolean $widgetOptions(-xfilesave)] } { $m add command \ -label "Save to file..." \ -command "[namespace code {my Save2File}]" \ -state $st } if { [my GetBoolean $widgetOptions(-xfileread)] } { $m add command \ -label "Open from file..." \ -command "[namespace code {my OpenFromFile}]" \ -state $st } # ----------------------- tk_popup $m $rootx $rooty # ----------------------- # make sure, popup-window stays on top # when using "tear-off" the 1st time wm withdraw $m wm deiconify $m } } ====== ***xtablelist_readwrite.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist_readwrite.tcl --- # ----------------------------------------------------------------------------- oo::define XTableList { method GetAllVisibleItems {} { # only take visible columns into account # "...what you see is what you get..." my variable tblwidget set is_hidden {} set cnt 0 foreach column [my GetTblColumnNames] { lappend is_hidden [$tblwidget columncget $cnt -hide] incr cnt } set lst {} foreach i [$tblwidget get 0 end] { set cnt 0 set sublst {} foreach xitem $i { if {[lindex $is_hidden $cnt] != 1} { lappend sublst $xitem } incr cnt } lappend lst $sublst } return $lst } method Write2File {fname} { my variable tblwidget my variable widgetCompounds if {$fname == ""} { return } set lst [my GetAllVisibleItems] set fp [open $fname "w"] foreach i $lst { # regsub -all "\{" $i "" i # regsub -all "\}" $i "" i set str "" foreach item $i { if {$str == ""} { set str $item } else { append str $widgetCompounds(DELIM) append str $item } } puts $fp $str } close $fp } method Save2File {} { my variable tblwidget #-now we use this one- set fname [xtablelist::getfilename \ -parent $tblwidget \ -title "Select file where to store Listbox information:" \ -oktext " Save to File... "] if {[string length $fname] > 0} { my Write2File $fname } } method OpenFromFile {} { my variable tblwidget my variable widgetCompounds set in_file [ \ tk_getOpenFile \ -parent $tblwidget \ -title "Select file:" \ -initialdir $widgetCompounds(default_dir) \ -defaultextension {.txt} \ -filetypes {{"Text-Files" "*.txt*"} {all "*.*"}} \ -initialfile ""] # read values from file and uptdate listbox ... if {$in_file != ""} { set data {} set fp [open $in_file "r"] while {![eof $fp]} { set i [string trim [gets $fp]] if {$i != ""} { lappend data [split $i $widgetCompounds(DELIM)] } } close $fp # foreach i $data {puts "--> $i <--"} my addValues $data # finally execute post command catch { $widgetOptions(-xfilereadpostcmd) } } } } ====== ***xtablelist_filesel.tcl*** ====== # ------------------------------------------------------------------------- # xtablelist_filesel.tcl --- # ------------------------------------------------------------------------- # # Purpose: # Utility package supporting a more convinient file selection dialog. # The following additional features where added: # - the possibility to generate a file-name, # - use the dialog's default file-name, # which might be sufficient for most of all cases, # - use standard file selection dialog # # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- # file action utility dialog ... # ------------------------------------------------------------------------- namespace eval xtablelist { variable widgetDefaults variable widgetImages switch -- $::tcl_platform(platform) { "windows" { set homeDir $::env(TEMP) } "unix" - default { set homeDir $::env(HOME) } } array set widgetDefaults { title "Selection file:" DEFNAME "NONAME" def_ext ".txt" oktext " OK " ENTRY_WITH 45 is_ok 0 } set widgetDefaults(init_dir) $homeDir set widgetDefaults(defaultfile) [file join $homeDir "NONAME.txt"] set widgetDefaults(filetypes) {{"Text-Files" "*.txt*"} {all "*.*"}} # initializing required images... set imgdir [file join [file dirname [info script]] "images"] proc LoadImages1 {imgdir {patterns {*.gif *.png}}} { foreach pattern $patterns { foreach file [glob -nocomplain -directory $imgdir $pattern] { set img [file tail [file rootname $file]] if { ![info exists images($img)]} { set images($img) [image create photo -file $file] } } } return [array get images] } array set widgetImages [LoadImages1 $imgdir] } proc xtablelist::PositionWindow {} { variable widgetDefaults wm geometry $widgetDefaults(this) "+250+350" } proc xtablelist::_ok_callback {} { variable widgetDefaults if [file exists [set fname [$widgetDefaults(input_entry) get]]] { set answer [tk_messageBox \ -parent $widgetDefaults(this) \ -title "Question: " \ -message "$fname\nalready exists\noverwrite ?" \ -type yesno -icon question] if {$answer eq "no"} { set widgetDefaults(is_ok) 2 return } } set widgetDefaults(is_ok) 1 } proc xtablelist::EntryBindingsCmd {} { variable widgetDefaults variable widgetImages if {[$widgetDefaults(input_entry) get] == ""} { $widgetDefaults(input_label) configure -image $widgetImages(isempty) $widgetDefaults(ok_button) configure -state disabled } else { $widgetDefaults(input_label) configure -image $widgetImages(ok) $widgetDefaults(ok_button) configure -state normal } } proc xtablelist::SelectFileCmd {} { variable widgetDefaults variable widgetImages set log_file [tk_getSaveFile \ -initialdir $widgetDefaults(init_dir) \ -defaultextension $widgetDefaults(def_ext) \ -filetypes $widgetDefaults(filetypes) \ -initialfile "" -title "Select file dialog..." \ -parent $widgetDefaults(this)] if {$log_file != ""} { set widgetDefaults(init_dir) [file dirname $log_file] set widgetDefaults(entry_val) $log_file $widgetDefaults(input_label) configure -image $widgetImages(ok) $widgetDefaults(ok_button) configure -state normal } } proc xtablelist::GenerateFilename {} { variable widgetDefaults variable widgetImages # note: it is not possible under windows to use ":" as date separator! # clock format [clock seconds] -format "%H:%M:%S" set fname [clock format [clock seconds] -format "%Y-%m-%d"] append fname "_" append fname $widgetDefaults(DEFNAME) append fname $widgetDefaults(def_ext) set widgetDefaults(entry_val) [file join $widgetDefaults(init_dir) $fname] $widgetDefaults(input_label) configure -image $widgetImages(ok) } proc xtablelist::CancelCmd {} { variable widgetDefaults set widgetDefaults(is_ok) 2 } # ------------------------------------------------------------------------- # gui declaration # ------------------------------------------------------------------------- proc xtablelist::getfilename {args} { variable widgetDefaults variable widgetImages set wparent "" set ind 0 while { $ind < [llength $args] } { switch -exact -- [lindex $args $ind] { "-parent" { incr ind set wparent [lindex $args $ind] incr ind } "-title" { incr ind set widgetDefaults(title) [lindex $args $ind] incr ind } "-defaultfile" { incr ind set widgetDefaults(defaultfile) [lindex $args $ind] incr ind } "-defaultext" { incr ind set widgetDefaults(def_ext) [lindex $args $ind] incr ind } "-filetypes" { incr ind set widgetDefaults(filetypes) [lindex $args $ind] incr ind } "-oktext" { incr ind set widgetDefaults(oktext) [lindex $args $ind] incr ind } default { puts "unknown option [lindex $args $ind]" return "" } } } set w $wparent.getfilename set widgetDefaults(this) $w catch {destroy $w} toplevel $w wm title $w $widgetDefaults(title) wm iconname $w $widgetDefaults(title) PositionWindow wm transient $w $wparent bind $w "[namespace current]::CancelCmd" set f [ttk::frame $w.info -relief flat] pack $f -side top -fill x -padx 1 -pady 1 ttk::label $f.img -image $widgetImages(job_engineering_logo) set msg " Select a filename or press \"generate-filename\" to create one." ttk::label $f.msg -text $msg pack $f.img $f.msg -side left # button row # ---------- set f [ttk::frame $w.buttons -relief groove] pack $f -side bottom -fill x -pady 2 # image + button # -------------- set fb [ttk::frame $f.img_button] # pack follows later on: pack $fb -side left -fill x -expand true ttk::button $fb.ok \ -text $widgetDefaults(oktext) \ -image $widgetImages(filesaveas) \ -compound left \ -command "[namespace current]::_ok_callback" \ -state disabled pack $fb.ok -side left -padx 4 -pady 4 set widgetDefaults(ok_button) $fb.ok ttk::button $f.cancel \ -text "Cancel" \ -command "[namespace current]::CancelCmd" pack $fb $f.cancel -side left -padx 4 -pady 4 -expand true set f [ttk::frame $w.rbuttons] pack $f -side bottom -fill x -padx 2 -pady 2 ttk::button $f.getlatest \ -text "Generate filename ..." \ -command "[namespace current]::GenerateFilename" \ -style Toolbutton pack $f.getlatest -padx 4 -pady 4 set f_file1 [ttk::frame $f.part_num1] pack $f_file1 -fill x -expand true ttk::label $f_file1.img -image $widgetImages(isempty) pack $f_file1.img -side left set widgetDefaults(input_label) $f_file1.img pack [ttk::label $f_file1.lb -text "File-name:"] -side left ttk::entry $f_file1.en \ -width $widgetDefaults(ENTRY_WITH) \ -textvariable "[namespace current]::widgetDefaults(entry_val)" pack $f_file1.en -side left -fill x -padx 4 -expand true set widgetDefaults(input_entry) $f_file1.en ttk::button $f_file1.b \ -text "..." \ -command "[namespace current]::SelectFileCmd" pack $f_file1.b -side left bind $widgetDefaults(input_entry) "[namespace current]::EntryBindingsCmd" bind $widgetDefaults(input_entry) "[namespace current]::EntryBindingsCmd" set widgetDefaults(entry_val) $widgetDefaults(defaultfile) focus $widgetDefaults(input_entry) if {[$widgetDefaults(input_entry) get] != ""} { $widgetDefaults(input_label) configure -image $widgetImages(ok) $widgetDefaults(input_entry) selection range 0 end $widgetDefaults(ok_button) configure -state normal } # wait user grab $widgetDefaults(this) tkwait variable "[namespace current]::widgetDefaults(is_ok)" grab release $widgetDefaults(this) if { $widgetDefaults(is_ok) == 1 } { set retval [$widgetDefaults(input_entry) get] } else { set retval "" } destroy $w return $retval } # ------------------------------------------------------------------------- # test-run ... # ------------------------------------------------------------------------- if 0 { package require Tk wm withdraw . catch {console show} set rval [xtablelist::getfilename \ -parent "" \ -title "Select file where to store Listbox information:" \ -defaultfile [file join $env(HOME) "Test.txt"] \ -filetypes {{"Text-Files" "*.txt"} {all "*.*"}} \ -defaultext ".txt" \ -oktext " Save to File... "] puts "File selection result: \"$rval\"" } ====== ***ImageLib.tcl*** ====== # ImageLib.tcl --- # Automatically created by: CreateImageLib.tcl set images(up) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAABl0RVh0 U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAL/SURBVDiNtZRNaFxVFMd/5368eZkxRmQs bTEGxbZC0IWMpU5SbCmxILapFCO2LgSlWbhLbFJBcKErP0BcCIqCdeEiUAviQoJIwIgW3biwCoYG jTImTIXWTjsz7+O4yLzwUkuSgjlwuPdd7vmd/z33vCuqymaY2RTqZoLdRjfunXTvg2zfNh8PT01p 8r+AByf9S9vv6DuGQWr627vA6Hox65ZiYMIdva1Ufvlg9WhpaM+RYs+t5eN7J4IX1ouTtbpicCyo FEulmacOniidr8+SpBG7ynv4dPrjxpVW48i3b0Rf3rTiR8al13o3/cSBZ0uLV+f46/IFapfmWLh8 nsf2PVnyzp0ZnAx33RR4cFK6U2dnDu97pie1LS5c/BFnHNZ4fl36nkZSZ6h6qBuNv6qOye0bAo+M iFXc54/uHundUt5qfln6Dmt8xx2I8MPCF5RuKcrAg0NbjHfTlVHx64Jrd9v3qv1Du/t3VPxPta+x YvHOUwgCfGBQ28Z45dzCWfruvMfdf+9D/V099vSa4IEX/fh9d1WO7a8Mhz/XZjFOCMMCYVggCD2R aeAKQlAw4CPO/XmGygMPh33bdg5XJ/ypPGulK6rj7vG+rTumnjt0qss5j5KikjAzf5pYWtSvzXMt +Wc5SuHwzpNoqmgKzXaLs9OfXK1f/OPp2bfizyD3gxgr478vznW98sHzAFgvzVdPfBj6wNFoLxLZ Bt4bBFAF44R3PnqtGbc17CCKOBkDVoNnX4/2X1cWNdbiA8+V1hK+YDAGEEFVsVaI2xp+82Yk19d3 FfhGZozQiP9GbYwLBOMEEUFTRewNeRsEi6WZXkIMGCs4bzBOiNspsjZ3dVfIsjkRKWRrzbgBCppC mihJpGgC6EpMUUQKIrJKpMuAgO98u84cVTjQO4pKirEgIizfHqTpyhvTDcRAJCJxNne5BDYHdUD9 5NvHy2sfmHomImcKJKKqmeI8NBuzZKbjHb2kHY+BJFMJtIG2qqb/eTY7SWzOM6jtbElz8CQHV83B /gXtSQriGSyg6AAAAABJRU5ErkJggg== }] set images(filesaveas) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAAXNSR0IArs4c6QAAAU1QTFRFtQBI AAAAOGeLP2qJO2yRP2yGQWyKPG2RQm6IZmhkSW6CZ2lkQnCSP3KWTXKCVHJ7bnBrRHicVHeAV3h9 TXmRbXRlbnRlUXmKU3mKW3pycnVrR32iR32jXnx5YH1udXlsSoCmW36ISoCod3l1ToewfIFtbIV3 UIixUImyf4F+UYu1aImTU4y1cIqCg4WAbY2OWJK9W5bBYpa7XJfDjo+NXpnGXprHYJzKYJ3LlJaR Yp/OY6DOY6HQZ6LOZ6PSa6XTm52ZdKjTdKjUdanVga3Rj7bbsbGwuLi4yMjIysrKy8vLzMzLytDE zs7Oz8/NzNHF0NDQ0tbM09jM2NrY3t7e3t7f397e3t/f39/e39/f4ODg4eHh4eLh4uLh4+Pj5eXl 5ubm5+fn6Ojo6eno6uvq6+vr7Ozs7e3t7u7u8PDv8PDw8PDx9vb2+vn6////640m9AAAAAF0Uk5T AEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYLFTEZSbLK vAAAACJ0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUCBvbiBhIE1hY4eod0MAAAEjSURBVBjT bc9nV8IwFIDhNKJ1G/feVXBhapGoqLgnLowURa2oqSv2/3/0pvRAOfh+aO95mnNPihBCsz0YauhG 1bWuHOwe7qcGmqu0f6uzLTKS2ktP1YV0dHkSno3DyaQ5UV/h9iX/FVmk5lrXWJkHZwg0jim00KHm kg9Jlc8Mq7HkcVcKITCNUbqJhbgVcZ933HcJ91a8gXX8KNaVkvNnOMvYdmyemtYqnL9UW8gL8I3O jKgRMyz9SghX8bS/OoOZYUQtnBFCunPACdeR8kO5r1I6bgJ2HBffivBBZjHTs4DO08MRQS3XJKgX 9wXTRRMikti5O27zPOd2jms8fw+ESIG8npb71L5+voEU/1bY0zzPC9gLFeKaFJ8VajqB3yT/hP4A lj1VqgSJVQgAAAAASUVORK5CYII= }] set images(folder) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAAXNSR0IArs4c6QAAAhlQTFRFAAAN PDw8RUVFRkZGSkpKTU1NLFWJUlJSVVVVOVqFVVdTVlhUVllXV1lVWFpWWlpaWVtYWlxZWlxbW11Z M2OhXF5bXl5eNGShNGSiXV9bXl9cNWWkNWakNWalNWelNmekYWFhNmelNmemN2ilN2imOGmmOWmn OWmoO2mlOmuoZWVlPGumQW+pRG+ma2tqQnKvb29vTHSmcnJyVnqmdnZ2TX22VX6xToC2enp6UYG4 e3t7YH+laX+aa4SlXom9dYumkZGQcJjFc5nEj5ehi5iolpeVcJ7PcZ7PdKDQnJ2bnJ2cgKLLm5+j np+hn6CeoKCffKbTfabUfqfUoqOlgKnVhqjPpKWnhKvVpaamhKvWpqampqeph63XqKioja3Sia7Y qqqqiq/Yq6uri7DZjLHXrKysjbHZra2tjrLYj7LakLLZjrPZrq6ukLPZr6+vlbPWkrTbkrXakrXb sbGxlLbblLbclbbclLfclbfcs7Ozlrjclrjdm7fZl7jctbW0nbnamrrdnbzeubm5ob7eor/go7/e vb29p8Hep8HfqMPiqcTiwcHBqcXiqsXhxMTEycnIts7my8vLzc3Nz8/P0NDQvtPq0NHQv9TqwNTq 0tLS09PT1dXU1NXX2tra3Nzc3d3d4ODg4eHh4uLi4uPl4+Pj4+Tm5OXn5eXl5ebo5ubm5ufp6enp 9/f3+Pj4+fn5+vr6+/v7/f39/v7+lBbl4QAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBI WXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYLFTEsHwEOnwAAACJ0RVh0Q29tbWVudABDcmVhdGVk IHdpdGggR0lNUCBvbiBhIE1hY4eod0MAAAE3SURBVBjTY2CAAm5ebl5ePj4pBlTAvWbtuvUbNvgL QPkWVmDANXfWrJmTJ21yEIUIm8yaMnnSpIlc87yAYPamja6CYGGjyZV56UkJ3IsWLVy4YMHq5VMk wcIGk/JSE2KjuFf6eXp6zl+yZJowWFivPzU6LNiXZ9WKFcuWLV26eI4QWFirz0VeVVVVWU1NDUip qqjIyCoBhRW67Z2mT506dToEzJgxY4I0UFiszda7JxsJVPWqAIX5m6zjuoqQQHmrOlCYo864prMa AZJL6zWBwuzFhu2dDTBQmxbTmA8SZs3R7WgBCVSUFGTGx8TENIaqAYVZEjSayxIjgwJgoNBRDijM FCGT5eGOBMLtQN5h8tEOcUMGgaZgYWez3BRkkKEPEma20bFEAeaKIGFGTnEUICHCxkAiAADVtH2Y SZPqewAAAABJRU5ErkJggg== }] set images(mail) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAAXNSR0IArs4c6QAAAsRQTFRFNmut VTFgXzRlQD1zHUeBHkiCWzxYIkqFdDpQJUyHbD86J06Jb0oLNFCHYFETR1Q/MFaMMVeNQlSNYU19 f1IEJF+fNluSQlmGilEJZFNxllAFglIyaF0Wj1QDNWKeLWSmNmOfPmKZRmCZOGSgX2YaVmkhMWep MmiqYWsKkldAO2ejQGeYkVwdUGOYNWqsfmA/Z2ksrVcWaWonRGqbOW2vZ2hmaHEUpWEYa3EsR3Cu cHEta21qz1oAmGgmTXKkj2lDbncbzF4AbnBtSHWsjGpVQ3ezw2MJymIARHi0RXm1THivV3ajwWcJ Rnyy1GQAdXs2T3qyVXmsw2kNq20wwGsLdXd0UXy0eX85U362S4G3Wn6xVX+3eXt4q3YeXICzUIW8 XIOwvXUlfoB9WYe4XIa/sXwsWoi5Yoa5r4Aug4WCx30l1Xgwt4ExaouyYI2/hZBBynw8YY7A03wy iIqHcY2vt4YtaY+8co6wt4c1uIg9eZK7wYo6fJSxvY1CcJfEcpnGxY5F24k8c5rHw5E/dJvIu5JR eprDwpJNmZiQyZBh4o46tphmf6DIgaLKuJtvxZpTy5lO4pgm2JhKu55y35sniaXIz51Qi6fKjKjL janM359Qj6vOkKzP4KM90KVd5aI+4aQ+46JTqauo5aNO5KNU5KdBlbHVmbHPlrLWm7LQ3qpd56pL 66lasbOvrLS85K5U465bo7bPr7bL46+CqbnM4LRrwLq57rhkssHVrsLb6bxz67108rxutMTXssXe wsTB9L5x7sB3uMjcu8rex8nGwsvTycvI9MZ878Sg+8Z+v8/iy87KwNDjzc/L98qGzdLV786a5dC/ y9flzNjm09vk3d/c8dzL3+He2eLq6evo7vDt7/Hu8PLv8fPw8vTx9fP38/Xy+fTy9Pfz9vj09/n2 +/j9+Pr3+fv4+vz5/fzz/P/7/v/8YPjk8wAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBI WXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYLFTAZUKn7/QAAACJ0RVh0Q29tbWVudABDcmVhdGVk IHdpdGggR0lNUCBvbiBhIE1hY4eod0MAAAGvSURBVBjTY2Bg6ChGB6YMQFD8Gh0Ug4QzTz9/8ezJ kyePgejx40dP75zOBAknvT794vHjB4+AQo8f3Xv8YtHrJJBwzOvHR148uAcEd+/effJi7Z3XMSDh 0Nf37519DhS6e+fOvdfnb95+HQoWPmErJRu8+c6tuw9vvd5/+zZU2L5x0rxpDebXQG7YdhUk7AQS 1pnV316R6GPjXtB57PpjkLA1SFhiQm1rVtDicwfWFF18ua789u0tN0DCIs2llSFrju9efbAr+yi7 wO3bNZf2AoX5qjNi/U7uvrB+/gZD9svsp28bHyoBCnNJ56S67Vm6dcrcyexnTrG/fq290puBgd9C RZ9HZsn2iQu62ffNOSzGqWjXJsjA7++Qn2/AoblwVR/7oZUzZ67obWkqFAcKm+UbMU2XdHFk31mW Funr5eURH8UCEjZjmq5nskmYfWWYl6enp0dgPQvQaH9VDbZ0Nb2NV5zZZ6e4BtT3TOVmBwmHWzGl yaup74gTZe/Jq+Pm5hYE+Yafn58pQV5IOVdBjpd95jJ2Bjhgio7W9bS0tFTSYq9CEmZkggFmdlaw CAAubtLM/zAGbQAAAABJRU5ErkJggg== }] set images(reload) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBI WXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH1gcaChMjSyiLTwAAArdJREFUOMutlE1rE1EUht9z5yOt qa39NNaKjSKiVAtWhYJYqShtlSwEEcGVyPwGl/4BF+ouGxf6C2bhR6GgoBQXxbYLsdQWa2maJpiJ zUczNzP3uknCZJiktXjgMHDP4TnvvHPmAv8YsbguY3H94G59DPuL7Vhc7/zv4CsT5wEg0wy+X8W7 wmkXP8MAHgJ47odul1No1/rw6d0iAHSZBrf2BI7F9UkAbyb1/kX38sDZYltJrdbKZQd5noGdE4hE IoFwagC9CeD97fFRFFpd/Mla4HIHjBFIJXDbBlMJVrIAYkA0Gq3Cw6bBi4HgWFw/AWDl+q1RlGUR aStZkyAcCaYQpGbDzknYeQGqfCUPXDMN7qgBgl9cvXTaJlAoZW1CuvVFl2yoCsGxRe3MA+0yDe4A QBB4SvaGkMyvQlEYujsPA2DQKARZaZBwsS2WoIcJA5HBQI+DwNCoFQqp6Ohph7ZVxMzscl392tRF qC1oCG2yx4S2jlZspRNyZnY5C+CMaXAyDU4AoJDWFNoQrEBFRBmSS5+zLoC7psG/e+u2W6hCjwVB G1phy5xbkqoDIHQqwb/5t8cD3djrL00AVo/Ou7k/pTQA4OkTJCt9VB3AC/K4afCE96yZYgJAUsov v62FCcKwqDnjCdPguk+U9GVdsTqZ5TfxeHpH6XRcLtVSKDv5TLtfgau+1CpPxf9GXjVUKbKfH0Tx 5A2WSqxlYhfGoyK5kRmzVmW8mAZV+r3JPFB4FSs+xQSAlt+Kr4NjbC6VtB70dx9Ybx9y7x0ZYT/W PoqEB1YFKhWg8Nqh+C6jGnxlWqwcitJLrjoaAUSMcpFhZod7ycn+krZwahARACbygZnHlprvI4+U 7r5z7A4x9EkXWwuv3NfClaJHKCLST2qoRYqNdbkzP+c61SEUsG5B2eiK9W5DnRV/AfIcOgCbYwEf AAAAAElFTkSuQmCC }] set images(delete_reverse) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAABl0RVh0 U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAPESURBVDiNtZVfaFt1FMe/53eT3CQ3N+uS tmnarC6hGGVizdrRTgoTJutDUJ988GnI9jSqgmzgWwhbQV8mqAx98MXhk0/Cxh7WgQ4GrStkxbbU bSk1/ZPENqHrTW5u7r+fD2lcm9YyhR74wu8Pv8/v/A7n/A5xznEYxg6FCsBx0CYRCQD8ANwA3DIg KkAdgLatLc659Z/AROSTge7vgPfDRGe8QL/AeYdF9FcNmFnh/JdLwE9EVOCcV/ac3y/GPp8v9Anw +juq+k3HwMBL7cmk6OrthaO9HWapBH15GRt379bXHzxY/Nnr/fhr4PdKpVI8EByNRtuubGyMDpvm 98fHxry+06epns/D2tqCVa2CiSIESYLY0wN1dpb/ef26+itj57/q7JzIZrPP9gUPDg46+1Q1/unC wr1X0ulOR1cXak+egJsmwHlDtg1YFjgRvPE4rM1N/JFOF76Ix99e8ngeT09PG0BLVoRCoeClbPaz 7mQy4OzpQTWTga0ogKY9V73eULWK6vQ0nMEgQmfPBscWF6/IshxssnaB/X6/WzKMd4PnzjnUR48A Vd0Xyut1QNeBWg3KxASC/f1On66/19XV5d4DTqfTjrdyubDzyBGReTwwi0XwWm0XlDQNpGng6+sw 5+ehT01Bm5oCMQaHKHrfXF3tTKfTjtZ0c/UuL7/qDYdNY27OZWazEHw+MFEEt+2Gh5oGXi7DNgxw zkG2DUYEq1yGLxKx+paWXvsNmAVg7gTbJMuKoSiAYcDO5wHGwBkDMQYiaohzMMbAOQcHYNs2yOWC oWkcfv8WALs1xnp1dHReKxREoa0NzOl8DiMCa14gCI1xc93phOD3o7a25tpIJucA6LvAqVTKppGR Z5zzolEsQozFQERAC3wnFEQQYzEYxSIgCGvS0JCSSqX2eIxAIFCxYrHx1du3NWlgAEySdnu9reZc kCR4Tp7E6p07mh6Nfh4IBP4p7dbKo5mZmW5rZOSHUCJx5uipU0JtchJWoQAmCA0vAXDbBguF4B4a wubDh1Yhk7lH9+9/mEgk8gD4fmAAcM1fvXqiPj7+o9zbG+1OJt22qsIulcArFTBZBgsGQV4v8rdu aUout+i5du2D+OXLC834/hsYKysrnnZB6Hg8PDzGi8WP5L4+LoXDoisQYHq5bKv5fH3r6VOiUOjL lycnv92wrPVIJFLb9fQDOogA4Oj6jRuR0s2bb+i5XAKVygkmy7OOY8cygQsXMp0XL64BKDdT7EXB Oy8QAbgURXHIsmxuP7kOYN9P/kXB/8sOref9DbaUvAtd86h8AAAAAElFTkSuQmCC }] set images(down) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAABl0RVh0 U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAL8SURBVDiNtZRPbBRVHMc/781Md1bTGMCk hYNtOIiAnkw0bSFpNCGeOEAwMRyMMaReNCY0JXpFozQWT3JWExsEIzaxJkSREGiJIglRNCqVDSEI xlKqsN3ZeX9+HnZ2O112Wznwkl/e78283+f33nd+v1Eiwv0Y+r5QgbDdi4GR6AaermWjNX9NjZru ewLj6Xp76COsNzhvsT7FeYvzBusNqUs4dPittonbgwFQnP7jCFW7QNUukLqk4T+3cc8Kl7nHoVD/ a98KYEFYrBqR2lrEs1I1LQtehHgEX3signHVFU/c0HjLSHRSPIONjKFKRHws4vF4vNQsdRUSW27s GRiOFo+uOTU1agaXgL2TsZ7uR5/es/3NYhhEOLGx8xYvFrRHh4L3CQm3iAoaHcAru96IRcCYKhMn xhdmb/15sM5Tea0GhqO9m9Y/uX/H4MvFC9e+oWLnsVSp+jvMVa+R2H9BAQIiEOtOtvbs5uTUVwuX r8/snx4177bUeOo9M/brlR/Gvz13LNm8rp8gVBhV5u/qDFbfIYo1HbEmijXFYszW9bs4f/FscuXG pYk89C4wwNqSG5r+5evvf7z0ndm4tp/ZtITq8EQZMIoDOuKAvp4dlK5etj/9fu7nyrx7sZmjWpXN ln2qU6nowvZnX+gNH6roi/PHCUKNDhVKweOrtlGZ0zIxefS6M/aJ6YMy18xoWW5nDshtbczg5Imj /xTcKjas6SfsUEQFzYaH+yi61Xx5/IvbQvBMK2hbMMCpMblqU7vt2OSn5e5oE+sefKxmhc0c/ny8 XE3NzjMHkt/axbeUIj8GRsKdqzvXfLz7+ZceCCLFJ599WL45e3Pf6dH0g+XiloCVUgoIcqYB3fda sPeR3t7hoKBUaaZ05Oz77nXA58wBTkTsEnAGjKg1TJjzg2zWT70avBMEuuv8ITOUppgMaDOoBUw2 W8DUwVEO2Ow3r00OYtqs03pL16/Q/E+sX1NnlvVdQ4LmE6dAKiL+ro/XTufMryerw10OLpKD/Qce AIZcIO5IFQAAAABJRU5ErkJggg== }] set images(ok) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAFzUkdC AK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dE AAAAAAAA+UO7fwAAAAlwSFlzAABJ0gAASdIBqEWK+AAAAAl2cEFnAAAAGAAAABgAeEylpgAAA3dJ REFUSMftlE1MHGUYx/8zszO7M8t+FOxSoHZbRCzFtLQH2lCbIMWqbUiNsSH2YGNMPBlNLxZ64qKk 1XixMTGNmnjxq0YvhESFkm1AUJvCtnalAlKWlcrusuzMztc7X15Y3a5LacB48p/887555nmeXybP kxf4X2uI2khxW1dZG0u7LlEMNUeI3j14Tun/1wAdPRA0wz/T9fz5Ssdx8MngRSmR+i1hqKRz4G05 ms+j1wtQia9n/yMHAz6vB7oTx6vPnvU981jnTs7jfr8wb12A1m7fTreLf+VI83HPbHIUSXEaKhFx fXpCMWzz8w0DOJr+6OiB426FLCKr3EGFtw6TczecqcTNhMmJ724I0H7WezLkr9rdEG6k55eicNEC eFcFvox8qpu2fWqoB+a6AU/3lPtpuC4ca+kQ/shOghgqQr56RMa/03WS+2KgV/q+uKYk4MQJMKXi FrHeaqrbxwu8GylxFl5uM5YlCaOxEWLazulSNXcBWl/nt7Z3+xcydWXKE2f8r6Fgjdu7hL0Mw73Q 3NDs+T3zMxwHCPDV6B/tUyzHOj3QK6VLAf5ucGZTAIx1tXV36/btVTuY/rE+Obmc+smC0XmIk5Mj JDDxeFPbrupQOZ2WZlHhCyORzNhD44PXv3kjuxeAc88/YBj7q6aH9tSEq6oZUY3j6IEnvfvqm1oY sL9EVO/X5f6K2m1bqumUdBsM7YbtcLgSvUIM0zy1WnMAcOUvtuM0Ch43Z1kmND0HWYuhrmYrWxnc HBwaHz528NH99JIUh2kYCPprMHbjB802yQeXz8kT91qMv4ZZ28L2JdILT2VlkQ9X1rK2bSKr3AHL 0mgI11OWrSCnpeHhfBBlHVdvXRNli+uIDyvkvgAzwyT14GH9oiyR8MzCXP2WTZWc4PZC1jKQtQx0 QwZAgWeDiETHZJXoL0fOL1/DGir52B3uLnuOoZgPd4UfFraFQoyii7BsAt4dwPxi2ozFp0a/fVM8 tFbzf6xpXgO9uUsg2HPz9mRsLBZVABYsw0PTdcTiU6atOS/hPl9iZpWYa3pEl5cS5OPgDvuB+fRi o08Q2FvxuCrl9PcuvyP1AeBW7FqpoVZ810ZRRXemlJtf5I/4Q+wF2Pj1x8/Ek9k5qACsNeyUmgG9 0rTwLHQ+3wFgF9kqOlcfctG3fGOqCOAUgPKx/15/ArQwg1fnUtydAAAAJXRFWHRkYXRlOmNyZWF0 ZQAyMDEwLTAyLTE3VDA2OjQ2OjUwLTA3OjAwat5j0AAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMC0w MS0xMVQwOToxMzoyNS0wNzowMAO3oKwAAAA0dEVYdExpY2Vuc2UAaHR0cDovL2NyZWF0aXZlY29t bW9ucy5vcmcvbGljZW5zZXMvR1BMLzIuMC9sagaoAAAAE3RFWHRTb3VyY2UAR05PTUUtQ29sb3Jz qplE4gAAADF0RVh0U291cmNlX1VSTABodHRwOi8vY29kZS5nb29nbGUuY29tL3AvZ25vbWUtY29s b3JzL1AdtesAAAAASUVORK5CYII= }] set images(delete) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAAXNSR0IArs4c6QAAAF1QTFRFAAAA xwgAzRUA0R4A1ycA3jIA6QIA6h0D/gEA/hoC6i8I4zoA/ikG/jUL6EMA60cS7V4e/kcU/lYd73It +2cq/XY38oc9/oZH9JVJ+phV/qFm/qx1/riG/sSX/sui1vsBTgAAAAF0Uk5TAEDm2GYAAAABYktH RACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYLFTAtcR0PSAAAALhJREFUGNN9 0dkSgyAMBVCSgBsVqIji1v//zLoB6kzLE3PmTshVxn4fpdKdKKmSSQmDDl6KoMYgnvpZvNidk3FO 766kX5a543zPOtdqgC0ipZ/nyXEKeg6Xopum0fK7Mia4HcfBtqtWSdenuB36fssiXgtxsofCrefx 2pOJtrlN01QAj6zT+l3XefJzX4SqfpVZ8NgNIS+L4vRLN4CsCE5oYrfdQxx1XGz1OBwxrQuQVrl+ B4A/f/cLR24LBcAhtFwAAAAASUVORK5CYII= }] set images(printer) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAAXNSR0IArs4c6QAAAV9QTFRFAAAA a2lobGtpbGxpbW1rbm1sbm5scXFudnV0dnd0d3d1eHl3enp3fX57gYB/g4OAhISBhYWDh4aDh4eF ioqIi4qIiouIi4uIi4uJjIyKjo2KkpKQk5ORlJSSlJSUlZWVl5eVmZmXnJuanJyanZybnpyanp6e n5+dn5+foaGfoqKgo6Ogo6OhpaSjpaWkpqWkpqamp6enqKinq6qpq6uprKuoq6urrKuqra2tr7Cu sLCws7OxtLS0tbW0t7e1uLe1uLi4ubq4urq4urq5vLy7vLy8vb29vr68v7+/wMDAw8PDxMTExcXF x8fGyMjHy8vJy8vLzc3Nzs7O09PT1NTU4ODf4eHh4uLi5OTj5OTk5eXl5+fm5+fn6Ofn6Ojo6eno 6enp6urq6+vr7Ozs7e3t7u7u8O/u8PDw8fDu8fDw8vLy8/Py9/b19/f3+Pf3+fn4+fn5+vr6+/v7 /f39////KTpVyAAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwY AAAAB3RJTUUH3AYLFTIVaynVVAAAACJ0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUCBvbiBh IE1hY4eod0MAAAD7SURBVBjTY2DAAyyRALJwSTEUlKAKhwUEiEgEBsWhC4dJy8jIxiWiC0sAgaRk EppweGSUrGxCUjKacGRgkKJeUnIqsjCvZUlUTJyvX0pqeoklL1y0xDIrCgqyLLV5YaIZlmzMUCBk GuHPCxEtyS1BAgkJwSBx3jSr6CKvlOTU1KT4+Nj4+Hhxd7BwsHy2R2h+QVFhUVFeXl5OJo8DWDhE joOdjYWNlYWFmZmJkZ2NywYs7O1srqyqoqKkIMrHLyAoKCwFEfZ0tLc2MTYy0jc00NXR0lRXswAL 8/rwogANMU6wC+1c3TyAwMXV1cXJycnWDOIfXnTAzUAiAACtUkaqnD2S7AAAAABJRU5ErkJggg== }] set images(reverselist) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAABl0RVh0 U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAOwSURBVDiNtZRfTBxVFMa/e2dmB3aBFRZK FWSLLYWlqYXShYTFSK3GtFRt++qfxBdNjG9uGh/0ycQHM4/qg2nfNCYY20STmkhatDjQYghIS/gj WJZlLbusXbplt8vOzD0+dHczrlvoS09ycmbO3Pubb7659zIiwuMI/lioAOTiRiCouMHwvqSwl8mi DiI4uMTWGUdYmHRVWPhU14zkTmBmtyIQVF7nEvvcd2B/eWtrq+qp8cDpqEI6ncLdzQT+XFja+uPG dEaY4iyAc7pmiB3BfWeVj+tqd30YePGwc3dtA5ySG2lrA4spHVkzBdmowi65Dfx+FYZHLqdvx8KD v31mvL0tOBBUjjxRWTPSfniPGgnFN9ciMadDVY2WfXvFEb/f+dfmNfydWEQ2I1CB3fC5+zH066V0 fCP6hq4ZF0uCez+Quao6Qi7V3ZC8fydkGtZ7AEYBuBnHO25nTfDVgTPqVOwS7iTXkc0I1KiNOFD3 PC4MfZ0kIdp1zYgUg2UAh7a2so2miI9aBh3TNSOTe3YXwEeBoDLzy9Xh8z3dR8tH1r6HEBbiZhhp TwJ7vfuUxVsLpwB8UQzmALqYhIRl0GkbtBC6Znwbji6NRSKraKr2FfrhxCyan2orZxx9pazgagVv BOETXTNiD/sRJPDVWmwtVVlWW+glM3G4XJUA0F1qjmwZNEoCE/lGIKhIAL4DcNo+MB5fp2fbOwv3 WSuDMocKEmgOBJXi7XuRldrSgaCiMo4rntqarqPdJ9Uy2fVAOQg/z52DoAfL97jv3cIcS5i4Mv7D VjQWnSCBF0qCc3AX4xhtaGhoC3S85Lge+hGbW4n/jatQq9HjfQXXpoezK+HQHAn06pqReuhZoWtG igT6V1cjK5OzY6a/6QTyyvNRJrvgbzqBydkxM7QSWiGBfl0zUsAOh5CuGQkQ+haW5qPzyzeF3zsA RVIBAIqkwu8dwPzyTbGwNB8FoU/XjMInlbSCMcZzL+UA2KE3Ja+rno12d/ZW19c9ySfCP6Hr6eOI rq+J8Uk9YaSp+/cvrVtkgxXAjDEGQMolt1UGgPvO8JbqZj70XM+xysb6PWw1ukwj45fvbd6m/ulv rDkAAoAFwCIiYkSUVyhtkxwAa3uNH/S0yBcO+jqcN2an0hsr1smZQWsqD7SlmQfnAXIRUC6+bjvF O6uf4eeTq/TWzKA1lgfZoXbwIynOJXn2M+c/C3SvhFILgElE5iN7nKv5oJyn+WqHiu1WhR1mV8ty sP+A8zB7/AuncspNor9CdAAAAABJRU5ErkJggg== }] set images(isempty) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI WXMAAAsTAAALEwEAmpwYAAAACXZwQWcAAAAYAAAAGAB4TKWmAAADkklEQVRIx+1US2xUVRj+eu/M GZ37AJf42GkrpQ0aTVxQbXRnQhOTaWKiCCqlU6cQ9o6ZVzqtwYUJ2BfWtqPBsOjCgAsXRor1sTFC x3bDRlACovS+5869587c34UztaEPinFl/JN/c873OPf/bz7gP1m5XLork3/7+X8DK9x5kMmne4SI uBARI19l8umercTvBbtKKI7kfbfqkuu6VBzJ+5sRm1in4pBTcbbENgmJwlCGqlWXwjCkMAzJtMwN iU1x3dCIc5845+Q4NhWGMpTLvfPChiMSqEUHACIAIPCAQ5IkHE0dZzHG5pommXy6J8bYXOqtYywe l2BXLBBoVTBsoQfWGrTc+bIYY3NHU8eZJMnwuY8YY3AcB6PjJ3nAeSnK2KHUwDEWlyTYjgVZUuBW KhibPMU5D3oL2eL5be3BMA0KagHZjkVBwEk3NBp+t0CarpHPPbqt/U6e75GmrdDQSM7f1pLXmRg6 8YCTYerk+x6FYUie79EfK7fI86vbEhc3Orw4v3Cl67l9iz9e+iHxxN4nxfj9cdgVC261At/zoEgq XNfF+MQHnAdbj0XY7KKQLZ4POC+NjZ9CNMoQhuFfTSEYi2FiYhS1ICjdbebiZheZfLqHMTY80D8o CkILPL8KIgIRQRRFdHR04vLlS51d3fsWL84vXLkng+bf1H8kxSRZguWYkGUVqrIDoiDCtHQoioL2 9g7xp/JiYiuTDaMiFo3OHekbYJIUh2kZkOMKbMvCifeGYVkWVGUHNGMFkiThtYOvMxaJzm22aHEj 8b7DSSbLMizHhCKpME0T09Mf8loQTJfLi51tbY+LqqJCN1egKipaW9vE5eWlxLPdXeu+RFgjnogI 4rlkcpDJigLLNiHHFeiGgZmZKc5rQW8uW+zntaC39PEM1w0dqrITmn4biqLgwIGDTBSEc3eNinpY BxFBisvQDR2zs1NcN41XC9niBQByIVu8YNn2K2fOfMI1TYOq7EQYhqjX6gDWR8XqiObnv/7l6Wee Ki8tlV9qb98jcp9jdnYquHHz1uGT749+CYABuA+A+N0331/dvWf38rVrP+9/9LFW0fc8nD37Kbcr zssjQyc+A/4Op2YWRQDEAMSSqb79D+7aVQKAX69ff3NqcuYLAEGj641HRQFE+pJvvPjIQw9PA8CN 324emhyb+hyA3+jaWgM0SDEAkeRgXzcFVDt9+qNvG0C/YfBPsP/X1vUnKKIevOk3P2MAAAAldEVY dGNyZWF0ZS1kYXRlADIwMDktMTEtMTVUMjM6MDQ6MjUtMDc6MDBt/LoyAAAAJXRFWHRkYXRlOmNy ZWF0ZQAyMDEwLTAxLTExVDA5OjEwOjE5LTA3OjAw0PLOhAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAx MC0wMS0xMVQwOToxMDoxOS0wNzowMKGvdjgAAAA0dEVYdExpY2Vuc2UAaHR0cDovL2NyZWF0aXZl Y29tbW9ucy5vcmcvbGljZW5zZXMvR1BMLzIuMC9sagaoAAAAJXRFWHRtb2RpZnktZGF0ZQAyMDA5 LTExLTE1VDIzOjA0OjI1LTA3OjAwMk3MBgAAABd0RVh0U291cmNlAEdOT01FIEljb24gVGhlbWXB +SZpAAAAIHRFWHRTb3VyY2VfVVJMAGh0dHA6Ly9hcnQuZ25vbWUub3JnLzLkkXkAAAAASUVORK5C YII= }] set images(job_engineering_logo) [image create photo -data { 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 nv8PbNpb9t40/Q8AAAAASUVORK5CYII= }] ===== ***xtablelist_demo.tcl*** ====== # ----------------------------------------------------------------------------- # xtablelist_demo.tcl --- # ----------------------------------------------------------------------------- # for development: try to find autoscroll, etc ... set dir [file normalize [file dirname [info script]]] # where to find required packages... set auto_path [linsert $auto_path 0 [file join $dir "."]] set auto_path [linsert $auto_path 0 [file join $dir "../lib"]] package require Tk package require TclOO package require autoscroll package require tablelist_tile package require xtablelist # --------- # demo code # --------- # catch {console show} # 1st example: set t [xtablelist::xtablelist .t \ -showseparators "yes" \ -labelcommand "tablelist::sortByColumn" \ -width 80 -height 10 \ -xfilesave 1 \ -xfileread 1 \ -xshowbuttons "yes" \ -xrefreshpostcmd {puts "Refresh postcommand done."}] pack $t -fill both -expand true # maybe some configuration changes later on ... $t configure \ -xmoveovereffect "yes" # create some random test data... set header { {"ID" 10 left} {"Category" 22 left} {"test-column" 16 left} {"Hello\\nWorld" 10 left} {"test" "hidden" center} {"last\\ncolumn" 10 left} } $t configure \ -xtabheader $header set data_list {} set cnt 0 while {$cnt < 40} { lappend data_list \ [list $cnt \ [expr {$cnt +3}] [expr {$cnt +4}] \ [expr {$cnt +1}] [expr {$cnt +2}] \ [expr {$cnt +5}]] incr cnt } foreach item $data_list { $t insert end $item } # 2nd example: set t1 [xtablelist::xtablelist .t1 \ -showseparators "yes" \ -labelcommand "tablelist::sortByColumn" \ -width 80 -height 10 \ -xfilesave 1 \ -xfileread 1 \ -xshowbuttons "yes" \ -xrefreshpostcmd {puts "Refresh postcommand done."}] pack $t1 -fill both -expand true set header { {"ID" 10 left} {"Info_Procs" 20 left} {"Body" hidden left} } $t1 configure \ -snipstring "..." \ -xtabheader $header set data_list {} set cnt 0 foreach p [lsort -dictionary [info procs]] { # set body [string map {"\n" " "} [info body $p]] set row [list $cnt $p [string trim [info body $p]]] $t1 insert end $row incr cnt } ====== <> Widget | TclOO