Copyright (C) 1994, Digital Equipment Corp.
<* PRAGMA LL *> <* PRAGMA SUBTYPE *>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!).
INTERFACEThe call toViewportVBT ; IMPORT Axis, HVSplit, Rect, Shadow, VBT; TYPE <* SUBTYPE T <: MultiFilter.T *> T <: Public; Public = HVSplit.T OBJECT METHODS <* LL <= VBT.mu *> init (ch : VBT.T; axis : Axis.T := Axis.T.Ver; shadow : Shadow.T := NIL; step : CARDINAL := 10; adjustableViews: BOOLEAN := TRUE; scrollStyle := ScrollStyle.AlaViewport; shapeStyle := ShapeStyle.Unrelated): T; END;
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 internal structure of a viewport is a rather complex
collection of JoinedVBTs, HVSplits, ScrollerVBTs, and
others. It depends on the options with which the viewport
was created. Be sure to use the MultiFilter 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 places a scrollbar at the bottom.
\item VerOnly places a scrollbar at the left side.
\item NoScroll specifies that views will not have scrollbars.
\item AlaViewport specifies that there is a scrollbar in the
same axis as the viewport. Thus, AlaViewport for a vertical
viewport is equivalent to VerOnly.
\item Auto specifies that scrollbars appear only when the
preferred size of the child exceeds the size of the viewport (in
that dimension).
\end{itemize}
There are two possible shape-relationships between a viewport and its child:
TYPE ShapeStyle = {Unrelated, Related};
Unrelated makes the shape of the child equal to its preferred
shape---completely unrelated to the viewport's current shape.
Related makes the child's shape equal to 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.
\subsubsection{Panning the contents}
PROCEDURE ScrollTo ( v : T;
READONLY r : Rect.T;
view : View := 0;
force: BOOLEAN := TRUE);
<* LL = VBT.mu *>
Scroll the viewportvso that rectangleris visible in viewview. Rectanglerwill be roughly centered withinv, but ifris too big to be seen entirely, its northwest corner will be made visible. IfforceisFALSEandris 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 ofwis non-empty and it's entirely visible, do nothing. Otherwise, do aScrollTotow's domain in viewview.
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
VBTs to be redisplayed after it calls ScrollTo.
\subsubsection{Multiple views}
PROCEDURE AddView (v: T; pred: View := -1; split := TRUE): View; <* LL = VBT.mu *>
Add another view after the viewpred(-1 means add as the first view) of the child. IfsplitisTRUE, then the new view and the viewpredwill occupy the area previously occupied by the viewpred. 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 viewviewfromv's child. The ID for the initial view created by theinitmethod is 0.
END ViewportVBT.