-- File: MBWindowsImpl.mesa -- Contents: package implementing set of buttons in viewer when there are too many things to actually create buttons for all. Client passes procedures to go forward and backward through enumeration, and MBWindowsImpl implements scrolling, calling client button proc on appropriate thing whenever user pushes a button. -- Last Edited by: Cattell, July 28, 1983 6:29 pm -- Last Edited by: Elabbadi, July 28, 1983 11:28 am DIRECTORY Buttons, MBQueue, MBWindows, NutViewer, Rope, ViewerLocks, ViewerOps, ViewerClasses; MBWindowsImpl: PROGRAM IMPORTS NutViewer, ViewerLocks, ViewerOps EXPORTS MBWindows = -- Future modifications: -- make independent of NutViewer by copying code -- allow shift selection to get text BEGIN OPEN MBWindows; ButtonCount: CARDINAL = 50; -- number of buttons that fit vertically on screen ButtonHeight: CARDINAL = 16; -- height of button in pixels MBWindowData: TYPE = REF MBWindowDataRec; MBWindowDataRec: TYPE = RECORD [ scrolledTo: INTEGER, -- position of first button in the full enumeration prevProc, nextProc: EnumProc, -- to go forward and back in enumeration enum: REF ANY, -- always kept pointing to last button in window buttonProc: Buttons.ButtonProc, -- to call when user pushes a button getThingCount: PROC [enum: REF ANY] RETURNS [INT] -- to get total count ]; Viewer: TYPE = ViewerClasses.Viewer; CreateMBWindow: PUBLIC PROC[ getThingCount: PROC [enum: REF ANY] RETURNS[INT], -- number of things in enum enum: REF ANY, -- client object used to represent state of enumeration next, prev: EnumProc, buttonProc: Buttons.ButtonProc, -- called with the thing associated with button info: ViewerClasses.ViewerRec_ [], -- allows client to fill in ViewerRec fields q: MBQueue.Queue_ NIL] -- MBQueue under which to synchronize RETURNS [viewer: ViewerClasses.Viewer] = BEGIN button: ViewerClasses.Viewer; info.data_ NEW[MBWindowDataRec_ [0, next, prev, enum, buttonProc, getThingCount]]; viewer_ ViewerOps.CreateViewer[ flavor: $MBWindow, info: info, paint: FALSE]; -- Create empty buttons in the viewer, in order from top to bottom. button_ NutViewer.Initialize[viewer]; FOR i: INT IN [0..ButtonCount) DO button_ NutViewer.MakeButton[q, NIL, buttonProc, button]; ENDLOOP; -- WARNING: The following line depends on the fact that children of a viewer are in -- the sibling list in the reverse order they are created by MakeButton. After the list -- is reversed, they are in order down the screen. viewer.child_ ReverseChildList[viewer.child].first; -- Fill in button labels and data by faking scroll to zero position NARROW[viewer.data, MBWindowData].scrolledTo_ 0; []_ MBWindowScroll[viewer, thumb, ButtonCount]; END; ReverseChildList: PROC[child: Viewer] RETURNS[first, last: Viewer] = { IF child.sibling=NIL THEN RETURN[child, child]; [first, last]_ ReverseChildList[child.sibling]; last.sibling_ child; child.sibling_ NIL; RETURN[first, child] }; -- MBWindow maintenance strategy: -- The scrolledTo variable says where the last non-empty button on the screen lies in the -- enumeration. The first button is at MAX[scrolledTo-ButtonCount, 0] in the enumeration. -- If we are initially scrolled to the beginning, it is zero. The enum variable is left pointing -- at the last button currently on the screen; that turns out to be more efficent than leaving -- it pointing at the first. When we scroll up, we move the label and data fields of the -- buttons up, changing scrolledTo and enum in the process; then we repaint the screen. -- And conversely scrolling down. MBWindowScroll: ViewerClasses.ScrollProc = TRUSTED BEGIN my: MBWindowData _ NARROW[self.data]; incr: INTEGER; height: INTEGER; LockedScroll: SAFE PROC = TRUSTED { -- We assume that enum has been moved to first item on screen, we simply re-fill in -- the buttons. We assume that the buttons are in order top to bottom in the viewer. -- (Scott says, well... it's not likely to change). FOR v: Viewer _ self.child, v.sibling UNTIL v=NIL DO [v.name, v.data] _ my.nextProc[my.enum]; ENDLOOP; my.scrolledTo _ my.scrolledTo+incr; ViewerOps.PaintViewer[self, client]}; IF my = NIL THEN RETURN; IF op=query OR op=thumb THEN BEGIN -- compute total height thumbPos: LONG INTEGER; height _ my.getThingCount[my.enum]; IF op=thumb THEN BEGIN thumbPos _ LONG[amount]*height/100; height _ thumbPos; -- narrow to short integer END; END; IF op=query THEN BEGIN top, bottom: INT; IF self.child = NIL OR height=0 THEN RETURN [0, 100]; top _ LONG[100]*TopOfWindow[my]/height; bottom _ 100 - my.scrolledTo/height; RETURN[top, bottom]; END; incr _ SELECT op FROM up => MIN[LONG[amount]/ButtonHeight, my.getThingCount[my.enum]-my.scrolledTo], down => MIN[LONG[amount]/ButtonHeight, my.scrolledTo], thumb => height-my.scrolledTo+ButtonCount, ENDCASE => ERROR; IF incr=0 THEN RETURN; MoveEnum[my, incr]; IF incr#0 THEN ViewerLocks.CallUnderWriteLock[LockedScroll, self]; END; MoveEnum: PROC[my: MBWindowData, incr: INTEGER] = BEGIN -- Moves enumeration forward or backward by incr. Just move as far as can if incr -- is farther than nextProc and prevProc are willing to go. up: BOOL_ TRUE; IF incr<0 THEN {up_ FALSE; incr_ -incr}; FOR i: INT IN [1..incr) DO IF up THEN []_ my.nextProc[my.enum] ELSE []_ my.prevProc[my.enum] ENDLOOP; END; TopOfWindow: PROC[my: MBWindowData] RETURNS [INT] = {RETURN[MAX[0, my.scrolledTo-ButtonCount]]}; mbWindowClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ scroll: MBWindowScroll, coordSys: top, icon: tool, bltContents: top ]]; ViewerOps.RegisterViewerClass[$MBWindow, mbWindowClass]; -- plug in to Viewers END. ÊΘJšœœÏkœœ˜·šœœœ˜!Jšœ œ5˜HJšœF˜FJ˜?J˜DJ˜GJ˜J˜—Jšœ$˜$J˜Jšœ œœœœ(œ¸œ$œÎœß˜—JšœÏbœÚ˜çJšœåœ˜éJšœy˜yJšœ|˜|šœ˜ ˜¥Jšœœ ˜%Jšœœ˜Jšœœ˜šÏn œ œœ˜#J˜SJ˜UJ˜3šœ#œœ˜4J˜(Jšœ˜—Jšœ#˜#J˜%J˜—Jšœœœœ˜š œ œ œœÏc˜:Jšœ œœ˜Jšœ#˜#šœ œ˜Jšœ œ˜#Jšœ ˜-Jšœ˜—Jšœ˜—šœ œ˜Jšœ œ˜Jš œœœ œœ ˜5Jšœœ˜'Jšœ$˜$Jšœ˜Jšœ˜—šœœ˜Jšœœœ@˜PJšœ œœ&˜7Jšœ*˜*Jšœœ˜—Jšœœœ˜J˜Jšœœ4˜BJšœ˜J˜—J˜šœ˜JšœL˜L—Jšœ˜J˜J˜Jšœ3˜3Jšœ.˜.J˜Jšœ+œ!˜OJ˜J˜J˜ J˜˜J˜—Jšœ9 ˜NJ˜J˜—…—N"