[WJG] (25th August, 2005) I thought that it would be useful to 'collapse' or 'fold' a selected range of content in a text widget. So, this is snippet I came up with. #---------------------------------------------------------------- # TextCollapser.tcl #---------------------------------------------------------------- # Create by William J Giddings, 2005 # # Notes: # ------ # Blocks can be nested. # # Use: # ---- # Enter text then select a region with click and mouse drag. # Click the button in the toolbar. # The first line will have a toggle button, the 'sub-text' will be coloured. # To remove the folding effect simply delete the toggle button # #---------------------------------------------------------------- #---------------------------------------------------------------- # application namespace #---------------------------------------------------------------- namespace eval collapser { # tag base name set tagbase cb_ # button data image create photo collapser::downarrow \ -data R0lGODlhDAAMAJEAAP///9TQyAAAAAAAACwAAAAADAAMAAACEIyPqcudAqNQcq7orNu8qwIAOw== image create photo collapser::uparrow \ -data R0lGODlhDAAMAJEAAP///9TQyAAAAAAAACwAAAAADAAMAAACEoyPqcsobcRrcq5qU6VZdQgmBQA7 image create photo collapser::button \ -data R0lGODlhDAAMAJEAAP////4AAAAAAAAAACwAAAAADAAMAAACGoSPJ8ttDUWaJ9iLDd5B8+t9HTVFDmAyZFIAADs= } #---------------------------------------------------------------- # obtain a unique name for a new block of text #---------------------------------------------------------------- proc collapser::name {path} { llapser::name {path} { # get a sorted list of the current windows set windowlist "" foreach {a b c} [$path dump -window 1.0 end] { if { [string first $path.$collapser::tagbase $b 0 ] != "-1" } { lappend windowlist $b } } set windowlist [lsort $windowlist] set windowlist [lsort $windowlist] # get the last one the list set next [lindex $windowlist end] # increment the number and return the new tag name set j [string trimleft $next $path.${collapser::tagbase}] if {$j == "" } {set j 0} return ${collapser::tagbase}[incr j] } #---------------------------------------------------------------- # add a toolbar button #---------------------------------------------------------------- proc collapser::addbutton {path} { button $path -text Block -borderwidth 0 -command collapser::block -image collapser::button pack $path -side left } #---------------------------------------------------------------- # create a new collapsable text block #---------------------------------------------------------------- proc collapser::block {} { # get path to active widget set path [focus] # only works on text widgets if {[winfo class $path]!="Text"} {return} # get tag name for the new block set tag [collapser::name $path] set tag [collapser::name $path] # create and configure new tag $path tag add $tag {sel.first lineend} sel.last $path tag configure $tag -foreground red # create block toggle button button $path.$tag \ -borderwidth 0 \ -text {-} \ -image collapser::downarrow \ -command "collapser::toggle $path $tag" # add the button to the text $path window create {insert linestart} -window $path.$tag $path window create {insert linestart} -window $path.$tag # remove text tagging if the button is deleted bind $path.$tag {$path] tag delete $tag} } #---------------------------------------------------------------- # toggle tag settings #---------------------------------------------------------------- proc collapser::toggle {path tag} { if {[$path tag cget $tag -elide] == 1} { $path tag configure $tag -elide 0 $path.$tag configure -text - -image collapser::downarrow } else { $path tag configure $tag -elide 1 $path.$tag configure -text + -image collapser::uparrow } } #---------------------------------------------------------------- # demo code to test the package #---------------------------------------------------------------- proc demo {} { console show frame .fr pack .fr -fill x text .txt -font {Ariel 12} pack .txt -fill both -expand 1 focus .txt collapser::addbutton .fr.b_1 } #---------------------------------------------------------------- # the ubiquitious demo! #---------------------------------------------------------------- demo ---- ''[escargo] 26 Aug 2005'' - I got this message deleting a tag: can't read "path": no such variable can't read "path": no such variable while executing "$path] tag delete $tag" (command bound to event) I deleted the tag by selecting it and typing control-x on Windows XP Pro. When a tag is deleted, it appears that the text associated with the tag is also deleted. It would be nice if the cursor shape could change over the tag. [LV] on line 97 of this file, it looks like this bind is wrong bind $path.$tag {$path] tag delete $tag} I don't see a reason for that ]] in the command. ---- See also [Text widget elision] ---- [Category Widget]