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.
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.