(* Copyright (C) 1992, Digital Equipment Corporation                         *)
(* All rights reserved.                                                      *)
(* See the file COPYRIGHT for a full description.                            *)
(*                                                                           *)
(* File HVSplit.i3 coded by MSM and CGN, Mon Nov 18 21:52:15 1985 *)
(* Last modified on Tue Mar 10 19:00:23 1992 by steveg  *)
(*      modified on Mon Feb 24 13:53:24 PST 1992 by muller  *)
(*      modified on Sat Dec 21 16:14:45 PST 1991 by gnelson *)
(*      modified on Thu Sep  6 21:11:15 PDT 1990 by msm *)
(*      modified on Fri Feb  2 14:01:44 PST 1990 by glassman *)
<*PRAGMA LL*>

(* An "HVSplit.T" is a parent window that splits its screen into a
   row or column of child windows, depending on the <I>axis</I> of
   the split.

   If the axis is horizontal, "Split.Succ" enumerates the children 
   from west to east; if the axis is vertical, it enumerates them 
   from north to south.

   An "HVSplit" can be <I>adjustable</I> or <I>unadjustable</I>, a 
   property that affects the way its space is divided between its children.    

   The <I>size</I> of a child is the extent of its domain in the 
   axis of split, the <I>cross-size</I> is its extent in the other axis.  
   For example, for a vertical split, a child's size is its height 
   and its cross-size is its width.

   The children of an "HVSplit" all have the same cross-size as the
   parent.  To determine the sizes of the children, the "HVSplit" begins
   by computing the range of desirable sizes and the preferred size
   for each child by calling its shape method, passing the method the
   cross-size, so that, for example, the height of a child of a vertical
   split can depend on its width.  At this point there are several cases.

   If the sum of the minimum sizes of the children is greater than the
   size of the parent, then the split is said to be <I>overfull</I>.
   In this case the children are considered in order and given their
   minimum sizes, as long as there is room.  The first child that
   doesn't fit is given all the space that's left, and the remaining
   children are given size zero.

   If the split is not overfull, then the children are stretched
   according to the TeX model of boxes and glue.  The details depend
   on whether the split is adjustable or unadjustable.  For an
   adjustable split, each child's <I>stretchability</I> is its maximum
   desirable size minus its current size, and its <I>shrinkability</I>
   is its current size minus its minimum desirable size.  If the size
   of the parent is increased by some amount "X", then the sizes of
   the children are increased by amounts that total to "X" and are
   proportional to the children's stretchabilities.  Similarly, if the
   size of the parent is decreased by some amount "X", then the sizes
   of the children are decreased by amounts that total to "X" and are
   proportional to the children's shrinkabilities.

   For a non-adjustable split, all the children's sizes are first set
   to their preferred sizes, and then they are stretched or shrunk the
   same as an adjustable split.  Thus for a non-adjustable split each
   redistribution of space depends only on the children's shape methods,
   not on their current sizes.

   A non-adjustable split is best if the layout can be controlled purely
   by stretchability and shrinkability.  If the layout is also changed
   under user or program control, an adjustable split is required.  For
   example, in a column of editable text windows, you should make the
   vertical split adjustable, since if the user makes one window big,
   and then the parent changes size slightly, you do not want the big
   window child to snap back to being small.  On the other hand if you
   are using a horizontal split to center a "ButtonVBT" between two
   stretchy "TextureVBTs", you should make it unadjustable, since in
   this case you always want to compute the division of space from the
   children's original shapes.

   If the sum of the maximum sizes of the children is less than the
   size of the parent, the split is said to be <I>underfull</I>.  There
   are no special rules for the underfull case: the TeX stretching
   algorithm is used without change.  This produces a state in which
   the children are stretched larger than their maximum sizes.

   A split is <I>infeasible</I> if it is overfull or underfull, and <I>
   feasible</I> otherwise.
    
   The shape of an "HVSplit" is computed as follows: its maximum,
   minimum, and preferred sizes are obtained by adding up the
   corresponding values of its children.  The cross-size range is the
   intersection of the cross-size ranges of its children (if this
   intersection is empty, the children's maximum cross-sizes are
   increased until the intersection is non-empty).  The preferred
   cross-size of "v" is the maximum of the preferred cross-sizes
   of its children, projected into "v"'s cross-size range.  *)

   
INTERFACE HVSplit;

IMPORT VBT, Split, Axis, Interval;

TYPE
  T <: Public;
  Private <: Split.T;
  Public = Private OBJECT METHODS
    <* LL.sup <= VBT.mu *>
    init(hv: Axis.T;
      saveBits := FALSE;
      parlim := -1;
      adjustable := TRUE): T
  END;

(* The call "v.init(...)" initializes "v" as an "HVSplit" with axis 
   "hv" and no children.

   If "saveBits" is "TRUE", the implementation will try to save the
   children's old bits when reshaping; if the children don't use them
   anyway, it is faster to let "saveBits" default to "FALSE".  The value of
   "parlim" is the minimum area of a child for which a separate thread
   will be forked to "reshape" or "repaint"; if it is "-1", it is set
   to an appropriate default (see the "VBTTuning" interface).  *)


PROCEDURE New(
    hv: Axis.T;
    saveBits := FALSE;
    parlim := -1;
    adjustable := TRUE): T;
<* LL.sup <= VBT.mu *>
(* "New(...)" is equivalent to "NEW(T).init(...)". *)


PROCEDURE AxisOf(v: T): Axis.T; 
<* LL.sup = VBT.mu *>
(* Return the axis of "v". *)

(* <H3> Inserting children </H3> *)

(* See the "Split" interface to insert and reorder children. *) 

PROCEDURE Cons(
    hv: Axis.T;
    ch0, ch1, ch2, ch3, ch4, 
      ch5, ch6, ch7, ch8, ch9: VBT.T := NIL;
    saveBits := FALSE;
    parlim := -1;
    adjustable := TRUE): T; <* LL.sup = VBT.mu *>
 (* Create an "HVSplit" with axis "hv" and children "ch0", "ch1", .... *) 
 
(* "Cons" is equivalent to the following:

| result := New(hv, saveBits, parlim, adjustable);
| Split.AddChild(result, ch0, ch1, ..., ch9);
| RETURN result

*)


PROCEDURE ConsArray(
    hv: Axis.T;
    READONLY ch: ARRAY OF VBT.T;
    saveBits := FALSE;
    parlim := -1;
    adjustable := TRUE): T; <* LL.sup = VBT.mu *>
(* Create an "HVSplit" with axis "hv" and children "ch[0]", "ch[1]", .... *)

(* "ConsArray" ignores any "NILs" in the array "ch".  It is equivalent to:

| VAR result := New(hv, saveBits, parlim, adjustable);
| BEGIN
|   Split.AddChildArray(result, ch);
|   RETURN result
| END

  *)

(* <H3> Adjusting the division of space </H3> *)

(* The <I>division point after a child</I> is the sum of the sizes of
   all children up to and including the child. *)
   

PROCEDURE Adjust(v: T; ch: VBT.T; totsz: INTEGER) 
RAISES {Split.NotAChild}; <* LL.sup = VBT.mu *>
(* Change the sizes of the children of "v" so that the division point
   after "ch" is as close to "totsz" as possible, and mark "v" for
   redisplay. *)

(* "Adjust" respects the size constraints on the children, and resizes
   children near the division point in preference to children far from
   the division point.  For example, a sufficiently small adjustment
   will be made by resizing only "ch" and its successor.  An adjustment
   large enough to make one of these children reach its max or min size
   will also resize the neighbor of that child, and so forth.

   "Adjust" is a no-op if the split is infeasible or non-adjustable. *)


PROCEDURE FeasibleRange(v: T; ch: VBT.T): Interval.T 
RAISES {Split.NotAChild}; <* LL.sup = VBT.mu *>
(* Return the interval of feasible positions for the division point
   after "ch". *)
   

PROCEDURE AvailSize(v: T): CARDINAL;
<* LL.sup = VBT.mu *>
(* Return the largest size of a child that can be inserted into "v"
   without making "v" infeasible. *)

(* If the split is infeasible, "AvailSize" returns 0 and "FeasibleRange" 
   returns the empty interval.  Both procedures assume the 
   total size available is the total of all child sizes. *)


END HVSplit.
