<> <> <> <> DIRECTORY Imager, Interminal, IO, Menus, MenusPrivate, MessageWindow USING [Append, Clear], Process USING [Detach, Milliseconds, MsecToTicks, priorityNormal, SetPriority, SetTimeout], Real USING [RoundC], Rope USING [Equal, FromRefText, ROPE], UserTerminal, TIPUser USING [TIPScreenCoords], UserProfile USING [Boolean, CallWhenProfileChanges, Number, ProfileChangedProc], VFonts USING [defaultFont, Font, FontAscent, FontHeight, RopeWidth], ViewerBLT USING [ChangeMenuHeight], ViewerClasses, ViewerOps USING [EnumProc, EnumerateViewers, InvertForMenus, PaintViewer], ViewerSpecs USING [captionHeight, menuHeight, windowBorderSize], WindowManager USING [RestoreCursor], WindowManagerPrivate USING [closePos, DrawCaptionMenu, growPos, windowMenus]; MenusImpl: CEDAR MONITOR LOCKS entry USING entry: EntryState IMPORTS IO, Imager, MessageWindow, Process, Real, Rope, UserProfile, UserTerminal, VFonts, ViewerBLT, ViewerOps, WindowManager, WindowManagerPrivate EXPORTS Menus, MenusPrivate SHARES ViewerOps = BEGIN OPEN Menus, MenusPrivate; Viewer: TYPE = ViewerClasses.Viewer; menuFont: VFonts.Font _ VFonts.defaultFont; fontHeight: INTEGER; baselineOffset: INTEGER; menuHLeading: INTEGER = 5; -- white space before first entry menuHSpace: INTEGER = 12; -- white space between entries registeredMenus: LIST OF InternalFormatMenuRef _ NIL; widthFudge: INTEGER = 3; targetNotFound: PUBLIC SIGNAL = CODE; MarkMenu: PUBLIC PROC [menus: ViewerMenus, parent: Viewer, mousePos: TIPUser.TIPScreenCoords] = { entry: EntryState _ ResolveEntry[menus, mousePos]; IF menus.inverted # entry THEN { IF menus.inverted # NIL THEN InvertEntry[menus,parent]; menus.inverted _ entry; IF menus.inverted # NIL THEN InvertEntry[menus,parent]; }; }; HitMenu: PUBLIC PROC [menus: ViewerMenus, parent: Viewer, mousePos: TIPUser.TIPScreenCoords, trigger: MenuEntryTrigger] = BEGIN entry: EntryState _ ResolveEntry[menus, mousePos]; hit: BOOL _ menus.inverted#NIL AND entry=menus.inverted; IF menus.inverted#NIL THEN InvertEntry[menus, parent]; -- take down menus.inverted _ NIL; IF hit THEN ProcessMenuHit[entry, menus, parent, trigger]; END; ProcessMenuHit: ENTRY PROC [entry: EntryState, menus: ViewerMenus, parent: Viewer, trigger: MenuEntryTrigger] = TRUSTED BEGIN response: REF ANY; SELECT entry.guardState FROM guarded => BEGIN entry.guardState _ arming; Process.Detach[FORK ArmMenuProc[entry, menus, parent]]; response _ FindNotifyRecord[entry,trigger].guardResponse; IF response#NIL THEN Process.Detach[ FORK GuardResponse[response] ]; END; arming=> NULL; -- no action armed => BEGIN IF entry.commonData.guarded THEN entry.guardState _ guarded; MenuPusher[entry, menus, parent, trigger, FALSE]; END; ENDCASE; END; ArmMenuProc: ENTRY PROC [entry: EntryState, menus: ViewerMenus, parent: Viewer] = BEGIN menuWaitCondition: CONDITION; <> TRUSTED {Process.SetTimeout[@menuWaitCondition, Process.MsecToTicks[armingTime]]}; WAIT menuWaitCondition; IF entry.guardState = arming THEN BEGIN entry.guardState _ armed; RedrawMenu[parent, menus, entry]; TRUSTED {Process.SetTimeout[@menuWaitCondition, Process.MsecToTicks[armedTime]]}; WAIT menuWaitCondition; END; IF entry.guardState#guarded THEN BEGIN entry.guardState _ guarded; RedrawMenu[parent, menus, entry]; END; END; MenuPusher: PROC [entry: EntryState, menus: ViewerMenus, parent: Viewer, trigger: MenuEntryTrigger, normalPriority: BOOL _ TRUE] = BEGIN changeOccurred: BOOLEAN _ FALSE; notifyRecord: EntryNotifyRecord _ FindNotifyRecord[entry,trigger]; notifyProc: ViewerClasses.NotifyProc _ FindViewerMenu[menus,entry].commonData.notify; IF notifyProc = NIL THEN { notifyProc _ parent.class.notify; IF notifyProc = NIL THEN Debug[msg: "using NIL class notifyproc", waitForLeftShift: TRUE, level: 2] ELSE Debug[msg: "using NON-NIL class notifyproc", waitForLeftShift: TRUE, level: 2] } ELSE Debug[msg: "using specially specified notifyproc", waitForLeftShift: TRUE, level: 2]; entry.greyed _ TRUE; RedrawMenu[parent, menus, entry]; IF normalPriority THEN TRUSTED {Process.SetPriority[Process.priorityNormal]}; <> IF notifyProc # NIL THEN notifyProc[parent, notifyRecord.notifyData]; entry.greyed _ FALSE; RedrawMenu[parent, menus, entry]; changeOccurred _ FALSE; FOR m: LIST OF Rope.ROPE _ notifyRecord.makeActive, m.rest UNTIL m = NIL DO MakeActive[viewer: parent, menu: m.first, paint: FALSE]; changeOccurred _ TRUE; ENDLOOP; FOR m: LIST OF Rope.ROPE _ notifyRecord.makeInActive, m.rest UNTIL m = NIL DO MakeInActive[viewer: parent, menu: m.first, paint: FALSE]; changeOccurred _ TRUE; ENDLOOP; FOR m: LIST OF Rope.ROPE _ notifyRecord.toggle, m.rest UNTIL m = NIL DO Toggle[viewer: parent, menu: m.first, paint: FALSE]; changeOccurred _ TRUE; ENDLOOP; IF changeOccurred THEN RePaintBecauseOfMenuChange[parent]; WindowManager.RestoreCursor[]; END; RedrawMenu: PROC [viewer: Viewer, menus: ViewerMenus, entry: EntryState] = BEGIN IF menus = WindowManagerPrivate.windowMenus THEN WindowManagerPrivate.DrawCaptionMenu[viewer, FALSE] ELSE ViewerOps.PaintViewer[viewer: viewer, hint: menu, whatChanged: entry]; END; GuardResponse: PROC [response: REF ANY] = BEGIN WITH response SELECT FROM response: Rope.ROPE => MessageWindow.Append[response, TRUE]; response: REF UnGuardRec => response.proc[response.data]; ENDCASE => ERROR; -- not valid response END; ClearMenu: PUBLIC PROC [menus: ViewerMenus, parent: Viewer, paint: BOOL _ TRUE] = BEGIN IF menus.inverted#NIL THEN BEGIN IF paint THEN InvertEntry[menus, parent]; menus.inverted _ NIL; END; END; DrawSingleEntry: PROC [viewer: Viewer, context: Imager.Context, entry: EntryState, clearFirst: BOOLEAN _ TRUE] = { OPEN Imager; myGrey: REF CARDINAL = NEW[CARDINAL _ 001010B]; lowerLeftX: INTEGER _ viewer.wx + entry.xPos; lowerLeftY: INTEGER _ viewer.wy + entry.yPos; IF clearFirst THEN { SetColor[context, white]; MaskIntRectangle[context, [lowerLeftX - widthFudge, lowerLeftY, entry.width + (2*widthFudge), fontHeight-1]]; SetColor[context, black]; }; IF entry.greyed THEN { SetColor[context, myGrey]; MaskIntRectangle[context, [lowerLeftX - widthFudge, lowerLeftY, entry.width + (2*widthFudge), fontHeight-1]]; SetColor[context, black]; }; WITH entry.commonData.displayData SELECT FROM r: Rope.ROPE => { SetIntCP[context, [lowerLeftX, lowerLeftY + baselineOffset]]; MaskCharacters[context, VFonts.defaultFont, r]; }; user: REF DrawingRec => { CallUserDrawProc: PROC = { <> ClipIntRectangle[context, [lowerLeftX-widthFudge, lowerLeftY, entry.width+(2*widthFudge), fontHeight-1]]; [] _ user.proc[op: draw, ctx: context, clientData: user.data]; }; SetIntCP[context, [lowerLeftX, lowerLeftY]]; DoSave[context, CallUserDrawProc]; }; ENDCASE => ERROR; <> IF entry.commonData.guarded AND entry.guardState # armed THEN MaskIntRectangle[context, [lowerLeftX - 1, lowerLeftY + baselineOffset+2, entry.width + 2, 1]]; }; DrawMenu: PUBLIC PROC [v: Viewer, menus: ViewerMenus, context: Imager.Context, whatChanged: REF ANY _ NIL] = BEGIN <> Debug[msg: IO.PutFR["drawing menus of height: %d", IO.int[menus.h]], level: 2]; IF whatChanged # NIL THEN DrawSingleEntry[v, context, NARROW[whatChanged, EntryState]] ELSE { FOR m: LIST OF ViewerMenu _ menus.list, m.rest UNTIL m = NIL DO IF m.first.active THEN FOR e: LIST OF EntryState _ m.first.entries, e.rest UNTIL e = NIL DO DrawSingleEntry[v, context, e.first, FALSE]; ENDLOOP; ENDLOOP; menus.inverted _ NIL; }; END; resolveCacheMenus: ViewerMenus _ NIL; resolveCacheMenu: ViewerMenu _ NIL; rce: EntryState _ NIL; -- stands for ResolveCacheEntry ResolveEntry: PROC [menus: ViewerMenus, mousePos: TIPUser.TIPScreenCoords] RETURNS [entry: EntryState] = { <> <> IF resolveCacheMenus = menus THEN IF resolveCacheMenu.active THEN { IF mousePos.mouseX IN [rce.xPos..(rce.xPos + rce.width)] AND mousePos.mouseY IN [rce.yPos..(rce.yPos+(fontHeight-1))] THEN RETURN[rce]; }; <> FOR m: LIST OF ViewerMenu _ menus.list, m.rest UNTIL m = NIL DO IF NOT m.first.active THEN LOOP; FOR e: LIST OF EntryState _ m.first.entries, e.rest UNTIL e = NIL DO IF mousePos.mouseX IN [e.first.xPos..(e.first.xPos + e.first.width)] AND mousePos.mouseY IN [e.first.yPos..(e.first.yPos+(fontHeight-1))] THEN { <> resolveCacheMenus _ menus; resolveCacheMenu _ m.first; rce _ e.first; RETURN[e.first]; }; ENDLOOP; ENDLOOP; RETURN[NIL]; }; InvertEntry: PROC [menus: ViewerMenus, parent: Viewer] = { IF ~parent.destroyed AND ~parent.iconic THEN { entry: EntryState _ menus.inverted; ViewerOps.InvertForMenus[parent, (parent.wx+entry.xPos)-widthFudge, parent.wy+entry.yPos, entry.width+(2*widthFudge), fontHeight-1]; }; }; ComputeFontInfo: PROC = BEGIN ascent: INTEGER = VFonts.FontAscent[menuFont]; fontHeight _ VFonts.FontHeight[menuFont]; baselineOffset _ Real.RoundC[fontHeight-ascent]; END; FindNotifyRecord: PROC [entry: EntryState, trigger: MenuEntryTrigger] RETURNS [answer: EntryNotifyRecord] = { FOR l: LIST OF EntryNotifyRecord _ entry.commonData.actions, l.rest UNTIL l = NIL DO FOR t: LIST OF MenuEntryTrigger _ l.first.trigger, t.rest UNTIL t = NIL DO <> IF t.first = trigger OR t.first = all THEN RETURN[l.first]; ENDLOOP; ENDLOOP; ERROR; }; FindViewerMenu: PROC [menus: ViewerMenus, entry: EntryState] RETURNS [menu: ViewerMenu] = { FOR l: LIST OF ViewerMenu _ menus.list, l.rest UNTIL l = NIL DO FOR e: LIST OF EntryState _ l.first.entries, e.rest UNTIL e = NIL DO IF e.first = entry THEN RETURN[l.first]; ENDLOOP; ENDLOOP; RETURN[NIL]; }; CreateInternalFormatMenu: PROC [menu: Menu] RETURNS [answer: InternalFormatMenuRef] = { <> reversedList: LIST OF EntryRef _ NIL; answer _ NEW[InternalFormatMenu]; answer.name _ menu.name; answer.beginsActive _ menu.beginsActive; answer.breakBefore _ menu.breakBefore; answer.breakAfter _ menu.breakAfter; answer.notify _ menu.notify; answer.entries _ NIL; FOR e: LIST OF Entry _ menu.entries, e.rest UNTIL e = NIL DO reversedList _ CONS[MakeNewEntry[e.first], reversedList]; ENDLOOP; FOR e: LIST OF EntryRef _ reversedList, e.rest UNTIL e = NIL DO answer.entries _ CONS[e.first, answer.entries]; ENDLOOP; RETURN[answer]; }; MakeNewEntry: PROC[entry: Entry] RETURNS[answer: EntryRef] = { answer _ NEW[Entry _ entry]; <> IF answer.displayData = NIL THEN answer.displayData _ answer.name ELSE WITH answer.displayData SELECT FROM <> dispData: REF TEXT => answer.displayData _ Rope.FromRefText[dispData]; okRope: Rope.ROPE => NULL; okProc: REF DrawingRec => NULL; ENDCASE => ERROR; -- invalid data type for DisplayData field. <> FOR t: LIST OF EntryNotifyRecord _ answer.actions, t.rest UNTIL t = NIL DO IF t.first.guardResponse # NIL THEN WITH t.first.guardResponse SELECT FROM textRef: REF TEXT => t.first.guardResponse _ Rope.FromRefText[textRef]; okRope: Rope.ROPE => NULL; okRec: REF UnGuardRec => NULL; ENDCASE => ERROR; -- invalid data type for guardResponse field. ENDLOOP; RETURN[answer]; }; CreateExternalFormatMenu: PROC [menu: InternalFormatMenuRef] RETURNS [Menu] = { <> reversedList: LIST OF Entry _ NIL; answer: REF Menu _ NEW[Menu]; answer.name _ menu.name; answer.beginsActive _ menu.beginsActive; answer.breakBefore _ menu.breakBefore; answer.breakAfter _ menu.breakAfter; answer.notify _ menu.notify; answer.entries _ NIL; FOR e: LIST OF EntryRef _ menu.entries, e.rest UNTIL e = NIL DO temp: EntryRef _ NEW[Entry _ e.first^]; reversedList _ CONS[temp^, reversedList]; ENDLOOP; FOR e: LIST OF Entry _ reversedList, e.rest UNTIL e = NIL DO answer.entries _ CONS[e.first, answer.entries]; ENDLOOP; RETURN[answer^]; }; RegisterMenu: PUBLIC PROC [menu: Menu] = { registeredMenus _ CONS[CreateInternalFormatMenu[menu], registeredMenus]; }; AlreadyRegistered: PUBLIC PROC [name: Rope.ROPE] RETURNS [registered: BOOLEAN] = { FOR m: LIST OF InternalFormatMenuRef _ registeredMenus, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.name, name] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; ReRegisterMenu: PUBLIC PROC [menu: Menu, paint: BOOL _ TRUE] = { newMenu: ViewerMenuRec; MenuDefinitonChanged: ViewerOps.EnumProc = { <<[v: viewer] RETURNS [BOOL _ TRUE] >> FOR m: LIST OF ViewerMenu _ NARROW[v.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[menu.name, m.first.commonData.name] THEN m.first _ NEW[ViewerMenuRec _ newMenu]; ENDLOOP; IF paint THEN RePaintBecauseOfMenuChange[v]; }; FOR m: LIST OF InternalFormatMenuRef _ registeredMenus, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.name, menu.name] THEN { m.first _ CreateInternalFormatMenu[menu]; newMenu _ MakeNewViewerMenuRec[m.first]; ViewerOps.EnumerateViewers[MenuDefinitonChanged]; RETURN; }; ENDLOOP; SIGNAL targetNotFound; }; GetRegisteredMenu: PUBLIC PROC [name: Rope.ROPE] RETURNS [menu: Menu] = { FOR m: LIST OF InternalFormatMenuRef _ registeredMenus, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.name, menu.name] THEN RETURN[CreateExternalFormatMenu[m.first] ]; ENDLOOP; SIGNAL targetNotFound; }; ClearMenus: PUBLIC PROC [viewer: Viewer, paint: BOOL _ TRUE] = { viewer.menus _ NIL; IF paint THEN RePaintBecauseOfMenuChange[viewer]; }; AddMenu: PUBLIC PROC [viewer: Viewer, name: Rope.ROPE, paint: BOOL _ TRUE, addBefore: Rope.ROPE _ NIL] = { IF viewer.menus = NIL THEN { IF addBefore # NIL THEN SIGNAL targetNotFound; viewer.menus _ NEW[ViewerMenusRec]; NARROW[viewer.menus, ViewerMenus].list _ LIST[MakeNewViewerMenu[name]]; } ELSE IF addBefore # NIL THEN { <> prev: LIST OF ViewerMenu _ NIL; foundIt: BOOLEAN _ FALSE; FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, name] THEN { prev.rest _ CONS[MakeNewViewerMenu[name], m]; foundIt _ TRUE; }; prev _ m; ENDLOOP; IF NOT foundIt THEN SIGNAL targetNotFound; } ELSE IF GetInternalFormatMenuRef[name].breakBefore THEN { <> prev: LIST OF ViewerMenu _ NIL; FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO prev _ m; ENDLOOP; prev.rest _ LIST[MakeNewViewerMenu[name]]; } ELSE { <> prev: LIST OF ViewerMenu _ NIL; FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL OR ((prev # NIL AND prev.first.commonData.breakAfter = FALSE) AND m.first.commonData.breakBefore) DO prev _ m; ENDLOOP; prev.rest _ CONS[MakeNewViewerMenu[name],prev.rest]; }; IF paint THEN RePaintBecauseOfMenuChange[viewer]; }; ViewerlessAddMenu: PUBLIC PROC [name: Rope.ROPE, addBefore: Rope.ROPE _ NIL, paint: BOOL _ TRUE] = { <> IF WindowManagerPrivate.windowMenus = NIL THEN { IF addBefore # NIL THEN SIGNAL targetNotFound; WindowManagerPrivate.windowMenus _ NEW[ViewerMenusRec]; WindowManagerPrivate.windowMenus.list _ LIST[MakeNewViewerMenu[name]]; } ELSE IF addBefore # NIL THEN { <> prev: LIST OF ViewerMenu _ NIL; foundIt: BOOLEAN _ FALSE; FOR m: LIST OF ViewerMenu _ WindowManagerPrivate.windowMenus.list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, name] THEN { prev.rest _ CONS[MakeNewViewerMenu[name], m]; foundIt _ TRUE; }; prev _ m; ENDLOOP; IF NOT foundIt THEN SIGNAL targetNotFound; } ELSE IF GetInternalFormatMenuRef[name].breakBefore THEN { <> prev: LIST OF ViewerMenu _ NIL; FOR m: LIST OF ViewerMenu _ WindowManagerPrivate.windowMenus.list, m.rest UNTIL m = NIL DO prev _ m; ENDLOOP; prev.rest _ LIST[MakeNewViewerMenu[name]]; } ELSE { <> prev: LIST OF ViewerMenu _ NIL; FOR m: LIST OF ViewerMenu _ WindowManagerPrivate.windowMenus.list, m.rest UNTIL m = NIL OR ((prev # NIL AND prev.first.commonData.breakAfter = FALSE) AND m.first.commonData.breakBefore) DO prev _ m; ENDLOOP; prev.rest _ CONS[MakeNewViewerMenu[name],prev.rest]; }; }; MakeNewViewerMenu: PROC [name: Rope.ROPE] RETURNS [answer: ViewerMenu] = { FOR m: LIST OF InternalFormatMenuRef _ registeredMenus, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.name, name] THEN RETURN[NEW[ViewerMenuRec _ MakeNewViewerMenuRec[m.first] ] ]; ENDLOOP; SIGNAL targetNotFound; }; MakeNewViewerMenuRec: PROC [data: InternalFormatMenuRef] RETURNS [answer: ViewerMenuRec] = { answer.commonData _ data; answer.active _ answer.commonData.beginsActive; answer.entries _ MakeNewViewerMenuEntries[data]; RETURN[answer]; }; MakeNewViewerMenuEntries: PROC [menu: InternalFormatMenuRef] RETURNS [answer: LIST OF EntryState] = { reversedList: LIST OF EntryState _ NIL; answer _ NIL; FOR e: LIST OF EntryRef _ menu.entries, e.rest UNTIL e = NIL DO reversedList _ CONS[NEW[EntryStateRec _ [commonData: e.first]],reversedList]; ENDLOOP; FOR e: LIST OF EntryState _ reversedList, e.rest UNTIL e = NIL DO IF e.first.commonData.guarded THEN e.first.guardState _ guarded; answer _ CONS[e.first, answer]; ENDLOOP; RETURN[answer]; }; MakeActive: PUBLIC PROC [viewer: Viewer, menu: Rope.ROPE, paint: BOOL _ TRUE] = { FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, menu] THEN { IF NOT m.first.active THEN { m.first.active _ TRUE; IF paint THEN RePaintBecauseOfMenuChange[viewer]; }; RETURN; }; ENDLOOP; SIGNAL targetNotFound; }; MakeInActive: PUBLIC PROC [viewer: Viewer, menu: Rope.ROPE, paint: BOOL _ TRUE] = { FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, menu] THEN { IF m.first.active THEN { m.first.active _ FALSE; IF paint THEN RePaintBecauseOfMenuChange[viewer]; }; RETURN; }; ENDLOOP; SIGNAL targetNotFound; }; Toggle: PUBLIC PROC [viewer: Viewer, menu: Rope.ROPE, paint: BOOL _ TRUE] = { FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, menu] THEN { m.first.active _ NOT m.first.active; IF paint THEN RePaintBecauseOfMenuChange[viewer]; RETURN; }; ENDLOOP; SIGNAL targetNotFound; }; MenuInViewer: PUBLIC PROC [viewer: Viewer, menu: Rope.ROPE] RETURNS [exists: BOOLEAN] = { FOR m: LIST OF ViewerMenu _ NARROW[viewer.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.commonData.name, menu] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; <> wrap: BOOLEAN _ TRUE; -- TRUE iff user wants menu entries to ALWAYS be displayed wrapIndent: INTEGER _ (menuHLeading*4); -- indention on non-first lines of wrapped menu tooNarrowToWrapMenus: INTEGER _ 150; -- don't wrap if the window is ridiculously narrow <> ReEstablishUserProfileParamaters: PUBLIC UserProfile.ProfileChangedProc = { wrap _ UserProfile.Boolean[key: "ViewerMenusWrap", default: TRUE]; wrapIndent _ UserProfile.Number[key: "ViewerMenusWrapIndent", default: (menuHLeading*4)]; tooNarrowToWrapMenus _ UserProfile.Number["ViewerMenusTooNarrowToWrap", 150]; }; ReComputeMenus: PUBLIC PROC [v: Viewer] RETURNS[heightDelta: INTEGER] = { <> <> originalHeight: INTEGER; prevLineHadBreakafter: BOOLEAN _ TRUE; -- starting true forces first line to move down wbs: INTEGER _ IF v.border THEN ViewerSpecs.windowBorderSize ELSE 0; TopLeftCornerX: INTEGER _ wbs; TopLeftCornerY: INTEGER _ v.wh-ViewerSpecs.captionHeight; CurrentX: INTEGER _ TopLeftCornerX + menuHLeading; CurrentY: INTEGER _ TopLeftCornerY; IF v.menus=NIL OR v.iconic THEN RETURN[0]; originalHeight _ NARROW[v.menus, ViewerMenus].h; IF wrap THEN Debug[msg: IO.PutFR["ReComputeMenus for %g ==> wrap is true", IO.rope[ NARROW[v.menus, ViewerMenus].list.first.commonData.name]], level: 2] ELSE Debug[msg: IO.PutFR["ReComputeMenus for %g ==> wrap is false", IO.rope[NARROW[v.menus, ViewerMenus].list.first.commonData.name]], level: 2]; FOR m: LIST OF ViewerMenu _ NARROW[v.menus, ViewerMenus].list, m.rest UNTIL m = NIL DO IF NOT m.first.active THEN LOOP; IF prevLineHadBreakafter OR m.first.commonData.breakBefore THEN { CurrentX _ TopLeftCornerX + menuHLeading; CurrentY _ CurrentY - ViewerSpecs.menuHeight; }; prevLineHadBreakafter _ m.first.commonData.breakAfter; FOR e: LIST OF EntryState _ m.first.entries, e.rest UNTIL e = NIL DO e.first.width _ WITH e.first.commonData.displayData SELECT FROM r: Rope.ROPE => VFonts.RopeWidth[r], user: REF DrawingRec => user.proc[op: query, clientData: user.data] ENDCASE => ERROR; IF wrap AND (v.ww > tooNarrowToWrapMenus) THEN IF (CurrentX + e.first.width) > (v.ww - wbs) THEN { <> Debug[msg: "we just decided to wrap!", level: 2]; CurrentX _ TopLeftCornerX + wrapIndent; CurrentY _ CurrentY - ViewerSpecs.menuHeight; }; e.first.xPos _ CurrentX; e.first.yPos _ CurrentY; CurrentX _ CurrentX + e.first.width + menuHSpace; ENDLOOP; ENDLOOP; NARROW[v.menus, ViewerMenus].x _ TopLeftCornerX; NARROW[v.menus, ViewerMenus].y _ CurrentY; NARROW[v.menus, ViewerMenus].w _ v.ww - (2 * wbs); NARROW[v.menus, ViewerMenus].h _ TopLeftCornerY - CurrentY; Debug[msg: IO.PutFR["menu height deterimined to be: %d, a difference of: %d",IO.int[TopLeftCornerY - CurrentY], IO.int[NARROW[v.menus, ViewerMenus].h - originalHeight] ],level: 2]; RETURN[NARROW[v.menus, ViewerMenus].h - originalHeight]; }; ReComputeWindowMenus: PUBLIC PROC [v: Viewer, guard: BOOL, color: BOOL] = { <> CurrentX: INTEGER _ menuHLeading + ViewerSpecs.windowBorderSize; CurrentY: INTEGER ~ v.wh - ViewerSpecs.captionHeight; -- all have same Y coordinate WindowManagerPrivate.windowMenus.x _ ViewerSpecs.windowBorderSize; WindowManagerPrivate.windowMenus.y _ v.wh - ViewerSpecs.captionHeight; WindowManagerPrivate.windowMenus.w _ v.ww - (2 * ViewerSpecs.windowBorderSize); WindowManagerPrivate.windowMenus.h _ ViewerSpecs.captionHeight; Debug["ReComputeWindowMenus entered", TRUE, 3]; IF guard THEN { Debug["ReComputeWindowMenus: guard is true", TRUE, 4]; SetDisplay["windowDestroyMenu", FALSE]; SetDisplay["windowGuardedDestroyMenu", TRUE]; } ELSE { Debug["ReComputeWindowMenus: guard is false", TRUE, 4]; SetDisplay["windowDestroyMenu", TRUE]; SetDisplay["windowGuardedDestroyMenu", FALSE]; }; IF color THEN SetDisplay["windowColorMenu", TRUE] ELSE SetDisplay["windowColorMenu", FALSE]; FOR m: LIST OF ViewerMenu _ WindowManagerPrivate.windowMenus.list, m.rest UNTIL m = NIL DO IF NOT m.first.active THEN LOOP; FOR e: LIST OF EntryState _ m.first.entries, e.rest UNTIL e = NIL DO e.first.width _ WITH e.first.commonData.displayData SELECT FROM r: Rope.ROPE => VFonts.RopeWidth[r], user: REF DrawingRec => user.proc[op: query, clientData: user.data] ENDCASE => ERROR; e.first.xPos _ CurrentX; e.first.yPos _ CurrentY; <> IF Rope.Equal[e.first.commonData.name, "Grow"] THEN { WindowManagerPrivate.growPos.mouseX _ e.first.xPos+1; WindowManagerPrivate.growPos.color _ FALSE; WindowManagerPrivate.growPos.mouseY _ e.first.yPos+1; }; IF Rope.Equal[e.first.commonData.name, "Close"] THEN { WindowManagerPrivate.closePos.mouseX _ e.first.xPos+1; WindowManagerPrivate.closePos.color _ FALSE; WindowManagerPrivate.closePos.mouseY _ e.first.yPos+1; }; CurrentX _ CurrentX + e.first.width + menuHSpace; ENDLOOP; ENDLOOP; }; SetDisplay: PROC [name: Rope.ROPE, setting: BOOL] = { FOR l: LIST OF ViewerMenu _ WindowManagerPrivate.windowMenus.list, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first.commonData.name, name] THEN { l.first.active _ setting; RETURN; }; ENDLOOP; ERROR; }; GetInternalFormatMenuRef: PROC [name: Rope.ROPE] RETURNS [answer: InternalFormatMenuRef] = { FOR m: LIST OF InternalFormatMenuRef _ registeredMenus, m.rest UNTIL m = NIL DO IF Rope.Equal[m.first.name, name] THEN RETURN[m.first]; ENDLOOP; ERROR; }; RePaintBecauseOfMenuChange: PROC [v: Viewer] = { ViewerBLT.ChangeMenuHeight[v, ReComputeMenus[v]]; <> }; AlterDebuggingLevel: PUBLIC PROC [amount: INTEGER, relative: BOOL _ TRUE] = { string: Rope.ROPE; IF relative THEN currentDebugLevel _ currentDebugLevel + amount ELSE currentDebugLevel _ amount; string _ IO.PutFR["Debugging Level Set to %d", IO.int[currentDebugLevel]]; Debug[string, TRUE, currentDebugLevel]; }; currentDebugLevel: INTEGER _ 3; Debug: PUBLIC PROC [msg: Rope.ROPE, waitForLeftShift: BOOL _ TRUE, level: INTEGER _ 1] = TRUSTED { keys: LONG POINTER TO Interminal.KeyState = LOOPHOLE[UserTerminal.keyboard]; IF currentDebugLevel >= level THEN { MessageWindow.Append[msg, TRUE]; IF waitForLeftShift THEN { MessageWindow.Append[" ... HIT LEFT SHIFT TO CONTINUE", FALSE]; WHILE keys.bits[LeftShift]#down DO ENDLOOP; WHILE keys.bits[LeftShift]#up DO ENDLOOP; MessageWindow.Clear[]; }; }; }; -- Debug ComputeFontInfo[]; UserProfile.CallWhenProfileChanges[ReEstablishUserProfileParamaters]; END.