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

Last change on this file since 26 was 26, checked in by mmc, 17 years ago

Fixed the rendering of groups, and groups within groups.
If groups are mixed in with other elements, then they are
drawn with a gray outline/heading, with the title taken
from the <group><about><label>. However, if a group
contains only other groups, then it is treated as a tabbed
notebook, and each group within is put on a separate page.

WARNING: There are many bad interactions between the
blt::tabset, the Rappture::Scroller, and the Rappture::Pager.
Pages shake violently when all are in play. The only way I
could get them to settle down was by putting the tabs above
the pages they control. Have to revisit this some time to
make it look better...

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