## line-of-widgets.api
#
# Left-to-right or top-to-bottom linear layout.
#
# We actually implement a tree of recursive
# linear layouts, each of which can be
# vertical or horizontal.
#
# "The layout algorithm is simple. We describe the
# case for a horizontal box. Vertical boxes work
# the same way, switching the roles of horizontal
# and vertical. Each child is given its [ideal] width.
# If the sum of these widths does not fill the width
# of the [widget], the slack is allocated uniformly
# to the child widgets, but only in multiples of a
# child's [step_size] value and a child's maximum
# width is never exceeded.
# If there is still slack after all children have been
# increased to the maximum widths, it is placed to the
# right of all the children.
# If the sum of the widths is too large for the box, the
# excess is removed uniformly from the child widgets,
# but a child's minimum width and step size are respected.
# If there is still excess after all children have been
# decreased to the minimum widths, some of the rightmost
# children will not appear in the window.
#
# "Each child is guaranteed its minimum height. If this
# does not equal the height of the box, the child's height
# is increased as much as possible, in multiples of the
# child's [step_size], up to its maximum height. If this
# is still not equal to the height of the box, the child
# is aligned vertically according to the [widget's]
# alignment parameter. Thus, a HZ_CENTER [widget] will
# center its components vertically, while a HZ_TOP [widget]
# will top justify its components. If a child's height is
# too large for the [widget], the child is still aligned
# vertically according to the [widget]'s alignment parameter,
# but part of the child will not be visible.
#
# "We now describe the sizing of the [widget]. It seems
# reasonable that the minimum, ideal and maximum widths
# of a horizontal box should be the sums of the respective
# widths of its children. To this end we set the base
# width to be the sum of the minimum widths of its children,
# in pixels. The horizontal [step_size] is the minimum of
# the horizontal [step_size]s of all children with a
# non-fixed horizontal size. The [min_size] value is
# set to zero. The [best_size] value is the least integer
# such that [start_at]+[best_steps]*[step_size] is greater
# than or equal to the sum of the ideal widths of its children.
# The [max_steps] value is defined analogously. The ideal
# height of the [widget] is the maximimum of the ideal heights
# of its children. The minimum height a [line-of-widgets widget]
# is the maximum of the minimum heights of its children.
# The maximum height of a [line-of-widgets widget] is the
# maximum of the natural height of the [widget] along with
# the non-infinite maximum heights of its children, or infinite
# if all children have infinite height. We then set the
# base height to the minimum height and the [min_steps] to 0.
# The vertical increment is the minimum of the vertical increments
# of all children with non-fixed vertical size and whose vertical
# increment is greater than 1. If there are no such children, the
# vertical increment is set to 1. As in the horizontal direction,
# [best_steps] and [max_steps] are taken to be the smallest
# integers such that [start_at]+[best_steps]*[step_size] and
# [start_at]+[max_steps]*[step_size] are greater than or equal
# to the ideal height and maximum height respectively.
# In horizontal [line-of-widgets widgets] SPACER components
# act like widgets whose horizontal [size preferences] are
# given by the SPACER's parameters, with an implicit [start_at]
# of 0 and [step_size] of 1, and whose vertical size preferences
# have an [best_size] of zero, with infinite shrinking and
# stretching."
#
# "The rules given above for determining the [size preferences]
# of a [line-of-widgets widget] are obviously heuristics. They
# should work well in a given dimension when the sub-boxes have
# a fixed size in that dimension, have a [step_size] of one,
# or have "compatible" sizes (e.g., the same [best_size] with
# [step_sizes] that are multiples of some base [step_size].
# These conditions hold true in such common cases as attaching
# a scrollbar or using sufficient [SPACERs]. When these conditions
# are not satisfied, the resultant bounds can be unexpected. <=============
#
# "If the [Layout_Tree] argument b to [make_line_of_widgets] is a
# [SPACER] or [WIDGET] value, it is treated as HZ_CENTER [b]. The
# [?] exception is raised if a widget has a zero [step_size].
#
# "The [Layout_Tree] managed by a [line-of-widgets widget] can be
# dynamically altered using [the insert, delete and append functions]
# provided by the [Line_Of_Widgets API]. At present these changes
# can only be made in the top-level list in the box tree. (This is not a
# serious restriction, as a [line_of_widgets] can be inserted
# within another [line_of_widgets].)"
#
# -- Adapted from p14-15 of Gansner and Reppy's 1993 widget manual
# http://mythryl.org/pub/exene/1993-widgets.ps
#
# Compiled by:
#
src/lib/x-kit/widget/xkit-widget.sublib### "A good composer does not imitate; he steals."
###
### -- Igor Stravinsky
# This api is implemented in:
#
#
src/lib/x-kit/widget/old/layout/line-of-widgets.pkgstipulate
package wg = widget; # Widget is from
src/lib/x-kit/widget/old/basic/widget.apiherein
api Line_Of_Widgets {
#
exception BAD_INDEX;
Layout_Tree
#
= HZ_TOP List( Layout_Tree )
| HZ_CENTER List( Layout_Tree )
| HZ_BOTTOM List( Layout_Tree )
#
| VT_LEFT List( Layout_Tree )
| VT_CENTER List( Layout_Tree )
| VT_RIGHT List( Layout_Tree )
#
| WIDGET wg::Widget
#
| SPACER { min_size: Int,
best_size: Int,
max_size: Null_Or( Int )
}
;
Line_Of_Widgets;
make_line_of_widgets: wg::Root_Window -> Layout_Tree -> Line_Of_Widgets;
line_of_widgets: (wg::Root_Window, wg::View, List(wg::Arg)) -> Layout_Tree -> Line_Of_Widgets;
as_widget: Line_Of_Widgets -> wg::Widget;
insert: Line_Of_Widgets -> (Int, List(Layout_Tree)) -> Void;
#
# Insert given List(Layout_Tree) before the nth element
# in the toplevel line-of-widgets list, where the first
# element is numbered 0. Impractical values raise BAD_INDEX.
# The widgets in the List(Layout_Tree) are assumed to be
# unrealized; they will be realized at this time.
append: Line_Of_Widgets -> (Int, List(Layout_Tree)) -> Void;
#
# append line_of_widgets (n,list) is equivalent to
# insert line_of_widgets (n+1,list)
delete: Line_Of_Widgets -> List(Int) -> Void;
#
# Remove the toplevel Layout_Tree elements with
# the indices given in List(Int), destroying
# any associated X-server windows and effectively
# destroying the widgets. Bad indices raise BAD_INDEX.
hide: Line_Of_Widgets -> List(Int) -> Void;
#
# Tell line_of_widgets to treat the toplevel
# layout elements whose indices are given
# as zero-width and reposition the remaining
# elements accordingly. Hiding an already-hidden
# element is a no-op. Bad indices raise BAD_INDEX.
show: Line_Of_Widgets -> List(Int) -> Void;
#
# Make visible again toplevel layout elements
# previously hidden via 'hide'. Showing
# already-visible elements is a no-op.
# Bad indices raise BAD_INDEX.
};
end; # stipulate