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

Last change on this file since 3093 was 2995, checked in by gah, 13 years ago
File size: 8.8 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        if {$type == "loader"} {
82            #
83            # Add <loader>'s at the top of the page.
84            #
85            if {![winfo exists $frame.loaders]} {
86                frame $frame.loaders
87                pack $frame.loaders -side top -fill x
88
89                frame $frame.loaders.sep -height 2 \
90                    -borderwidth 1 -relief sunken
91                pack $frame.loaders.sep -side bottom -fill x -pady 4
92            }
93            set w "$frame.loaders.l[incr num]"
94            Rappture::Controls $w $_owner
95            pack $w -fill x
96            $w insert end $path.$cname
97        } elseif {$type == "structure"} {
98            #
99            # Add <structure>'s as the central element of the page.
100            #
101            set w "$frame.device[incr num]"
102            Rappture::DeviceEditor ::$w $_owner@$path.$cname.current
103            pack $w -expand yes -fill both
104            $_owner widgetfor $path.$cname $w
105            bind $w <<Value>> [list $_owner changed $path.$cname]
106
107            if {"" == $deveditor} {
108                set deveditor $w
109            }
110
111            # if there's a default value, load it now
112            if {"" != [$xmlobj element -as type $path.$cname.current]} {
113                set elem $path.$cname.current
114            } else {
115                set elem $path.$cname.default
116            }
117            if {"" != [$xmlobj element -as type $elem]} {
118                set val [$xmlobj get $elem]
119                if {[string length $val] > 0} {
120                    $w value $val
121                    $xmlobj put $path.$cname.current $val
122                } else {
123                    set obj [$xmlobj element -as object $elem]
124                    $w value $obj
125                    $xmlobj put $path.$cname.current $obj
126                }
127            }
128
129            # if there's a link, then set up a callback to load from it
130            set link [$xmlobj get $path.$cname.link]
131            if {"" != $link} {
132                $_owner notify add $this $link \
133                    [itcl::code $this _link $xmlobj $link $w $path.$cname]
134            }
135        } elseif {$type == "tool"} {
136            set service [Rappture::Service ::#auto $_owner $path.$cname]
137            #
138            # Scan through all extra inputs associated with this subtool
139            # and create corresponding inputs in the top-level tool.
140            # Then, add the input names to the list being processed here,
141            # so that we'll create the controls during subsequent passes
142            # through the loop.
143            #
144            set extra ""
145            foreach obj [$service input] {
146                set cname [$obj element]
147                $xmlobj copy $path.$cname from $obj ""
148                lappend extra $cname
149            }
150
151            #
152            # If there's a control for this service, then add it
153            # to the end of the extra controls added above.
154            #
155            foreach obj [$service control] {
156                set cname [$obj element]
157                $xmlobj copy $path.$cname from $obj ""
158                $xmlobj put $path.$cname.service $service
159                lappend extra $cname
160            }
161            if {[llength $extra] > 0} {
162                set clist [eval linsert [list $clist] 0 $extra]
163            }
164
165            #
166            # Scan through all outputs associated with this subtool
167            # and create any corresponding feedback widgets.
168            #
169            foreach obj [$service output] {
170                set cname [$obj element]
171                $xmlobj copy $cname from $obj ""
172
173                # pick a good size based on output type
174                set w $frame.results.result[incr num]
175                set type [$obj element -as type]
176                switch -- $type {
177                    number - integer - boolean - choice {
178                        Rappture::ResultViewer $w -width 0 -height 0
179                        pack $w -fill x -padx 4 -pady 4
180                    }
181                    default {
182                        Rappture::ResultViewer $w -width 4i -height 4i
183                        pack $w -expand yes -fill both -padx 4 -pady 4
184                    }
185                }
186                $service output for $obj $w
187            }
188        } elseif {$type == "current"} {
189            # Don't do anything.
190        } else {
191            # create a control panel, if necessary
192            if {![winfo exists $frame.cntls]} {
193                Rappture::Controls $frame.cntls $_owner
194                pack $frame.cntls -expand yes -fill both -pady 4
195            }
196
197            # if this is a group, then build that group
198            if {[$xmlobj element -as type $path.$cname] == "group"} {
199                if {[$xmlobj element -as id $path.$cname] == "ambient"
200                       && $deveditor != ""} {
201                    set w [$deveditor component top]
202                } else {
203                    if {[catch {$frame.cntls insert end $path.$cname} c]} {
204                        global errorInfo
205                        error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
206                    } else {
207                        set gentry [$frame.cntls control $c]
208                        set w [$gentry component inner]
209                    }
210                }
211                _buildGroup $w $xmlobj $path.$cname
212            } else {
213                if {[catch {$frame.cntls insert end $path.$cname} c]} {
214                    global errorInfo
215                    error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
216                }
217            }
218        }
219    }
220}
221
222itcl::body Rappture::Page::_link {xmlobj path w path2} {
223    if {"" != [$xmlobj element -as type $path.current]} {
224        set val [$xmlobj get $path.current]
225        if {[string length $val] > 0} {
226            $w value $val
227            $xmlobj put $path.current $val
228        } else {
229            set obj [$xmlobj element -as object $path.current]
230            $w value $obj
231            $xmlobj put $path.current $obj
232        }
233    }
234    $_owner changed $path2
235}
Note: See TracBrowser for help on using the repository browser.