PreviousUpNext

15.3.690  src/lib/x-kit/widget/old/layout/line-of-widgets.api

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

stipulate
    package wg = widget;                        # Widget        is from   src/lib/x-kit/widget/old/basic/widget.api
herein

    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



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext