TIP:            41
Title:          Paned Window Tk Widget
Version:        $Revision: 1.13 $
Author:         Eric Melski <ericm@interwoven.com>
State:          Final
Type:           Project
Vote:           Done
Created:        04-Jul-2001
Post-History:   
Keywords:       widget,tk,panedwindow
Tcl-Version:    8.4a2

~ Abstract

This TIP proposes a C-based paned window widget for inclusion in the
Tk core.  A paned window consists of one or more vertical or
horizontal "panes", each pair separated by a movable "sash" and each
containing one widget, called a "slave".  Paned windows are common in
modern graphical user interfaces and should therefore be provided
directly by the Tk core.  Examples of the widget can be found in
Windows Explorer; Netscape Messenger; many email clients; and
virtually every graphical World Wide Web browser.

~ Rationale

Tk has long lagged other graphical toolkits in terms of the selection
of widgets provided by the toolkit.  In order to keep Tk vibrant,
useful, and relevant, it is imperative that the widget set be enhanced
with widgets which have become commonplace in modern graphical user
interfaces.  One such widget is the paned window widget.  A widget
that makes it easy to create robust paned windows should be included
with Tk.

This paned window widget could be implemented in C or in Tcl; in fact,
several Tcl-based paned window widgets already exist.  However, these
each have quirks, mostly caused by the inability to completely manage
the geometry of Tk windows from Tcl (i.e. there is no way to make
calls to things like ''Tk_MaintainGeometry'' or
''Tk_ManageGeometry'').  This issue could possibly be addressed by the
creation of a proper megawidget system for Tk, but that goal seems
very far from reality right now.  If we wait for that system before
creating new widgets, it may be too late.  In addition, megawidget
implementations suffer from "widget bloat" - each paned window widget
corresponds to, typically two widgets, plus two or more widgets for
each pane after the first.  For a Motif-style paned window with two
panes, this means five widgets are created (one frame for the paned
window container widget; one frame for each pane; one frame for the
sash; one frame for the sash handle).  Even assuming the existence of
a proper megawidget system, we may not be able to address the widget
bloat issue with a megawidget.

A C-based paned window implementation will be able to address both of
these issues, and should be more robust, reliable, and lightweight.  A
C implementation will be able to access Tk's geometry management
functions.  Also, it will require only one widget for each paned window,
regardless of how many panes are in the window.

One obvious argument is that this widget could easily be distributed
as an extension, and need not be included directly in the Tk core.
However, extension widget libraries have been largely unsuccessful in
winning over users.  Developers are reluctant to use those extension
widgets because they cannot rely on their presence in an end-user's
system, and because of concerns of version incompatibilities between
the extension and the core.  Users are reluctant to take on the
responsibility of maintaining the extension in addition to the core.
If this widget is to be truly useful to the Tk community and not just
a programming exercise for the author, it must be included in the Tk core.

In addition, Tk should be a full-featured widget toolkit on its own.
Other popular GUI toolkits are ready out-of-the-box to create
sophisticated, modern applications.  Tk should be as well, and should
not require the procurement of additional extensions to provide what
are truly fundamental widgets in a modern GUI toolkit.  By all means,
esoteric widgets should be left to the extensions, but core widgets
belong in the core.  This question could be made irrelevant with the
introduction of a proper "Batteries Included" distribution, but like
the proper megawidget system, this seems like a goal far from reality
at this time.

Another possibility is to distribute the widget with the core, but have it placed in a separate package and namespace.  This provides the same level of availability as direct inclusion in the core, but does not actually make the widget part of Tk directly.  There are two possible arguments in favor of this approach.  First, since this widget will be in its own namespace, future panedwindow widgets could be included without name conflicts.  However, if each widget is put in its own namespace, the name conflict has not actually been resolved.  The point of contention has simply been moved from the global command space to the global namespace space.  Namespaces make sense when grouping blocks of related functions and data, but widgets have only one command.  It's just as easy to pick a unique command name as a unique namespace name.  The second possible advantage is that the widget could be loaded on demand, rather than automatically being pulled in with Tk.  However, most machines that Tk runs on use a virtual memory system.  Thus, 
only those pages/widgets that are actually used will be resident in memory.  The benefit of incorporating this widget into the Tk distribution in this manner seem marginal.

#image:41example Example Panedwindow Widget

~ Specification

The manual entry for the paned window widget is included here:

|NAME
|       panedwindow - Create and manipulate panedwindow widgets
|
|SYNOPSIS
|       panedwindow pathName ?options?
|
|STANDARD OPTIONS
|       -background           -height              -width
|       -borderwidth          -orient
|       -cursor               -relief
|
|       See  the  options manual entry for details on the standard
|       options.
|
|WIDGET-SPECIFIC OPTIONS
|       Command-Line Name:-handlepad
|       Database Name:  handlePad
|       Database Class: HandlePad
|
|              When sash handles are drawn, specifies the distance
|              from  the top or left end of the sash (depending on
|              the orientation of the widget) at which to draw the
|              handle.  May be any value accepted by Tk_GetPixels.
|
|       Command-Line Name:-handlesize
|       Database Name:  handleSize
|       Database Class: HandleSize
|
|              Specifies the side length of a sash  handle.   Han-
|              dles are always drawn as squares.  May be any value
|              accepted by Tk_GetPixels.
|
|       Command-Line Name:-opaqueresize
|       Database Name:  opaqueResize
|       Database Class: OpaqueResize
|
|              Specifies whether panes should be resized as a sash
|              is  moved (true), or if resizing should be deferred
|              until the sash is placed (false).
|
|       Command-Line Name:-sashcursor
|       Database Name:  sashCursor
|       Database Class: SashCursor
|
|              Mouse cursor to use when over  a  sash.   If  null,
|              sb_h_double_arrow   will  be  used  for  horizontal
|              panedwindows, and sb_v_double_arrow  will  be  used
|              for vertical panedwindows.
|
|       Command-Line Name:-sashpad
|       Database Name:  sashPad
|       Database Class: SashPad
|
|              Specifies  the  amount  of padding to leave of each
|              side of a sash.   May  be  any  value  accepted  by
|              Tk_GetPixels.
|
|       Command-Line Name:-sashrelief
|       Database Name:  sashRelief
|       Database Class: SashRelief
|
|              Relief  to  use when drawing a sash.  May be any of
|              the standard Tk relief values.
|
|       Command-Line Name:-sashwidth
|       Database Name:  sashWidth
|       Database Class: SashWidth
|
|              Specifies the width of each sash.  May be any value
|              accepted by Tk_GetPixels.
|
|       Command-Line Name:-showhandle
|       Database Name:  showHandle
|       Database Class: ShowHandle
|
|              Specifies whether or not sash handles should be shown.
|              May be any valid Tcl boolean value.
|
|DESCRIPTION
|       The panedwindow command creates a new window (given by the
|       pathName argument) and makes it into a panedwindow widget.
|       Additional  options,  described above, may be specified on
|       the command line or in the option  database  to  configure
|       aspects  of the panedwindow such as its default background
|       color and relief.  The  panedwindow  command  returns  the
|       path name of the new window.
|
|       A   panedwindow  widget  contains  any  number  of  panes,
|       arranged horizontally  or  vertically,  according  to  the
|       value  of the -orient option.  Each pane contains one wid-
|       get, and each pair of panes is  separated  by  a  moveable
|       (via mouse movements) sash.  Moving a sash causes the wid-
|       gets on either side of the sash to be resized.
|
|WIDGET COMMAND
|       The panedwindow command creates a new  Tcl  command  whose
|       name  is  the  same  as the path name of the panedwindow's
|       window.  This command may be used to invoke various opera-
|       tions on the widget.  It has the following general form:
|              pathName option ?arg arg ...?
|       PathName  is the name of the command, which is the same as
|       the panedwindow widget's path name.  Option and  the  args
|       determine  the exact behavior of the command.  The follow-
|       ing commands are possible for panedwindow widgets:
|
|       pathName add slave ?slave ...? ?option value ...?
|              Add one or more slaves to the panedwindow, each  in
|              a  separate  pane.   The  arguments  consist of the
|              names of one or  more  slave  windows  followed  by
|              pairs  of  arguments that specify how to manage the
|              slaves.  Option may have any of the values accepted
|              by the configure subcommand.
|
|       pathName cget option
|              Returns  the  current  value  of  the configuration
|              option given by option.  Option may have any of the
|              values accepted by the panedwindow command.
|
|       pathName configure ?option? ?value option value ...?
|              Query  or  modify  the configuration options of the
|              widget.  If no option is specified, returns a  list
|              describing  all  of the available options for path-
|              Name (see Tk_ConfigureInfo for information  on  the
|              format  of this list).  If option is specified with
|              no value, then the command returns a list  describ-
|              ing the one named option (this list will be identi-
|              cal to  the  corresponding  sublist  of  the  value
|              returned  if  no  option  is specified).  If one or
|              more option-value pairs  are  specified,  then  the
|              command modifies the given widget option(s) to have
|              the given  value(s);   in  this  case  the  command
|              returns an empty string. Option may have any of the
|              values accepted by the panedwindow command.
|
|       pathName forget slave ?slave ...?
|              Remove the pane containing slave from the panedwin-
|              dow.   All  geometry  management  options for slave
|              will be forgotten.
|
|       pathName identify x y
|              Identify the panedwindow component  underneath  the
|              point  given by x and y, in window coordinates.  If
|              the point is over a sash  or  a  sash  handle,  the
|              result  is  a two element list containing the index
|              of the  sash  or  handle,  and  a  word  indicating
|              whether  it  is over a sash or a handle, such as {0
|              sash} or {2 handle}.  If  the  point  is  over  any
|              other  part  of  the  panedwindow, the result is an
|              empty list.
|
|       pathName proxy ?args?
|              This command is used to query and change the  posi-
|              tion  of  the sash proxy, used for rubberband-style
|              pane resizing. It can take  any  of  the  following
|              forms:
|
|              pathName proxy coord
|                     Return a list containing the x and y coordi-
|                     nates of the most recent proxy location.
|
|              pathname proxy forget
|                     Remove the proxy from the display.
|
|              pathName proxy place x y
|                     Place  the  proxy  at  the  given  x  and  y
|                     coordinates.
|
|       pathName sash ?args?
|              This  command is used to query and change the posi-
|              tion of sashes in the panedwindow.  It can take any
|              of the following forms:
|
|              pathName sash coord index
|                     Return  the  current x and y coordinate pair
|                     for the sash given by index.  Index must  be
|                     an  integer  between  0  and 1 less than the
|                     number of slaves in  the  panedwindow.   The
|                     coordinates  given are those of the top left
|                     corner of the region  containing  the  sash.
|                     pathName  sash dragto index x y This command
|                     computes the difference  between  the  given
|                     coordinates and the coordinates given to the
|                     last sash coord command for the given  sash.
|                     It then moves that sash the computed differ-
|                     ence.  The return value is the empty string.
|
|              pathName sash mark index x y
|                     Records x and y for the sash given by index;
|                     used in conjunction with later  dragto  com-
|                     mands to move the sash.
|
|              pathName sash place index x y
|                     Place  the  sash given by index at the given
|                     coordinates.
|
|       pathName slavecget slave option
|              Query a management option for slave.  Option may be
|              any value allowed by the slaveconfigure subcommand.
|
|       pathName slaveconfigure slave ?option? ?value option value
|       ...?
|              Query  or  modify the management options for slave.
|              If no option is specified, returns a list  describ-
|              ing  all of the available options for pathName (see
|              Tk_ConfigureInfo for information on the  format  of
|              this  list).  If option is specified with no value,
|              then the command returns a list describing the  one
|              named  option  (this  list will be identical to the
|              corresponding sublist of the value returned  if  no
|              option  is specified).  If one or more option-value
|              pairs are specified, then the command modifies  the
|              given  widget option(s) to have the given value(s);
|              in this case the command returns an  empty  string.
|              The following options are supported:
|
|              -after slave
|                     Insert  the slave after the slave specified.
|                     slave should be the name of a window already
|                     managed by pathName.
|
|              -before slave
|                     Insert the slave before the slave specified.
|                     slave should be the name of a window already
|                     managed by pathName.
|
|              -height size
|                     Specify  a height for the slave.  The height
|                     will be the outer  dimension  of  the  slave
|                     including its border, if any.  If size is an
|                     empty string, or if -height  is  not  speci-
|                     fied,  then  the height requested internally
|                     by the slave will  be  used  initially;  the
|                     height may later be adjusted by the movement
|                     of sashes in the panedwindow.  Size  may  be
|                     any value accepted by Tk_GetPixels.
|
|              -minsize n
|                     Specifies  that the size of the slave cannot
|                     be made less than n.  This  constraint  only
|                     affects  the size of the widget in the paned
|                     dimension -- the x dimension for  horizontal
|                     panedwindows,  the  y dimension for vertical
|                     panedwindows.  May be any value accepted  by
|                     Tk_GetPixels.
|
|              -padx n
|                     Specifies  a  non-negative  value indicating
|                     how much extra space to leave on  each  side
|                     of  the slave in the X-direction.  The value
|                     may  have  any  of  the  forms  accepted  by
|                     Tk_GetPixels.
|
|              -pady n
|                     Specifies  a  non-negative  value indicating
|                     how much extra space to leave on  each  side
|                     of  the slave in the Y-direction.  The value
|                     may  have  any  of  the  forms  accepted  by
|                     Tk_GetPixels.
|
|              -sticky style
|                     If   a  slave's  pane  is  larger  than  the
|                     requested  dimensions  of  the  slave,  this
|                     option  may be used to position (or stretch)
|                     the slave within  its  pane.   Style   is  a
|                     string  that  contains  zero  or more of the
|                     characters n, s, e or  w.   The  string  can
|                     optionally  contains  spaces  or commas, but
|                     they are ignored.  Each letter refers  to  a
|                     side  (north, south, east, or west) that the
|                     slave will "stick" to.  If both n and s  (or
|                     e  and  w)  are specified, the slave will be
|                     stretched to  fill  the  entire  height  (or
|                     width) of its cavity.
|
|              -width size
|                     Specify  a  width  for the slave.  The width
|                     will be the outer  dimension  of  the  slave
|                     including its border, if any.  If size is an
|                     empty string, or if -width is not specified,
|                     then  the  width requested internally by the
|                     slave will be used initially; the width  may
|                     later  be adjusted by the movement of sashes
|                     in the panedwindow.  Size may be  any  value
|                     accepted by Tk_GetPixels.
|
|       pathName slaves
|              Returns  an  ordered list of the widgets managed by
|              pathName.
|
|
|RESIZING PANES
|       A pane is resized by grabbing the sash (or sash handle  if
|       present)  and  dragging  with  the  mouse.  This is accom-
|       plished via mouse motion bindings on the widget.   When  a
|       sash  is moved, the sizes of the panes on each side of the
|       sash, and thus the widgets in those panes, are adjusted.
|
|       When a pane is resized from outside (eg, it is  packed  to
|       expand  and fill, and the containing toplevel is resized),
|       space is added to the final (rightmost or bottommost) pane
|       in the window.

~ Reference Implementation

The widget described here has already been implemented, with
documentation and a full test suite.  The widget is included with the
Vu widget extension, part of the ''tktable'' SourceForge project at
http://tktable.sourceforge.net

~ Notes

Suggestions for possible future enhancements:

 * Allow specification of a weight for each pane, similar to the -weight option supported by
grid, to be used when allocating space from a resize to panes in the
widget.

 * Allow a bindable image to be placed on the window sash, a la 
Netscape's Messenger, or Java Swing, to allow one-click expand and
collapse of the pane.

 * Integrate with the -setgrid option such that if a pane contains
a -setgrided widget, the sash can only be moved in grid size steps.

None of these are prohibited by the current design, and could be 
implemented at a later date as enhancements to the widget.

~ Copyright

This document has been placed in the public domain.

