DIRECTORY Basics USING [bitsPerWord], BasicTime USING [Now, GMT, Period], Cursors, Imager, ImagerBackdoor, ImagerFont, ImagerTerminal, InputFocus, Interminal, PopUpMenu USING [], PrincOps USING [BBptr, BitAddress, BBTableSpace], PrincOpsUtils USING [AlignedBBTable, BITBLT], Real USING [RoundC], Rope USING [ROPE], RuntimeError, Terminal, TIPUser, UserProfile, VFonts, ViewerClasses, ViewerLocks, ViewerPrivate; PopUpMenuImpl: CEDAR MONITOR IMPORTS BasicTime, Cursors, Imager, ImagerBackdoor, ImagerFont, ImagerTerminal, InputFocus, Interminal, PrincOpsUtils, --Process,-- Real, RuntimeError, Terminal, TIPUser, UserProfile, VFonts, ViewerLocks, ViewerPrivate EXPORTS PopUpMenu = BEGIN localTipTable: Rope.ROPE = "PopUp.tip"; remoteTipTable: Rope.ROPE = "[Cedar]PopUpMenu>PopUp.tip"; mSaved: REF; -- pointer to save area bits mSaved2: REF; -- pointer to save area bits mHeight: INTEGER; -- menu height in mLines mWidthPixels: INTEGER; -- menu width in pixels mWidthWords: INTEGER; mWidthWords2: INTEGER; mContext: Imager.Context; -- menu context mX, mY: INTEGER; -- menu position lastMouse: Interminal.MousePosition; -- at start; remember between calls is only creaturecomfort mOnColor: BOOL; -- menu position; NOT current cursor position later lastRemoved: BasicTime.GMT _ BasicTime.Now[]; --for crazy heuristics allDone: CONDITION; reallyAllDone: BOOL _ TRUE; moduleFree: CONDITION; moduleOccupied: BOOL _ TRUE; --until initalized escaped: BOOL _ FALSE; blackBorderThick: INTEGER = 2; whiteBorderThick: INTEGER = 2; borderThick: INTEGER = blackBorderThick+whiteBorderThick; font: Imager.Font _ NIL; lineHeight: INTEGER; gSelection: CARDINAL _ 0; gTitleLines: CARDINAL; gLabel: Rope.ROPE; gChoice: LIST OF Rope.ROPE; gDefault: CARDINAL; gMouse: REF _ NIL; virtual: Terminal.Virtual _ Terminal.Current[]; frameBuffer: Terminal.FrameBuffer; frameBuffer2: Terminal.FrameBuffer; bitBlitTable: PrincOps.BBTableSpace; bitBlitTable2: PrincOps.BBTableSpace; blit: PrincOps.BBptr; blit2: PrincOps.BBptr; tipTable: TIPUser.TIPTable; BroadCast: ENTRY PROC [] = BEGIN reallyAllDone _ TRUE; BROADCAST allDone END; Wait: ENTRY PROC [] = BEGIN WHILE ~reallyAllDone DO WAIT allDone ENDLOOP; END; Enter: ENTRY PROC [] = BEGIN WHILE moduleOccupied DO WAIT moduleFree ENDLOOP; moduleOccupied _ TRUE END; Leave: ENTRY PROC [] = BEGIN moduleOccupied _ FALSE; BROADCAST moduleFree END; InitFontGlobals: UserProfile.ProfileChangedProc = BEGIN lineHeightX: INT _ MAX[-whiteBorderThick, MIN[20, UserProfile.Number[key: "PopUpMenu.LineHeightChange", default: 0]] ]; font _ VFonts.EstablishFont[ family: UserProfile.Token[key: "PopUpMenu.FontFamily", default: "Helvetica"], size: UserProfile.Number[key: "PopUpMenu.FontSize", default: 10], bold: UserProfile.Boolean[key: "PopUpMenu.FontBold", default: FALSE], italic: UserProfile.Boolean[key: "PopUpMenu.FontItalic", default: FALSE], defaultOnFailure: TRUE ]; lineHeight _ VFonts.FontHeight[font]+whiteBorderThick+lineHeightX; END; InitTipTable: PROC [] = BEGIN tryAgain: BOOL_FALSE; tipTable _ TIPUser.InstantiateNewTIPTable[localTipTable ! RuntimeError.UNCAUGHT => {tryAgain _ TRUE; CONTINUE} ]; IF tryAgain THEN tipTable _ TIPUser.InstantiateNewTIPTable[remoteTipTable]; END; BLTScreenToSaveArea: PROC [frameBuffer: Terminal.FrameBuffer, mWidthWords: INTEGER, mSaved: REF, blit: PrincOps.BBptr] = TRUSTED BEGIN screenPoint: PrincOps.BitAddress; screenPoint.word _ frameBuffer.base + (LONG[mY]*frameBuffer.wordsPerLine) + (LONG[mX]*frameBuffer.bitsPerPixel)/Basics.bitsPerWord; screenPoint.bit _ (mX*frameBuffer.bitsPerPixel) MOD Basics.bitsPerWord; blit.src _ screenPoint; blit.srcDesc.srcBpl _ frameBuffer.bitsPerPixel*frameBuffer.width; blit.dst _ [LOOPHOLE[mSaved],,0]; blit.dstBpl _ mWidthWords*Basics.bitsPerWord; blit.width_ mWidthPixels*frameBuffer.bitsPerPixel; blit.height _ mHeight; PrincOpsUtils.BITBLT[blit]; END; BLTSavedToScreen: PROC [frameBuffer: Terminal.FrameBuffer, mWidthWords: INTEGER, mSaved: REF, blit: PrincOps.BBptr] = TRUSTED BEGIN blit.dst _ blit.src; blit.dstBpl _ blit.srcDesc.srcBpl; blit.src _ [LOOPHOLE[mSaved],,0]; blit.srcDesc.srcBpl _ mWidthWords*Basics.bitsPerWord; PrincOpsUtils.BITBLT[blit]; END; SaveScreen: PROC [] = BEGIN BLTScreenToSaveArea[frameBuffer, mWidthWords, mSaved, blit]; IF frameBuffer2#NIL THEN BLTScreenToSaveArea[frameBuffer2, mWidthWords2, mSaved2, blit2]; END; RestoreScreen: PROC [] = BEGIN BLTSavedToScreen[frameBuffer, mWidthWords, mSaved, blit]; IF frameBuffer2#NIL THEN BLTSavedToScreen[frameBuffer2, mWidthWords2, mSaved2, blit2]; END; AllocateBitmap: PROC [w: CARDINAL] RETURNS [REF] = INLINE BEGIN Words: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL]; RETURN[NEW[Words[w]]]; END; PopUpNotify: ViewerClasses.NotifyProc = BEGIN DoIt: PROC [input: LIST OF REF ANY] = BEGIN IF reallyAllDone THEN BroadCast[] ELSE { FOR list: LIST OF REF ANY _ input, list.rest WHILE list#NIL DO WITH input.first SELECT FROM coords: TIPUser.TIPScreenCoords => MoveCursor[coords^.mouseX, frameBuffer.height-coords^.mouseY, coords^.color]; atom: ATOM => IF atom=$Done THEN BroadCast[] ELSE IF atom=$Escaped THEN { escaped _ TRUE; BroadCast[]; }; ENDCASE => NULL; ENDLOOP }; END; DoIt[input ! RuntimeError.UNCAUGHT => GOTO failed]; EXITS failed => BroadCast[]; END; PrepareMenu: PROC [] = BEGIN ComputedSize: PROC [label: Rope.ROPE, gChoice: LIST OF Rope.ROPE] RETURNS [lines: CARDINAL_0, width: CARDINAL_0] = INLINE BEGIN IF label#NIL THEN { lines _ 1; width _ Real.RoundC[ImagerFont.RopeWidth[font, label].x]; }; gTitleLines _ lines; FOR l: LIST OF Rope.ROPE _ gChoice, l.rest WHILE l#NIL DO lines _ lines+1; width _ MAX[width, Real.RoundC[ImagerFont.RopeWidth[font, l.first].x]]; ENDLOOP END; -- ComputedSize SetUpBW: PROC [] = BEGIN mOnColor _ FALSE; frameBuffer _ Terminal.GetBWFrameBuffer[virtual]; frameBuffer2 _ NIL; mContext _ ImagerTerminal.BWContext[vt: virtual, pixelUnits: TRUE]; END; -- SetUpBW SetUpColor: PROC [] = INLINE BEGIN m: Terminal.ColorMode = Terminal.GetColorMode[virtual]; IF m.full THEN { frameBuffer _ Terminal.GetColorFrameBufferA[virtual]; frameBuffer2 _ Terminal.GetColorFrameBufferB[virtual]; mContext _ ViewerPrivate.CreateContext[color]; } ELSE IF m.bitsPerPixelChannelA#0 THEN { frameBuffer _ Terminal.GetColorFrameBufferA[virtual]; frameBuffer2 _ NIL; mContext _ ViewerPrivate.CreateContext[color]; } ELSE SetUpBW[]; --ERROR, but what do else? IF frameBuffer=NIL THEN SetUpBW[]; END; -- SetUpColor mLines: CARDINAL; -- textlines of menu including header [lines: mLines, width: mWidthPixels] _ ComputedSize[gLabel, gChoice]; mWidthPixels _ mWidthPixels + 2*borderThick; mHeight _ mLines*lineHeight + 2*borderThick; IF mOnColor THEN SetUpColor[] ELSE SetUpBW[]; mWidthWords _ (mWidthPixels*frameBuffer.bitsPerPixel+Basics.bitsPerWord-1)/Basics.bitsPerWord; mSaved _ AllocateBitmap[mWidthWords*mHeight]; IF frameBuffer2#NIL THEN { mWidthWords2 _ (mWidthPixels*frameBuffer2.bitsPerPixel+Basics.bitsPerWord-1)/Basics.bitsPerWord; mSaved2 _ AllocateBitmap[mWidthWords2*mHeight]; }; mX _ MIN[MAX[0, lastMouse.mouseX], frameBuffer.width-mWidthPixels]; mY _ MIN[MAX[0, lastMouse.mouseY], frameBuffer.height-mHeight]; END; -- PrepareMenu RequestSelection: PUBLIC PROC [ label: Rope.ROPE _ NIL, choice: LIST OF Rope.ROPE, default: NAT _ 0, mouse: REF _ NIL] RETURNS [NAT] = BEGIN ENABLE UNWIND => Leave[]; selection: NAT; PrepareRequestSelection: PROC [] = BEGIN Cursors.SetCursor[menu]; IF gMouse=NIL THEN { IF BasicTime.Period[from: lastRemoved, to: BasicTime.Now[]]>0 THEN lastMouse _ Interminal.GetMousePosition[]; } ELSE WITH gMouse SELECT FROM m: TIPUser.TIPScreenCoords => { frameBuffer: Terminal.FrameBuffer _ IF m.color THEN Terminal.GetColorFrameBufferA[virtual] ELSE Terminal.GetBWFrameBuffer[virtual]; lastMouse _ [mouseX: m.mouseX, mouseY: frameBuffer.height-m.mouseY, color: m.color]; }; m: REF Interminal.MousePosition => lastMouse _ m^; ENDCASE => lastMouse _ Interminal.GetMousePosition[]; mOnColor _ lastMouse.color; PrepareMenu[]; END; LockedRequestSelection: PROC [] = BEGIN escaped _ FALSE; SetUpScreen[]; CheatDefaultMousePos[]; reallyAllDone _ FALSE; Wait[]; RemoveMenu[]; lastRemoved _ BasicTime.Now[]; END; Enter[]; virtual _ Terminal.Current[]; InputFocus.PushInputFocus[]; InputFocus.CaptureButtons[PopUpNotify, tipTable]; gDefault _ default; gLabel _ label; gChoice _ choice; gMouse _ mouse; gSelection _ 0; DO PrepareRequestSelection[]; IF mOnColor THEN ViewerLocks.CallUnderColumnLock[LockedRequestSelection, color] ELSE ViewerLocks.CallUnderViewerTreeLock[LockedRequestSelection]; IF ~escaped THEN EXIT; gMouse _ $Escaped ENDLOOP; InputFocus.ReleaseButtons[]; InputFocus.PopInputFocus[]; selection _ gSelection; gMouse _ NIL; --just once! Leave[]; RETURN [selection] END; --RequestSelection SetUpScreen: PROC [] = BEGIN PaintMenu: PROC [] = INLINE BEGIN titelAddHight: CARDINAL = 3; baseLine: CARDINAL = 4; cH: CARDINAL _ mHeight-borderThick+baseLine; mContext.ClipRectangleI[mX, frameBuffer.height-mY-mHeight, mX+mWidthPixels, frameBuffer.height-mY]; mContext.TranslateT[[mX, frameBuffer.height-mY-mHeight]]; mContext.SetColor[Imager.white]; mContext.MaskBox[[0, 0, mWidthPixels, mHeight]]; mContext.SetColor[Imager.black]; mContext.MaskBox[[0, 0, mWidthPixels, blackBorderThick]]; mContext.MaskBox[[0, 0, blackBorderThick, mHeight]]; mContext.MaskBox[[0, mHeight-blackBorderThick, mWidthPixels, mHeight]]; mContext.MaskBox[[mWidthPixels-blackBorderThick, 0, mWidthPixels, mHeight]]; mContext.SetFont[font]; IF gLabel#NIL THEN { cH _ cH-lineHeight; mContext.SetXYI[borderThick, cH+titelAddHight]; mContext.ShowRope[rope: gLabel]; }; mContext.SetFont[font]; FOR l: LIST OF Rope.ROPE _ gChoice, l.rest WHILE l#NIL DO cH _ cH-lineHeight; mContext.SetXYI[borderThick, cH]; mContext.ShowRope[rope: l.first]; ENDLOOP; mContext.SetColor[ImagerBackdoor.invert]; IF gTitleLines=1 THEN mContext.MaskBox[ [blackBorderThick, mHeight-borderThick-lineHeight+1, mWidthPixels-blackBorderThick, mHeight-blackBorderThick] ] END; -- PaintMenu PrepareMenu[]; IF mOnColor THEN Terminal.ModifyColorFrame[virtual, SaveScreen] ELSE SaveScreen[]; PaintMenu[]; END; -- SetUpScreen RemoveMenu: PROC [] = INLINE BEGIN IF mOnColor THEN Terminal.ModifyColorFrame[virtual , RestoreScreen] ELSE RestoreScreen[]; mSaved _ mSaved2 _ NIL; frameBuffer _ frameBuffer2 _ NIL; END; -- RemoveMenu CheatDefaultMousePos: PROC [] = TRUSTED INLINE BEGIN m: Interminal.MousePosition; m _ Interminal.GetMousePosition[]; -- includes color bit IF gDefault#0 THEN { m.mouseX _ mX+mWidthPixels/2; m.mouseY _ ((gDefault-(1-gTitleLines))*lineHeight+mY+lineHeight/2); Interminal.SetMousePosition[m]; }; MoveCursor[m.mouseX, m.mouseY, m.color]; END; MoveCursor: PROC [x, y: INTEGER, col: BOOL] = BEGIN InvertPictureLine: PROC [pos: CARDINAL] = INLINE BEGIN cH: CARDINAL = mHeight-borderThick-lineHeight*pos; Imager.MaskBox[mContext, [borderThick, cH, mWidthPixels-borderThick, cH+lineHeight]]; END; sel: CARDINAL; IF col#mOnColor THEN sel _ 0 ELSE IF x<=(mX+blackBorderThick) OR x>=(mX+mWidthPixels-blackBorderThick) THEN sel _ 0 ELSE IF y<=(mY+borderThick) OR (y>=mY+mHeight-borderThick) THEN sel_0 ELSE sel _ (1-gTitleLines)+(y-borderThick-mY)/lineHeight; IF gSelection#sel THEN { IF gSelection#0 THEN InvertPictureLine[gSelection+gTitleLines]; gSelection _ sel; IF gSelection#0 THEN InvertPictureLine[gSelection+gTitleLines]; }; END; -- MoveCursor --module initialization TRUSTED { blit _ PrincOpsUtils.AlignedBBTable[@bitBlitTable]; blit.flags.disjoint _ TRUE; blit.flags.disjointItems _ TRUE; blit2 _ PrincOpsUtils.AlignedBBTable[@bitBlitTable2]; blit2.flags.disjoint _ TRUE; blit2.flags.disjointItems _ TRUE; }; UserProfile.CallWhenProfileChanges[InitFontGlobals]; InitTipTable[]; Leave[]; --initializes monitor locks END. "PopUpMenuImpl.mesa Copyright c 1983, 1985 by Xerox Corporation. All rights reserved. by Christian Jacobi, November 9, 1983 12:14 pm Last Edited by: Christian Jacobi, July 23, 1985 2:06:05 pm PDT --Process, --global variables are protected with MONITOR Enter and Leave --initialized to mouse.color, but might be different --EmergencyProcess for debugging purposes, if you think the notify proc hangs EmergencyProcess: PROC = BEGIN virtual: Terminal.Virtual _ Terminal.Current[]; DO -- forever Process.Pause[Process.SecondsToTicks[1]]; IF Terminal.GetKeys[virtual][ESC]=down THEN BroadCast[]; ENDLOOP; END; --BroadCast and Wait for scheduling interaction menu --Enter and Leave for scheduling module entrance --the hell, if font and lineHeight are not changed atomic... --do not catch errors again; land in debugger --globals mY, mX, mHeight, mWidthPixels --made sequential by viewer package --computes lines and width (in pixels) of menu and save area mContext _ ImagerTerminal.ColorContext[vt: virtual, pixelUnits: TRUE]; mContext _ ImagerTerminal.ColorContext[vt: virtual, pixelUnits: TRUE]; --PrepareMenu -- Only use real cursor coordinates if interval since last pupup menu is big enough -- Reuse same position if immediately following, and is different menu; -- Some few cases change position even if not clear, to make it possible -- to visualize area below pop up menu. --default: use mouseposition or last position according of time --else reuse last mouse position --RequestSelection --SetUpScreen --sets the cursor such that it points into the default field --use Interminal to do this: uses current intead of buffered mouseposition --MoveCursor --Cursors.GetCursorInfo[].hotX.. is already included in x, y by window package... --For debugging: TRUSTED {Process.Detach[FORK EmergencyProcess[]]}; Ê¿˜šœ™Jšœ Ïmœ7™BJšœ.™.Jšœ>™>—J˜šÏk ˜ Jšœžœ˜Jšœ žœžœ ˜#J˜J˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ ˜ J˜ Jšœ žœ˜Jšœ žœ#˜1Jšœžœžœ˜-Jšœ ™ Jšœžœ ˜Jšœžœžœ˜J˜ J˜ J˜J˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜J˜—šÏb œžœž˜šžœ˜JšœÒ˜Ò—Jšžœ ˜—Jšžœ˜J˜Jšœžœ˜'Jšœžœ/˜HJ˜Jšœ=™=J˜JšœžœÏc˜*Jšœ žœ ˜+Jšœ žœ ˜*Jšœžœ ˜.Jšœ žœ˜Jšœžœ˜Jšœ ˜*Jšœžœ ˜!Jšœ& ;˜ašœ žœ 4˜EJšœ;™;—Jšœžœ ˜DJ˜Jšœ ž œ˜Jšœž œ˜Jšœ ž œ˜Jšœžœžœ ˜/Jšœ žœžœ˜J˜Jšœžœ˜Jšœžœ˜Jšœ žœ%˜9Jšœžœ˜Jšœ žœ˜J˜Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜Jšœ žœžœžœ˜Jšœ žœ˜Jšœžœžœ˜J˜Jšœ/˜/Jšœ"˜"Jšœ#˜#J˜Jšœ%˜%Jšœ%˜%Jšœ˜Jšœ˜J˜Jšœ˜J˜Jš M™MšÏnœžœ™Jšž™Jšœ/™/šžœ  ™ Jšœ)™)Jšžœžœžœ ™8Jšžœ™—Jšžœ™J™—Jšœ4™4J˜š¡ œžœžœ˜Jšž˜Jšœžœ˜Jšž œ˜Jšžœ˜—J˜š¡œžœžœ˜Jšž˜šžœž˜Jšžœ˜ Jšžœ˜—Jšžœ˜J˜—Jšœ0™0J˜š¡œžœžœ˜Jšž˜šžœž˜Jšžœ ˜Jšžœ˜—Jšœž˜Jšžœ˜—J˜š¡œžœžœ˜Jšž˜Jšœžœ˜Jšž œ ˜Jšžœ˜—J˜šŸœ"˜1Jšžœ˜šœ žœžœžœ˜2JšœB˜BJšœ˜—šœ˜JšœN˜NJšœB˜BJšœ>žœ˜EJšœBžœ˜IJšœž˜Jšœ˜—JšœB˜BJšœ=™=Jšžœ˜—J˜š¡ œžœ˜Jšž˜Jšœ žœžœ˜šœ:˜:Jšœ žœžœžœ˜4Jšœ˜—Jšžœ žœ;˜KJšœ-™-Jšžœ˜J˜—š¡œžœ2žœ žœ˜yJšœ'™'Jšžœž˜ Jšœ!˜!šœ&˜&Jšœžœ ˜%Jšœžœ3˜8—Jšœ0žœ˜GJ˜JšœA˜AJšœ žœ ˜!Jšœ-˜-Jšœ2˜2J˜Jšœžœ˜Jšžœ˜—J˜š¡œžœ2žœ žœ˜vJšžœž˜ Jšœ˜Jšœ"˜"Jšœ žœ ˜!Jšœ5˜5Jšœžœ˜Jšžœ˜—J˜š¡ œžœ˜Jšž˜Jšœ<˜<šžœžœž˜Jšœ@˜@—Jšžœ˜—J˜š¡ œžœ˜Jšž˜Jšœ9˜9šžœžœž˜Jšœ=˜=—Jšžœ˜—J˜š ¡œžœžœžœžœ˜3Jšžœž˜ Jšœžœžœžœžœžœžœžœ˜=Jšžœžœ ˜Jšžœ˜J˜—šŸ œ˜(Jšœ#™#Jšž˜J˜š ¡œžœ žœžœžœžœ˜%Jšž˜Jšžœžœ ˜"šžœ˜šžœžœžœžœžœžœžœž˜>šžœ žœž˜šœ#˜#JšœM˜M—šœžœ˜Jšžœ žœ ˜šžœžœžœ˜Jšœ žœ˜Jšœ ˜ Jšœ˜——Jšžœžœ˜—Jšž˜—J˜—Jšž˜—J˜Jšœžœžœ ˜3Jšžœ˜Jšžœ˜—J˜š¡ œžœ˜Jšž˜J˜š ¡ œžœžœ žœžœžœ˜BJšžœ žœ žœ˜1Jšœ<™F