Version 9 of a widget serializer

Updated 2003-06-24 03:17:35

if 0 {

Limitations: text images and windows are not saved. listbox item configurations, text tags and marks can get quite slow if you have large listboxes or many tags

Usage example:

 set state [serialize .frame]
 destroy .frame

 toplevel .frame
 eval [join $state \;]

--AF 23-06-03

}

proc serialize {w} {

    upvar state state delay delay
    foreach c [winfo children $w] {
        if {[string match .#* $c]} {continue}
        set new $c
        if {[catch {$c configure -class} widget]} {set widget "{} {} {} [winfo class $c]"}
        set widget [string tolower [lindex $widget 3]]
        lappend state "$widget $new [getconfig $c]"                              if {$widget == "listbox"} {
            lappend state "$new insert 0 [$c get 0 end]"                             set len [$c index end]
            for {set x 0} {$x < $len} {incr x} {
                if {[set config [getconfig $c "itemconfigure $x"]] != " "} {
                    lappend state "$new itemconfigure $x $config"
                }
            }
        } elseif {$widget == "entry"} {
            lappend state "$new configure -state normal"
            lappend state "$new insert 0 [list [$c get]]"
            lappend state "$new configure -state [$c cget -state]"
        } elseif {$widget == "text"} {
            lappend state "$new configure -state normal"                             lappend state "$new insert 1.0 [list [$c get 1.0 end-1c]]"
            lappend state "$new delete end end-1l"                                   lappend state "addtags $new [list [$c dump -tag 1.0 end]]"
            foreach x [$c tag names] {lappend state "$new tag configure $x [getconfig $c "tag configure $x"]"}
            lappend state [string map "mark \"\;$new mark set\"" [$c dump -mark 1.0 end]]
            lappend state "$new configure -state [$c cget -state]"
        } elseif {$widget == "menu"} {
            set end [$c index end]
            for {set x 0} {$x <= $end} {incr x} {
                lappend state "$new add [$c type $x] [getconfig $c "entryconfigure $x"]"
            }
        }
        lappend state "bindtags $new [list [bindtags $c]]"
        if {[set bindings [bind $c]] != ""} {
            foreach x $bindings {lappend state "bind $new $x [list [bind $c $x]]"}
        }
        if {[winfo children $c] != ""} {serialize $c}
    }
    set list {}
    set manager [winfo manager [lindex [winfo children $w] 0]]
    if {$manager == "grid" || $manager == "pack" || $manager == "place"} {
        foreach x [$manager slaves $w] {lappend state "$manager $x [lrange [$manager info $x] 2 end]"}
    } elseif {$manager == "panedwindow"} {
        foreach x [$w panes] {lappend state "$w add $x [getconfig $w "paneconfigure $x"]"}
    }
    set grid [grid size $w]
    if {[set cols [lindex $grid 0]] > 0} {
        for {incr cols -1} {$cols > -1} {incr cols -1} {
            lappend state "grid columnconfigure $w $cols [grid columnconfigure $w $cols]"
        }
    }
    if {[set rows [lindex $grid 1]] > 0} {
        for {incr rows -1} {$rows > -1} {incr rows -1} {
            lappend state "grid rowconfigure $w $rows [grid columnconfigure $w $rows]"
        }
    }
    return $state

}

 proc getconfig {w {cmd configure}} {
    set args {}
    foreach x [eval $w $cmd] {
        if {[set opt [lindex $x 4]] != [lindex $x 3]} {lappend args [list [lindex $x 0] $opt]}
    }
    return [join $args]

}

 proc getconfig {w {cmd configure}} {
    set args {}
    foreach x [eval $w $cmd] {
        if {[set opt [lindex $x 4]] != [lindex $x 3]} {lappend args [list [lindex $x 0] $opt]}
    }
    return [join $args]
 }

 proc addtags {w tags} {
    foreach {d tag pos} $tags {
        if {$d == "tagon"} {
            set t($tag) $pos
        } elseif {$d == "tagoff"} {
            if {[info exists t($tag)] && $t($tag) != ""} {
                $w tag add $tag $t($tag) $pos
                unset t($tag)
            }
        }
    }
 }