(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Tue Sep 22 11:26:42 PDT 1992 by steveg *) (* modified on Tue Aug 11 21:05:34 PDT 1992 by meehan *) (* modified on Tue Jun 16 13:08:04 PDT 1992 by muller *) (* modified on Mon Jun 15 21:49:37 1992 by mhb *) <* PRAGMA LL *> (* A "ViewportVBT" is a multi-filter that displays multiple views of a child "VBT", with optional horizontal and vertical scrollbars. When the child's preferred size is larger than the viewport's {\em interior} (that is, the screen of the viewport minus the scrollbars), the child is reformatted to its preferred size. Since only part of the child is visible, the user can pan the child using the scrollbars. When the child's preferred size is smaller than the viewport's screen, the child is reformatted to the size of the viewport interior, and the scrollbars are ineffective. Views may be added or deleted under program control or by appropriate gestures in the scrollbar: Option Left click adds a new view after the view in which the user clicked. Option Right click removes the view (unless, of course, it would leave the viewport with zero views!). *) INTERFACE ViewportVBT; IMPORT Axis, HVSplit, MultiClass, Rect, Shadow, VBT; TYPE T <: Public; Public = HVSplit.T OBJECT METHODS init (ch : VBT.T; axis := Axis.T.Ver; shadow : Shadow.T := NIL; step : CARDINAL := 10; adjustableViews := TRUE; scrollStyle := ScrollStyle.AlaViewport; shapeStyle := ShapeStyle.Related; multiclass : MC := NIL ): T; END; (* The call to "v.init(..)" initializes "v" as a "ViewportVBT.T". The "axis" parameter says whether the views are arranged vertically or horizontally. "step" is the number of pixels to move while auto-scrolling. "shadow" gives the shadow for displaying scrollbars, resets and hvbars. When "adjustableViews" is "TRUE", an "HVBar" will be inserted between views so the user can adjust the screen allocated to each view. "scrollStyle" and "shapeStyle" are explained below. The initial view of "ch" is numbered 0 for use by "RemoveView". *) TYPE MC <: MultiClass.T; (* The type "MC" overrides the "replace", "pred", and "succ" methods of "MultiClass.T". *) (* The internal structure of a viewport is a rather complex collection of "JoinVBT"s, "HVSplit"s, "ScrollerVBT"s, and others. It depends on the options with which the viewport was created. A viewport is a multi-filter; that is, to the "Multi" interface, it gives clients an abstraction of a single child. Be sure to use the "Multi" interface to get at the child. *) TYPE View = INTEGER; (* A "View" is an internal ID for a view. The value is valid for the life of a view (i.e., until it is removed by a user gesture or by a call to "RemoveView"). Thereafter, the ID may be reused. The initial view created by the "init" method has a value of 0. *) (* A viewport can be created with a number of different styles of scrollbars: *) TYPE ScrollStyle = {HorAndVer, HorOnly, VerOnly, NoScroll, AlaViewport, Auto}; (* \noindent The styles are as follows: \begin{itemize} \item "HorAndVer" puts a horizontal and vertical scrollbar on every view. In addition, nestled between the scrollbars in the southwest corner, there's a little ``reset'' button that moves the northwest corner of the child to the northwest corner of the view. \item "HorOnly" and "VerOnly" place a scrollbar at the bottom (for horizontal scrolling) or the left side (for vertical scrolling). \item "NoScroll" specifies that views will not have scrollbars. \item "AlaViewport" specifies that there is a scroll bar in the same axis as the viewport. Thus, "AlaViewport" for a vertical viewport is equivalent to "VerOnly". \item "Auto" specifies that scroll bars appear only when the preferred size of the child exceeds the size of the viewport (in that dimension). \end{itemize} *) (* There are two styles of shape relationships between a viewport and its child: *) TYPE ShapeStyle = {Unrelated, Related}; (* "Unrelated" makes the shape of the viewed child equal to the child's preferred shape---completely unrelated to the viewport's current shape. "Related" makes the shape of the viewed child's shape equal to the the viewport's shape in the non-axis direction of the viewport. In the viewport's axis direction, the child's preferred shape is used. For example, the width of the child in a "Vertical" viewport is the width of the viewport. *) (* Here's how to change which part of child is within the viewport: *) PROCEDURE ScrollTo ( v : T; READONLY r : Rect.T; view : View := 0; force := TRUE); <* LL = VBT.mu *> (* Scroll the viewport "v" so that rectangle "r" is visible in view "view". Rectangle "r" will be roughly centered within "v", but if "r" is too big to be seen entirely, its northwest corner will be made visible. If "force" is "FALSE" and "r" is already entirely visible, this procedure is a no-op. *) PROCEDURE Normalize (v: T; w: VBT.T; view: View := 0); <* LL = VBT.mu *> (* If the domain of "w" is non-empty and it's entirely visible, do nothing. Otherwise, do a "ScrollTo" to "w"'s domain in view "view". *) (* At first blush, "Normalize" seems to be just a call to | ScrollTo(v, VBT.Domain(w), FALSE) However, if "w" doesn't have a domain, as is the case when "w" has been recently installed and the "VBT" tree has not been redisplayed, a thread is forked to wait until it can acquire "VBT.mu" (recall that "Normalize" and "ScrollTo" have "LL = VBT.mu"). After the lock is acquired, all pending redisplays are satisfied, and then "ScrollTo" of "w"'s domain is invoked. Since the thread executes outside event-time, it explicitly causes all marked "VBT"s to be redisplayed after it calls "ScrollTo". *) (* Finally, here's how to add and delete views from a program: *) PROCEDURE AddView (v: T; after: View := -1; split := TRUE): View; <* LL = VBT.mu *> (* Add another view after the view "after" (-1 means add as the first view) of the child. If "split" is "TRUE", then the new view and the view "after" will occupy the area previously occupied by the view "after". The area of all other views will be unchanged. The value returned is an internal ID for the view. This value may be reused after the view has been removed. *) PROCEDURE RemoveView (v: T; view: View); <* LL = VBT.mu *> (* Remove the view "view" from "v"'s child. The ID for the initial view created by the "init" method is 0. *) END ViewportVBT.