DIRECTORY Atom, BasicTime, BiScrollers, CodeTimer, Convert, Feedback, GGActive, GGBasicTypes, GGControlPanelTypes, GGCoreOps, GGCoreTypes, GGEmbedTypes, GGEvent, GGFont, GGInterfaceTypes, GGModelTypes, GGScrollMonitor, GGSlice, GGState, GGTransform, GGUserInput, GGUserProfile, GGViewerOps, GGWindow, GGWorld, Imager, ImagerTransformation, InputFocus, IO, List, Menus, Process, Real, RealFns, RefTab, Rope, ScreenCoordsTypes, SlackProcess, TIPUser, UserProfile, Vector2, ViewerClasses; GGUserImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, BiScrollers, CodeTimer, Convert, Feedback, GGActive, GGCoreOps, GGEvent, GGFont, GGScrollMonitor, GGSlice, GGState, GGTransform, GGUserInput, GGViewerOps, GGWindow, ImagerTransformation, InputFocus, IO, List, Process, RealFns, RefTab, Rope, SlackProcess, UserProfile EXPORTS GGInterfaceTypes, GGUserInput, GGUserProfile = BEGIN Camera: TYPE = GGModelTypes.Camera; ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes EmbedDataObj: PUBLIC TYPE = GGEmbedTypes.EmbedDataObj; -- exported to GGInterfaceTypes Event: TYPE = GGCoreTypes.Event; EventListt: TYPE = GGCoreTypes.EventListt; External: TYPE = GGUserInput.External; ExternalRec: TYPE = GGUserInput.ExternalRec; FeatureData: TYPE = GGModelTypes.FeatureData; FontData: TYPE = GGModelTypes.FontData; GGData: TYPE = GGInterfaceTypes.GGData; Point: TYPE = GGBasicTypes.Point; RawInputHandlerProc: TYPE = GGUserInput.RawInputHandlerProc; Scene: TYPE = GGModelTypes.Scene; SlackHandle: TYPE = SlackProcess.SlackHandle; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; Transformation: TYPE = ImagerTransformation.Transformation; UserInputProc: TYPE = GGUserInput.UserInputProc; VEC: TYPE = Imager.VEC; XVEC: TYPE = RECORD [x, y: REAL]; Viewer: TYPE = ViewerClasses.Viewer; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem; externalCV: CONDITION; WaitExternal: PUBLIC ENTRY PROC [External] = { WAIT externalCV; }; BroadcastExternal: PUBLIC ENTRY PROC [External] = { BROADCAST externalCV; }; NotifyExternal: PUBLIC ENTRY PROC [External] = { NOTIFY externalCV; }; EventNotify: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData ¬ NARROW[clientData]; ProcessAndQueueEvent[event, ggData]; }; UnQueuedEventNotify: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData ~ NARROW[clientData]; atom: ATOM ~ NARROW[event.first]; regEvent: RegisteredEvent ~ FetchAction[atom]; IF regEvent=NIL THEN { NotYetImplementedMessage[atom, ggData]; } ELSE { event ¬ GetAnyArguments[event, regEvent, ggData]; TRUSTED {Process.Detach[FORK regEvent.eventProc[ggData, event] ]; }; }; }; PlayAction: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData ¬ NARROW[clientData]; IF event.first = $Version OR event.first = $Store OR event.first = $Save OR event.first = $ToIP OR event.first = $ToIPScreen OR event.first = $ToIPLit OR event.first = $IPToTioga OR event.first = $IPToTiogaBordered OR event.first = $IPToTiogaFit OR event.first = $IPToTiogaBorderedAndFit OR event.first = $IPToTiogaAlt OR event.first = $StuffToTioga OR event.first = $StuffToFile OR event.first = $MergeFromTioga OR event.first = $StuffToTiogaBordered OR event.first = $StuffToFileAlt OR event.first = $GrabFromTioga OR event.first = $StuffToTiogaFit OR event.first = $GetFromTioga OR event.first = $StuffToTiogaBorderedAndFit OR event.first = $MergeFromGargoyle OR event.first = $StuffToTiogaAlt THEN RETURN; ProcessAndQueueEvent[event, ggData]; }; gRawInputHandler: GGUserInput.RawInputHandlerProc ¬ GGActive.ActiveInputHandler; InputNotify: PUBLIC ViewerClasses.NotifyProc = { ggData: GGData ~ NARROW[BiScrollers.ClientDataOfViewer[self]]; notify: PROC [input: LIST OF REF] ~ { InputFocus.SetInputFocus[ggData.controls.actionArea]; ProcessAndQueueEvent[input, ggData]; }; gRawInputHandler[self, ggData, input, notify]; }; BiScrollerInputNotify: PUBLIC PROC [ggData: GGData, event: LIST OF REF] = { BiScrollerQueue: PROC [event: LIST OF REF ANY, ggData: GGData] = { first: ATOM ¬ NARROW[event.first]; IF first=$Shift THEN { vec: REF VEC _ NARROW[event.rest.first]; -- Shift VECTOR xVec: REF XVEC ¬ NEW[XVEC ¬ [vec.x, vec.y] ]; -- put it in a record different from type VEC event ¬ LIST[$Shift, xVec]; }; ProcessAndQueueEvent[event, ggData]; }; IF ISTYPE[event.first, LIST OF REF] THEN { FOR list: LIST OF REF _ event, list.rest UNTIL list = NIL DO sublist: REF ¬ list.first; IF ISTYPE[sublist, LIST OF REF] THEN BiScrollerQueue[NARROW[sublist], ggData]; ENDLOOP; } ELSE BiScrollerQueue[event, ggData]; }; finishText: LIST OF REF ANY ~ LIST[$SawTextFinish]; finishMouse: LIST OF REF ANY ~ LIST[$SawMouseFinish]; ProcessAndQueueEvent: PROC [event: LIST OF REF ANY, ggData: GGData] = { IF ggData.embed.beingBorn THEN RETURN; -- don't handle events while the window is being created WITH event.first SELECT FROM refChar: REF CHAR => { myRefChar: REF CHAR ~ NEW[CHAR ¬ refChar­]; event ¬ LIST[$AddChar, myRefChar]; }; atom: ATOM => { regEvent: RegisteredEvent ~ FetchAction[atom]; IF regEvent=NIL THEN NotYetImplementedMessage[atom, ggData] ELSE { atomName: Rope.ROPE ~ Atom.GetPName[atom]; startAction: BOOL ~ Rope.Equal[Rope.Substr[atomName, 0, 5], "Start", TRUE]; IF startAction THEN QueueInput[ggData, finishText]; -- need this before selection changes IF regEvent.causeMouseEventsToComplete THEN QueueInput[ggData, finishMouse]; event ¬ GetAnyArguments[event, regEvent, ggData]; IF atom = $OneScroll THEN { IF event.rest # NIL THEN BEGIN x, y: INTEGER ¬ 0; WITH event.rest.first SELECT FROM change: REF Imager.VEC => { GGScrollMonitor.ConcatToDue[ggData, ImagerTransformation.Translate[[change.x, change.y]] ]; GOTO EasyCase; }; i: REF INTEGER => x ¬ i­; ENDCASE; IF event.rest.rest # NIL THEN { WITH event.rest.rest.first SELECT FROM i: REF INTEGER => y ¬ i­; ENDCASE; }; GGScrollMonitor.ConcatToDue[ggData, ImagerTransformation.Translate[[x, y]] ]; EXITS EasyCase => NULL; END; } ELSE IF atom = $OneZoom THEN { originViewer: Point; x: INTEGER ¬ 0; fx, scalar: REAL; viewport: Imager.Rectangle ¬ GGState.GetViewport[ggData]; originViewer ¬ [viewport.x+(viewport.w/2.0), viewport.y+(viewport.h/2.0)]; IF event.rest # NIL THEN { WITH event.rest.first SELECT FROM i: REF INTEGER => x ¬ i­; ENDCASE; }; fx ¬ x; -- convert to float scalar ¬ RealFns.Power[base: 2.0, exponent: fx/50.0]; -- fifty clicks of the track ball gives a factor of two GGScrollMonitor.ConcatToDue[ggData, GGTransform.ScaleAboutPoint[originViewer, scalar] ]; }; }; }; ENDCASE => ERROR; QueueInput[ggData, event, NIL]; }; Timestamp: TYPE = REF TimestampObj; TimestampObj: TYPE = RECORD [ startTime: CARD32 ]; timeQueue: BOOL ¬ FALSE; QueueInput: PROC [ggData: GGData, event: LIST OF REF ANY, optimizeHint: REF ANY ¬ NIL] ~ { handle: SlackHandle ~ ggData.slackHandle; GGEvent.PrintAllInput[ggData, event]; -- KAP IF timeQueue THEN event ¬ List.Nconc1[event, NEW[TimestampObj ¬ [NowInMilliseconds[]]] ]; -- for timing how much time is spent on the queue SlackProcess.QueueAction[handle, Dispatch, event, ggData, optimizeHint]; }; GetAnyArguments: PROC [event: LIST OF REF ANY, regEvent: RegisteredEvent, ggData: GGData] RETURNS [newEvent: LIST OF REF ANY] = { atom: ATOM ¬ NARROW[event.first]; SELECT regEvent.argType FROM none => newEvent ¬ event; rope => newEvent ¬ CheckForSelectedRope[atom, event]; rope2 => newEvent ¬ CheckForSelectedRope2[atom, event]; refReal => newEvent ¬ CheckForSelectedReal[atom, event]; refInt => newEvent ¬ CheckForSelectedInt[atom, event]; refCard => newEvent ¬ CheckForSelectedCard[atom, event]; refExt => newEvent ¬ CheckForActualExt[atom, event]; ENDCASE => ERROR; }; RegisterRawInputHandler: PUBLIC PROC [rawInputHandler: RawInputHandlerProc] = { gRawInputHandler ¬ rawInputHandler; }; NowInMilliseconds: PROC RETURNS [CARD32] = { RETURN[(BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]]+500)/1000]; }; PrintUserTrace: PROC [ggData: GGInterfaceTypes.GGData, eventProc: GGUserInput.UserInputProc, event: LIST OF REF ANY] ~ { procName: Rope.ROPE ¬ "?"; moduleName: Rope.ROPE ¬ "?"; thisArgName: Rope.ROPE; allArgs: Rope.ROPE; FOR list: LIST OF REF ANY ¬ event, list.rest UNTIL list = NIL DO thisArgName ¬ IO.PutFR1["%g", [refAny[list.first]] ]; IF allArgs = NIL THEN allArgs ¬ thisArgName ELSE allArgs ¬ Rope.Cat[allArgs, ", ", thisArgName]; ENDLOOP; Feedback.PutFL[ggData.router, oneLiner, $Typescript, "%g.%g[%g]", LIST[[rope[moduleName]], [rope[procName]], [rope[allArgs]]] ]; }; Dispatch: PROC [clientData: REF ANY, inputAction: REF] = { ggData: GGData ~ NARROW[clientData]; atom: ATOM; startTime, endTime: CARD32; startTimeRef: REF; regEvent: RegisteredEvent; event: LIST OF REF ¬ NARROW[inputAction]; UpdateCoords: PROC [input: LIST OF REF] RETURNS [o: LIST OF REF] = { i, l: LIST OF REF; viewerToClient: Transformation _ GGState.GetBiScrollersTransforms[ggData].viewerToClient; IF input.first = $AlignFracs OR (input.rest # NIL AND input.rest.first = $AlignFracs) THEN RETURN[input]; -- because BiScrollers uses REF Vector2.VEC for the shift amount FOR i ¬ input, i.rest WHILE i # NIL DO l ¬ IF l = NIL THEN o ¬ CONS[i.first, NIL] ELSE l.rest ¬ CONS[i.first, NIL]; WITH l.first SELECT FROM z: TIPUser.TIPScreenCoords => { l.first ¬ NEW [Vector2.VEC ¬ viewerToClient.Transform[[z.mouseX, z.mouseY]]]; }; v: REF Vector2.VEC => { l.first _ NEW [Vector2.VEC _ viewerToClient.Transform[v^]]; }; z: REF XVEC => { l.first _ NEW [Vector2.VEC _ [z.x, z.y] ]; }; ENDCASE; ENDLOOP; }; event ¬ UpdateCoords[event]; -- perform the BiScrollers transform IF timeQueue THEN { startTimeRef ¬ List.NthElement[event, -1]; WITH startTimeRef SELECT FROM timeStamp: Timestamp => { startTime ¬ timeStamp.startTime; event ¬ List.DRemove[startTimeRef, event]; endTime ¬ NowInMilliseconds[]; CodeTimer.SetIntMilliseconds[$TimeOnQueue, startTime, endTime, $Gargoyle]; }; ENDCASE; }; atom ¬ NARROW[event.first]; regEvent ¬ FetchAction[atom]; IF regEvent=NIL THEN NotYetImplementedMessage[atom, ggData] ELSE { IF event.first=$Again THEN { IF NOT GGCoreOps.NoEvents[ggData.lastEvents] THEN { FOR list: LIST OF Event ¬ ggData.lastEvents.list, list.rest UNTIL list = NIL DO thisEvent: LIST OF REF ANY ~ list.first; thisAtom: ATOM ~ NARROW[thisEvent.first]; thisRegEvent: RegisteredEvent ~ FetchAction[thisAtom]; IF thisRegEvent=NIL THEN NotYetImplementedMessage[thisAtom, ggData] ELSE thisRegEvent.eventProc[ggData, thisEvent]; ENDLOOP; } ELSE {}; -- there is nothing to do again } ELSE { SELECT GetEventClass[atom] FROM select => ggData.justSawSelect ¬ TRUE; action => { IF ggData.justSawSelect THEN { GGCoreOps.FlushEventListt[ggData.lastEvents]; ggData.justSawSelect ¬ FALSE; }; GGCoreOps.AppendEvent[event, ggData.lastEvents]; }; suppress => {}; -- $During. Ignore it. neutral => { IF ggData.justSawSelect THEN {} -- this is the during or end of a select operation ELSE GGCoreOps.AppendEvent[event, ggData.lastEvents]; }; ENDCASE => ERROR; IF GGUserInput.GetUserTraceOn[] THEN PrintUserTrace[ggData, regEvent.eventProc, event]; regEvent.eventProc[ggData, event]; }; }; }; EventClass: TYPE = {select, neutral, action, suppress}; GetEventClass: PROC [atom: ATOM] RETURNS [eventClass: EventClass] = { IF ( atom = $During OR atom = $GuardUp OR atom = $MouseUp OR atom = $AllUp OR atom = $SawTextFinish OR atom = $SawMouseFinish ) THEN RETURN [neutral]; IF ( atom = $StartSelectWithBox OR atom = $StartSelectJoint OR atom = $StartExtSelectJoint OR atom = $StartSelectSegment OR atom = $StartExtSelectSegment OR atom = $StartSelectTrajectory OR atom = $StartExtSelectTrajectory OR atom = $StartSelectTopLevel OR atom = $StartExtSelectTopLevel OR atom = $StartExtendSelection OR atom = $StartDeselectJoint OR atom = $StartDeselectSegment OR atom = $StartDeselectTrajectory OR atom = $StartDeselectTopLevel OR atom = $CycleSelection OR atom = $AreaSelectNew OR atom = $AreaSelectNewAndDelete OR atom = $SelectAll OR atom = $AreaSelectDegenerate OR atom = $SelectCoincident OR atom = $SelectUnseeableSegs OR atom = $SelectUnseeableObjs ) THEN RETURN [select]; IF ( atom = $StartCaretPos OR atom = $StartAdd OR atom = $StartBox OR atom = $StartDrag OR atom = $StartCopyAndDrag OR atom = $StartAddAndDrag OR atom = $StartRotate OR atom = $StartScale OR atom = $StartSixPoint ) THEN RETURN [action]; IF ( atom = $OneZoom OR atom = $OneScroll ) THEN RETURN [suppress]; -- added November 4, 1992. KAP. RETURN [action]; }; NotYetImplementedMessage: PROC [atom: ATOM, ggData: GGData] = { Feedback.Append[ggData.router, begin, $Warning, "User event "]; Feedback.Append[ggData.router, middle, $Warning, Atom.GetPName[atom]]; Feedback.Append[ggData.router, end, $Warning, " is not yet implemented"]; }; CheckForSelectedRope: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { IF event.rest = NIL THEN { -- interactive call r: Rope.ROPE ¬ GGViewerOps.GetSelectionContents[]; newAction ¬ LIST[atom, r]; } ELSE IF ISTYPE[event.rest.first, REF TEXT] THEN { -- TIP table call newAction ¬ CONS[atom, CONS[Rope.FromRefText[NARROW[event.rest.first]], event.rest.rest]]; } ELSE newAction ¬ event; -- SessionLog call }; CheckForSelectedRope2: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { IF event.rest = NIL THEN ERROR; IF event.rest.rest = NIL THEN { -- interactive call r: Rope.ROPE ¬ GGViewerOps.GetSelectionContents[]; newAction ¬ LIST[atom, event.rest.first, r]; } ELSE IF ISTYPE[event.rest.rest.first, REF TEXT] THEN { -- TIP table call newAction ¬ LIST[atom, event.rest.first, Rope.FromRefText[NARROW[event.rest.rest.first]], event.rest.rest.rest]; } ELSE newAction ¬ event; -- SessionLog call }; CheckForSelectedReal: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { rope: Rope.ROPE; real: REAL; IF event.rest = NIL THEN { -- interactive call rope ¬ GGViewerOps.GetSelectionContents[]; real ¬ Convert.RealFromRope[rope ! Convert.Error => {real ¬ Real.LargestNumber; CONTINUE}]; newAction ¬ LIST[atom, NEW[REAL ¬ real]]; } ELSE IF ISTYPE[event.rest.first, REF TEXT] THEN { -- TIP table call rope ¬ Rope.FromRefText[NARROW[event.rest.first]]; real ¬ Convert.RealFromRope[rope ! Convert.Error => {real ¬ Real.LargestNumber; CONTINUE}]; newAction ¬ LIST[atom, NEW[REAL ¬ real]]; } ELSE newAction ¬ event; -- SessionLog call }; CheckForSelectedCard: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { rope: Rope.ROPE; card: CARD; IF event.rest = NIL THEN { -- interactive call rope ¬ GGViewerOps.GetSelectionContents[]; card ¬ IO.GetCard[IO.RIS[rope] ! IO.EndOfStream, IO.Error => {card ¬ LAST[CARD]; CONTINUE}]; newAction ¬ LIST[atom, NEW[CARD ¬ card]]; } ELSE IF ISTYPE[event.rest.first, REF CARD] THEN { -- TIP table call or SessionLog call newAction ¬ event; } ELSE ERROR; }; CheckForSelectedInt: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { rope: Rope.ROPE; int: INT; IF event.rest = NIL THEN { -- interactive call rope ¬ GGViewerOps.GetSelectionContents[]; int ¬ IO.GetInt[IO.RIS[rope] ! IO.EndOfStream, IO.Error => {int ¬ LAST[INT]; CONTINUE}]; newAction ¬ LIST[atom, NEW[INT ¬ int]]; } ELSE { WITH event.rest.first SELECT FROM int: REF INT => newAction ¬ event; -- TIP table call or SessionLog call card: REF CARD => newAction ¬ List.Append[LIST[atom, NEW[INT ¬ card­]], event.rest.rest]; -- type coersion ENDCASE => ERROR; }; }; CheckForActualExt: PROC [atom: ATOM, event: LIST OF REF ANY] RETURNS [newAction: LIST OF REF ANY] = { IF event.rest=NIL OR NOT ISTYPE[event.rest.first, REF GGUserInput.ExternalRec] THEN ERROR; newAction ¬ event; }; RegisteredEvent: TYPE = REF RegisteredEventObj; RegisteredEventObj: TYPE = RECORD [ eventProc: UserInputProc, argType: GGUserInput.ArgumentType, causeMouseEventsToComplete: BOOL ]; RegisterAction: PUBLIC PROC [atom: ATOM, eventProc: UserInputProc, argType: GGUserInput.ArgumentType, causeMouseEventsToComplete: BOOL ¬ TRUE, ensureUnique: BOOL ¬ TRUE] = { regEvent: RegisteredEvent ¬ NEW[RegisteredEventObj ¬ [eventProc, argType, causeMouseEventsToComplete]]; justInserted: BOOL ¬ RefTab.Insert[eventTable, atom, regEvent]; IF NOT justInserted THEN [] ¬ RefTab.Replace[eventTable, atom, regEvent]; }; FetchAction: PROC [atom: ATOM] RETURNS [RegisteredEvent] ~ { WITH RefTab.Fetch[eventTable, atom].val SELECT FROM regEvent: RegisteredEvent => RETURN[regEvent]; ENDCASE => RETURN[NIL]; }; LookAtProfile: PUBLIC UserProfile.ProfileChangedProc = { gravExtent: REAL; -- in inches defaultHistorySize: INT; heuristics: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.Heuristics", default: FALSE]; quickClickMode: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.QuickClickEnable", default: FALSE]; useLatestIPVersion: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.UseLatestIPVersion", default: FALSE]; autoOpenTypescript: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.AutoOpenTypescript", default: TRUE]; autoOpenHistory: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.AutoOpenHistory", default: TRUE]; autoScriptingOn: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.AutoScriptingOn", default: FALSE]; separateControlPanel: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.SeparateControlPanel", default: FALSE]; defaultIncludeIPBy: Rope.ROPE ¬ UserProfile.Token[key: "Gargoyle.DefaultIncludeIPBy", default: "Reference"]; holdThatTiger: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.HoldThatTiger", default: FALSE]; newBoxesUnfilled: BOOL ¬ UserProfile.Boolean[key: "Gargoyle.NewBoxesUnfilled", default: FALSE]; defaultHistorySize ¬ Convert.IntFromRope[UserProfile.Token[key: "Gargoyle.DefaultHistorySize", default: "40"] ! Convert.Error => IF reason = syntax THEN {defaultHistorySize ¬ -1; CONTINUE;} ELSE REJECT]; gravExtent ¬ Convert.RealFromRope[UserProfile.Token[key: "Gargoyle.GravityExtent", default: "-1.0"] ! Convert.Error => IF reason = syntax THEN {gravExtent ¬ -1.0; CONTINUE;} ELSE REJECT]; IF gravExtent=-1.0 THEN gravExtent ¬ 25.0/72.0; IF defaultHistorySize<1 THEN defaultHistorySize ¬ IF defaultHistorySize=0 THEN 1 ELSE 40; SetDefaultHeuristics[on: heuristics]; SetDefaultGravityExtent[inches: gravExtent]; GGState.SetQuickClickMode[quickClickMode]; SetDefaultUseLatestIPVersion[useLatestIPVersion]; SetAutoOpenTypescript[autoOpenTypescript]; SetAutoOpenHistory[autoOpenHistory]; SetDefaultHistorySize[defaultHistorySize]; SetAutoScriptingOn[autoScriptingOn]; SetSeparateControlPanel[separateControlPanel]; SetHoldThatTiger[holdThatTiger]; SetNewBoxesUnfilled[newBoxesUnfilled]; SetDefaultIncludeIPByValue[Rope.Equal[defaultIncludeIPBy, "Value", FALSE]]; BEGIN -- set the default default font description: Rope.ROPE ¬ UserProfile.Token[key: "Gargoyle.DefaultDefaultFont", default: NIL]; descriptionStream: IO.STREAM; defaultFont: FontData; IF description = NIL THEN description ¬ "xerox/xc1-2-2/helvetica [r1: 0.0 s: [10.0 10.0] r2: 0.0] 1.0 1.0"; descriptionStream ¬ IO.RIS[description]; defaultFont ¬ GGFont.ParseFontData[inStream: descriptionStream, literalP: TRUE, transformP: TRUE, storedSizeP: TRUE, designSizeP: TRUE]; SetDefaultDefaultFont[defaultFont]; END; IF reason#firstTime THEN GGWindow.InitIcons[]; -- don't do this on first registering this proc }; MasterData: TYPE = REF MasterDataObj; MasterDataObj: TYPE = RECORD [ defaultGravityExtent: REAL ¬ 25.0, -- in screen dots defaultHeuristics: BOOL ¬ TRUE, objectsBeingCopied: LIST OF REF ANY, -- for copying objects from viewer to viewer, defaultDefaultFont: FontData, autoOpenTypescript: BOOL ¬ TRUE, autoOpenHistory: BOOL ¬ TRUE, defaultHistorySize: INT ¬ 40, autoScriptingOn: BOOL ¬ TRUE, separateControlPanel: BOOL ¬ FALSE, defaultIncludeIPByValue: BOOL ¬ FALSE, holdThatTiger: BOOL ¬ FALSE, newBoxesUnfilled: BOOL ¬ FALSE, turboOn: BOOL ¬ FALSE, userTraceOn: BOOL ¬ FALSE ]; SetUserTraceOn: PUBLIC PROC [on: BOOL] = { masterData.userTraceOn ¬ on; }; GetUserTraceOn: PUBLIC PROC RETURNS [on: BOOL] = { on ¬ masterData.userTraceOn; }; SetDefaultHeuristics: PUBLIC PROC [on: BOOL] = { masterData.defaultHeuristics ¬ on; }; GetDefaultHeuristics: PUBLIC PROC RETURNS [on: BOOL] = { on ¬ masterData.defaultHeuristics; }; SetDefaultGravityExtent: PUBLIC PROC [inches: REAL] = { masterData.defaultGravityExtent ¬ inches*72.0; }; GetDefaultGravityExtent: PUBLIC PROC RETURNS [screenDots: REAL] = { screenDots ¬ masterData.defaultGravityExtent; }; SetDefaultUseLatestIPVersion: PUBLIC PROC [useLatestIPVersion: BOOL] = { GGSlice.SetDefaultUseLatestIPVersion[useLatestIPVersion]; }; GetDefaultUseLatestIPVersion: PUBLIC PROC [] RETURNS [useLatestIPVersion: BOOL] = { RETURN[GGSlice.GetDefaultUseLatestIPVersion[]]; }; SetDefaultDefaultFont: PUBLIC PROC [font: FontData] = { masterData.defaultDefaultFont ¬ font; }; GetDefaultDefaultFont: PUBLIC PROC RETURNS [font: FontData] = { font ¬ masterData.defaultDefaultFont; }; SetAutoOpenTypescript: PUBLIC PROC [autoOpenTypescript: BOOL] = { masterData.autoOpenTypescript ¬ autoOpenTypescript; }; GetAutoOpenTypescript: PUBLIC PROC [] RETURNS [autoOpenTypescript: BOOL] = { autoOpenTypescript ¬ masterData.autoOpenTypescript; }; SetAutoOpenHistory: PUBLIC PROC [autoOpenHistory: BOOL] = { masterData.autoOpenHistory ¬ autoOpenHistory; }; GetAutoOpenHistory: PUBLIC PROC [] RETURNS [autoOpenHistory: BOOL] = { autoOpenHistory ¬ masterData.autoOpenHistory; }; SetDefaultHistorySize: PUBLIC PROC [defaultHistorySize: INT] = { masterData.defaultHistorySize ¬ defaultHistorySize; }; GetDefaultHistorySize: PUBLIC PROC RETURNS [defaultHistorySize: INT] = { defaultHistorySize ¬ masterData.defaultHistorySize; }; SetAutoScriptingOn: PUBLIC PROC [autoScriptingOn: BOOL] = { masterData.autoScriptingOn ¬ autoScriptingOn; }; GetAutoScriptingOn: PUBLIC PROC [] RETURNS [autoScriptingOn: BOOL] = { autoScriptingOn ¬ masterData.autoScriptingOn; }; SetSeparateControlPanel: PUBLIC PROC [separateControlPanel: BOOL] = { masterData.separateControlPanel ¬ separateControlPanel; }; GetSeparateControlPanel: PUBLIC PROC [] RETURNS [separateControlPanel: BOOL] = { separateControlPanel ¬ masterData.separateControlPanel; }; SetDefaultIncludeIPByValue: PUBLIC PROC [defaultIncludeIPByValue: BOOL] = { masterData.defaultIncludeIPByValue ¬ defaultIncludeIPByValue; }; GetDefaultIncludeIPByValue: PUBLIC PROC [] RETURNS [defaultIncludeIPByValue: BOOL] = { defaultIncludeIPByValue ¬ masterData.defaultIncludeIPByValue; }; SetHoldThatTiger: PUBLIC PROC [holdThatTiger: BOOL] = { masterData.holdThatTiger ¬ holdThatTiger; }; GetHoldThatTiger: PUBLIC PROC [] RETURNS [holdThatTiger: BOOL] = { holdThatTiger ¬ masterData.holdThatTiger; }; SetNewBoxesUnfilled: PUBLIC PROC [newBoxesUnfilled: BOOL] = { masterData.newBoxesUnfilled ¬ newBoxesUnfilled; }; GetNewBoxesUnfilled: PUBLIC PROC [] RETURNS [newBoxesUnfilled: BOOL] = { newBoxesUnfilled ¬ masterData.newBoxesUnfilled; }; masterData: MasterData; eventTable: RefTab.Ref; masterData ¬ NEW[MasterDataObj]; UserProfile.CallWhenProfileChanges[LookAtProfile]; eventTable ¬ RefTab.Create[255]; END. δGGUserImpl.mesa Copyright Σ 1986, 1989, 1991, 1992 by Xerox Corporation. All rights reserved. Contents: Routines for reading the Gargoyle entries in the user profile and setting Gargoyle options. Also, procedures which handle user actions (menu buttons and mouse events). Kurlander August 24, 1986 1:00:26 pm PDT Goodisman, August 11, 1989 4:59:38 pm PDT Pier, November 4, 1992 3:36 pm PST Bier, August 20, 1993 7:12 pm PDT Doug Wyatt, April 20, 1992 12:24 pm PDT ExternalRec is used by applications external to Gargoyle to return results to those applications. Clients should call EventNotify with a registered external proc name and a REF to an ExternalRec on a two-element event list. Client should then call WaitExternal in a loop checking their particular "valid" bit. Gargoyle completes the desired action, puts results in "results", and sets "valid" to TRUE. Gargoyle external procs will call BroadcastExternal when actions complete. Before the Queue (done by InputNotifier, Menu Process or Playback Process) From Buttons and Menus Used by several menu classes as the procedure to call when a menu click occurs. Used by several menu classes as the procedure to call when a menu click occurs. From Playback Scripts Regular Input Notification Called by the TIP table machinery when an action is received from mouse or keyboard. Self is an ActionArea. Problem: If a gargoyle scene changes from active to inactive due to a queued action, the length of the queue will determine when Gargoyle gets the input focus. An action has been received from BiScroller (e.g. from the ScrollBar). The event will be in one of two forms: 1) LIST[REF CHAR]. 2) LIST[ATOM, ... ]. Need our own copy of the ref and char, because the system reuses the storage. DKW: Yecch! Maybe the RegisteredEvent could contain this information. Feedback.PutFL[ggData.router, oneLiner, $Typescript, "[%g %g: %g] ", LIST[ [real[originViewer.x]], [real[originViewer.y]], [real[scalar]] ]]; DKW: REF VEC values come from Biscrollers, which treats them as immutable, so the following is unnecessary. Maybe this code is left over from pre-Biscrollers days; TIPScreenCoords values straight from TIP are mutable, and would have to be copied. none => { tail: LIST OF REF ANY; Copy all of the VECs since the TIP table reuses the storage. tail _ newEvent _ CONS[event.first, NIL]; FOR list: LIST OF REF ANY _ event.rest, list.rest UNTIL list = NIL DO IF ISTYPE[list.first, REF VEC] THEN { mousePlace: REF VEC _ NARROW[list.first]; tail.rest _ CONS[NEW[VEC _ [mousePlace.x, mousePlace.y]], NIL]; } ELSE tail.rest _ CONS[list.first, NIL]; tail _ tail.rest; ENDLOOP; }; After the Queue (Done by SlackProcess) procTV: AMTypes.TV _ AMBridge.TVForProc[eventProc]; moduleTV: AMTypes.TV _ AMTypes.GlobalParent[procTV]; procName: Rope.ROPE _ AMTypes.TVToName[procTV]; moduleName: Rope.ROPE _ AMTypes.TVToName[moduleTV]; IF ( -- oops. You can't suppress all of the Durings. You must not suppress the last one for a given operation. Yuk. atom = $During ) THEN RETURN [suppress]; Utility Routines Expect a rope as the second argument. If the event has already been registered and ensureUnique is true, an error will be signalled. If the event has been registered and ensureUnique is FALSE, the action will be reregistered. IF ensureUnique THEN SIGNAL Problem[msg: IO.PutFR1["Event %g was already registered in Gargoyle's event table.", [rope[Atom.GetPName[atom]]]]] ELSE [] ¬ RefTab.Replace[eventTable, atom, regEvent]; -- register again GGUserProfile [reason: UserProfile.ProfileChangeReason] formerly "xerox/pressfonts/helvetica-mrr [r1: 0.0 s: [10.0 10.0] r2: 0.0] 1.0 1.0" No matter how many Gargoyle viewers are present, there is only one MasterData. When a new viewer is created, should heuristics be turned on? When a new viewer is created, should heuristics be turned on? When a new viewer is created, how strong should its gravity be? When a new viewer is created, how strong should its gravity be? interval _ CodeTimer.CreateInterval[$UserInput]; CodeTimer.AddInt[interval, $Gargoyle]; Κ–(cedarcode) style•NewlineDelimiter ˜codešœ™Kšœ ΟeœC™NKšΟnœ«™³Kšœ%Οk™(K™)K™"K™"K™'K™—šŸ ˜ JšœΦŸœƒ˜ΫK˜—šž œŸœŸ˜JšŸœΩŸœA˜£KšŸœ0Ÿ˜š œŸœ ŸœŸœŸœ˜%šœ Οb œ˜5Kšžœ˜™Ÿ—Kšœ$˜$K˜—K˜.K˜K˜—š žœŸœŸœŸœŸœŸœ˜KKšœF™Fš žœŸœ ŸœŸœŸœŸœ˜BKšœŸœŸœ˜"šŸœŸœ˜KšœŸœŸœŸœ ˜8Kš œŸœŸœŸœŸœ -˜[KšœŸœ˜K˜—J˜$K˜—š ŸœŸœŸœŸœŸœŸœ˜*š ŸœŸœŸœŸœŸœŸœŸ˜˜JK˜šŸœŸœŸœ˜šŸœŸœŸ˜!KšœŸœŸœ ˜KšŸœ˜—K˜—Kšœ ˜Kšœ6 7˜mKšœEŸœ£œ£œ™Kšœž œ+£œ ˜XK˜—K˜—K˜—KšŸœŸœ˜—KšœŸœ˜K˜K˜—Kšœ ŸœŸœ˜#šœŸœŸœ˜Kšœ Ÿ˜K˜K˜—Kšœ ŸœŸœ˜šž œŸœŸœŸœŸœŸœŸœŸœŸœ˜ZKšœ)˜)K˜Kšœ& ˜,KšŸœ ŸœŸœ* 1˜‹KšœH˜HK˜K˜—šžœŸœ ŸœŸœŸœŸœ-Ÿœ ŸœŸœŸœŸœ˜KšœŸœŸœ˜!šŸœŸ˜˜KšœŸœΒœ&™χ—™ Kš œŸœŸœŸœŸœ™K™