source: branches/blt4/gui/scripts/filechoiceentry.tcl @ 1829

Last change on this file since 1829 was 1695, checked in by gah, 14 years ago
File size: 9.3 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: FileChoiceEntry - widget for entering a choice of strings
4#
5#  This widget represents a <choice> entry on a control panel.
6#  It is used to choose one of several mutually-exclusive strings.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2005  Purdue Research Foundation
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15
16itcl::class Rappture::FileChoiceEntry {
17    inherit itk::Widget
18
19    itk_option define -state state State "normal"
20   
21    private variable _rebuildPending 0
22
23    constructor {owner path args} {
24        # defined below
25    }
26    destructor {
27        # defined below
28    }
29    public method value {args}
30
31    public method label {}
32    public method tooltip {}
33
34    protected method _rebuild {}
35    protected method _newValue {}
36    protected method _tooltip {}
37    protected method _whenidle {}
38
39    private variable _owner ""    ;# thing managing this control
40    private variable _path ""     ;# path in XML to this number
41    private variable _str2val     ;# maps option label => option value
42}
43
44
45itk::usual FileChoiceEntry {
46    keep -cursor -font
47    keep -foreground -background
48    keep -textforeground -textbackground
49    keep -selectbackground -selectforeground -selectborderwidth
50}
51
52# ----------------------------------------------------------------------
53# CONSTRUCTOR
54# ----------------------------------------------------------------------
55itcl::body Rappture::FileChoiceEntry::constructor {owner path args} {
56    if {[catch {$owner isa Rappture::ControlOwner} valid] != 0 || !$valid} {
57        error "bad object \"$owner\": should be Rappture::ControlOwner"
58    }
59    set _owner $owner
60    set _path $path
61
62    #
63    # Create the widget and configure it properly based on other
64    # hints in the XML.
65    #
66    itk_component add choice {
67        Rappture::Combobox $itk_interior.choice -editable no
68    }
69    pack $itk_component(choice) -expand yes -fill both
70    bind $itk_component(choice) <<Value>> [itcl::code $this _newValue]
71
72    # First time, parse the <pattern> elements to generate notify callbacks
73    # for each template found.
74    foreach cname [$_owner xml children -type pattern $_path] {
75        set glob [string trim [$_owner xml get $_path.$cname]]
76        # Successively replace each template with its value.
77        while { [regexp -indices {@@[^@]*@@} $glob range] } {
78            foreach {first last} $range break
79            set i1 [expr $first + 2]
80            set i2 [expr $last  - 2]
81            set cpath [string range $glob $i1 $i2]
82            set value [$_owner xml get $cpath.$cname]
83            set glob [string replace $glob $first $last $value]
84            $_owner notify add $this $cpath [itcl::code $this _whenidle]
85        }
86    }
87    $_owner notify sync
88    eval itk_initialize $args
89    _rebuild
90}
91
92# ----------------------------------------------------------------------
93# DESTRUCTOR
94# ----------------------------------------------------------------------
95itcl::body Rappture::FileChoiceEntry::destructor {} {
96    $_owner notify remove $this
97}
98
99# ----------------------------------------------------------------------
100# USAGE: value ?-check? ?<newval>?
101#
102# Clients use this to query/set the value for this widget.  With
103# no args, it returns the current value for the widget.  If the
104# <newval> is specified, it sets the value of the widget and
105# sends a <<Value>> event.  If the -check flag is included, the
106# new value is not actually applied, but just checked for correctness.
107# ----------------------------------------------------------------------
108itcl::body Rappture::FileChoiceEntry::value {args} {
109    set onlycheck 0
110    set i [lsearch -exact $args -check]
111    if {$i >= 0} {
112        set onlycheck 1
113        set args [lreplace $args $i $i]
114    }
115
116    if {[llength $args] == 1} {
117        if {$onlycheck} {
118            # someday we may add validation...
119            return
120        }
121        set newval [lindex $args 0]
122        if {[info exists _str2val($newval)]} {
123            # this is a label -- use it directly
124            $itk_component(choice) value $newval
125            set newval $_str2val($newval)  ;# report the actual value
126        } else {
127            # this is a value -- search for corresponding label
128            foreach str [array names _str2val] {
129                if {$_str2val($str) == $newval} {
130                    $itk_component(choice) value $str
131                    break
132                }
133            }
134        }
135        return $newval
136
137    } elseif {[llength $args] != 0} {
138        error "wrong # args: should be \"value ?-check? ?newval?\""
139    }
140
141    #
142    # Query the value and return.
143    #
144    set str [$itk_component(choice) value]
145    if {[info exists _str2val($str)]} {
146        return $_str2val($str)
147    }
148    return $str
149}
150
151# ----------------------------------------------------------------------
152# USAGE: label
153#
154# Clients use this to query the label associated with this widget.
155# Reaches into the XML and pulls out the appropriate label string.
156# ----------------------------------------------------------------------
157itcl::body Rappture::FileChoiceEntry::label {} {
158    set label [$_owner xml get $_path.about.label]
159    if {"" == $label} {
160        set label "Choice"
161    }
162    return $label
163}
164
165# ----------------------------------------------------------------------
166# USAGE: tooltip
167#
168# Clients use this to query the tooltip associated with this widget.
169# Reaches into the XML and pulls out the appropriate description
170# string.  Returns the string that should be used with the
171# Rappture::Tooltip facility.
172# ----------------------------------------------------------------------
173itcl::body Rappture::FileChoiceEntry::tooltip {} {
174    # query tooltip on-demand based on current choice
175    return "@[itcl::code $this _tooltip]"
176}
177
178# ----------------------------------------------------------------------
179# USAGE: _rebuild
180#
181# Used internally to rebuild the contents of this choice widget
182# whenever something that it depends on changes.  Scans through the
183# information in the XML spec and builds a list of choices for the
184# widget.
185# ----------------------------------------------------------------------
186itcl::body Rappture::FileChoiceEntry::_rebuild {} {
187    set _rebuildPending 0
188    # get rid of any existing choices
189    $itk_component(choice) choices delete 0 end
190    array unset _str2val
191    #
192    # Plug in the various options for the choice.
193    #
194    set max 10
195    $_owner notify sync
196    set allfiles {}
197    foreach cname [$_owner xml children -type pattern $_path] {
198        set glob [string trim [$_owner xml get $_path.$cname]]
199        # Successively replace each template with its value.
200        while { [regexp -indices {@@[^@]*@@} $glob range] } {
201            foreach {first last} $range break
202            set i1 [expr $first + 2]
203            set i2 [expr $last  - 2]
204            set cpath [string range $glob $i1 $i2]
205            set value [$_owner xml get $cpath.current]
206            if { $value == "" } {
207                set value [$_owner xml get $cpath.default]
208            }
209            set glob [string replace $glob $first $last $value]
210        }
211        # Replace the template with the substituted value.
212        set files [glob -nocomplain $glob]
213        set allfiles [concat $allfiles $files]
214    }
215    set first ""
216    set tail ""
217    foreach file $allfiles {
218        set tail [file tail $file]
219        if { $first == "" } {
220            set first $tail
221        }
222        set tail [file root $tail]
223        $itk_component(choice) choices insert end $file $tail
224        set _str2val($tail) $file
225        set len [string length $tail]
226        if {$len > $max} { set max $len }
227    }
228    $itk_component(choice) configure -width $max
229    $itk_component(choice) value $tail
230}
231
232# ----------------------------------------------------------------------
233# USAGE: _newValue
234#
235# Invoked automatically whenever the value in the choice changes.
236# Sends a <<Value>> event to notify clients of the change.
237# ----------------------------------------------------------------------
238itcl::body Rappture::FileChoiceEntry::_newValue {} {
239    event generate $itk_component(hull) <<Value>>
240}
241
242# ----------------------------------------------------------------------
243# USAGE: _tooltip
244#
245# Returns the tooltip for this widget, given the current choice in
246# the selector.  This is normally called by the Rappture::Tooltip
247# facility whenever it is about to pop up a tooltip for this widget.
248# ----------------------------------------------------------------------
249itcl::body Rappture::FileChoiceEntry::_tooltip {} {
250    set tip [string trim [$_owner xml get $_path.about.description]]
251    # get the description for the current choice, if there is one
252    set str [$itk_component(choice) value]
253    set path [$itk_component(choice) translate $str]
254    set desc $path
255    if {$path == ""} {
256        set desc [$_owner xml get $_path.about.description]
257    }
258
259    if {[string length $str] > 0 && [string length $desc] > 0} {
260        append tip "\n\n$str:\n$desc"
261    }
262    return $tip
263}
264
265# ----------------------------------------------------------------------
266# CONFIGURATION OPTION: -state
267# ----------------------------------------------------------------------
268itcl::configbody Rappture::FileChoiceEntry::state {
269    set valid {normal disabled}
270    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
271        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
272    }
273    $itk_component(choice) configure -state $itk_option(-state)
274}
275
276itcl::body Rappture::FileChoiceEntry::_whenidle {} {
277    if { !$_rebuildPending } {
278        after 10 [itcl::code $this _rebuild]
279        set _rebuildPending 1
280    }
281}
Note: See TracBrowser for help on using the repository browser.