DIRECTORY BasicTime USING [GMT, Now, Period, Update], CedarProcess USING [Priority, SetPriority], Cursors USING [SetCursor], Imager, ImagerBackdoor USING [DiscardBuffer, MakeStipple, RestoreBuffer, SaveBufferRectangle, ViewReset], ImagerColor, ImagerFont USING [Extents, FontBoundingBox, RopeBoundingBox], InputFocus USING [CaptureButtons, PopInputFocus, PushInputFocus, ReleaseButtons], MachineDependentPopping USING [maySetMouse, ScreenCoords, SetMouse, ToScreenCoords], PopUpButtons, PopUpSelection2, PopUpSelection2Private, Process USING [Detach, InitializeCondition, MsecToTicks, SecondsToTicks], Real USING [Fix, Round], Rope USING [InlineIsEmpty, ROPE], RuntimeError USING [UNCAUGHT], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords, TIPTable], UserProfile USING [Boolean, CallWhenProfileChanges, Number, ProfileChangedProc, Token], VFonts USING [DefaultFont, EstablishFont], ViewerClasses USING [NotifyProc], ViewerLocks USING [CallUnderColumnLock, CallUnderViewerTreeLock], ViewerPrivate USING [CreateContext, Screen], ViewerSpecs USING [colorScreenHeight, colorScreenWidth, bwScreenHeight, bwScreenWidth]; PopUpSelection2Impl: CEDAR MONITOR IMPORTS BasicTime, CedarProcess, Cursors, Imager, ImagerBackdoor, ImagerColor, ImagerFont, InputFocus, MachineDependentPopping, Process, Real, Rope, RuntimeError, TIPUser, UserProfile, VFonts, ViewerLocks, ViewerPrivate, ViewerSpecs EXPORTS PopUpSelection2 = BEGIN OPEN MDP:MachineDependentPopping, PopUpSelection2; Menu: TYPE = REF MenuPrivate; MenuPrivate: PUBLIC TYPE = PopUpSelection2Private.MenuPrivate; RopeImage: TYPE ~ REF RopeImagePrivate; RopeImagePrivate: TYPE ~ PopUpButtons.RopeImagePrivate; Colors: TYPE ~ REF ColorsPrivate; ColorsPrivate: TYPE ~ PopUpButtons.ColorsPrivate; State: TYPE ~ {idle, preparing, selecting, recovering}; reCheck: CONDITION; state: State _ idle; repositioned: BOOL _ FALSE; timedOut: BOOL _ FALSE; timeOutKey: REF BasicTime.GMT; --NIL means no time out expected; SetUpTimeOutWatcher is only writer gSelection: NAT _ 0; gMB: MouseButton _ red; gMouse: REF _ NIL; gHelpOn: INTEGER _ -1; gHelpMode: BOOL _ FALSE; gXOrg, gYOrg: INTEGER _ 0; -- initial mouse position, relative to [mx, my], 0 at bottom sHeight, sWidth: INTEGER _ 0; -- size of screen, in pixels; [screen containing menu] mx, my: INTEGER _ 0; -- menu position, 0 at bottom context: Imager.Context _ NIL; -- menu context mOnColor: BOOL _ FALSE; -- menu [NOT cursor] on color screen lastMouse: MDP.ScreenCoords; -- at start; remember between calls is creature comfort; 0 at bottom NotifyConsumer: Consumer _ NIL; notifyConsumerData: REF ANY _ NIL; gm: Menu _ NIL; gDefault: NAT; CallerBug: ERROR = CODE; Bug: ERROR = CODE; bordThick: NAT = 2; bordSep: NAT = 2; borderW: NAT = bordThick+bordSep; border2W: NAT = borderW+borderW; debug: BOOL _ FALSE; tipTable: TIPUser.TIPTable = TIPUser.InstantiateNewTIPTable["PopUpSelection2.tip"]; font: Imager.Font _ NIL; Reason: TYPE ~ {done, reposition, allup}; SetDoneAndNotify: PROC [reason: Reason, mb: MouseButton] --must only be called from the notifier process, because it passes result to NotifyConsumer-- = { Consume: Consumer; sel: INT; data: REF ANY; [Consume, sel, data] _ SetDone[reason, mb]; IF Consume # NIL THEN Consume[sel, mb, data]; RETURN}; SetDone: ENTRY PROC [reason: Reason, mb: MouseButton] RETURNS [Consume: Consumer, sel: INT, data: REF ANY] = { ENABLE UNWIND => NULL; IF reason=allup AND gm.allMayBeUp THEN RETURN [NIL, -1, NIL]; IF state#selecting THEN RETURN [NIL, INT.FIRST, NIL]; state _ recovering; repositioned _ SELECT reason FROM done, allup => FALSE, reposition => TRUE, ENDCASE => ERROR; IF repositioned THEN Consume _ NIL ELSE Consume _ NotifyConsumer; sel _ IF timedOut THEN -1 ELSE gSelection; gMB _ mb; data _ notifyConsumerData; BROADCAST reCheck; RETURN}; Wait: ENTRY PROC RETURNS [reposd: BOOL] = { ENABLE UNWIND => NULL; IF state#preparing THEN RETURN WITH ERROR Bug; state _ selecting; BROADCAST reCheck; WHILE state#recovering DO WAIT reCheck ENDLOOP; IF (reposd _ repositioned) THEN state _ preparing; RETURN}; Enter: ENTRY PROC [] = { ENABLE UNWIND => NULL; WHILE state#idle DO WAIT reCheck ENDLOOP; state _ preparing; BROADCAST reCheck; RETURN}; Leave: ENTRY PROC [] = { ENABLE UNWIND => NULL; IF state#recovering THEN RETURN WITH ERROR Bug; state _ idle; BROADCAST reCheck; RETURN}; Restore: PROC [s: ATOM] = { ImagerBackdoor.RestoreBuffer[context, s]; IF discard THEN ImagerBackdoor.DiscardBuffer[context, s]; }; discard: BOOL _ TRUE; SetUpTimeOutWatcher: ENTRY PROC [i: NAT] = { ENABLE UNWIND => NULL; timedOut _ FALSE; IF i<=0 OR i>10000 THEN timeOutKey _ NIL --upper limit to prevent overflow ELSE { timeOutKey _ NEW[BasicTime.GMT _ BasicTime.Update[BasicTime.Now[], i]]; TRUSTED {Process.Detach[FORK TimeOutWatcherProcess[key: timeOutKey]]}; } }; TimeOutWatcherProcess: ENTRY PROC [key: REF BasicTime.GMT] = { ENABLE UNWIND => NULL; cond: CONDITION; CedarProcess.SetPriority[excited]; TRUSTED {Process.InitializeCondition[@cond, Process.SecondsToTicks[MIN[MAX[BasicTime.Period[from: BasicTime.Now[], to: key^], 1], 10]]]}; WHILE timeOutKey=key AND state=selecting AND BasicTime.Period[from: BasicTime.Now[], to: key^]>0 DO WAIT cond ENDLOOP; IF timeOutKey=key AND state=selecting THEN { state _ recovering; timedOut _ TRUE; BROADCAST reCheck}; }; helpSave: ATOM _ NIL; Box: PROC [x, y, w, h, border: INTEGER] = { Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, x, y, w, h]; Imager.SetColor[context, Imager.black]; Imager.MaskRectangleI[context, x, y, border, h]; Imager.MaskRectangleI[context, x+w-border, y, border, h]; Imager.MaskRectangleI[context, x, y, w, border]; Imager.MaskRectangleI[context, x, y+h-border, w, border]; }; HelpMessage: PROC [n: INTEGER] = { IF n#gHelpOn THEN { msg: ROPE _ NIL; gHelpOn _ n; IF helpSave#NIL THEN {Restore[helpSave]; helpSave _ NIL}; msg _ IF n = 0 THEN gm.doc ELSE IF n <= gm.choices.length AND gm.choices[n-1] # nullChoice THEN gm.choices[n-1].doc ELSE "no-op"; IF ~Rope.InlineIsEmpty[msg] THEN { bordThick: NAT ~ 2; bordDist: NAT ~ 4; below: NAT ~ 2; e: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[font, msg]; h: INTEGER _ Real.Fix[MIN[e.descent+e.ascent+2*bordDist, sHeight]]; --text height w: INTEGER _ Real.Fix[MIN[e.rightExtent+e.leftExtent+2*bordDist+1, sWidth]]; --text width ty: INTEGER _ my-h-below; --text box's lower y in upright coordinates tx: INTEGER _ MIN[MAX[mx + (gm.width - w)/2, 0], sWidth-w]; --text box's left x in screen coordinates IF ty<0 THEN { ty _ my+gm.height+below; IF ty+h>=sHeight THEN RETURN; }; ImagerBackdoor.SaveBufferRectangle[context, helpSave _ $Help, [tx, ty, w, h]]; Box[tx, ty, w, h, bordThick]; Imager.SetColor[context, Imager.black]; Imager.SetXY[context, [(tx+bordDist)+e.leftExtent, ty+bordDist+e.descent]]; Imager.SetFont[context, font]; Imager.ShowRope[context, msg]; }; } }; MoveCursor: ENTRY PROC [x, y: INTEGER, onCol: BOOL] = { ENABLE UNWIND => NULL; row, col, sel: NAT _ 0; IF state#selecting THEN RETURN; IF onCol=mOnColor THEN { dx: INTEGER ~ x - mx; dy: INTEGER ~ y - my; SELECT TRUE FROM dx IN [borderW .. gm.width-border2W) AND dy IN (gm.fullRowsBot .. gm.headerBot] => { sel _ (gm.headerBot-dy) / gm.fullRowHeight + 1; }; dx IN [gm.arrayLeft .. gm.arrayRight) AND dy IN (gm.arrayBot .. gm.arrayTop] => { row _ (gm.arrayTop-dy)/gm.rowHeight; col _ (dx-gm.arrayLeft)/gm.colWidth; sel _ gm.fullRows + row*gm.cols + col + 1; }; ENDCASE => { gHelpMode _ TRUE; HelpMessage[0]; }; }; IF gSelection#sel THEN { ll: INTEGER ~ mx; by: INTEGER ~ my; IF gSelection#0 THEN PaintEntry[ll, by, gSelection-1, FALSE]; gSelection _ sel; IF gSelection#0 THEN PaintEntry[ll, by, gSelection-1, TRUE]; IF gHelpMode THEN HelpMessage[gSelection]; }; }; PopUpNotify: ViewerClasses.NotifyProc = { ProtectedNotify: PROC [input: LIST OF REF ANY] = { IF state=selecting THEN { mb: MouseButton _ red; FOR list: LIST OF REF ANY _ input, list.rest WHILE list#NIL DO WITH list.first SELECT FROM coords: TIPUser.TIPScreenCoords => MoveCursor[coords^.mouseX, coords^.mouseY, coords^.color]; atom: ATOM => SELECT atom FROM $Red => mb _ red; $Yellow => mb _ yellow; $Blue => mb _ blue; $Done => SetDoneAndNotify[done, mb]; $Reposition => SetDoneAndNotify[reposition, mb]; $AllUp => SetDoneAndNotify[allup, mb]; ENDCASE => ERROR; ENDCASE => ERROR; ENDLOOP }; }; ProtectedNotify[input ! RuntimeError.UNCAUGHT => GOTO failed]; EXITS failed => {gSelection _ 0; SetDoneAndNotify[reposition, red]}; }; defaultFont: PUBLIC Imager.Font _ VFonts.DefaultFont[NIL]; dontPaint: PUBLIC Imager.Color _ ImagerColor.ColorFromStipple[ word: 0, function: [xor, null]]; sparseGrey: Imager.Color ~ ImagerBackdoor.MakeStipple[stipple: 00208H]; denseGrey: Imager.Color ~ ImagerBackdoor.MakeStipple[stipple: 0FDF7H]; defaultColors: PUBLIC Colors _ NEW [ColorsPrivate _ [ [ALL[[Imager.black, Imager.white]], ALL[[Imager.black, sparseGrey]]], [ALL[[Imager.white, Imager.black]], ALL[[Imager.white, denseGrey]]] ]]; inverseColors: PUBLIC Colors _ NEW [ColorsPrivate _ [ [ALL[[Imager.white, Imager.black]], ALL[[Imager.white, denseGrey]]], [ALL[[Imager.black, Imager.white]], ALL[[Imager.black, sparseGrey]]] ]]; leftMargin: INTEGER _ 3; rightMargin: INTEGER _ 2; bottomMargin: INTEGER _ 0; topMargin: INTEGER _ 1; ImageForRope: PUBLIC PROC [rope: ROPE, colors: Colors _ NIL, font: Imager.Font _ NIL, align: Align _ bottomLeft] RETURNS [image: Image] = { IF font = NIL THEN font _ defaultFont; IF colors = NIL THEN colors _ defaultColors; { e: ImagerFont.Extents = ImagerFont.RopeBoundingBox[font, rope]; f: ImagerFont.Extents = ImagerFont.FontBoundingBox[font]; ri: RopeImage = NEW [RopeImagePrivate _ [ rope, colors, font, align, [Real.Round[e.leftExtent] + leftMargin, Real.Round[f.descent]+bottomMargin] ]]; image _ NEW [ImagePrivate _ [ size: [ri.org.x + Real.Round[e.rightExtent] + rightMargin, ri.org.y + Real.Round[f.ascent] + topMargin], Draw: DrawRope, data: ri]]; }}; DrawRope: PROC [image: Image, context: Imager.Context, bounds: Imager.Rectangle, state: PopUpButtons.VisibleState] --Drawer-- = { ri: RopeImage = NARROW[image.data]; ybot: REAL = bounds.y + ri.org.y + (bounds.h - image.size.y)*ri.align.y; xbot: REAL ~ bounds.x + ri.org.x + (bounds.w - image.size.x)*ri.align.x; foreground, background, strike: Imager.Color; [foreground, background, strike] _ ri.colors[state.highlight][state.executing][state.guarded]; Imager.SetColor[context, background]; Imager.MaskRectangle[context, bounds]; Imager.SetColor[context, foreground]; Imager.SetXY[context, [xbot, ybot]]; Imager.SetFont[context, ri.font]; Imager.ShowRope[context, ri.text]; IF state.guarded THEN { guardOffset: REAL = ri.font.FontBoundingBox[].ascent*(1.0/3); IF strike = NIL THEN strike _ foreground; Imager.SetColor[context, strike]; Imager.MaskRectangle[context, [bounds.x, ybot+guardOffset, bounds.w, 1]]; }; }; Sequify: PUBLIC PROC [list: ChoiceList] RETURNS [seq: ChoiceS] ~ { len: NAT _ 0; FOR l: ChoiceList _ list, l.rest WHILE l#NIL DO len _ len+1 ENDLOOP; seq _ NEW [ChoiceSequence[len]]; FOR i: NAT IN [0 .. len) DO seq[i] _ [ImageForRope[list.first.key], list.first.doc]; list _ list.rest; ENDLOOP; IF list#NIL THEN ERROR; RETURN}; PopRopes: PUBLIC PROC [ choices: ChoiceList, doc: ROPE, allMayBeUp: BOOL, default: NAT _ 0, header: ROPE _ NIL, left, top: Label _ nullLabel, columns: NAT _ 1, fullRows: NAT _ 0, timeOut: NAT _ 0, position: REF _ NIL, InNotifier: Consumer _ NIL, notifyData: REF ANY _ NIL] RETURNS [sel: INT, mb: MouseButton] ~ { menu: Menu ~ Create[Sequify[choices], doc, allMayBeUp, IF header#NIL THEN ImageForRope[header] ELSE NIL, left, top, columns, fullRows, timeOut]; [sel, mb] _ Pop[menu, default, position, InNotifier, notifyData]; RETURN}; Create: PUBLIC PROC [choices: ChoiceS, doc: ROPE, allMayBeUp: BOOL, header: Image _ NIL, left, top: Label _ nullLabel, columns: NAT _ 1, fullRows: NAT _ 0, timeOut: NAT _ 0] RETURNS [m: Menu] = { fullWidth: NAT _ 0; m _ NEW [MenuPrivate _ [ choices: choices, header: header, doc: doc, allMayBeUp: allMayBeUp, left: left, top: top, fullRows: fullRows, arrayRows: (choices.length - fullRows + columns-1) / columns, cols: columns, timeOut: timeOut ]]; FOR i: NAT IN [0 .. fullRows) DO IF choices[i] # nullChoice THEN { m.fullRowHeight _ MAX[m.fullRowHeight, Ceiling[choices[i].image.size.y]]; fullWidth _ MAX[fullWidth, Ceiling[choices[i].image.size.x]]; }; ENDLOOP; m.fullRowsSize _ m.fullRowHeight * fullRows; FOR i: NAT IN [fullRows .. choices.length) DO IF choices[i] # nullChoice THEN { m.rowHeight _ MAX[m.rowHeight, Ceiling[choices[i].image.size.y]]; m.colWidth _ MAX[m.colWidth, Ceiling[choices[i].image.size.x]]; }; ENDLOOP; IF top # nullLabel THEN { m.colWidth _ MAX[m.colWidth, top.minSpacing]; m.topLabelSize _ top.minWidth; }; IF left # nullLabel THEN { m.rowHeight _ MAX[m.rowHeight, left.minSpacing]; m.leftLabelSize _ left.minWidth; }; IF header # NIL THEN { m.headerSize _ Ceiling[header.size.y]; fullWidth _ MAX[fullWidth, Ceiling[header.size.x]]; }; m.arrayWidth _ m.cols * m.colWidth; IF fullWidth > m.arrayWidth+m.leftLabelSize THEN { IF m.arrayWidth # 0 THEN { m.colWidth _ Real.Round[fullWidth/REAL[m.arrayWidth+m.leftLabelSize] * m.colWidth]; m.arrayWidth _ m.cols * m.colWidth; }; m.leftLabelSize _ fullWidth - m.arrayWidth; }; m.arrayHeight _ m.arrayRows * m.rowHeight; m.arrayLeft _ borderW + m.leftLabelSize; m.arrayRight _ m.arrayLeft + m.arrayWidth; m.arrayBot _ borderW; m.arrayTop _ m.arrayBot + m.arrayHeight; m.fullRowsBot _ m.arrayTop + m.topLabelSize; m.headerBot _ m.fullRowsBot + m.fullRowsSize; m.height _ m.headerBot + m.headerSize + borderW; m.width _ m.arrayRight + borderW; }; Pop: PUBLIC PROC [menu: Menu, default: NAT _ 0, position: REF _ NIL, InNotifier: Consumer _ NIL, notifyData: REF ANY _ NIL] RETURNS [selection: INT _ 0, mouseButton: MouseButton _ red] = { IF InNotifier#NIL AND menu.timeOut IN (0..10000] THEN ERROR CallerBug--InNotifier can't be called from the TIP notifier in the case of a timeout--; Enter[]; {ENABLE UNWIND => {NotifyConsumer _ NIL; Leave[]}; reposd: BOOL _ FALSE; WithViewerLock: PROC [] = { saved: ATOM _ PrepareMenu[]; Imager.DoSave[context, PaintMenu]; HelpMessage[default]; CheatMousePos[]; SetUpTimeOutWatcher[gm.timeOut]; reposd _ Wait[]; RemoveMenu[saved]; }; gm _ menu; gDefault _ default; gMouse _ position; repositioned _ FALSE; NotifyConsumer _ InNotifier; notifyConsumerData _ notifyData; SELECT gSelection _ default FROM IN [1 .. menu.fullRows] => { gXOrg _ menu.width/2; gYOrg _ menu.headerBot - (gSelection-1)*menu.fullRowHeight - menu.fullRowHeight/2; }; IN (menu.fullRows .. menu.choices.length] => { gRow: NAT ~ (gSelection-menu.fullRows-1)/menu.cols; gCol: NAT ~ gSelection-menu.fullRows-1 - gRow * menu.cols; gXOrg _ menu.arrayLeft + gCol * menu.colWidth + menu.colWidth / 2; gYOrg _ menu.arrayTop - gRow * menu.rowHeight - menu.rowHeight/2; }; ENDCASE => { gXOrg _ menu.width/2; gYOrg _ menu.headerBot + menu.headerSize/2; }; gHelpMode _ TRUE; InputFocus.PushInputFocus[]; InputFocus.CaptureButtons[PopUpNotify, tipTable]; Cursors.SetCursor[menu]; DO ComputeMenuPosition[]; gHelpOn _ -1; IF debug THEN WithViewerLock[] ELSE IF mOnColor THEN ViewerLocks.CallUnderColumnLock[WithViewerLock, color] ELSE ViewerLocks.CallUnderViewerTreeLock[WithViewerLock]; IF ~reposd THEN EXIT; gMouse _ NIL; gSelection _ default; repositioned _ FALSE; ENDLOOP; InputFocus.ReleaseButtons[]; InputFocus.PopInputFocus[]; NotifyConsumer _ NIL; IF timedOut THEN selection _ -1 ELSE selection _ gSelection; mouseButton _ gMB; gMouse _ NIL; }; Leave[]; }; ComputeMenuPosition: PROC [] = INLINE { lastMouse _ MDP.ToScreenCoords[gMouse]; mOnColor _ lastMouse.color; }; PrepareMenu: PROC [] RETURNS [saved: ATOM] = INLINE { IF mOnColor THEN { sHeight _ ViewerSpecs.colorScreenHeight; sWidth _ ViewerSpecs.colorScreenWidth; context _ ViewerPrivate.CreateContext[color]; } ELSE { sHeight _ ViewerSpecs.bwScreenHeight; sWidth _ ViewerSpecs.bwScreenWidth; context _ ViewerPrivate.CreateContext[ViewerPrivate.Screen.FIRST]; }; ImagerBackdoor.ViewReset[context]; mx _ MIN[MAX[0, lastMouse.x - gXOrg], sWidth-gm.width]; my _ MIN[MAX[0, lastMouse.y - gYOrg], sHeight-gm.height]; ImagerBackdoor.SaveBufferRectangle[context, saved _ $Menu, [mx, my, gm.width, gm.height]]; context.SetFont[font]; }; RemoveMenu: PROC [saved: ATOM] = INLINE { IF helpSave#NIL THEN { Restore[helpSave]; helpSave _ NIL }; Restore[saved]; }; PaintMenu: PROC [] = { ll: INTEGER ~ mx; by: INTEGER ~ my; Imager.ClipRectangleI[context, ll, by, gm.width, gm.height]; Box[ll, by, gm.width, gm.height, bordThick]; IF gm.header # NIL THEN gm.header.Draw[gm.header, context, [ll + borderW, by + gm.headerBot, gm.width - 2*borderW, gm.headerSize], [FALSE, FALSE, FALSE]]; IF gm.left # NIL THEN gm.left.Draw[context, [ll + gm.arrayLeft, by + gm.arrayTop], gm.arrayRows, gm.rowHeight, gm.leftLabelSize, gm.left.data]; IF gm.top # NIL THEN gm.top.Draw[context, [ll + gm.arrayLeft, by + gm.arrayTop], gm.cols, gm.colWidth, gm.topLabelSize, gm.top.data]; FOR i: NAT IN [0 .. gm.choices.length) DO PaintEntry[ll, by, i, gSelection = i+1]; ENDLOOP; }; PaintEntry: PROC [ll, by: INTEGER, i: NAT, highlight: BOOL] = { image: Image = IF i < gm.choices.length THEN gm.choices[i].image ELSE NIL; IF image # NIL THEN SELECT i FROM < gm.fullRows => image.Draw[image, context, [ll + borderW, by + gm.headerBot - (i+1) * gm.fullRowHeight, gm.width-border2W, gm.fullRowHeight], [highlight, FALSE, FALSE]]; ENDCASE => { row: NAT ~ (i - gm.fullRows) / gm.cols; col: NAT ~ i - gm.fullRows - row*gm.cols; image.Draw[image, context, [ll + gm.arrayLeft + col * gm.colWidth, by + gm.arrayTop - (row+1) * gm.rowHeight, gm.colWidth, gm.rowHeight], [highlight, FALSE, FALSE]]; }; }; CheatMousePos: PROC [] = { IF MDP.maySetMouse THEN MDP.SetMouse[[x: mx + gXOrg, y: my + gYOrg, color: mOnColor]]; }; InitFontGlobals: UserProfile.ProfileChangedProc = { font _ VFonts.EstablishFont[ family: UserProfile.Token["PopUpSelection.FontFamily", "Helvetica"], size: UserProfile.Number["PopUpSelection.FontSize", 10], bold: UserProfile.Boolean["PopUpSelection.FontBold", FALSE], italic: UserProfile.Boolean["PopUpSelection.FontItalic", FALSE], defaultOnFailure: TRUE ]; }; Ceiling: PROC [r: REAL] RETURNS [i: INTEGER] = { d: INT = Real.Fix[r] + 1; i _ Real.Fix[r-d]+d}; Floor: PROC [r: REAL] RETURNS [i: INTEGER] = { d: INT = Real.Fix[r] - 1; i _ Real.Fix[r-d]+d}; TRUSTED {Process.InitializeCondition[@reCheck, Process.MsecToTicks[1000]]}; UserProfile.CallWhenProfileChanges[InitFontGlobals]; END. PopUpSelection2Impl.Mesa Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, November 9, 1983 12:14 pm Last Edited by: Christian Jacobi, August 26, 1986 10:31:27 am PDT Last Edited by: Pier, June 23, 1986 11:39:21 am PDT Last tweaked by Mike Spreitzer on October 9, 1990 2:36:23 pm PDT Mike Spreitzer February 12, 1987 5:36:04 pm PST --data of the basic monitor --data of the constructed monitor --unmonitored data --for scheduling interaction menu --Enter and Leave for scheduling module entrance -- saving and restoring screen contents --timeout nonsense --does not modify timeOutKey --never called with key=NIL --help and move --Cursors.GetCursorInfo[].hotX.. is already included in x, y by window package... --made sequential by viewer package -- the main stuff -- sets variables lastMouse and mOnColor --must be called with DoSave; changes state --sets the cursor such that it points into the default field, or header TRUSTED {Process.Detach[FORK DebugProcess[]]}; ΚΤ•NewlineDelimiter – "cedar" style˜codešœ™Kšœ Οmœ7™BKšœ6™6K™AK™3K™@K™/—K˜šΟk ˜ Kšœ žœžœ˜+Kšœ žœ˜+Kšœžœ ˜Kšœ˜KšœžœM˜aK˜ Kšœ žœ-˜>Kšœ žœA˜QKšœžœ7˜TKšœ ˜ Kšœ˜Kšœ˜Kšœ žœ<˜JKšœžœ˜Kšœžœžœ˜"Kšœ žœžœ˜Kšœžœ5˜CKšœ žœF˜XKšœžœ˜+Kšœžœ˜!Kšœ žœ0˜AKšœžœ˜,Kšœ žœF˜WK˜—šΟbœžœž˜"Kšžœα˜θKšžœ˜—K˜Kšžœžœžœ*˜8K˜Kšœžœžœ ˜Kšœ žœžœ&˜>K˜Kšœ žœžœ˜'Kšœžœ!˜7K˜Kšœžœžœ˜!Kšœžœ˜1K˜Kšœžœ,˜7K˜Kšœ™K˜Kšœ ž œ˜K˜Kšœžœžœ˜Kšœ žœžœ˜Kšœ žœ žœΟcD˜cKšœ žœ˜K˜Kšœžœžœ˜Kšœ žœ˜Kšœ žœžœ˜Kšœžœ <˜WK˜Kšœ!™!K˜Kšœžœ 6˜TKšœžœ ˜2Kšœžœ ˜/Kšœ žœžœ %˜?Kšœ žœ D˜bKšΟnœ žœ˜Kšœžœžœžœ˜"Kšœ žœ˜Kšœ žœ˜K˜Kšœ™K˜Kš‘ œžœžœ˜Kš‘œžœžœ˜K˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜!Kšœ žœ˜ K˜Kšœžœžœ˜K˜KšœS˜SKšœžœ˜K˜Kšœ!™!K˜Kšœžœ˜)K˜š‘œžœ# ]œ˜šKš‘œ ˜Kšœžœ˜ Kšœžœžœ˜Kšœ+˜+Kšžœ žœžœ˜-Kšžœ˜K˜—š‘œžœžœ#žœ‘œžœžœžœ˜nKšžœžœžœ˜Kš žœžœžœžœžœžœ˜=Kšžœžœžœžœžœžœžœ˜5Kšœ˜Kš œžœžœžœžœžœžœ˜]Kšžœžœ žœžœ˜AKšœžœ žœžœ ˜*K˜ K˜Kšž œ ˜Kšžœ˜—K˜š ‘œžœžœžœ žœ˜+Kšžœžœžœ˜Kš žœžœžœžœžœ˜.K˜Kšž œ ˜Kšžœžœžœ žœ˜/Kšžœžœ˜2Kšžœ˜K˜—K™Kšœ0™0K˜š‘œžœžœ˜Kšžœžœžœ˜Kšžœ žœžœ žœ˜)K˜Kšž œ ˜Kšžœ˜—K˜š‘œžœžœ˜Kšžœžœžœ˜Kš žœžœžœžœžœ˜/K˜ Kšž œ ˜Kšžœ˜—K˜K™Kšœ'™'K™š‘œžœžœ˜Kšœ)˜)Kšžœ žœ*˜9K˜Kšœ žœžœ˜—K™J™Jšœ™K˜š‘œžœžœžœ˜,Kšžœžœžœ˜Kšœ žœ˜Kš žœžœ žœžœ !˜Jšžœ˜Kšœ žœ žœ)˜GKšžœžœ*˜FK˜—Kšœ˜—K˜š ‘œžœžœžœ žœ˜>Kš ™Kš ™Kšžœžœžœ˜Kšœž œ˜Kšœ"˜"Kšžœ<žœžœ?˜‰Kš žœžœžœ5žœžœžœ˜všžœžœžœ˜,Kšœ˜Kšœ žœ˜Kšž œ ˜—Kšœ˜—K˜J™Jšœ™K˜Kšœ žœžœ˜K˜š‘œžœžœ˜+Kšœ'˜'Kšœ+˜+Kšœ'˜'Kšœ0˜0Kšœ9˜9Kšœ0˜0Kšœ9˜9Kšœ˜—K˜š‘ œžœžœ˜"šžœ žœ˜Kšœž œ˜Kšœ ˜ Kšžœ žœžœžœ˜9Kšœžœžœžœžœžœžœžœ ˜šžœžœ˜"Kšœ žœžœ žœ˜7Kšœ>˜>Kšœžœ žœ+  ˜QKšœžœ žœ4  ˜ZKšœžœ +˜EKšœžœžœžœ' )˜ešžœžœ˜Kšœ˜Kšžœžœžœ˜K˜—KšœN˜NKšœ˜Kšœ'˜'KšœK˜KK˜Kšœ˜K˜—K˜—K˜—K˜š ‘ œžœžœžœ žœ˜7Kšžœžœžœ˜Kšœžœ˜KšœQ™QKšžœžœžœ˜ šžœžœ˜Kšœžœ ˜Kšœžœ ˜šžœžœž˜šœžœ žœžœ&˜TKšœ/˜/K˜—šœžœ!žœžœ"˜QK˜$Kšœ$˜$Kšœ*˜*K˜—šžœ˜ Kšœ žœ˜Kšœ˜K˜——K˜—šžœžœ˜Kšœžœ˜Kšœžœ˜Kšžœžœ"žœ˜=K˜Kšžœžœ"žœ˜šžœ žœž˜Kšœ]˜]šœžœžœž˜K˜K˜K˜Kšœ$˜$Kšœ0˜0Kšœ&˜&Kšžœžœ˜—Kšžœžœ˜—Kšž˜—K˜—Kšœ˜—K˜Kšœ%žœžœ ˜>Kšžœ?˜DKšœ˜—K˜K™Kšœ žœ"žœ˜:K˜Kšœ žœN˜_KšœG˜GKšœF˜FK˜šœžœ žœ˜5Kšœžœ žœ˜EKšœžœ žœ˜CKšœ˜—K˜šœžœ žœ˜5Kšœžœ žœ˜DKšœžœ žœ˜DKšœ˜—K˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœ žœ˜K˜š‘ œžœžœžœžœžœžœ˜‹Kšžœžœžœ˜&Kšžœ žœžœ˜,Kšœ˜Kšœ?˜?Kšœ9˜9šœžœ˜)Kšœ˜Kšœ˜Kšœ˜K˜K˜KKšœ˜—šœžœ˜Kšœh˜hKš‘œ ˜Kšœ ˜ —K˜K˜—š‘œžœe  œ˜Kšœžœ ˜#Kšœžœ>˜HKšœžœ>˜HKšœ-˜-Kšœ^˜^Kšœ%˜%Kšœ&˜&Kšœ%˜%Kšœ$˜$Kšœ!˜!Kšœ"˜"šžœžœ˜Kšœ žœ,˜=Kšžœ žœžœ˜)K˜!K˜IK˜—K˜K˜—š‘œžœžœžœ˜BKšœžœ˜ Kš žœžœžœžœ žœ˜DKšœžœ˜ šžœžœžœ ž˜K˜8K˜Kšžœ˜—Kšžœžœžœžœ˜Kšžœ˜K˜—K™K˜š‘œžœž˜˜Kšœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜Kšœžœžœ˜Kšœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœžœ˜Kš‘ œ žœ˜Kšœ žœžœžœ˜—Kšžœžœ˜#˜Kš œ7žœžœžœžœžœ)˜KšœA˜AKšžœ˜——K˜š‘œžœžœžœžœžœ)žœžœžœžœ˜ΓKšœ žœ˜šœžœ˜K˜K˜K˜ Kšœ˜K˜ K˜ K˜Kšœ=˜=Kšœ˜K˜K˜—šžœžœžœž˜ šžœžœ˜!Kšœžœ4˜IKšœ žœ.˜=K˜—Kšžœ˜—Kšœ,˜,šžœžœžœž˜-šžœžœ˜!Kšœžœ0˜AKšœ žœ/˜?K˜—Kšžœ˜—šžœžœ˜Kšœ žœ˜-K˜Kšœ˜—šžœžœ˜Kšœžœ˜0K˜ Kšœ˜—šžœ žœžœ˜Kšœ&˜&Kšœ žœ$˜3K˜—Kšœ#˜#šžœ*žœ˜2šžœžœ˜Kšœ"žœ-˜SKšœ#˜#Kšœ˜—Kšœ+˜+K˜—Kšœ*˜*Kšœ(˜(Kšœ*˜*Kšœ˜Kšœ(˜(Kšœ,˜,Kšœ-˜-Kšœ0˜0Kšœ!˜!K˜—K˜š‘œžœžœžœžœžœ‘ œ žœžœžœžœžœ žœ)˜ΌKšžœ žœžœžœ žœžœ  Mœ˜“šœ˜Kšœžœžœžœ ˜2Kšœžœžœ˜š‘œžœ˜Kšœžœ˜Kšœ"˜"Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—K˜ Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜K˜ šžœž˜ šžœ˜Kšœ˜KšœR˜RK˜—šžœ,˜.Kšœžœ*˜3Kšœžœ1˜:K˜BKšœB˜BK˜—šžœ˜ Kšœ˜Kšœ+˜+Kšœ˜——Kšœ žœ˜K˜Kšœ1˜1Kšœ˜šž˜Kšœ˜Kšœ ˜ Kšžœžœ˜Kšžœ žœ7˜LKšžœ5˜9Kšžœ žœžœ˜Kšœ žœ˜ Kšœ˜Kšœžœ˜Kšžœ˜—K˜K˜Kšœžœ˜Kšžœ žœžœ˜