(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Tue Aug 11 20:24:55 PDT 1992 by meehan *) (* modified on Tue Jun 16 13:08:21 PDT 1992 by muller *) (* modified on Mon Jun 15 21:49:41 1992 by mhb *) (* modified on Fri Mar 27 02:13:18 1992 by steveg *) <* PRAGMA LL *> (* A "ScrollerVBT" is a scrollbar with an orientation along an {\em axis}. (For the sake of brevity in this interface, we'll only talk about vertical scrollers. For horizontal scrollers, replace phrases like ``top and bottom edges'' by ``left and right edges'', and so on.) The scrollbar contains a {\em stripe} that spans some fraction of the height of the scrollbar and is slightly narrower than the scrollbar. Various user-gestures cause methods on the "ScrollerVBT" to be invoked; typically, these methods will move the stripe vertically and possibly change its length. Clients may find it easier to use the "NumericScrollerVBT" subclass. That provides a ``bounded value'' abstraction with reasonable user-gestures to change the value (displayed visually by the location of the stripe within the scrollbar) and move the stripe accordingly. Also, it introduces a single ``callback'' method that is invoked whenever the user changes the value. Although each "VBT" class that uses a "ScrollerVBT" is free to associate any meaning with the length of the stripe, the following conventions are suggested for using scrollbars to view an object: \begin{quote} The ratio of the height of the stripe to the height of the scrollbar should be the same as the ratio of the amount of the object visible vertically to its entire height. The position of top of the stripe reflects the position of top of the view of the object within the entire object. \end{quote} Here is some terminology and user-interface guidelines: \begin{itemize} \item To {\em scroll}\index{scrolling} means to left-click or right-click in the scrollbar. \item You need to release the button (``upclick'') relatively quickly, or else you'll start {\em continuous scrolling}. You stop continuous scrolling by releasing the button, by {\em chord-cancelling}\index{chord} (clicking on any other mouse button), or by moving the mouse. \item When you move the mouse, you are then using {\em proportional scrolling}. This means that the more pixels that you move the mouse vertically, the more the stripe should be moved in the direction of the mouse movement. You stop proportional scrolling by upclicking or chord-cancelling. \item In general, the left and right buttons should be inverses: the left button should move the stripe downward and the right button should move the stripe upward. \item You {\em thumb}\index{thumb} with a middle-click. The top of the stripe should be moved to the position of the cursor. Thus, middle-click above the top of the stripe moves the stripe up, and middle-click below the top moves the stripe down. \item Middle-drag causes {\em continuous thumbing}. As you drag to a new position, the top of the stripe should be moved to match the current cursor position. You stop continuous thumbing by middle-upclicking or chord-canceling. \end{itemize} *) INTERFACE ScrollerVBT; IMPORT Axis, PaintOp, Pixmap, VBT; TYPE Points = REAL; T <: Public; Public = VBT.Leaf OBJECT METHODS <* LL.sup = VBT.mu *> init (axis: Axis.T; colors: PaintOp.ColorQuad): T; <* LL = VBT.mu *> scroll (READONLY cd : VBT.MouseRec; part : INTEGER; height : INTEGER; towardsEOF: BOOLEAN ); autoScroll (READONLY cd : VBT.MouseRec; linesToScroll: CARDINAL; towardsEOF : BOOLEAN ); thumb (READONLY cd : VBT.MouseRec; part : INTEGER; height: INTEGER ); END; (* The call to "v.init(axis, colors)" initializes "v" as a "ScrollerVBT" in the "axis" orientation, and returns "v". It is displayed using "colors". The default methods for "scroll", "autoScroll", and "thumb" are no-ops: the stripe within the scroller doesn't change. When the user scrolls, the implementation calls | v.scroll(cd, part, height, towardsEOF) on the up-click. "cd" is the mouse event; "height" is the number of pixels in the domain of "v" in the "v.axis" orientation. "part" is number of pixels away from the top/left edge that the upclick happened. "towardEOF" is "TRUE" when invoked from a left-upclick, "FALSE" when invoked from a right-upclick. (Of these, only "cd" is really needed; the others can be computed from "v" and "cd".) While the user is in continuous or proportional scrolling, the implementation calls "v.autoScroll(...)" repeatedly. The "linesToScroll" is somewhat of a misnomer (but kept for historical purposes). For continuous scrolling, the value is always 1. For proportional scrolling, the value is the number of pixels the mouse has moved. Think of "linesToScroll" as simply the ``amount that should be scrolled.'' The "cd" field in proportional scrolling is fine, except it's really a position event, not a mouse event, that caused the action (this is a good use for an "AnyEvent", but for historical reasons\dots). For continuous scrolling, "cd" is set to be the mouse record for the down-click that initiate the scrolling, but with "cd.time = 0". Finally, "v.thumb(cd, part, height)" is called when the user thumbs or continuous thumbs. "height" is the number of pixels in the domain of "v" in the "v.axis" orientation. "part" is the distance in pixels between the mouse and the top/left edge. The "cd" always has a valid time, cursor position, and modifier fields. (OK, it isn't the real event, since continuous thumbing is a position event whereas thumbing is a mouse event. Again, a good potential client of "AnyEvent".) By and large, these methods will change the position and size of the stripe. This is done using the following procedure: *) PROCEDURE Update (v: T; start, end, length: CARDINAL); <* LL.sup < v *> (* Set new values of the stripe and mark "v" for redisplay. The coordinate system for "start", "end", and "length" is as follows (we'll consider just a horizontal scrollbar): The left edge of the domain of "v" is at coordinate 0, and the right edge consider to be at "length". The stripe extends from "max(start,0)" to "max(min(end,length),start)". The implementation will draw a stripe to represent these quantities, subject to constraints such as the minimum number of pixels that the length of the stripe. *) (* The visual appearance of a "ScrollerVBT" is governed by the following data structures and procedures: *) TYPE Attributes = RECORD axis : Axis.T; margin : Points; scrollPaintOps : ARRAY Axis.T OF PaintOp.T; scrollPixmaps : ARRAY Axis.T OF Pixmap.T; minStripeLen : Points; stripeWidth : Points; stripePaintOps : ARRAY Axis.T OF PaintOp.T; stripePixmaps : ARRAY Axis.T OF Pixmap.T; stripeBorder : Points; stripeBorderPaintOp: PaintOp.T; stripeBorderPixmap : Pixmap.T; END; PROCEDURE GetAttributes (v: T): Attributes; (* Return the attribute currently in effect for "v". *) PROCEDURE SetAttributes (v: T; READONLY a: Attributes); <* LL.sup = VBT.mu *> (* Change the attributes on "v" to be "a". Mark "v" for redisplay and notify "v"'s parent that its shape might have changed. *) PROCEDURE Colorize (v: T; colors: PaintOp.ColorQuad); <* LL.sup = VBT.mu *> (* Sets the paint op of all the scroller's textures and borders to be "colors.bgFg". Mark "v" for redisplay. *) END ScrollerVBT.