source: trunk/gui/scripts/page.tcl @ 640

Last change on this file since 640 was 438, checked in by mmc, 18 years ago

Fixed the <enable> facility so that it will work correctly even
when an <enable> statement references an element that is loaded
dynamically into a <structure> parameters section. The element
is not found at first, so Rappture prints out a warning message
to stderr. But when the element is loaded later, the <enable>
condition works as expected.

NOTE: When referencing an element that produces one of these
warnings, you must use the standard notation (i.e., type(name))
for each element in the path. Otherwise, the enable/disable
won't work, but you won't get an error about it.

File size: 8.6 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: page - single page of widgets
3#
4#  This widget is a smart frame.  It takes the XML description for
5#  a Rappture <input> or an <input><phase> and decides how to lay
6#  out the widgets for the controls within it.  It uses various
7#  heuristics to achieve a decent layout under a variety of
8#  circumstances.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005  Purdue Research Foundation
12#
13#  See the file "license.terms" for information on usage and
14#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15# ======================================================================
16package require Itk
17
18itcl::class Rappture::Page {
19    inherit itk::Widget
20
21    constructor {owner path args} { # defined below }
22
23    protected method _buildGroup {frame xmlobj path}
24    protected method _link {xmlobj path widget path2}
25
26    private variable _owner ""       ;# thing managing this page
27}
28                                                                               
29itk::usual Page {
30}
31
32# ----------------------------------------------------------------------
33# CONSTRUCTOR
34# ----------------------------------------------------------------------
35itcl::body Rappture::Page::constructor {owner path args} {
36    if {[catch {$owner isa Rappture::ControlOwner} valid] || !$valid} {
37        error "object \"$owner\" is not a Rappture::ControlOwner"
38    }
39    set _owner $owner
40    set xmlobj [$owner xml object]
41
42    set type [$xmlobj element -as type $path]
43    if {$type != "input" && $type != "phase"} {
44        error "bad path \"$path\" in $xmlobj: should be <input> or <input><phase>"
45    }
46
47    eval itk_initialize $args
48
49    # build all of the controls for this page
50    _buildGroup $itk_interior $xmlobj $path
51}
52
53# ----------------------------------------------------------------------
54# USAGE: _buildGroup <frame> <xmlobj> <path>
55#
56# Used internally when this page is being constructed to build the
57# controls within the group at the specified <path> in the <xmlobj>.
58# The controls are added to the given <frame>.
59# ----------------------------------------------------------------------
60itcl::body Rappture::Page::_buildGroup {frame xmlobj path} {
61    frame $frame.results
62    pack $frame.results -side right -fill y
63
64    set deveditor ""
65
66    #
67    # Scan through all remaining input elements.  If there is an
68    # ambient group, then add its children to the device editor,
69    # if there is one.
70    #
71    set num 0
72    set clist [$xmlobj children $path]
73    while {[llength $clist] > 0} {
74        set cname [lindex $clist 0]
75        set clist [lrange $clist 1 end]
76
77        set type [$xmlobj element -as type $path.$cname]
78        if {$type == "about"} {
79            continue
80        }
81
82        if {$type == "loader"} {
83            #
84            # Add <loader>'s at the top of the page.
85            #
86            if {![winfo exists $frame.loaders]} {
87                frame $frame.loaders
88                pack $frame.loaders -side top -fill x
89
90                frame $frame.loaders.sep -height 2 \
91                    -borderwidth 1 -relief sunken
92                pack $frame.loaders.sep -side bottom -fill x -pady 4
93            }
94            set w "$frame.loaders.l[incr num]"
95            Rappture::Controls $w $_owner
96            pack $w -fill x
97            $w insert end $path.$cname
98        } elseif {$type == "structure"} {
99            #
100            # Add <structure>'s as the central element of the page.
101            #
102            set w "$frame.device[incr num]"
103            Rappture::DeviceEditor ::$w $_owner@$path.$cname.current
104            pack $w -expand yes -fill both
105            $_owner widgetfor $path.$cname $w
106            bind $w <<Value>> [list $_owner changed $path.$cname]
107
108            if {"" == $deveditor} {
109                set deveditor $w
110            }
111
112            # if there's a default value, load it now
113            if {"" != [$xmlobj element -as type $path.$cname.current]} {
114                set elem $path.$cname.current
115            } else {
116                set elem $path.$cname.default
117            }
118            if {"" != [$xmlobj element -as type $elem]} {
119                set val [$xmlobj get $elem]
120                if {[string length $val] > 0} {
121                    $w value $val
122                    $xmlobj put $path.$cname.current $val
123                } else {
124                    set obj [$xmlobj element -as object $elem]
125                    $w value $obj
126                    $xmlobj put $path.$cname.current $obj
127                }
128            }
129
130            # if there's a link, then set up a callback to load from it
131            set link [$xmlobj get $path.$cname.link]
132            if {"" != $link} {
133                $_owner notify add $this $link \
134                    [itcl::code $this _link $xmlobj $link $w $path.$cname]
135            }
136        } elseif {$type == "tool"} {
137            set service [Rappture::Service ::#auto $_owner $path.$cname]
138            #
139            # Scan through all extra inputs associated with this subtool
140            # and create corresponding inputs in the top-level tool.
141            # Then, add the input names to the list being processed here,
142            # so that we'll create the controls during subsequent passes
143            # through the loop.
144            #
145            set extra ""
146            foreach obj [$service input] {
147                set cname [$obj element]
148                $xmlobj copy $path.$cname from $obj ""
149                lappend extra $cname
150            }
151
152            #
153            # If there's a control for this service, then add it
154            # to the end of the extra controls added above.
155            #
156            foreach obj [$service control] {
157                set cname [$obj element]
158                $xmlobj copy $path.$cname from $obj ""
159                $xmlobj put $path.$cname.service $service
160                lappend extra $cname
161            }
162            if {[llength $extra] > 0} {
163                set clist [eval linsert [list $clist] 0 $extra]
164            }
165
166            #
167            # Scan through all outputs associated with this subtool
168            # and create any corresponding feedback widgets.
169            #
170            foreach obj [$service output] {
171                set cname [$obj element]
172                $xmlobj copy $cname from $obj ""
173
174                # pick a good size based on output type
175                set w $frame.results.result[incr num]
176                set type [$obj element -as type]
177                switch -- $type {
178                    number - integer - boolean - choice {
179                        Rappture::ResultViewer $w -width 0 -height 0
180                        pack $w -fill x -padx 4 -pady 4
181                    }
182                    default {
183                        Rappture::ResultViewer $w -width 4i -height 4i
184                        pack $w -expand yes -fill both -padx 4 -pady 4
185                    }
186                }
187                $service output for $obj $w
188            }
189        } else {
190            # create a control panel, if necessary
191            if {![winfo exists $frame.cntls]} {
192                Rappture::Controls $frame.cntls $_owner
193                pack $frame.cntls -expand yes -fill both -pady 4
194            }
195
196            # if this is a group, then build that group
197            if {[$xmlobj element -as type $path.$cname] == "group"} {
198                if {[$xmlobj element -as id $path.$cname] == "ambient"
199                       && $deveditor != ""} {
200                    set w [$deveditor component top]
201                } else {
202                    if {[catch {$frame.cntls insert end $path.$cname} c]} {
203                        global errorInfo
204                        error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
205                    } else {
206                        set gentry [$frame.cntls control $c]
207                        set w [$gentry component inner]
208                    }
209                }
210                _buildGroup $w $xmlobj $path.$cname
211            } else {
212                if {[catch {$frame.cntls insert end $path.$cname} c]} {
213                    error $c "$c\n    (while building control for $path.$cname)"
214                }
215            }
216        }
217    }
218}
219
220itcl::body Rappture::Page::_link {xmlobj path w path2} {
221    if {"" != [$xmlobj element -as type $path.current]} {
222        set val [$xmlobj get $path.current]
223        if {[string length $val] > 0} {
224            $w value $val
225            $xmlobj put $path.current $val
226        } else {
227            set obj [$xmlobj element -as object $path.current]
228            $w value $obj
229            $xmlobj put $path.current $obj
230        }
231    }
232    $_owner changed $path2
233}
Note: See TracBrowser for help on using the repository browser.