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

Last change on this file since 3636 was 3636, checked in by mmc, 9 years ago

Fixed the drawing widget to handle notifications from outside widgets, so
that canvas items react to value changes. Also added tooltips for drawing
items.

Nudged the next/back buttons for the pager in a bit, so they're a little
easier to press in the iPad app.

Fixed the Ruby template for the builder to include the overwrite/append flag.

File size: 9.1 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: page - single page of widgets
4#
5#  This widget is a smart frame.  It takes the XML description for
6#  a Rappture <input> or an <input><phase> and decides how to lay
7#  out the widgets for the controls within it.  It uses various
8#  heuristics to achieve a decent layout under a variety of
9#  circumstances.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require Itk
18
19itcl::class Rappture::Page {
20    inherit itk::Widget
21
22    constructor {owner path args} { # defined below }
23
24    protected method _buildGroup {frame xmlobj path}
25    protected method _link {xmlobj path widget path2}
26
27    private variable _owner ""       ;# thing managing this page
28}
29                                                                               
30itk::usual Page {
31}
32
33# ----------------------------------------------------------------------
34# CONSTRUCTOR
35# ----------------------------------------------------------------------
36itcl::body Rappture::Page::constructor {owner path args} {
37    if {[catch {$owner isa Rappture::ControlOwner} valid] || !$valid} {
38        error "object \"$owner\" is not a Rappture::ControlOwner"
39    }
40    set _owner $owner
41    set xmlobj [$owner xml object]
42
43    set type [$xmlobj element -as type $path]
44    if {$type != "input" && $type != "phase"} {
45        error "bad path \"$path\" in $xmlobj: should be <input> or <input><phase>"
46    }
47
48    eval itk_initialize $args
49
50    # build all of the controls for this page
51    _buildGroup $itk_interior $xmlobj $path
52}
53
54# ----------------------------------------------------------------------
55# USAGE: _buildGroup <frame> <xmlobj> <path>
56#
57# Used internally when this page is being constructed to build the
58# controls within the group at the specified <path> in the <xmlobj>.
59# The controls are added to the given <frame>.
60# ----------------------------------------------------------------------
61itcl::body Rappture::Page::_buildGroup {frame xmlobj path} {
62    frame $frame.results
63    pack $frame.results -side right -fill y
64
65    set deveditor ""
66
67    #
68    # Scan through all remaining input elements.  If there is an
69    # ambient group, then add its children to the device editor,
70    # if there is one.
71    #
72    set num 0
73    set clist [$xmlobj children $path]
74    while {[llength $clist] > 0} {
75        set cname [lindex $clist 0]
76        set clist [lrange $clist 1 end]
77
78        set type [$xmlobj element -as type $path.$cname]
79        if {$type == "about"} {
80            continue
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        } elseif {$type == "current"} {
190            # Don't do anything.
191        } else {
192            # create a control panel, if necessary
193            if {![winfo exists $frame.cntls]} {
194                Rappture::Controls $frame.cntls $_owner
195                pack $frame.cntls -expand yes -fill both -pady 4
196            }
197
198            # if this is a group, then build that group
199            if {[$xmlobj element -as type $path.$cname] eq "group"} {
200                if {[$xmlobj element -as id $path.$cname] eq "ambient"
201                       && $deveditor != ""} {
202                    set w [$deveditor component top]
203                } else {
204                    if {[$_owner widgetfor $path.$cname] ne ""} {
205                        # widget already created -- skip this
206                    } elseif {[catch {$frame.cntls insert end $path.$cname} c]} {
207                        global errorInfo
208                        error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
209                    } else {
210                        set gentry [$frame.cntls control $c]
211                        set w [$gentry component inner]
212                    }
213                }
214                _buildGroup $w $xmlobj $path.$cname
215            } else {
216                if {[$_owner widgetfor $path.$cname] ne ""} {
217                    # widget already created -- skip this
218                } elseif {[catch {$frame.cntls insert end $path.$cname} c]} {
219                    global errorInfo
220                    error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
221                }
222            }
223        }
224    }
225}
226
227itcl::body Rappture::Page::_link {xmlobj path w path2} {
228    if {"" != [$xmlobj element -as type $path.current]} {
229        set val [$xmlobj get $path.current]
230        if {[string length $val] > 0} {
231            $w value $val
232            $xmlobj put $path.current $val
233        } else {
234            set obj [$xmlobj element -as object $path.current]
235            $w value $obj
236            $xmlobj put $path.current $obj
237        }
238    }
239    $_owner changed $path2
240}
Note: See TracBrowser for help on using the repository browser.