home *** CD-ROM | disk | FTP | other *** search
Text File | 2001-10-22 | 41.1 KB | 1,263 lines |
- # ------------------------------------------------------------------------------
- # widget.tcl
- # This file is part of Unifix BWidget Toolkit
- # $Id: widget.tcl,v 1.17 2001/06/11 23:58:40 hobbs Exp $
- # ------------------------------------------------------------------------------
- # Index of commands:
- # - Widget::tkinclude
- # - Widget::bwinclude
- # - Widget::declare
- # - Widget::addmap
- # - Widget::init
- # - Widget::destroy
- # - Widget::setoption
- # - Widget::configure
- # - Widget::cget
- # - Widget::subcget
- # - Widget::hasChanged
- # - Widget::_get_tkwidget_options
- # - Widget::_test_tkresource
- # - Widget::_test_bwresource
- # - Widget::_test_synonym
- # - Widget::_test_string
- # - Widget::_test_flag
- # - Widget::_test_enum
- # - Widget::_test_int
- # - Widget::_test_boolean
- # ------------------------------------------------------------------------------
- # Each megawidget gets a namespace of the same name inside the Widget namespace
- # Each of these has an array opt, which contains information about the
- # megawidget options. It maps megawidget options to a list with this format:
- # {optionType defaultValue isReadonly {additionalOptionalInfo}}
- # Option types and their additional optional info are:
- # TkResource {genericTkWidget genericTkWidgetOptionName}
- # BwResource {nothing}
- # Enum {list of enumeration values}
- # Int {Boundary information}
- # Boolean {nothing}
- # String {nothing}
- # Flag {string of valid flag characters}
- # Synonym {nothing}
- #
- # Next, each namespace has an array map, which maps class options to their
- # component widget options:
- # map(-foreground) => {.e -foreground .f -foreground}
- #
- # Each has an array ${path}:opt, which contains the value of each megawidget
- # option for a particular instance $path of the megawidget, and an array
- # ${path}:mod, which stores the "changed" status of configuration options.
-
- # Steps for creating a bwidget megawidget:
- # 1. parse args to extract subwidget spec
- # 2. Create frame with appropriate class and command line options
- # 3. Get initialization options from optionDB, using frame
- # 4. create subwidgets
-
- # Uses newer string operations
- package require Tcl 8.1.1
-
- namespace eval Widget {
- variable _optiontype
- variable _class
- variable _tk_widget
-
- array set _optiontype {
- TkResource Widget::_test_tkresource
- BwResource Widget::_test_bwresource
- Enum Widget::_test_enum
- Int Widget::_test_int
- Boolean Widget::_test_boolean
- String Widget::_test_string
- Flag Widget::_test_flag
- Synonym Widget::_test_synonym
- }
-
- proc use {} {}
- }
-
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::tkinclude
- # Includes tk widget resources to BWidget widget.
- # class class name of the BWidget
- # tkwidget tk widget to include
- # subpath subpath to configure
- # args additionnal args for included options
- # ------------------------------------------------------------------------------
- proc Widget::tkinclude { class tkwidget subpath args } {
- foreach {cmd lopt} $args {
- # cmd can be
- # include options to include lopt = {opt ...}
- # remove options to remove lopt = {opt ...}
- # rename options to rename lopt = {opt newopt ...}
- # prefix options to prefix lopt = {pref opt opt ..}
- # initialize set default value for options lopt = {opt value ...}
- # readonly set readonly flag for options lopt = {opt flag ...}
- switch -- $cmd {
- remove {
- foreach option $lopt {
- set remove($option) 1
- }
- }
- include {
- foreach option $lopt {
- set include($option) 1
- }
- }
- prefix {
- set prefix [lindex $lopt 0]
- foreach option [lrange $lopt 1 end] {
- set rename($option) "-$prefix[string range $option 1 end]"
- }
- }
- rename -
- readonly -
- initialize {
- array set $cmd $lopt
- }
- default {
- return -code error "invalid argument \"$cmd\""
- }
- }
- }
-
- namespace eval $class {}
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::map$subpath submap
- upvar 0 ${class}::optionExports exports
-
- set foo [$tkwidget ".ericFoo###"]
- # create resources informations from tk widget resources
- foreach optdesc [_get_tkwidget_options $tkwidget] {
- set option [lindex $optdesc 0]
- if { (![info exists include] || [info exists include($option)]) &&
- ![info exists remove($option)] } {
- if { [llength $optdesc] == 3 } {
- # option is a synonym
- set syn [lindex $optdesc 1]
- if { ![info exists remove($syn)] } {
- # original option is not removed
- if { [info exists rename($syn)] } {
- set classopt($option) [list Synonym $rename($syn)]
- } else {
- set classopt($option) [list Synonym $syn]
- }
- }
- } else {
- if { [info exists rename($option)] } {
- set realopt $option
- set option $rename($option)
- } else {
- set realopt $option
- }
- if { [info exists initialize($option)] } {
- set value $initialize($option)
- } else {
- set value [lindex $optdesc 1]
- }
- if { [info exists readonly($option)] } {
- set ro $readonly($option)
- } else {
- set ro 0
- }
- set classopt($option) \
- [list TkResource $value $ro [list $tkwidget $realopt]]
-
- # Add an option database entry for this option
- set optionDbName ".[lindex [_configure_option $option ""] 0]"
- if { ![string equal $subpath ":cmd"] } {
- set optionDbName "$subpath$optionDbName"
- }
- option add *${class}$optionDbName $value widgetDefault
- lappend exports($option) "$optionDbName"
-
- # Store the forward and backward mappings for this
- # option <-> realoption pair
- lappend classmap($option) $subpath "" $realopt
- set submap($realopt) $option
- }
- }
- }
- ::destroy $foo
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::bwinclude
- # Includes BWidget resources to BWidget widget.
- # class class name of the BWidget
- # subclass BWidget class to include
- # subpath subpath to configure
- # args additionnal args for included options
- # ------------------------------------------------------------------------------
- proc Widget::bwinclude { class subclass subpath args } {
- foreach {cmd lopt} $args {
- # cmd can be
- # include options to include lopt = {opt ...}
- # remove options to remove lopt = {opt ...}
- # rename options to rename lopt = {opt newopt ...}
- # prefix options to prefix lopt = {prefix opt opt ...}
- # initialize set default value for options lopt = {opt value ...}
- # readonly set readonly flag for options lopt = {opt flag ...}
- switch -- $cmd {
- remove {
- foreach option $lopt {
- set remove($option) 1
- }
- }
- include {
- foreach option $lopt {
- set include($option) 1
- }
- }
- prefix {
- set prefix [lindex $lopt 0]
- foreach option [lrange $lopt 1 end] {
- set rename($option) "-$prefix[string range $option 1 end]"
- }
- }
- rename -
- readonly -
- initialize {
- array set $cmd $lopt
- }
- default {
- return -code error "invalid argument \"$cmd\""
- }
- }
- }
-
- namespace eval $class {}
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::map$subpath submap
- upvar 0 ${class}::optionExports exports
- upvar 0 ${subclass}::opt subclassopt
- upvar 0 ${subclass}::optionExports subexports
-
- # create resources informations from BWidget resources
- foreach {option optdesc} [array get subclassopt] {
- set subOption $option
- if { (![info exists include] || [info exists include($option)]) &&
- ![info exists remove($option)] } {
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- # option is a synonym
- set syn [lindex $optdesc 1]
- if { ![info exists remove($syn)] } {
- if { [info exists rename($syn)] } {
- set classopt($option) [list Synonym $rename($syn)]
- } else {
- set classopt($option) [list Synonym $syn]
- }
- }
- } else {
- if { [info exists rename($option)] } {
- set realopt $option
- set option $rename($option)
- } else {
- set realopt $option
- }
- if { [info exists initialize($option)] } {
- set value $initialize($option)
- } else {
- set value [lindex $optdesc 1]
- }
- if { [info exists readonly($option)] } {
- set ro $readonly($option)
- } else {
- set ro [lindex $optdesc 2]
- }
- set classopt($option) \
- [list $type $value $ro [lindex $optdesc 3]]
-
- # Add an option database entry for this option
- foreach optionDbName $subexports($subOption) {
- if { ![string equal $subpath ":cmd"] } {
- set optionDbName "$subpath$optionDbName"
- }
- # Only add the option db entry if we are overriding the
- # normal widget default
- if { [info exists initialize($option)] } {
- option add *${class}$optionDbName $value \
- widgetDefault
- }
- lappend exports($option) "$optionDbName"
- }
-
- # Store the forward and backward mappings for this
- # option <-> realoption pair
- lappend classmap($option) $subpath $subclass $realopt
- set submap($realopt) $option
- }
- }
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::declare
- # Declares new options to BWidget class.
- # ------------------------------------------------------------------------------
- proc Widget::declare { class optlist } {
- variable _optiontype
-
- namespace eval $class {}
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::optionExports exports
- upvar 0 ${class}::optionClass optionClass
-
- foreach optdesc $optlist {
- set option [lindex $optdesc 0]
- set optdesc [lrange $optdesc 1 end]
- set type [lindex $optdesc 0]
-
- if { ![info exists _optiontype($type)] } {
- # invalid resource type
- return -code error "invalid option type \"$type\""
- }
-
- if { ![string compare $type "Synonym"] } {
- # test existence of synonym option
- set syn [lindex $optdesc 1]
- if { ![info exists classopt($syn)] } {
- return -code error "unknow option \"$syn\" for Synonym \"$option\""
- }
- set classopt($option) [list Synonym $syn]
- continue
- }
-
- # all other resource may have default value, readonly flag and
- # optional arg depending on type
- set value [lindex $optdesc 1]
- set ro [lindex $optdesc 2]
- set arg [lindex $optdesc 3]
-
- if { ![string compare $type "BwResource"] } {
- # We don't keep BwResource. We simplify to type of sub BWidget
- set subclass [lindex $arg 0]
- set realopt [lindex $arg 1]
- if { ![string length $realopt] } {
- set realopt $option
- }
-
- upvar 0 ${subclass}::opt subclassopt
- if { ![info exists subclassopt($realopt)] } {
- return -code error "unknow option \"$realopt\""
- }
- set suboptdesc $subclassopt($realopt)
- if { $value == "" } {
- # We initialize default value
- set value [lindex $suboptdesc 1]
- }
- set type [lindex $suboptdesc 0]
- set ro [lindex $suboptdesc 2]
- set arg [lindex $suboptdesc 3]
- set optionDbName ".[lindex [_configure_option $option ""] 0]"
- option add *${class}${optionDbName} $value widgetDefault
- set exports($option) $optionDbName
- set classopt($option) [list $type $value $ro $arg]
- continue
- }
-
- # retreive default value for TkResource
- if { ![string compare $type "TkResource"] } {
- set tkwidget [lindex $arg 0]
- set foo [$tkwidget ".ericFoo##"]
- set realopt [lindex $arg 1]
- if { ![string length $realopt] } {
- set realopt $option
- }
- set tkoptions [_get_tkwidget_options $tkwidget]
- if { ![string length $value] } {
- # We initialize default value
- set ind [lsearch $tkoptions [list $realopt *]]
- set value [lindex [lindex $tkoptions $ind] end]
- }
- set optionDbName ".[lindex [_configure_option $option ""] 0]"
- option add *${class}${optionDbName} $value widgetDefault
- set exports($option) $optionDbName
- set classopt($option) [list TkResource $value $ro \
- [list $tkwidget $realopt]]
- set optionClass($option) [lindex [$foo configure $realopt] 1]
- ::destroy $foo
- continue
- }
-
- set optionDbName ".[lindex [_configure_option $option ""] 0]"
- option add *${class}${optionDbName} $value widgetDefault
- set exports($option) $optionDbName
- # for any other resource type, we keep original optdesc
- set classopt($option) [list $type $value $ro $arg]
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::addmap
- # ------------------------------------------------------------------------------
- proc Widget::addmap { class subclass subpath options } {
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::optionExports exports
- upvar 0 ${class}::optionClass optionClass
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::map$subpath submap
-
- foreach {option realopt} $options {
- if { ![string length $realopt] } {
- set realopt $option
- }
- set val [lindex $classopt($option) 1]
- set optDb ".[lindex [_configure_option $realopt ""] 0]"
- if { ![string equal $subpath ":cmd"] } {
- set optDb "$subpath$optDb"
- }
- option add *${class}${optDb} $val widgetDefault
- lappend exports($option) $optDb
- # Store the forward and backward mappings for this
- # option <-> realoption pair
- lappend classmap($option) $subpath $subclass $realopt
- set submap($realopt) $option
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::syncoptions
- # ------------------------------------------------------------------------------
- proc Widget::syncoptions { class subclass subpath options } {
- upvar 0 ${class}::sync classync
-
- foreach {option realopt} $options {
- if { ![string length $realopt] } {
- set realopt $option
- }
- set classync($option) [list $subpath $subclass $realopt]
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::init
- # ------------------------------------------------------------------------------
- proc Widget::init { class path options } {
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::$path:mod pathmod
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::$path:init pathinit
-
- if { [info exists pathopt] } {
- unset pathopt
- }
- if { [info exists pathmod] } {
- unset pathmod
- }
- # We prefer to use the actual widget for option db queries, but if it
- # doesn't exist yet, do the next best thing: create a widget of the
- # same class and use that.
- set fpath $path
- set rdbclass [string map [list :: ""] $class]
- if { ![winfo exists $path] } {
- set fpath ".#BWidgetClass#$class"
- if { ![winfo exists $fpath] } {
- frame $fpath -class $rdbclass
- }
- }
- foreach {option optdesc} [array get classopt] {
- set pathmod($option) 0
- if { [info exists classmap($option)] } {
- continue
- }
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- continue
- }
- if { ![string compare $type "TkResource"] } {
- set alt [lindex [lindex $optdesc 3] 1]
- } else {
- set alt ""
- }
- set optdb [lindex [_configure_option $option $alt] 0]
- set def [option get $fpath $optdb $rdbclass]
- if { [string length $def] } {
- set pathopt($option) $def
- } else {
- set pathopt($option) [lindex $optdesc 1]
- }
- }
-
- set Widget::_class($path) $class
- foreach {option value} $options {
- if { ![info exists classopt($option)] } {
- unset pathopt
- unset pathmod
- return -code error "unknown option \"$option\""
- }
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set option [lindex $optdesc 1]
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- }
- set pathopt($option) [$Widget::_optiontype($type) $option $value [lindex $optdesc 3]]
- set pathinit($option) $pathopt($option)
- }
- }
-
- # Widget::parseArgs --
- #
- # Given a widget class and a command-line spec, cannonize and validate
- # the given options, and return a keyed list consisting of the
- # component widget and its masked portion of the command-line spec, and
- # one extra entry consisting of the portion corresponding to the
- # megawidget itself.
- #
- # Arguments:
- # class widget class to parse for.
- # options command-line spec
- #
- # Results:
- # result keyed list of portions of the megawidget and that segment of
- # the command line in which that portion is interested.
-
- proc Widget::parseArgs {class options} {
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::map classmap
-
- foreach {option val} $options {
- if { ![info exists classopt($option)] } {
- error "unknown option \"$option\""
- }
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set option [lindex $optdesc 1]
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- }
- if { ![string compare $type "TkResource"] } {
- # Make sure that the widget used for this TkResource exists
- Widget::_get_tkwidget_options [lindex [lindex $optdesc 3] 0]
- }
- set val [$Widget::_optiontype($type) $option $val [lindex $optdesc 3]]
-
- if { [info exists classmap($option)] } {
- foreach {subpath subclass realopt} $classmap($option) {
- lappend maps($subpath) $realopt $val
- }
- } else {
- lappend maps($class) $option $val
- }
- }
- return [array get maps]
- }
-
- # Widget::initFromODB --
- #
- # Initialize a megawidgets options with information from the option
- # database and from the command-line arguments given.
- #
- # Arguments:
- # class class of the widget.
- # path path of the widget -- should already exist.
- # options command-line arguments.
- #
- # Results:
- # None.
-
- proc Widget::initFromODB {class path options} {
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::$path:mod pathmod
- upvar 0 ${class}::map classmap
-
- if { [info exists pathopt] } {
- unset pathopt
- }
- if { [info exists pathmod] } {
- unset pathmod
- }
- # We prefer to use the actual widget for option db queries, but if it
- # doesn't exist yet, do the next best thing: create a widget of the
- # same class and use that.
- set fpath [_get_window $class $path]
- set rdbclass [string map [list :: ""] $class]
- if { ![winfo exists $path] } {
- set fpath ".#BWidgetClass#$class"
- if { ![winfo exists $fpath] } {
- frame $fpath -class $rdbclass
- }
- }
- foreach {option optdesc} [array get ${class}::opt] {
- set pathmod($option) 0
- if { [info exists classmap($option)] } {
- continue
- }
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- continue
- }
- if { ![string compare $type "TkResource"] } {
- set alt [lindex [lindex $optdesc 3] 1]
- } else {
- set alt ""
- }
- set optdb [lindex [_configure_option $option $alt] 0]
- set def [option get $fpath $optdb $rdbclass]
- if { [string length $def] } {
- set pathopt($option) $def
- } else {
- set pathopt($option) [lindex $optdesc 1]
- }
- }
-
- set Widget::_class($path) $class
- array set pathopt $options
- }
-
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::destroy
- # ------------------------------------------------------------------------------
- proc Widget::destroy { path } {
- variable _class
-
- set class $_class($path)
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::$path:mod pathmod
- upvar 0 ${class}::$path:init pathinit
-
- if {[info exists pathopt]} {
- unset pathopt
- }
- if {[info exists pathmod]} {
- unset pathmod
- }
- if {[info exists pathinit]} {
- unset pathinit
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::configure
- # ------------------------------------------------------------------------------
- proc Widget::configure { path options } {
- set len [llength $options]
- if { $len <= 1 } {
- return [_get_configure $path $options]
- } elseif { $len % 2 == 1 } {
- return -code error "incorrect number of arguments"
- }
-
- variable _class
- variable _optiontype
-
- set class $_class($path)
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::$path:mod pathmod
-
- set window [_get_window $class $path]
- foreach {option value} $options {
- if { ![info exists classopt($option)] } {
- return -code error "unknown option \"$option\""
- }
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set option [lindex $optdesc 1]
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- }
- if { ![lindex $optdesc 2] } {
- set newval [$_optiontype($type) $option $value [lindex $optdesc 3]]
- if { [info exists classmap($option)] } {
- set window [_get_window $class $window]
- foreach {subpath subclass realopt} $classmap($option) {
- if { [string length $subclass] } {
- set curval [${subclass}::cget $window$subpath $realopt]
- ${subclass}::configure $window$subpath $realopt $newval
- } else {
- set curval [$window$subpath cget $realopt]
- $window$subpath configure $realopt $newval
- }
- }
- } else {
- set curval $pathopt($option)
- set pathopt($option) $newval
- }
- set pathmod($option) [expr {![string equal $newval $curval]}]
- }
- }
-
- return {}
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::cget
- # ------------------------------------------------------------------------------
- proc Widget::cget { path option } {
- if { ![info exists ::Widget::_class($path)] } {
- return -code error "unknown widget $path"
- }
-
- set class $::Widget::_class($path)
- if { ![info exists ${class}::opt($option)] } {
- return -code error "unknown option \"$option\""
- }
-
- set optdesc [set ${class}::opt($option)]
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set option [lindex $optdesc 1]
- }
-
- if { [info exists ${class}::map($option)] } {
- foreach {subpath subclass realopt} [set ${class}::map($option)] {break}
- set path "[_get_window $class $path]$subpath"
- return [$path cget $realopt]
- }
- upvar 0 ${class}::$path:opt pathopt
- set pathopt($option)
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::subcget
- # ------------------------------------------------------------------------------
- proc Widget::subcget { path subwidget } {
- set class $::Widget::_class($path)
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::map$subwidget submap
- upvar 0 ${class}::$path:init pathinit
-
- set result {}
- foreach realopt [array names submap] {
- if { [info exists pathinit($submap($realopt))] } {
- lappend result $realopt $pathopt($submap($realopt))
- }
- }
- return $result
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::hasChanged
- # ------------------------------------------------------------------------------
- proc Widget::hasChanged { path option pvalue } {
- upvar $pvalue value
- set class $::Widget::_class($path)
- upvar 0 ${class}::$path:mod pathmod
-
- set value [Widget::cget $path $option]
- set result $pathmod($option)
- set pathmod($option) 0
-
- return $result
- }
-
- proc Widget::hasChangedX { path option args } {
- set class $::Widget::_class($path)
- upvar 0 ${class}::$path:mod pathmod
-
- set result $pathmod($option)
- set pathmod($option) 0
- foreach option $args {
- lappend result $pathmod($option)
- set pathmod($option) 0
- }
-
- set result
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::setoption
- # ------------------------------------------------------------------------------
- proc Widget::setoption { path option value } {
- # variable _class
-
- # set class $_class($path)
- # upvar 0 ${class}::$path:opt pathopt
-
- # set pathopt($option) $value
- Widget::configure $path [list $option $value]
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::getoption
- # ------------------------------------------------------------------------------
- proc Widget::getoption { path option } {
- # set class $::Widget::_class($path)
- # upvar 0 ${class}::$path:opt pathopt
-
- # return $pathopt($option)
- return [Widget::cget $path $option]
- }
-
- # Widget::getMegawidgetOption --
- #
- # Bypass the superfluous checks in cget and just directly peer at the
- # widget's data space. This is much more fragile than cget, so it
- # should only be used with great care, in places where speed is critical.
- #
- # Arguments:
- # path widget to lookup options for.
- # option option to retrieve.
- #
- # Results:
- # value option value.
-
- proc Widget::getMegawidgetOption {path option} {
- set class $::Widget::_class($path)
- upvar 0 ${class}::${path}:opt pathopt
- set pathopt($option)
- }
-
- # Widget::setMegawidgetOption --
- #
- # Bypass the superfluous checks in cget and just directly poke at the
- # widget's data space. This is much more fragile than configure, so it
- # should only be used with great care, in places where speed is critical.
- #
- # Arguments:
- # path widget to lookup options for.
- # option option to retrieve.
- # value option value.
- #
- # Results:
- # value option value.
-
- proc Widget::setMegawidgetOption {path option value} {
- set class $::Widget::_class($path)
- upvar 0 ${class}::${path}:opt pathopt
- set pathopt($option) $value
- }
-
- # ------------------------------------------------------------------------------
- # Command Widget::_get_window
- # returns the window corresponding to widget path
- # ------------------------------------------------------------------------------
- proc Widget::_get_window { class path } {
- set idx [string last "#" $path]
- if { $idx != -1 && ![string compare [string range $path [expr {$idx+1}] end] $class] } {
- return [string range $path 0 [expr {$idx-1}]]
- } else {
- return $path
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_get_configure
- # returns the configuration list of options
- # (as tk widget do - [$w configure ?option?])
- # ------------------------------------------------------------------------------
- proc Widget::_get_configure { path options } {
- variable _class
-
- set class $_class($path)
- upvar 0 ${class}::opt classopt
- upvar 0 ${class}::map classmap
- upvar 0 ${class}::$path:opt pathopt
- upvar 0 ${class}::$path:mod pathmod
-
- set len [llength $options]
- if { !$len } {
- set result {}
- foreach option [lsort [array names classopt]] {
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set syn $option
- set option [lindex $optdesc 1]
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- } else {
- set syn ""
- }
- if { ![string compare $type "TkResource"] } {
- set alt [lindex [lindex $optdesc 3] 1]
- } else {
- set alt ""
- }
- set res [_configure_option $option $alt]
- if { $syn == "" } {
- lappend result [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
- } else {
- lappend result [list $syn [lindex $res 0]]
- }
- }
- return $result
- } elseif { $len == 1 } {
- set option [lindex $options 0]
- if { ![info exists classopt($option)] } {
- return -code error "unknown option \"$option\""
- }
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- if { ![string compare $type "Synonym"] } {
- set option [lindex $optdesc 1]
- set optdesc $classopt($option)
- set type [lindex $optdesc 0]
- }
- if { ![string compare $type "TkResource"] } {
- set alt [lindex [lindex $optdesc 3] 1]
- } else {
- set alt ""
- }
- set res [_configure_option $option $alt]
- return [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_configure_option
- # ------------------------------------------------------------------------------
- proc Widget::_configure_option { option altopt } {
- variable _optiondb
- variable _optionclass
-
- if { [info exists _optiondb($option)] } {
- set optdb $_optiondb($option)
- } else {
- set optdb [string range $option 1 end]
- }
- if { [info exists _optionclass($option)] } {
- set optclass $_optionclass($option)
- } elseif { [string length $altopt] } {
- if { [info exists _optionclass($altopt)] } {
- set optclass $_optionclass($altopt)
- } else {
- set optclass [string range $altopt 1 end]
- }
- } else {
- set optclass [string range $option 1 end]
- }
- return [list $optdb $optclass]
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_get_tkwidget_options
- # ------------------------------------------------------------------------------
- proc Widget::_get_tkwidget_options { tkwidget } {
- variable _tk_widget
- variable _optiondb
- variable _optionclass
-
- set widget ".#BWidget#$tkwidget"
- if { ![winfo exists $widget] || ![info exists _tk_widget($tkwidget)] } {
- set widget [$tkwidget $widget]
- set config [$widget configure]
- foreach optlist $config {
- set opt [lindex $optlist 0]
- if { [llength $optlist] == 2 } {
- set refsyn [lindex $optlist 1]
- # search for class
- set idx [lsearch $config [list * $refsyn *]]
- if { $idx == -1 } {
- if { [string index $refsyn 0] == "-" } {
- # search for option (tk8.1b1 bug)
- set idx [lsearch $config [list $refsyn * *]]
- } else {
- # last resort
- set idx [lsearch $config [list -[string tolower $refsyn] * *]]
- }
- if { $idx == -1 } {
- # fed up with "can't read classopt()"
- return -code error "can't find option of synonym $opt"
- }
- }
- set syn [lindex [lindex $config $idx] 0]
- set def [lindex [lindex $config $idx] 3]
- lappend _tk_widget($tkwidget) [list $opt $syn $def]
- } else {
- set def [lindex $optlist 3]
- lappend _tk_widget($tkwidget) [list $opt $def]
- set _optiondb($opt) [lindex $optlist 1]
- set _optionclass($opt) [lindex $optlist 2]
- }
- }
- }
- return $_tk_widget($tkwidget)
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_test_tkresource
- # ------------------------------------------------------------------------------
- proc Widget::_test_tkresource { option value arg } {
- # set tkwidget [lindex $arg 0]
- # set realopt [lindex $arg 1]
- foreach {tkwidget realopt} $arg break
- set path ".#BWidget#$tkwidget"
- set old [$path cget $realopt]
- $path configure $realopt $value
- set res [$path cget $realopt]
- $path configure $realopt $old
-
- return $res
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_test_bwresource
- # ------------------------------------------------------------------------------
- proc Widget::_test_bwresource { option value arg } {
- return -code error "bad option type BwResource in widget"
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_test_synonym
- # ------------------------------------------------------------------------------
- proc Widget::_test_synonym { option value arg } {
- return -code error "bad option type Synonym in widget"
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_test_string
- # ------------------------------------------------------------------------------
- proc Widget::_test_string { option value arg } {
- set value
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::_test_flag
- # ------------------------------------------------------------------------------
- proc Widget::_test_flag { option value arg } {
- set len [string length $value]
- set res ""
- for {set i 0} {$i < $len} {incr i} {
- set c [string index $value $i]
- if { [string first $c $arg] == -1 } {
- return -code error "bad [string range $option 1 end] value \"$value\": characters must be in \"$arg\""
- }
- if { [string first $c $res] == -1 } {
- append res $c
- }
- }
- return $res
- }
-
-
- # -----------------------------------------------------------------------------
- # Command Widget::_test_enum
- # -----------------------------------------------------------------------------
- proc Widget::_test_enum { option value arg } {
- if { [lsearch $arg $value] == -1 } {
- set last [lindex $arg end]
- set sub [lreplace $arg end end]
- if { [llength $sub] } {
- set str "[join $sub ", "] or $last"
- } else {
- set str $last
- }
- return -code error "bad [string range $option 1 end] value \"$value\": must be $str"
- }
- return $value
- }
-
-
- # -----------------------------------------------------------------------------
- # Command Widget::_test_int
- # -----------------------------------------------------------------------------
- proc Widget::_test_int { option value arg } {
- if { ![string is int -strict $value] || \
- ([string length $arg] && \
- ![expr [string map [list %d $value] $arg]]) } {
- return -code error "bad $option value\
- \"$value\": must be integer ($arg)"
- }
- return $value
- }
-
-
- # -----------------------------------------------------------------------------
- # Command Widget::_test_boolean
- # -----------------------------------------------------------------------------
- proc Widget::_test_boolean { option value arg } {
- if { ![string is boolean -strict $value] } {
- return -code error "bad $option value \"$value\": must be boolean"
- }
-
- # Get the canonical form of the boolean value (1 for true, 0 for false)
- return [string is true $value]
- }
-
-
- # -----------------------------------------------------------------------------
- # Command Widget::focusNext
- # Same as tk_focusNext, but call Widget::focusOK
- # -----------------------------------------------------------------------------
- proc Widget::focusNext { w } {
- set cur $w
- while 1 {
-
- # Descend to just before the first child of the current widget.
-
- set parent $cur
- set children [winfo children $cur]
- set i -1
-
- # Look for the next sibling that isn't a top-level.
-
- while 1 {
- incr i
- if {$i < [llength $children]} {
- set cur [lindex $children $i]
- if {[winfo toplevel $cur] == $cur} {
- continue
- } else {
- break
- }
- }
-
- # No more siblings, so go to the current widget's parent.
- # If it's a top-level, break out of the loop, otherwise
- # look for its next sibling.
-
- set cur $parent
- if {[winfo toplevel $cur] == $cur} {
- break
- }
- set parent [winfo parent $parent]
- set children [winfo children $parent]
- set i [lsearch -exact $children $cur]
- }
- if {($cur == $w) || [focusOK $cur]} {
- return $cur
- }
- }
- }
-
-
- # -----------------------------------------------------------------------------
- # Command Widget::focusPrev
- # Same as tk_focusPrev, but call Widget::focusOK
- # -----------------------------------------------------------------------------
- proc Widget::focusPrev { w } {
- set cur $w
- while 1 {
-
- # Collect information about the current window's position
- # among its siblings. Also, if the window is a top-level,
- # then reposition to just after the last child of the window.
-
- if {[winfo toplevel $cur] == $cur} {
- set parent $cur
- set children [winfo children $cur]
- set i [llength $children]
- } else {
- set parent [winfo parent $cur]
- set children [winfo children $parent]
- set i [lsearch -exact $children $cur]
- }
-
- # Go to the previous sibling, then descend to its last descendant
- # (highest in stacking order. While doing this, ignore top-levels
- # and their descendants. When we run out of descendants, go up
- # one level to the parent.
-
- while {$i > 0} {
- incr i -1
- set cur [lindex $children $i]
- if {[winfo toplevel $cur] == $cur} {
- continue
- }
- set parent $cur
- set children [winfo children $parent]
- set i [llength $children]
- }
- set cur $parent
- if {($cur == $w) || [focusOK $cur]} {
- return $cur
- }
- }
- }
-
-
- # ------------------------------------------------------------------------------
- # Command Widget::focusOK
- # Same as tk_focusOK, but handles -editable option and whole tags list.
- # ------------------------------------------------------------------------------
- proc Widget::focusOK { w } {
- set code [catch {$w cget -takefocus} value]
- if { $code == 1 } {
- return 0
- }
- if {($code == 0) && ($value != "")} {
- if {$value == 0} {
- return 0
- } elseif {$value == 1} {
- return [winfo viewable $w]
- } else {
- set value [uplevel \#0 $value $w]
- if {$value != ""} {
- return $value
- }
- }
- }
- if {![winfo viewable $w]} {
- return 0
- }
- set code [catch {$w cget -state} value]
- if {($code == 0) && ($value == "disabled")} {
- return 0
- }
- set code [catch {$w cget -editable} value]
- if {($code == 0) && !$value} {
- return 0
- }
-
- set top [winfo toplevel $w]
- foreach tags [bindtags $w] {
- if { [string compare $tags $top] &&
- [string compare $tags "all"] &&
- [regexp Key [bind $tags]] } {
- return 1
- }
- }
- return 0
- }
-
- # Widget::varForOption --
- #
- # Retrieve a fully qualified variable name for the option specified.
- # If the option is not one for which a variable exists, throw an error
- # (ie, those options that map directly to widget options).
- #
- # Arguments:
- # path megawidget to get an option var for.
- # option option to get a var for.
- #
- # Results:
- # varname name of the variable, fully qualified, suitable for tracing.
-
- proc Widget::varForOption {path option} {
- variable _class
- variable _optiontype
-
- set class $_class($path)
- upvar 0 ${class}::$path:opt pathopt
-
- if { ![info exists pathopt($option)] } {
- error "unable to find variable for option \"$option\""
- }
- set varname "::Widget::${class}::$path:opt($option)"
- return $varname
- }
-
-