(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Fri Jan 1 21:08:56 PST 1993 by meehan *) (* modified on Tue Jun 16 13:08:36 PDT 1992 by muller *) (* modified on Sun Jun 14 02:09:56 1992 by mhb *) (* modified on Fri Mar 27 01:47:38 1992 by steveg*) <* PRAGMA LL *> (* A {\em multi}\index{multi} ("Multi.T") is a "VBT" with {\em logical children} that may or may not correspond to its children in the "VBT" hierarchy. A {\em multi-filter}\index{multi-filter} has a single logical child, and a {\em multi-split}\index{multi-split} has any number of logical children. Typically, logical children of multi "m" are also "VBT"-descendants of "m", but this is not necessary. A "BooleanVBT" is a good example of a multi-filter. It is implemented as an "HSplit" with 2 children. The first child is a "TSplit" with two "PixmapVBT"s corresponding to the ``on'' and ``off'' states; the second child is typically a string or a pixmap. A client views a "BooleanVBT" as having one child---the "HVSplit"'s 2nd child. "Multi.Child" retrieves this "VBT", and "Multi.ReplaceChild" changes the child. A "SplitterVBT" is a good example of a multi-split. It is built as an "HVSplit" with "HVBars" automatically inserted between children. The client of a "SplitterVBT" doesn't care about the "HVBars" at all. Invoking "Multi.Nth(v,i)" retrieves child "i" of the "SplitterVBT" (which is actually child "2*i" of the "HVSplit"), whereas "Split.Nth(v,i)" retrieves child "i" of the "HVSplit". Invoking "Multi.Delete(v, ch)" deletes child "ch" and its adjacent "HVBar", whereas "Split.Delete(v, ch)" deletes a single child "ch" of the "HVSplit". This interface defines the functionality that is common to all clients of multis (e.g., enumerating and deleting children). The "MultiClass" interface is for clients implementing "VBT" classes that are multis. Warning: Unless you are a wizard, don't use procedures from the "Split" or "Filter" interfaces on a multi; use the corresponding procedures from this interface instead. The procedures here work like their "Split" and "Filter" counterparts if the argument is not a multi. *) INTERFACE Multi; IMPORT Point, VBT; EXCEPTION NotAChild; TYPE T = VBT.T; (* A "Multi" is a "VBT" with a "MultiClass.T" in its property set. *) (* \subsubsection{Multi-filters} *) (* The following procedures can accept either a "Multi.T" or a non-multi "Filter.T" as the first argument. If the first argument is a non-multi "Filter.T", the procedure just calls the corresponding procedure in the "Filter" interface. *) PROCEDURE Child (v: VBT.T): VBT.T; (* Return the child of "v", or "NIL" if there is no child. *) PROCEDURE ReplaceChild (v: VBT.T; ch: VBT.T): VBT.T; (* Replace "v"'s child by "ch", detach and return "v"'s old child. *) (* \subsubsection{Multi-splits} *) (* The following procedures can accept either a "Multi.T" or a non-multi "Split.T". If "v" is a non-multi "Split.T", the procedure just calls the corresponding procedure in the "Split" interface. Any "Split.NotAChild\/" exceptions are re-raised as "NotAChild". *) PROCEDURE Delete (v: VBT.T; ch: VBT.T) RAISES {NotAChild}; <* LL = VBT.mu *> (* Delete the child "ch" of the multi "v" and detach "ch". Mark "v" for redisplay. *) PROCEDURE Replace (v: VBT.T; ch, new: VBT.T) RAISES {NotAChild}; <* LL = VBT.mu *> (* Replace child "ch" of "v" with "new", detach "ch" (which must not be "NIL"), and mark "v" for redisplay. *) PROCEDURE Succ (v: VBT.T; ch: VBT.T): VBT.T RAISES {NotAChild}; <* LL >= VBT.mu *> (* Return the child of "v" that follows the child "ch". If "ch = NIL", then return the first child. If the result is "NIL", then "ch" was the last child. The successor of "NIL" is "NIL" iff there are no children. The exception is raised if "ch" is not a child of "v". *) (* The multiclass is expected to implement "Succ" in constant time; "Pred", "Nth", and "Index" may take time proportional to the number of children. *) PROCEDURE Pred (v: VBT.T; ch: VBT.T): VBT.T RAISES {NotAChild}; <* LL >= VBT.mu *> (* "Pred(v,ch) = x" iff "Succ(v,x) = ch". *) PROCEDURE Nth (v: VBT.T; n: CARDINAL): VBT.T; <* LL >= VBT.mu *> (* Returns child "n" of "v" in succ order (child 0 is first), or "NIL" if there are "n" or fewer children. *) PROCEDURE NumChildren (v: VBT.T): CARDINAL RAISES {NotAChild}; <* LL >= VBT.mu *> (* Return the number of children of "v". *) PROCEDURE Index (v: VBT.T; ch: VBT.T): CARDINAL RAISES {NotAChild}; <* LL >= VBT.mu *> (* Return the value "n" such that "Nth(v,n)=ch". When "ch=NIL", return the number of children of "v". *) PROCEDURE Locate (v: VBT.T; READONLY pt: Point.T): VBT.T; <* LL = VBT.mu *> (* Return the child of "v" that would receive a mouse click at point "pt", or "NIL" if there is no such child. *) PROCEDURE Move (v: VBT.T; pred, ch: VBT.T) RAISES {NotAChild}; <* LL = VBT.mu *> (* Move child "ch" of "v" to follow "pred". "ch" and, if non-"NIL", "pred", must be children of "v". *) PROCEDURE Insert (v: VBT.T; pred, new: VBT.T) RAISES {NotAChild}; <* LL = VBT.mu *> (* Add "new" as a child of "v" following "pred". If "v" doesn't allow more children than it already has, "pred" (or the first child, if "pred = NIL") is deleted from the multi and discarded. The precise semantics are defined by the individual multis. The exception is raised if "pred" isn't a child of "v", and it's a checked runtime error if "new" isn't detached. *) PROCEDURE AddChildArray (v: VBT.T; READONLY new: ARRAY OF VBT.T); <* LL = VBT.mu *> (* The non-"NIL" elements of "new" become the last children of "v". Equivalent to | pred := Pred(v, NIL); | FOR i := FIRST(new) TO LAST(new) DO | IF new[i] # NIL THEN | Insert(v, pred, new[i]); | pred := new[i] | END | END *) PROCEDURE AddChild (v: VBT.T; n0, n1, n2, n3, n4, n5, n6, n7, n8, n9: VBT.T := NIL); <* LL = VBT.mu *> (* Equivalent to | AddChildArray(v, | ARRAY OF VBT.T{n0, n1, n2, n3, n4, n5, n6, n7, n8, n9}) *) END Multi.