DIRECTORY Basics USING [bitsPerWord], BasicTime USING [Now, GMT, Period], ColorWorld, Cursors, Graphics, InputFocus, Interminal, Keys, PopUpMenu USING [], PrincOps USING [BBptr, BitAddress, BBTableSpace], PrincOpsUtils USING [AlignedBBTable, BITBLT], Process, Real USING [FixC], Rope USING [ROPE, Equal], RuntimeError, Terminal, TerminalExtras, TIPUser, UserProfile, VFonts, ViewerClasses, ViewerLocks, ViewerSpecs USING [screenH, screenW]; PopUpMenuImpl: CEDAR MONITOR IMPORTS BasicTime, ColorWorld, Cursors, Graphics, InputFocus, Interminal, PrincOpsUtils, Process, Real, Rope, RuntimeError, Terminal, TerminalExtras, TIPUser, UserProfile, VFonts, ViewerLocks EXPORTS PopUpMenu = BEGIN localTipTable: Rope.ROPE = "PopUp.tip"; remoteTipTable: Rope.ROPE = "/Indigo/Chipndale/5.2/PopUpMenu/PopUp.tip"; RopeList: TYPE = LIST OF Rope.ROPE; mSaved: REF; -- pointer to save area bits mHeight: INTEGER; -- menu height in mLines mWidthPixels: INTEGER; -- menu width in pixels mWidthBits: INTEGER; -- menu width in bits mContext: Graphics.Context; -- menu context mX, mY: INTEGER; -- menu position mOnColor: BOOLEAN; -- menu position; not current cursor position later mouse: Terminal.Position; -- remember between calls is only creaturecomfort lastRemoved: BasicTime.GMT _ BasicTime.Now[]; font: Graphics.FontRef _ NIL; fontHeight: INTEGER; -- in mLines lineHeight: INTEGER; blackBorderThick: INTEGER = 2; whiteBorderThick: INTEGER = 2; borderThick: INTEGER = blackBorderThick+whiteBorderThick; gSelection: CARDINAL _ 0; titleLines: CARDINAL; gLabel: Rope.ROPE; choiceList: RopeList; gDefault: CARDINAL; screen: PrincOps.BitAddress; virtual: Terminal.Virtual; bitsPerPixel: CARDINAL; scWidthPixels: CARDINAL; -- Screen width in pixels scWidthBits: CARDINAL; -- Screen width in bits scWidthWords: CARDINAL; scHeight: CARDINAL; -- Screen height in pixels screenPoint: PrincOps.BitAddress; saveTable, restoreTable: PrincOps.BBTableSpace; saveBLT, restoreBLT: PrincOps.BBptr; myTipTable: TIPUser.TIPTable; PopUpNotify: ViewerClasses.NotifyProc = {}; -- NOP InitFontGlobals: ENTRY UserProfile.ProfileChangedProc --PROC [reason: ProfileChangeReason]-- = BEGIN ENABLE UNWIND => NULL; ymin, ymax: REAL; vFont: VFonts.Font; lineHeightX: INT; lineHeightX _ MAX[-whiteBorderThick, MIN[20, UserProfile.Number[key: "PopUpMenu.LineHeightChange", default: 0]] ]; vFont_ 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 ]; font _ VFonts.GraphicsFont[vFont]; [ymin: ymin, ymax: ymax] _ Graphics.FontBox[font]; fontHeight _ Real.FixC[ymax-ymin+0.1]; --Round lineHeight _ fontHeight+whiteBorderThick+lineHeightX; END; InitTipTable: PROC [] = BEGIN tryAgain: BOOL_FALSE; myTipTable _ TIPUser.InstantiateNewTIPTable[localTipTable ! RuntimeError.UNCAUGHT => {tryAgain_TRUE; CONTINUE} ]; IF tryAgain THEN myTipTable _ TIPUser.InstantiateNewTIPTable[remoteTipTable]; END; HideCursor: PROC [] = INLINE BEGIN IF mOnColor THEN TerminalExtras.LockColorFrame[virtual]; END; RestoreCursor: PROC [] = INLINE BEGIN IF mOnColor THEN TerminalExtras.UnlockColorFrame[virtual] END; RequestSelection: PUBLIC PROC [ label: Rope.ROPE _ NIL, choice: LIST OF Rope.ROPE, default: CARDINAL _ 0] RETURNS [CARDINAL] = BEGIN ENABLE UNWIND => NULL; selection: CARDINAL; escaped: BOOL _ FALSE; LockedRequestSelection: ENTRY PROCEDURE = BEGIN Wait: INTERNAL PROC RETURNS [escaped: BOOL_FALSE] = BEGIN WHILE keys[Red]=down OR keys[Blue]=down OR keys[Yellow]=down DO Process.Yield[]; keys _ Terminal.GetKeys[virtual]; IF keys[ESC]=down THEN RETURN [TRUE]; MoveCursor[]; ENDLOOP; UNTIL keys[Red]=down OR keys[Blue]=down OR keys[Yellow]=down DO Process.Yield[]; keys _ Terminal.GetKeys[virtual]; IF keys[ESC]=down THEN RETURN [TRUE]; MoveCursor[]; ENDLOOP; WHILE keys[Red]=down OR keys[Blue]=down OR keys[Yellow]=down DO Process.Yield[]; keys _ Terminal.GetKeys[virtual]; IF keys[ESC]=down THEN RETURN [TRUE]; MoveCursor[]; ENDLOOP; END; keys: Keys.KeyBits; virtual _ Terminal.Current[]; Cursors.SetCursor[menu]; IF BasicTime.Period[from: lastRemoved, to: BasicTime.Now[]]>0 OR Rope.Equal[gLabel, label] THEN { mouse _ Terminal.GetBWCursorPosition[virtual]; IF mOnColor _ (mouse = [-100, -100]) THEN mouse _ Terminal.GetColorCursorPosition[virtual]; }; gDefault _ default; gLabel _ label; choiceList _ choice; keys _ Terminal.GetKeys[virtual]; SetUpScreen[]; SetDefaultPosition[]; escaped _ Wait[]; RestoreScreen[]; selection _ gSelection; lastRemoved _ BasicTime.Now[]; END; --of LockedRequestSelection InputFocus.CaptureButtons[PopUpNotify, myTipTable]; InputFocus.PushInputFocus[]; DO ViewerLocks.CallUnderViewerTreeLock[LockedRequestSelection]; IF ~escaped THEN EXIT ENDLOOP; InputFocus.PopInputFocus[]; InputFocus.ReleaseButtons[]; RETURN [selection] END; --of RequestSelection SetUpScreen: INTERNAL PROC [] = BEGIN PrepareMenu: INTERNAL PROC [] = BEGIN AllocateBitmap: INTERNAL PROC [nWords: CARDINAL] RETURNS [REF] = INLINE BEGIN Words: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL]; RETURN[NEW[Words[nWords]]]; END; ComputedSize: INTERNAL PROC[label: Rope.ROPE, choiceList: RopeList] RETURNS [lines: CARDINAL_0, width: CARDINAL_0] = INLINE BEGIN IF label#NIL THEN { lines_1; width _ Real.FixC[Graphics.RopeWidth[font, label].xw+0.1]; }; titleLines _ lines; FOR l: RopeList _ choiceList, l.rest WHILE l#NIL DO lines_lines+1; width _ MAX[width, Real.FixC[Graphics.RopeWidth[font, l.first].xw+0.1]]; ENDLOOP END; -- of ComputedSize SetUpBW: INTERNAL PROC[] = BEGIN mOnColor _ FALSE; TRUSTED{screen _ Terminal.GetBitBltTable[virtual].bbt.dst}; bitsPerPixel _ 1; scWidthPixels _ ViewerSpecs.screenW; scHeight _ ViewerSpecs.screenH; mContext _ Graphics.NewContext[NIL]; END; -- of SetUpBW SetUpColor: INTERNAL PROC[] = INLINE BEGIN m: Terminal.ColorMode = Terminal.GetColorMode[virtual]; IF m.full THEN { SetUpBW[] } ELSE IF m.bitsPerPixelChannelA#0 THEN { scWidthPixels _ virtual.colorWidth; scHeight _ virtual.colorHeight; mContext _ ColorWorld.NewContext[]; bitsPerPixel_m.bitsPerPixelChannelA; screen.word _ virtual.colorBitmapA; screen.reserved _ 0; screen.bit _ 0; } ELSE --ERROR, but what do else? -- SetUpBW[]; END; -- of SetUpColor mLines: CARDINAL; -- textlines of menu including header mWidthWords: CARDINAL; -- menu words per line [lines: mLines, width: mWidthPixels] _ ComputedSize[gLabel, choiceList]; mWidthPixels _ mWidthPixels + 2*borderThick; mHeight _ mLines*lineHeight + 2*borderThick; IF mOnColor THEN SetUpColor[] ELSE SetUpBW[]; scWidthBits _ scWidthPixels*bitsPerPixel; scWidthWords _ (scWidthBits+Basics.bitsPerWord-1)/Basics.bitsPerWord; mWidthBits _ mWidthPixels*bitsPerPixel; mWidthWords _ (mWidthBits+Basics.bitsPerWord-1)/Basics.bitsPerWord; mSaved _ AllocateBitmap[mWidthWords*mHeight]; TRUSTED { restoreBLT.dstBpl _ saveBLT.srcDesc.srcBpl _ scWidthBits; saveBLT.dst _ [LOOPHOLE[mSaved],,0]; saveBLT.dstBpl _ mWidthWords*Basics.bitsPerWord; saveBLT.width_ restoreBLT.width _ mWidthBits; saveBLT.height _ restoreBLT.height _ mHeight; restoreBLT.src _ [LOOPHOLE[mSaved],,0]; restoreBLT.srcDesc.srcBpl _ mWidthWords*Basics.bitsPerWord; }; END; -- of PrepareMenu PaintMenu: INTERNAL PROC[] = BEGIN titelAddHight: CARDINAL = 3; baseLine: CARDINAL = 4; cH: CARDINAL _ mHeight-borderThick+baseLine; mContext.ClipBox[[mX, scHeight-mY-mHeight, mX+mWidthPixels, scHeight-mY]]; mContext.Translate[mX, scHeight-mY-mHeight]; mContext.SetColor[Graphics.white]; mContext.DrawBox[[0, 0, mWidthPixels, mHeight]]; mContext.SetColor[Graphics.black]; mContext.DrawBox[[0, 0, mWidthPixels, blackBorderThick]]; mContext.DrawBox[[0, 0, blackBorderThick, mHeight]]; mContext.DrawBox[[0, mHeight-blackBorderThick, mWidthPixels, mHeight]]; mContext.DrawBox[[mWidthPixels-blackBorderThick, 0, mWidthPixels, mHeight]]; IF gLabel#NIL THEN { cH_cH-lineHeight; mContext.SetCP[borderThick, cH+titelAddHight]; mContext.DrawRope[rope: gLabel, font: font]; }; FOR l: RopeList _ choiceList, l.rest WHILE l#NIL DO cH _ cH-lineHeight; mContext.SetCP[borderThick, cH]; mContext.DrawRope[rope: l.first, font: font]; ENDLOOP; [] _ mContext.SetPaintMode[invert]; IF titleLines=1 THEN mContext.DrawBox[ [blackBorderThick, mHeight-borderThick-lineHeight+1, mWidthPixels-blackBorderThick, mHeight-blackBorderThick] ] END; -- of PaintMenu ComputeScreenPoint: INTERNAL PROC = TRUSTED INLINE BEGIN screenPoint.word _ screen.word + (LONG[mY]*scWidthWords) + ((LONG[mX]*bitsPerPixel)/Basics.bitsPerWord); screenPoint.bit _ (mX*bitsPerPixel) MOD Basics.bitsPerWord; END; BLTScreenToSaveArea: INTERNAL PROC = TRUSTED INLINE BEGIN saveBLT.src _ screenPoint; PrincOpsUtils.BITBLT[saveBLT]; END; gSelection _ 0; PrepareMenu[]; mX _ MIN[MAX[0, mouse.x], scWidthPixels-mWidthPixels]; mY _ MIN[MAX[0, mouse.y], scHeight-mHeight]; ComputeScreenPoint[]; HideCursor[]; BLTScreenToSaveArea[]; PaintMenu[]; RestoreCursor[]; END; -- of SetUpScreen RestoreScreen: INTERNAL PROC = BEGIN BLTSavedToScreen: INTERNAL PROC = TRUSTED INLINE BEGIN restoreBLT.dst _ screenPoint; PrincOpsUtils.BITBLT[restoreBLT]; END; HideCursor[]; BLTSavedToScreen[]; RestoreCursor[]; mSaved _ NIL; END; -- of RestoreScreen SetDefaultPosition: INTERNAL PROC [] = TRUSTED INLINE BEGIN m: Interminal.MousePosition; IF gDefault=0 THEN RETURN; m _ Interminal.GetMousePosition[]; -- reads color m.mouseX _ mX+mWidthPixels/2; m.mouseY _ ((gDefault-(1-titleLines))*lineHeight+mY+lineHeight/2); Interminal.SetMousePosition[m]; END; MoveCursor: INTERNAL PROC [] = INLINE BEGIN InvertPictureLine: INTERNAL PROC [pos: CARDINAL] = BEGIN cH: CARDINAL = mHeight-borderThick-lineHeight*pos; Graphics.DrawBox[mContext, [borderThick, cH, mWidthPixels-borderThick, cH+lineHeight]]; END; sel: CARDINAL; cursorOnColorScreen: BOOL; cursorInfo: Cursors.CursorInfo _ Cursors.GetCursorInfo[]; lMouse: Terminal.Position _ Terminal.GetBWCursorPosition[virtual]; IF cursorOnColorScreen _ (lMouse = [-100, -100]) THEN lMouse _ Terminal.GetColorCursorPosition[virtual]; lMouse.x _ lMouse.x-cursorInfo.hotX; lMouse.y _ lMouse.y-cursorInfo.hotY; IF cursorOnColorScreen # mOnColor THEN sel _ 0 ELSE IF lMouse.x<=(mX+blackBorderThick) OR lMouse.x>=(mX+mWidthPixels-blackBorderThick) THEN sel _ 0 ELSE IF lMouse.y<=(mY+borderThick) OR (lMouse.y>=mY+mHeight-borderThick) THEN sel_0 ELSE sel _ (1-titleLines)+(lMouse.y-borderThick-mY)/lineHeight; IF gSelection#sel THEN { IF gSelection#0 THEN InvertPictureLine[gSelection+titleLines]; gSelection _ sel; IF gSelection#0 THEN InvertPictureLine[gSelection+titleLines]; }; END; -- of MoveCursor TRUSTED { saveBLT _ PrincOpsUtils.AlignedBBTable[@saveTable]; restoreBLT _ PrincOpsUtils.AlignedBBTable[@restoreTable]; saveBLT.flags.disjoint _ TRUE; saveBLT.flags.disjointItems _ TRUE; restoreBLT.flags.disjoint _ TRUE; restoreBLT.flags.disjointItems _ TRUE; }; UserProfile.CallWhenProfileChanges[InitFontGlobals]; InitTipTable[]; END. ÈPopUpMenuImpl.mesa Copyright c 1983, 1984 by Xerox Corporation. All rights reserved. by Christian Jacobi, November 9, 1983 12:14 pm Last Edited by: Christian Jacobi, January 2, 1985 2:01:13 pm PST works on black and white, 4bit and 8bit color mode. --global variables are protected with MONITOR --do not catch errors again; land in debugger --entry because global variables used -- 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. --RequestSelection --computes lines and width (in pixels) of menu and save area --sorry we do not know what to do --PrepareMenu --SetUpScreen --RestoreScreen --sets the cursor such that it points into the default field --use Interminal to do this: uses current intead of buffered mouseposition --MoveCursor ʘJšœ™™Jšœ Ïmœ7™BJšœ.™.Jšœ@™@—˜Jšœ3™3—J˜šÏk ˜ Jšœžœ˜Jšœ žœžœ ˜#J˜ J˜J˜ J˜ J˜ Jšœ˜Jšœ žœ˜Jšœ žœ#˜1Jšœžœžœ˜-Jšœ˜Jšœžœ˜Jšœžœžœ ˜J˜ J˜ Jšœ˜J˜J˜ Jšœ˜Jšœ˜J˜ Jšœ žœ˜%J˜—šÏb œžœž˜šžœ˜Jšœ·˜·—Jšžœ ˜—Jšžœ˜J˜Jšœžœ˜'Jšœžœ/˜HJ˜Jš œ žœžœžœžœ˜#J˜J™Jšœ-™-J˜JšœžœÏc˜*Jšœ žœ ˜*Jšœžœ ˜.Jšœ žœ ˜*Jšœ ˜,Jšœžœ ˜!Jšœ žœ 4˜HJšœ 1˜LJšœžœ˜-J˜Jšœžœ˜Jšœ žœ  ˜!Jšœ žœ˜J˜Jšœžœ˜Jšœžœ˜Jšœ žœ%˜9J˜Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜J˜Jšœ žœ˜J˜Jšœ˜J˜Jšœžœ˜Jšœžœ ˜3Jšœ žœ ˜.Jšœžœ˜Jšœ žœ ˜.Jšœ!˜!J˜Jšœ/˜/Jšœ$˜$J˜J˜J˜JšŸ œ! ˜2J˜šŸœžœ ˜6Jš &œ˜)šžœ˜Jšžœžœžœ˜—Jšœ žœ˜Jšœ˜Jšœ žœ˜šœžœžœ˜-JšœB˜BJšœ˜—šœ˜JšœN˜NJšœB˜BJšœ>žœ˜EJšœBžœ˜IJšœž˜Jšœ˜—Jšœ#˜#J˜2Jšœ' ˜.Jšœ5˜5Jšžœ˜—J˜šÏn œžœ˜Jšž˜Jšœ žœžœ˜šœ<˜J˜Jšžœžœ*˜>Jšœ˜—Jšžœ ˜—J˜šžœ˜ Jšœ3˜3Jšœ9˜9Jšœžœ˜Jšœžœ˜#Jšœžœ˜!Jšœ!žœ˜&Jšœ˜—Jšœ4˜4Jšœ˜Jšžœ˜J˜—…—+t=W