source: branches/r9/gui/scripts/page.tcl @ 4914

Last change on this file since 4914 was 3642, checked in by mmc, 11 years ago

Fixes for nanoHUB ticket #258058 and #258045 -- note within a group tab
doesn't fill out the area properly. Should work better now. Also fixed
tabs to contain the window, instead of floating above the cotents as they
have for a long time.

Fixed boolean controls to have a more obvious on/off switch instead of a
checkbox. Fixed integers and spinners to use larger +/- buttons that are
easier to press on an iPad. Fixed numbers and other gauges to have the
same relief style as entries and other widgets.

Added new layout styles to groups: horizontal, vertical, tabs, and sentence.
You can now explicitly make a layout vertical instead of tabs by setting
the layout to "vertical" instead of throwing in a separator. Updated the
zoo/groups example to show off new horizontal and sentence types.

Fixed the "drawing" example in the zoo to gray out the trapezoid top when
it is disabled.

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                    -layout [$xmlobj get $path.about.layout]
196                pack $frame.cntls -expand yes -fill both -pady 4
197            }
198
199            # if this is a group, then build that group
200            if {[$xmlobj element -as type $path.$cname] eq "group"} {
201                if {[$xmlobj element -as id $path.$cname] eq "ambient"
202                       && $deveditor != ""} {
203                    set w [$deveditor component top]
204                } else {
205                    if {[$_owner widgetfor $path.$cname] ne ""} {
206                        # widget already created -- skip this
207                    } elseif {[catch {$frame.cntls insert end $path.$cname} c]} {
208                        global errorInfo
209                        error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
210                    } else {
211                        set gentry [$frame.cntls control $c]
212                        set w [$gentry component inner]
213                    }
214                }
215                _buildGroup $w $xmlobj $path.$cname
216            } else {
217                if {[$_owner widgetfor $path.$cname] ne ""} {
218                    # widget already created -- skip this
219                } elseif {[catch {$frame.cntls insert end $path.$cname} c]} {
220                    global errorInfo
221                    error $c "$c\n$errorInfo\n    (while building control for $path.$cname)"
222                }
223            }
224        }
225    }
226}
227
228itcl::body Rappture::Page::_link {xmlobj path w path2} {
229    if {"" != [$xmlobj element -as type $path.current]} {
230        set val [$xmlobj get $path.current]
231        if {[string length $val] > 0} {
232            $w value $val
233            $xmlobj put $path.current $val
234        } else {
235            set obj [$xmlobj element -as object $path.current]
236            $w value $obj
237            $xmlobj put $path.current $obj
238        }
239    }
240    $_owner changed $path2
241}
Note: See TracBrowser for help on using the repository browser.