Index: /trunk/gui/scripts/controls.tcl
===================================================================
--- /trunk/gui/scripts/controls.tcl	(revision 25)
+++ /trunk/gui/scripts/controls.tcl	(revision 26)
@@ -11,4 +11,5 @@
 # ======================================================================
 package require Itk
+package require BLT
 
 option add *Controls.padding 4 widgetDefault
@@ -31,6 +32,9 @@
     protected method _controlChanged {path}
     protected method _formatLabel {str}
+    protected method _changeTabs {}
 
     private variable _owner ""       ;# controls belong to this owner
+    private variable _tabs ""        ;# optional tabset for groups
+    private variable _frame ""       ;# pack controls into this frame
     private variable _counter 0      ;# counter for control names
     private variable _dispatcher ""  ;# dispatcher for !events
@@ -51,4 +55,16 @@
 
     set _owner $owner
+
+    Rappture::Scroller $itk_interior.sc -xscrollmode none -yscrollmode auto
+    pack $itk_interior.sc -expand yes -fill both
+    set f [$itk_interior.sc contents frame]
+
+    set _tabs [blt::tabset $f.tabs -borderwidth 0 -relief flat \
+        -side top -tearoff 0 -highlightthickness 0 \
+        -selectbackground $itk_option(-background) \
+        -selectcommand [itcl::code $this _changeTabs]]
+
+    set _frame [frame $f.inner]
+    pack $_frame -expand yes -fill both
 
     eval itk_initialize $args
@@ -78,5 +94,5 @@
     set _name2info($name-path) $path
     set _name2info($name-label) ""
-    set _name2info($name-value) [set w $itk_interior.v$name]
+    set _name2info($name-value) [set w $_frame.v$name]
 
     set type [$_owner xml element -as type $path]
@@ -126,5 +142,5 @@
         set label [$w label]
         if {"" != $label} {
-            set _name2info($name-label) $itk_interior.l$name
+            set _name2info($name-label) $_frame.l$name
             set font [option get $itk_component(hull) labelFont Font]
             label $_name2info($name-label) -text [_formatLabel $label] \
@@ -257,40 +273,128 @@
         }
     }
+    if {[$_tabs size] > 0} {
+        $_tabs delete 0 end
+    }
 
     #
-    # Lay out the widgets in a simple "Label: Value" scheme...
+    # Decide on a layout scheme:
+    #   tabs ...... best if all elements within are groups
+    #   hlabels ... horizontal labels (label: value)
     #
-    set row 0
-    foreach name $_controls {
-        set wl $_name2info($name-label)
-        if {$wl != "" && [winfo exists $wl]} {
-            grid $wl -row $row -column 0 -sticky e
-        }
-
-        set wv $_name2info($name-value)
-        if {$wv != "" && [winfo exists $wv]} {
-            grid $wv -row $row -column 1 -sticky ew
-
-            set frame [winfo parent $wv]
-            grid rowconfigure $frame $row -weight 0
-            grid rowconfigure $frame $row -weight 0
-
-            switch -- [winfo class $wv] {
-                TextEntry {
-                    if {[regexp {[0-9]+x[0-9]+} [$wv size]]} {
-                        grid $wl -sticky n -pady 4
-                        grid $wv -sticky nsew
-                        grid rowconfigure $frame $row -weight 1
-                        grid columnconfigure $frame 1 -weight 1
+    if {[llength $_controls] >= 2} {
+        # assume tabs for multiple groups
+        set scheme tabs
+        foreach name $_controls {
+            set w $_name2info($name-value)
+
+            if {[winfo class $w] != "GroupEntry"} {
+                # something other than a group? then fall back on hlabels
+                set scheme hlabels
+                break
+            }
+        }
+    } else {
+        set scheme hlabels
+    }
+
+    switch -- $scheme {
+      tabs {
+        #
+        # SCHEME: tabs
+        # put a series of groups into a tabbed notebook
+        #
+
+        # use inner frame within tabs to show current group
+        pack $_tabs -before $_frame -fill x
+
+        set gn 1
+        foreach name $_controls {
+            set wv $_name2info($name-value)
+            $wv configure -heading no
+
+            set label [$wv component heading cget -text]
+            if {"" == $label} {
+                set label "Group #$gn"
+            }
+            set _name2info($name-label) $label
+
+            $_tabs insert end $label \
+                -activebackground $itk_option(-background)
+
+            incr gn
+        }
+
+        # compute the overall size
+        # BE CAREFUL: do this after setting "-heading no" above
+        set maxw 0
+        set maxh 0
+        update idletasks
+        foreach name $_controls {
+            set w [winfo reqwidth $wv]
+            if {$w > $maxw} { set maxw $w }
+            set h [winfo reqheight $wv]
+            if {$h > $maxh} { set maxh $h }
+        }
+        $_frame configure -width $maxw -height $maxh
+
+        grid propagate $_frame off
+        grid columnconfigure $_frame 0 -weight 1
+        grid rowconfigure $_frame 0 -weight 1
+
+        $_tabs select 0; _changeTabs
+      }
+
+      hlabels {
+        #
+        # SCHEME: hlabels
+        # simple "Label: Value" layout
+        #
+        pack forget $_tabs
+        grid propagate $_frame on
+        grid columnconfigure $_frame 0 -weight 0
+        grid rowconfigure $_frame 0 -weight 0
+
+        set row 0
+        foreach name $_controls {
+            set wl $_name2info($name-label)
+            if {$wl != "" && [winfo exists $wl]} {
+                grid $wl -row $row -column 0 -sticky e
+            }
+
+            set wv $_name2info($name-value)
+            if {$wv != "" && [winfo exists $wv]} {
+                if {$wl != ""} {
+                    grid $wv -row $row -column 1 -sticky ew
+                } else {
+                    grid $wv -row $row -column 0 -columnspan 2 -sticky ew
+                }
+
+                set frame [winfo parent $wv]
+                grid rowconfigure $frame $row -weight 0
+                grid rowconfigure $frame $row -weight 0
+
+                switch -- [winfo class $wv] {
+                    TextEntry {
+                        if {[regexp {[0-9]+x[0-9]+} [$wv size]]} {
+                            grid $wl -sticky n -pady 4
+                            grid $wv -sticky nsew
+                            grid rowconfigure $frame $row -weight 1
+                            grid columnconfigure $frame 1 -weight 1
+                        }
+                    }
+                    GroupEntry {
+                        $wv configure -heading yes
                     }
                 }
-            }
-            grid columnconfigure $frame 1 -weight 1
-        }
-
-
-        incr row
-        grid rowconfigure [winfo parent $w] $row -minsize $itk_option(-padding)
-        incr row
+                grid columnconfigure $frame 1 -weight 1
+            }
+
+
+            incr row
+            grid rowconfigure [winfo parent $w] $row \
+                -minsize $itk_option(-padding)
+            incr row
+        }
+      }
     }
 }
@@ -325,4 +429,25 @@
 
 # ----------------------------------------------------------------------
+# USAGE: _changeTabs
+#
+# Used internally to change tabs when the user clicks on a tab
+# in the "tabs" layout mode.  This mode is used when the widget
+# contains nothing but groups, as a compact way of representing
+# the groups.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Controls::_changeTabs {} {
+    set i [$_tabs index select]
+    set name [lindex $_controls $i]
+    if {"" != $name} {
+        foreach w [grid slaves $_frame] {
+            grid forget $w
+        }
+
+        set wv $_name2info($name-value)
+        grid $wv -row 0 -column 0 -sticky new
+    }
+}
+
+# ----------------------------------------------------------------------
 # OPTION: -padding
 # ----------------------------------------------------------------------
Index: /trunk/gui/scripts/deviceViewer1D.tcl
===================================================================
--- /trunk/gui/scripts/deviceViewer1D.tcl	(revision 25)
+++ /trunk/gui/scripts/deviceViewer1D.tcl	(revision 26)
@@ -205,10 +205,7 @@
     if {[llength $tabs] <= 0} {
         #
-        # == DEPRECATED FUNCTIONALITY ==
-        # (I like the look of the tab, even if there's only one)
-        #
-        # No fields or one field?  Then we don't need to bother
-        # with tabs.  Just pack the inner frame directly.  If
-        # there are no fields, get rid of the graph.
+        # No fields?  Then we don't need to bother with tabs.
+        # Just pack the inner frame directly.  If there are no
+        # fields, get rid of the graph.
         #
         pack $itk_component(inner) -expand yes -fill both
Index: /trunk/gui/scripts/groupentry.tcl
===================================================================
--- /trunk/gui/scripts/groupentry.tcl	(revision 25)
+++ /trunk/gui/scripts/groupentry.tcl	(revision 26)
@@ -12,6 +12,12 @@
 package require Itk
 
+option add *GroupEntry.headingBackground #cccccc widgetDefault
+option add *GroupEntry.headingForeground white widgetDefault
+option add *GroupEntry.font -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
+
 itcl::class Rappture::GroupEntry {
     inherit itk::Widget
+
+    itk_option define -heading heading Heading 1
 
     constructor {owner path args} { # defined below }
@@ -21,4 +27,6 @@
     public method label {}
     public method tooltip {}
+
+    protected method _fixheading {}
 
     private variable _owner ""    ;# thing managing this control
@@ -42,4 +50,34 @@
     set _owner $owner
     set _path $path
+
+    itk_component add heading {
+        ::label $itk_interior.heading -anchor w
+    } {
+        usual
+        rename -background -headingbackground headingBackground Background
+        rename -foreground -headingforeground headingForeground Foreground
+    }
+
+    $itk_component(heading) configure \
+        -text [$_owner xml get $_path.about.label]
+    Rappture::Tooltip::for $itk_component(heading) \
+        [$_owner xml get $_path.about.description]
+
+    itk_component add outline {
+        frame $itk_interior.outline -borderwidth 1
+    } {
+        usual
+        ignore -borderwidth
+        rename -background -headingbackground headingBackground Background
+    }
+    pack $itk_component(outline) -expand yes -fill both
+
+    itk_component add inner {
+        frame $itk_component(outline).inner -borderwidth 3
+    } {
+        usual
+        ignore -borderwidth
+    }
+    pack $itk_component(inner) -expand yes -fill both
 
     eval itk_initialize $args
@@ -67,5 +105,5 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::GroupEntry::label {} {
-    return [$_owner xml get $_path.about.label]
+    return ""  ;# manage the label inside this group
 }
 
@@ -81,2 +119,25 @@
     return [$_owner xml get $_path.about.description]
 }
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -heading
+# Turns the heading bar at the top of this group on/off.
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::GroupEntry::heading {
+    if {![string is boolean -strict $itk_option(-heading)]} {
+        error "bad value \"$itk_option(-heading)\": should be boolean"
+    }
+
+    set str [$itk_component(heading) cget -text]
+    if {$itk_option(-heading) && "" != $str} {
+        eval pack forget [pack slaves $itk_component(hull)]
+        pack $itk_component(heading) -side top -fill x
+        pack $itk_component(outline) -expand yes -fill both
+        $itk_component(outline) configure -borderwidth 1
+        $itk_component(inner) configure -borderwidth 3
+    } else {
+        pack forget $itk_component(heading)
+        $itk_component(outline) configure -borderwidth 0
+        $itk_component(inner) configure -borderwidth 0
+    }
+}
Index: /trunk/gui/scripts/page.tcl
===================================================================
--- /trunk/gui/scripts/page.tcl	(revision 25)
+++ /trunk/gui/scripts/page.tcl	(revision 26)
@@ -201,5 +201,6 @@
                         error $c "$c\n    (while building control for $path.$cname)"
                     } else {
-                        set w [$frame.cntls control $c]
+                        set gentry [$frame.cntls control $c]
+                        set w [$gentry component inner]
                     }
                 }
Index: /trunk/gui/scripts/pager.tcl
===================================================================
--- /trunk/gui/scripts/pager.tcl	(revision 25)
+++ /trunk/gui/scripts/pager.tcl	(revision 26)
@@ -401,8 +401,10 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Pager::_fixSize {} {
+    set sw [expr {[winfo screenwidth $itk_component(hull)]-200}]
+    set sh [expr {[winfo screenheight $itk_component(hull)]-200}]
+
     switch -- $itk_option(-arrangement) {
         pages {
             if {$itk_option(-width) <= 0} {
-                update idletasks
                 set maxw [expr {
                     [winfo reqwidth $itk_component(next)]
@@ -415,4 +417,5 @@
                 }
                 set maxw [expr {$maxw + 2*$itk_option(-padding)}]
+                if {$maxw > $sw} { set maxw $sw }
                 $itk_component(inside) configure -width $maxw
             } else {
@@ -421,5 +424,4 @@
 
             if {$itk_option(-height) <= 0} {
-                update idletasks
                 set maxh 0
                 foreach name $_pages {
@@ -428,4 +430,5 @@
                 }
                 set maxh [expr {$maxh + 2*$itk_option(-padding)}]
+                if {$maxh > $sh} { set maxh $sh }
                 $itk_component(inside) configure -height $maxh
             } else {
@@ -435,5 +438,4 @@
         side-by-side {
             if {$itk_option(-width) <= 0} {
-                update idletasks
                 set maxw [expr {
                     [winfo reqwidth $itk_component(next)]
@@ -447,4 +449,5 @@
                 }
                 if {$wtotal > $maxw} { set maxw $wtotal }
+                if {$maxw > $sw} { set maxw $sw }
                 $itk_component(inside) configure -width $maxw
             } else {
@@ -453,5 +456,4 @@
 
             if {$itk_option(-height) <= 0} {
-                update idletasks
                 set maxh 0
                 foreach name $_pages {
@@ -460,4 +462,5 @@
                 }
                 set maxh [expr {$maxh + 2*$itk_option(-padding)}]
+                if {$maxh > $sh} { set maxh $sh }
                 $itk_component(inside) configure -height $maxh
             } else {
Index: /trunk/gui/scripts/scroller.tcl
===================================================================
--- /trunk/gui/scripts/scroller.tcl	(revision 25)
+++ /trunk/gui/scripts/scroller.tcl	(revision 26)
@@ -34,6 +34,8 @@
     protected method _fixsbar {which {state ""}}
     protected method _fixframe {which}
+    protected method _fixsize {}
     protected method _lock {option}
 
+    private variable _dispatcher "" ;# dispatcher for !events
     private variable _contents ""   ;# widget being controlled
     private variable _frame ""      ;# for "contents frame" calls
@@ -52,4 +54,18 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Scroller::constructor {args} {
+    Rappture::dispatcher _dispatcher
+
+    $_dispatcher register !fixframe-inner
+    $_dispatcher dispatch $this !fixframe-inner \
+        "[itcl::code $this _fixframe inner]; list"
+
+    $_dispatcher register !fixframe-outer
+    $_dispatcher dispatch $this !fixframe-outer \
+        "[itcl::code $this _fixframe outer]; list"
+
+    $_dispatcher register !fixsize
+    $_dispatcher dispatch $this !fixsize \
+        "[itcl::code $this _fixsize]; list"
+
     itk_component add xsbar {
         scrollbar $itk_interior.xsbar -orient horizontal
@@ -104,6 +120,8 @@
             frame $_frame.f
             $_frame create window 0 0 -anchor nw -window $_frame.f -tags frame
-            bind $_frame.f <Configure> [itcl::code $this _fixframe inner]
-            bind $_frame <Configure> [itcl::code $this _fixframe outer]
+            bind $_frame.f <Configure> \
+                [itcl::code $_dispatcher event -idle !fixframe-inner]
+            bind $_frame <Configure> \
+                [itcl::code $_dispatcher event -idle !fixframe-outer]
         }
         set widget $_frame
@@ -207,8 +225,33 @@
         inner {
             $_frame configure -scrollregion [$_frame bbox all]
+            $_dispatcher event -idle !fixsize
         }
         outer {
             $_frame itemconfigure frame -width [winfo width $_frame]
         }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _fixsize
+#
+# Used internally to update the size options for the widget
+# whenever the -width/-height options change.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Scroller::_fixsize {} {
+    if {$itk_option(-width) == "0" && $itk_option(-height) == "0"} {
+        # for default size, let the frame being controlled set the size
+        grid propagate $itk_component(hull) yes
+        if {$_frame == "$itk_component(hull).ifr"} {
+            set w [winfo reqwidth $_frame.f]
+            set h [winfo reqheight $_frame.f]
+            $_frame configure -width $w -height $h
+        }
+    } else {
+        # for specific size, set the overall size of the widget
+        grid propagate $itk_component(hull) no
+        set w $itk_option(-width); if {$w == "0"} { set w 1i }
+        set h $itk_option(-height); if {$h == "0"} { set h 1i }
+        component hull configure -width $w -height $h
     }
 }
@@ -264,14 +307,8 @@
 # ----------------------------------------------------------------------
 itcl::configbody Rappture::Scroller::width {
-    if {$itk_option(-width) == "0"} {
-        if {$itk_option(-height) == "0"} {
-            grid propagate $itk_component(hull) yes
-        } else {
-            component hull configure -width 1i
-        }
-    } else {
-        grid propagate $itk_component(hull) no
-        component hull configure -width $itk_option(-width)
-    }
+    # check for proper value
+    winfo pixels $itk_component(hull) $itk_option(-width)
+
+    $_dispatcher event -idle !fixsize
 }
 
@@ -280,13 +317,7 @@
 # ----------------------------------------------------------------------
 itcl::configbody Rappture::Scroller::height {
-    if {$itk_option(-height) == "0"} {
-        if {$itk_option(-width) == "0"} {
-            grid propagate $itk_component(hull) yes
-        } else {
-            component hull configure -height 1i
-        }
-    } else {
-        grid propagate $itk_component(hull) no
-        component hull configure -height $itk_option(-height)
-    }
-}
+    # check for proper value
+    winfo pixels $itk_component(hull) $itk_option(-height)
+
+    $_dispatcher event -idle !fixsize
+}
Index: /trunk/gui/scripts/tooltip.tcl
===================================================================
--- /trunk/gui/scripts/tooltip.tcl	(revision 25)
+++ /trunk/gui/scripts/tooltip.tcl	(revision 26)
@@ -130,4 +130,9 @@
     }
 
+    # if there's no message to show, forget it
+    if {[string length $mesg] == 0} {
+        return
+    }
+
     # strings can't be too big, or they'll go off screen!
     if {[string length $mesg] > 1000} {
