Index: branches/1.4/gui/scripts/analyzer.tcl
===================================================================
--- branches/1.4/gui/scripts/analyzer.tcl	(revision 5059)
+++ branches/1.4/gui/scripts/analyzer.tcl	(revision 5060)
@@ -315,5 +315,9 @@
 
     itk_component add results {
-        Rappture::Panes $w.pane -sashwidth 1 -sashrelief solid -sashpadding {4 0}
+        Rappture::Panes $w.pane \
+            -sashwidth 2 -sashrelief solid -sashpadding {2 0}
+    } {
+        usual
+        ignore -sashwidth -sashrelief -sashpadding
     }
     pack $itk_component(results) -expand yes -fill both
Index: branches/1.4/gui/scripts/imageresult.tcl
===================================================================
--- branches/1.4/gui/scripts/imageresult.tcl	(revision 5059)
+++ branches/1.4/gui/scripts/imageresult.tcl	(revision 5060)
@@ -72,5 +72,7 @@
     pack propagate $itk_component(hull) no
 
-    Rappture::Panes $itk_interior.panes -sashwidth 1 -sashrelief solid -sashpadding 2
+    Rappture::Panes $itk_interior.panes \
+        -sashwidth 2 -sashrelief solid -sashpadding 1
+
     pack $itk_interior.panes -expand yes -fill both
     set main [$itk_interior.panes pane 0]
Index: branches/1.4/gui/scripts/panes.tcl
===================================================================
--- branches/1.4/gui/scripts/panes.tcl	(revision 5059)
+++ branches/1.4/gui/scripts/panes.tcl	(revision 5060)
@@ -1,4 +1,3 @@
-# -*- mode: tcl; indent-tabs-mode: nil -*- 
-
+# -*- mode: tcl; indent-tabs-mode: nil -*-
 # ----------------------------------------------------------------------
 #  COMPONENT: Panes - creates a series of adjustable panes
@@ -9,5 +8,5 @@
 # ======================================================================
 #  AUTHOR:  Michael McLennan, Purdue University
-#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
+#  Copyright (c) 2004-2015  HUBzero Foundation, LLC
 #
 #  See the file "license.terms" for information on usage and
@@ -21,13 +20,13 @@
 option add *Panes.sashWidth 2 widgetDefault
 option add *Panes.sashPadding 4 widgetDefault
-option add *Panes.sashCursor sb_v_double_arrow
+option add *Panes.orientation vertical widgetDefault
 
 itcl::class Rappture::Panes {
     inherit itk::Widget
 
-    itk_option define -sashcursor sashCursor SashCursor ""
     itk_option define -sashrelief sashRelief SashRelief ""
     itk_option define -sashwidth sashWidth SashWidth 0
     itk_option define -sashpadding sashPadding SashPadding 0
+    itk_option define -orientation orientation Orientation ""
 
     constructor {args} { # defined below }
@@ -35,7 +34,8 @@
     public method insert {pos args}
     public method pane {pos}
-    public method visibility {pos {newval ""}}
-    public method fraction {pos {newval ""}}
+    public method visibility {pos args}
+    public method fraction {pos args}
     public method hilite {state sash}
+    public method size {}
 
     protected method _grab {pane X Y}
@@ -49,10 +49,11 @@
     private variable _visibility ""  ;# list of visibilities for panes
     private variable _counter 0      ;# counter for auto-generated names
-    private variable _frac 0.0       ;# list of fractions
-    public variable orientation "vertical"
+    private variable _reqfrac 0.0    ;# requested fraction size of each pane
+    private variable _dragfrom 0     ;# starting coordinate of drag operation
+    private variable _dragfrac 0     ;# limit on fraction of drag operation
 }
 
 itk::usual Panes {
-    keep -background -cursor
+    keep -background -cursor -sashwidth -sashrelief
 }
 
@@ -80,5 +81,5 @@
     lappend _panes $pname
     lappend _visibility 1
-    set _frac 0.5
+    set _reqfrac 0.5
 
     eval itk_initialize $args
@@ -107,5 +108,5 @@
     } {
         usual
-        rename -cursor -sashcursor sashCursor SashCursor
+        ignore -cursor
     }
     bind $itk_component($sash) <Enter> [itcl::code $this hilite on $sash]
@@ -116,12 +117,15 @@
     } {
         usual
-        rename -cursor -sashcursor sashCursor SashCursor
         rename -relief -sashrelief sashRelief SashRelief
         ignore -borderwidth
     }
-    if { $orientation == "vertical" } {
+    if {$itk_option(-orientation) eq "vertical"} {
         pack $itk_component(${sash}ridge) -fill x 
+        $itk_component($sash) configure -cursor sb_v_double_arrow
+        $itk_component(${sash}ridge) configure -cursor sb_v_double_arrow
     } else {
         pack $itk_component(${sash}ridge) -fill y -side left
+        $itk_component($sash) configure -cursor sb_h_double_arrow
+        $itk_component(${sash}ridge) configure -cursor sb_h_double_arrow
     }
     foreach comp [list $sash ${sash}ridge] {
@@ -140,5 +144,5 @@
     set _panes [linsert $_panes $pos $pname]
     set _visibility [linsert $_visibility $pos 1]
-    set _frac [linsert $_frac $pos $params(-fraction)]
+    set _reqfrac [linsert $_reqfrac $pos $params(-fraction)]
 
     # fix sash characteristics
@@ -165,58 +169,59 @@
 
 # ----------------------------------------------------------------------
-# USAGE: visibility <pos> ?<newval>?
+# USAGE: visibility <pos> ?<newval>? ?<pos> <newval> ...?
 #
 # Clients use this to get/set the visibility of the pane at position
-# <pos>.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Panes::visibility {pos {newval ""}} {
-    if {"" == $newval} {
+# <pos>.  Can also be used to set the visibility for multiple panes
+# if multiple <pos>/<newval> pairs are specified in the same command.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Panes::visibility {pos args} {
+    if {[llength $args] == 0} {
         return [lindex $_visibility $pos]
     }
-    if {![string is boolean $newval]} {
-        error "bad value \"$newval\": should be boolean"
-    }
-    if {$pos == "end" || ($pos >= 0 && $pos < [llength $_visibility])} {
-        set _visibility [lreplace $_visibility $pos $pos [expr {$newval}]]
-        $_dispatcher event -idle !layout
-    } else {
-        error "bad index \"$pos\": out of range"
-    }
-}
-
-# ----------------------------------------------------------------------
-# USAGE: fraction <pos> ?<newval>?
+    if {[llength $args] % 2 == 0} {
+        error "wrong # args: should be \"visibility pos ?val pos val ...?\""
+    }
+
+    set args [linsert $args 0 $pos]
+    foreach {pos newval} $args {
+        if {![string is boolean -strict $newval]} {
+            error "bad value \"$newval\": should be boolean"
+        }
+        if {$pos eq "end" || ($pos >= 0 && $pos < [llength $_visibility])} {
+            set _visibility [lreplace $_visibility $pos $pos [expr {$newval}]]
+            $_dispatcher event -idle !layout
+        } else {
+            error "bad index \"$pos\": out of range"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: fraction <pos> ?<newval>? ?<pos> <newval> ...?
 #
 # Clients use this to get/set the fraction of real estate associated
-# with the pane at position <pos>.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Panes::fraction {pos {newval ""}} {
-    if {"" == $newval} {
-        return [lindex $_frac $pos]
-    }
-    if {![string is double $newval]} {
-        error "bad value \"$newval\": should be fraction 0-1"
-    }
-    if {$pos == "end" || ($pos >= 0 && $pos < [llength $_frac])} {
-        set len [llength $_frac]
-        set _frac [lreplace $_frac $pos $pos xxx]
-        set total 0
-        foreach f $_frac {
-            if {"xxx" != $f} {
-                set total [expr {$total+$f}]
-            }
-        }
-        for {set i 0} {$i < $len} {incr i} {
-            set f [lindex $_frac $i]
-            if {"xxx" == $f} {
-                set f $newval
-            } else {
-                set f [expr {$f/$total - $newval/double($len-1)}]
-            }
-            set _frac [lreplace $_frac $i $i $f]
-        }
-        $_dispatcher event -idle !layout
-    } else {
-        error "bad index \"$pos\": out of range"
+# with the pane at position <pos>.  Can also be used to set the
+# fractions for multiple panes if multiple <pos>/<newval> pairs
+# are specified in the same command.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Panes::fraction {pos args} {
+    if {[llength $args] == 0} {
+        return [lindex $_reqfrac $pos]
+    }
+    if {[llength $args] % 2 == 0} {
+        error "wrong # args: should be \"fraction pos ?val pos val ...?\""
+    }
+
+    set args [linsert $args 0 $pos]
+    foreach {pos newval} $args {
+        if {![string is double -strict $newval]} {
+            error "bad value \"$newval\": should be fraction 0-1"
+        }
+        if {$pos eq "end" || ($pos >= 0 && $pos < [llength $_reqfrac])} {
+            set _reqfrac [lreplace $_reqfrac $pos $pos $newval]
+            $_dispatcher event -idle !layout
+        } else {
+            error "bad index \"$pos\": out of range"
+        }
     }
 }
@@ -230,4 +235,11 @@
 itcl::body Rappture::Panes::hilite {state sash} {
     switch -- $itk_option(-sashrelief) {
+      flat {
+        if {$state} {
+            $itk_component(${sash}ridge) configure -background black
+        } else {
+            $itk_component(${sash}ridge) configure -background $itk_option(-background)
+        }
+      }
       sunken {
         if {$state} {
@@ -256,4 +268,14 @@
 
 # ----------------------------------------------------------------------
+# USAGE: size
+#
+# Returns the number of panes in this widget.  That makes it easier
+# to index the various panes, since indices run from 0 to size-1.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Panes::size {} {
+    return [llength $_panes]
+}
+
+# ----------------------------------------------------------------------
 # USAGE: _grab <pane> <X> <Y>
 #
@@ -262,4 +284,15 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Panes::_grab {pname X Y} {
+    set pos [lsearch $_panes $pname]
+    if {$pos < 0} return
+    set frac0 [lindex $_reqfrac [expr {$pos-1}]]
+    set frac1 [lindex $_reqfrac $pos]
+    set _dragfrac [expr {$frac0+$frac1}]
+
+    if {$itk_option(-orientation) eq "vertical"} {
+        set _dragfrom $Y
+    } else {
+        set _dragfrom $X
+    }
 }
 
@@ -270,27 +303,38 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Panes::_drag {pname X Y} {
-    if { $orientation == "vertical" } {
-        set realY [expr {$Y-[winfo rooty $itk_component(hull)]}]
+    set pos [lsearch $_panes $pname]
+    if {$pos < 0} return
+    set frac [lindex $_reqfrac $pos]
+
+    if {$itk_option(-orientation) eq "vertical"} {
+        set delY [expr {$_dragfrom-$Y}]
         set Ymax  [winfo height $itk_component(hull)]
-        set frac [expr double($realY)/$Ymax]
+        set delta [expr {double($delY)/$Ymax}]
+        set frac [expr {$frac + $delta}]
+        set _dragfrom $Y
     } else {
-        set realX [expr {$X-[winfo rootx $itk_component(hull)]}]
+        set delX [expr {$_dragfrom-$X}]
         set Xmax  [winfo width $itk_component(hull)]
-        set frac [expr double($realX)/$Xmax]
-    }
+        set delta [expr {double($delX)/$Xmax}]
+        set frac [expr {$frac + $delta}]
+        set _dragfrom $X
+    }
+    if {$delta == 0.0} {
+        return
+    }
+
+    # set limits so the pane can't get too large or too small
     if {$frac < 0.05} {
         set frac 0.05
     }
-    if {$frac > 0.95} {
-        set frac 0.95
-    }
-    if {[llength $_frac] == 2} {
-        set _frac [list $frac [expr {1-$frac}]]
-    } else {
-        set i [expr {[lsearch $_panes $pname]-1}]
-        if {$i >= 0} {
-            set _frac [lreplace $_frac $i $i $frac]
-        }
-    }
+    if {$frac > $_dragfrac-0.05} {
+        set frac [expr {$_dragfrac-0.05}]
+    }
+
+    # replace the fractions for this pane and the one before it
+    set prevfrac [expr {$_dragfrac-$frac}]
+    set _reqfrac [lreplace $_reqfrac [expr {$pos-1}] $pos $prevfrac $frac]
+
+    # normalize all fractions and fix the layout
     _fixLayout
 
@@ -314,10 +358,36 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Panes::_fixLayout {args} {
-    if { $orientation == "vertical" } {
+    # normalize the fractions for all panes to they add to 1.0
+    set total 0
+    foreach f $_reqfrac v $_visibility {
+        if {$v && $f > 0} {
+            set total [expr {$total + $f}]
+        }
+    }
+    if {$total == 0.0} { set total 1 }
+
+    set normfrac ""
+    foreach f $_reqfrac v $_visibility {
+        if {$v} {
+            lappend normfrac [expr {double($f)/$total}]
+        } else {
+            lappend normfrac [expr {double($f)/$total}]
+        }
+    }
+
+    # note that sash padding can be a single number or different on each side
+    if {[llength $itk_option(-sashpadding)] == 1} {
+        set pad [expr {2*$itk_option(-sashpadding)}]
+    } else {
+        set pad [expr [join $itk_option(-sashpadding) +]]
+    }
+
+    if {$itk_option(-orientation) eq "vertical"} {
         set h [winfo height $itk_component(hull)]
+        set sh [expr {$itk_option(-sashwidth) + $pad}]
 
         set plist ""
         set flist ""
-        foreach p $_panes f $_frac v $_visibility {
+        foreach p $_panes f $normfrac v $_visibility {
             set sash ${p}sash
             if {$v} {
@@ -326,5 +396,5 @@
                 lappend flist $f
                 if {[info exists itk_component($sash)]} {
-                    set h [expr {$h - [winfo reqheight $itk_component($sash)]}]
+                    set h [expr {$h - $sh}]
                 }
             } else {
@@ -336,14 +406,5 @@
             }
         }
-        
-        # normalize the fractions so they add up to 1
-        set total 0
-        foreach f $flist { set total [expr {$total+$f}] }
-        set newflist ""
-        foreach f $flist {
-            lappend newflist [expr {double($f)/$total}]
-        }
-        set flist $newflist
-        
+
         # lay out the various panes
         set y 0
@@ -351,5 +412,4 @@
             set sash ${p}sash
             if {[info exists itk_component($sash)]} {
-                set sh [winfo reqheight $itk_component($sash)]
                 place $itk_component($sash) -y $y -relx 0.5 -anchor n \
                     -relwidth 1.0 -height $sh
@@ -364,8 +424,9 @@
     } else {
         set w [winfo width $itk_component(hull)]
+        set sw [expr {$itk_option(-sashwidth) + $pad}]
 
         set plist ""
         set flist ""
-        foreach p $_panes f $_frac v $_visibility {
+        foreach p $_panes f $normfrac v $_visibility {
             set sash ${p}sash
             if {$v} {
@@ -374,5 +435,5 @@
                 lappend flist $f
                 if {[info exists itk_component($sash)]} {
-                    set w [expr {$w - [winfo reqwidth $itk_component($sash)]}]
+                    set w [expr {$w - $sw}]
                 }
             } else {
@@ -384,14 +445,5 @@
             }
         }
-        
-        # normalize the fractions so they add up to 1
-        set total 0
-        foreach f $flist { set total [expr {$total+$f}] }
-        set newflist ""
-        foreach f $flist {
-            lappend newflist [expr {double($f)/$total}]
-        }
-        set flist $newflist
-        
+
         # lay out the various panes
         set x 0
@@ -399,5 +451,4 @@
             set sash ${p}sash
             if {[info exists itk_component($sash)]} {
-                set sw [winfo reqwidth $itk_component($sash)]
                 place $itk_component($sash) -x $x -rely 0.5 -anchor w \
                     -relheight 1.0 -width $sw
@@ -420,5 +471,5 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Panes::_fixSashes {args} {
-    if { $orientation == "vertical" } {
+    if {$itk_option(-orientation) eq "vertical"} {
         set ht [winfo pixels $itk_component(hull) $itk_option(-sashwidth)]
         set bd [expr {$ht/2}]
@@ -426,12 +477,8 @@
             set sash "${pane}sashridge"
             if {[info exists itk_component($sash)]} {
-                $itk_component($sash) configure -height $ht -borderwidth $bd
-                if {$itk_option(-sashrelief) == "solid"} {
-                    $itk_component($sash) configure -background black
-                } else {
-                    $itk_component($sash) configure \
-                        -background $itk_option(-background)
-                }
-                pack $itk_component($sash) -pady $itk_option(-sashpadding)
+                $itk_component($sash) configure -height $ht \
+                    -borderwidth $bd -relief $itk_option(-sashrelief)
+                pack $itk_component($sash) -pady $itk_option(-sashpadding) \
+                    -side top
             }
         }
@@ -442,11 +489,6 @@
             set sash "${pane}sashridge"
             if {[info exists itk_component($sash)]} {
-                $itk_component($sash) configure -width $w -borderwidth $bd
-                if {$itk_option(-sashrelief) == "solid"} {
-                    $itk_component($sash) configure -background black
-                } else {
-                    $itk_component($sash) configure \
-                        -background $itk_option(-background)
-                }
+                $itk_component($sash) configure -width $w \
+                    -borderwidth $bd -relief $itk_option(-sashrelief)
                 pack $itk_component($sash) -padx $itk_option(-sashpadding) \
                     -side left
@@ -474,4 +516,58 @@
 # ----------------------------------------------------------------------
 itcl::configbody Rappture::Panes::sashpadding {
+    set count 0
+    foreach val $itk_option(-sashpadding) {
+        if {![string is integer -strict $val]} {
+            error "bad padding value \"$val\": should be integer"
+        }
+        incr count
+    }
+    if {$count < 1 || $count > 2} {
+        error "bad padding value \"$itk_option(-sashpadding)\": should be \"#\" or \"# #\""
+    }
     $_dispatcher event -idle !sashes
 }
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -orientation
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Panes::orientation {
+    foreach pname $_panes {
+        set sash "${pname}sash"
+        if {$itk_option(-orientation) eq "vertical"} {
+            place $itk_component($pname) -x 0 -relx 0.5 -relwidth 1 \
+                -y 0 -rely 0 -relheight 0
+
+            if {[info exists itk_component($sash)]} {
+                place $itk_component($sash) -x 0 -relx 0.5 -relwidth 1 \
+                    -y 0 -rely 0 -relheight 0
+                $itk_component($sash) configure \
+                    -cursor sb_v_double_arrow
+
+                pack $itk_component(${sash}ridge) -fill x -side top
+                $itk_component(${sash}ridge) configure \
+                    -cursor sb_v_double_arrow
+            }
+        } else {
+            place $itk_component($pname) -y 0 -rely 0.5 -relheight 1 \
+                -x 0 -relx 0 -relwidth 0
+
+            if {[info exists itk_component($sash)]} {
+                place $itk_component($sash) -y 0 -rely 0.5 -relheight 1 \
+                    -x 0 -relx 0 -relwidth 0
+                $itk_component($sash) configure \
+                    -cursor sb_h_double_arrow
+
+                pack $itk_component(${sash}ridge) -fill y -side left
+                $itk_component(${sash}ridge) configure \
+                    -cursor sb_h_double_arrow
+            }
+        }
+    }
+
+    # fix sash characteristics
+    $_dispatcher event -idle !sashes
+
+    # make sure we fix up the layout at some point
+    $_dispatcher event -idle !layout
+}
