DIRECTORY Atom, BasicTime, BiScrollers, CodeTimer, ColorTool, CubicSplines, Feedback, FeedbackOps, FeedbackTypes, FileNames, FS, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGControlPanelTypes, GGCoreOps, GGDescribe, GGEvent, GGEventExtras, GGFileIn, GGFileOps, GGFileOut, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGRefreshTypes, GGScene, GGSegmentTypes, GGSelect, GGSessionLog, GGShapes, GGSlice, GGSliceOps, GGState, GGStateExtras, GGUIUtility, GGUserInput, GGUserProfile, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorFns, ImagerDitherContext, IO, NamedColors, Random, Real, RealFns, Rope, SlackProcess, SystemNames, TiogaOpsDefs, ViewersWorld, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS Atom, BasicTime, CodeTimer, ColorTool, Feedback, FeedbackOps, FileNames, FS, GGAlign, GGCaret, GGCoreOps, GGDescribe, GGEvent, GGFileIn, GGFileOps, GGFileOut, GGHistory, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGScene, GGSelect, GGSessionLog, GGSlice, GGSliceOps, GGState, GGStateExtras, GGUIUtility, GGUserInput, GGUserProfile, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorFns, IO, NamedColors, Random, Real, RealFns, Rope, SlackProcess, SystemNames, ViewersWorld, ViewerTools EXPORTS GGEvent, GGEventExtras, GGInterfaceTypes = BEGIN AlignBag: TYPE = GGInterfaceTypes.AlignBag; BoundBox: TYPE = GGBoundBox.BoundBox; ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes FeatureData: TYPE = GGInterfaceTypes.FeatureData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; GGData: TYPE = GGInterfaceTypes.GGData; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; Point: TYPE = GGBasicTypes.Point; RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj; ROPE: TYPE = Rope.ROPE; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TriggerBag: TYPE = GGInterfaceTypes.TriggerBag; UserInputProc: TYPE = GGEvent.UserInputProc; Vector: TYPE = GGBasicTypes.Vector; WalkProc: TYPE = GGModelTypes.WalkProc; OpenAutoScript: PUBLIC PROC [ggData: GGData, openNoMatterWhat: BOOL _ FALSE] = { IF GGUserProfile.GetAutoScriptingOn[] THEN { time: BasicTime.Unpacked _ BasicTime.Unpack[BasicTime.Now[]]; userName: Rope.ROPE _ SystemNames.UserName[]; name: Rope.ROPE _ IO.PutFR["%g%02g%02g%02g-%02g-", [rope[userName]], [integer[time.year-1900]], [integer[ORD[time.month]+1]], [integer[time.day]], [integer[time.hour]] ]; IF NOT openNoMatterWhat AND ggData.debug.autoScriptActionCount = ggData.debug.lastAutoScriptActionCount THEN RETURN; -- the user is just repeatedly hitting Clear ggData.debug.lastAutoScriptActionCount _ ggData.debug.autoScriptActionCount; name _ Rope.Concat[name, IO.PutFR["%02g-%02g.script", [integer[time.minute]], [integer[time.second]] ] ]; [ggData.debug.autoScriptStream, ggData.debug.autoScriptName] _ GGSessionLog.OpenScript[name, ggData, ggData.debug.autoScriptStream, ggData.debug.autoScriptName]; GGCoreOps.AppendRope[ggData.debug.autoScriptName, ggData.debug.autoScriptNames]; [] _ SlackProcess.EnableSessionLogging[ggData.slackHandle]; }; }; FileNameFromEvent: PUBLIC PROC [opName: Rope.ROPE, event: LIST OF REF ANY, currentWDir: Rope.ROPE, router: MsgRouter, emergency: BOOL _ FALSE] RETURNS [fileName, fullName: Rope.ROPE _ NIL, success: BOOL _ FALSE, versionSpecified: BOOL _ FALSE, noName: BOOL _ FALSE] = { RopeFromRef: PROC [ref: REF ANY] RETURNS [rope: Rope.ROPE] ~ { WITH ref SELECT FROM text: REF TEXT => RETURN[Rope.FromRefText[text] ]; r: Rope.ROPE => RETURN[r]; ENDCASE => ERROR; }; fileName _ IF event#NIL AND event.first#NIL THEN RopeFromRef[event.first] ELSE NIL; IF Rope.Equal[fileName, NIL] THEN noName _ TRUE ELSE [fullName, success, versionSpecified] _ GGFileOps.GetGargoyleFileName[opName, fileName, currentWDir, router, emergency]; }; Get: PUBLIC UserInputProc = { fullName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; CodeTimer.StartInt[$Get, $Gargoyle]; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent["Get", event.rest, ggData.currentWDir, ggData.router]; IF noName THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: no filename specified"] ELSE IF success THEN { startTime, endTime: BasicTime.GMT; totalTime: INT; Feedback.Append[ggData.router, begin, $Statistics, "Clearing ..."]; startTime _ BasicTime.Now[]; ClearAux[event, ggData]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.Append[ggData.router, end, $Statistics, IO.PutFR[" done (%r)", [integer[totalTime]] ]]; ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; -- clear script list GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData, event]; GGState.NotNewVersion[ggData, $clean]; -- could be folded in to GGState.ClearAdvisory ?? OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. }; CodeTimer.StopInt[$Get, $Gargoyle]; }; Store: PUBLIC UserInputProc = { tKeep: CARDINAL _ 0; f: IO.STREAM; fullName, fsName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; startTime, endTime: BasicTime.GMT; totalTime: INT; msgRope, opName: Rope.ROPE; ofile: FS.OpenFile; emergency: BOOL _ event.first=$Emergency; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent[Atom.GetPName[NARROW[event.first]], event.rest, ggData.currentWDir, ggData.router, emergency]; IF noName AND NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: no filename specified"] ELSE IF versionSpecified AND NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: store to explicit version forbidden"] ELSE IF success THEN { tKeep _ FS.FileInfo[name: fullName ! FS.Error => CONTINUE].keep; ofile _ FS.Create[name: fullName, setPages: FALSE, setKeep: TRUE, keep: MAX[tKeep, 2] ! FS.Error => { msgRope _ IO.PutFR["%g failed: could not create: %g [FS.Error: %g]", [rope[opName]], [rope[fullName]], [rope[error.explanation]]]; IF NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, msgRope]; GOTO Abort; }; ]; fsName _ FS.GetName[ofile].fullFName; f _ FS.StreamFromOpenFile[openFile: ofile, accessRights: $write]; opName _ IF event.first = NIL THEN "someSave" ELSE Atom.GetPName[NARROW[event.first]]; msgRope _ IO.PutFR["%g: %g . . . ", [rope[opName]], [rope[fullName]]]; IF NOT emergency THEN Feedback.Append[ggData.router, begin, $Statistics, msgRope]; GGEvent.SawTextFinish[ggData, NIL]; -- do this before fileout startTime _ BasicTime.Now[]; GGFileOut.FileoutSceneAndOptions[f, ggData, fullName]; GGUIUtility.SafeClose[f, ggData.router]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; IF NOT emergency THEN Feedback.Append[ggData.router, end, $Statistics, msgRope]; GGState.StoreAdvisory[ggData, fsName, versionSpecified]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; GGState.NotNewVersion[ggData, $clean]; OpenAutoScript[ggData, FALSE]; -- close the current script. Open a new one and add to list. EXITS Abort => NULL; }; }; CleanVersion: UserInputProc = { GGState.NotNewVersion[ggData, $clean]; }; Save: PUBLIC UserInputProc = { IF GGState.GetFullName[ggData]#NIL THEN Store[event: LIST[$Save, FileNames.StripVersionNumber[GGState.GetFullName[ggData]]], ggData: ggData] ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "Save failed: can't save unnamed viewer; try Store"]; }; Destroy: PUBLIC UserInputProc = { ggData.controls _ NIL; -- prevent unwanted actions on active control panels ClearAux[event, ggData]; -- for garbage collection }; Clear: PUBLIC UserInputProc = { ClearAux[event, ggData]; IF event.first=$Clear THEN GGEvent.StandardAlignments[ggData, event]; GGState.ClearAdvisory[ggData]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; GGEvent.SawTextFinish[ggData, NIL]; IF event.first=$Clear THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; GGState.NotNewVersion[ggData, $clear]; -- could be folded in to GGState.ClearAdvisory ?? ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. IF event.first=$Clear THEN Feedback.Append[ggData.router, oneLiner, $Feedback, "Clear: completed"]; }; ConfirmClear: UserInputProc = { Feedback.Append[ggData.router, oneLiner, $Confirm, "Confirm deletion of all objects"]; }; Reset: PUBLIC UserInputProc = { IF GGState.AdviseRestore[ggData] THEN { fileName: Rope.ROPE _ GGState.GetFullName[ggData]; CodeTimer.StartInt[$Restore, $Gargoyle]; ClearAux[event, ggData]; ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; -- clear script list GetMergeAux[fileName, FALSE, $Get, "Restoring", ggData, event]; -- makes new script list GGState.NotNewVersion[ggData, $clean]; OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. CodeTimer.StopInt[$Restore, $Gargoyle]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Restore: completed"]; }; }; ConfirmReset: UserInputProc = { filename: Rope.ROPE _ GGState.GetFullName[ggData]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Restore failed: no file loaded. Do not confirm."] ELSE Feedback.Append[ggData.router, oneLiner, $Confirm, "Confirm restore to original file"]; }; ConfirmGet: UserInputProc = { fullName: Rope.ROPE; success: BOOL _ FALSE; filename: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: no filename specified. Do not confirm."] ELSE { [fullName, success, ----] _ GGFileOps.GetGargoyleFileName["Get", filename, ggData.currentWDir, ggData.router, FALSE]; IF NOT success THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: bad filename specified. Do not confirm."] ELSE Feedback.PutF[ggData.router, oneLiner, $Confirm, "Confirm Get of %g as a new scene", [rope[fullName]] ]; }; }; FileExists: PROC [fileName: Rope.ROPE] RETURNS [answer: BOOL _ TRUE] = { [] _ FS.FileInfo[fileName ! FS.Error => IF error.code=$unknownFile THEN { answer _ FALSE; CONTINUE }; ]; }; ConfirmStore: UserInputProc = { fullName: Rope.ROPE; success: BOOL _ FALSE; filename: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: no filename specified. Do not confirm."] ELSE { [fullName, success, ----] _ GGFileOps.GetGargoyleFileName["Store", filename, ggData.currentWDir, ggData.router, FALSE]; IF NOT success THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: bad filename specified. Do not confirm."] ELSE Feedback.PutF[ggData.router, oneLiner, $Confirm, "Confirm Store to %g [%g File]", [rope[fullName]], [rope[IF FileExists[fullName] THEN "Old" ELSE "New"]] ]; }; }; ClearAux: PROC [event: LIST OF REF ANY, ggData: GGData] = { GGState.SetActive[ggData, FALSE]; -- for now. This will prevent most (but not all) race conditions with the Input Notify process. ggData.refresh.overlayList _ NIL; GGState.SetExtendMode[ggData, none]; GGState.SetSliceToExtend[ggData, NIL]; -- forget sliceToExtend ggData.caret _ GGCaret.Create[]; -- forget caret and attractor ggData.anchor _ GGCaret.Create[]; -- forget anchor ggData.behavior.activeDoc _ NIL; -- next time this field is needed it will be recomputed GGHistory.ResetHistory[ggData]; -- do this before MakeSceneGarbage, in order to synchronize with any outstanding advance captures by history mechanism GGScene.MakeSceneGarbage[ggData.scene]; -- important unlink of circular garbage GGAlign.MakeFiltersGarbage[ggData.hitTest]; -- important unlink of circular garbage ggData.scene _ GGScene.CreateScene[]; -- drop old scene refs on floor ggData.rootSlice _ GGSlice.MakeCircleSlice[[999.0, 999.0], [99.0, 99.0]].slice; ggData.aborted _ ALL[FALSE]; ggData.refresh.dragInProgress _ FALSE; ggData.refresh.caretIsMoving _ FALSE; ggData.refresh.overlayList _ NIL; ggData.refresh.orderedOverlayList _ NIL; ggData.refresh.addedObject _ NIL; ggData.refresh.recentFeature _ NIL; ggData.refresh.textInProgress _ NIL; ggData.refresh.areaFollowColorTool _ FALSE; ggData.refresh.lineFollowColorTool _ FALSE; GGRefresh.InvalidateForeground[ggData]; GGRefresh.InvalidateBackground[ggData]; }; MergeAll: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeAll, "MergeAll"]; }; MergeShapes: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeShapes, "MergeShapes"]; }; MergeOptions: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeOptions, "MergeOptions"]; }; MergeAlignments: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeAlignments, "MergeAlignments"]; }; MergeAux: PROC [event: LIST OF REF ANY, ggData: GGData, op: ATOM, opName: Rope.ROPE] = { fullName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent[opName, event.rest, ggData.currentWDir, ggData.router]; IF noName THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Merge failed: no filename specified"] ELSE IF success THEN GetMergeAux[fullName, versionSpecified, op, opName, ggData, event]; }; GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOL _ FALSE, op: ATOM, opName: Rope.ROPE, ggData: GGData, event: LIST OF REF ANY] = { f: IO.STREAM; fsName: Rope.ROPE; startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; success: BOOL _ FALSE; successRope: Rope.ROPE; failedRope: Rope.ROPE = "failed: malformed file"; Feedback.PutF[ggData.router, begin, $Statistics, " Opening %g ...", [rope[fullName]]]; startTime _ BasicTime.Now[]; f _ FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => { Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: could not find %g (FS or IO Error)", [rope[opName]], [rope[fullName]]]; GOTO Abort; };]; fsName _ FS.GetName[FS.OpenFileFromStream[f]].fullFName; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.PutF[ggData.router, end, $Statistics, " done (%r)", [integer[totalTime]]]; Feedback.PutF[ggData.router, begin, $Statistics, "%g %g . . . ", [rope[opName]], [rope[fsName]]]; startTime _ BasicTime.Now[]; BEGIN SELECT op FROM $Get => { GGEvent.ClearAlignments[ggData, LIST[NIL]]; [success, successRope] _ GGFileIn.FileinSceneAndOptions[f, ggData, FALSE, FALSE]; -- NIL if filein aborted IF success THEN { directory: ROPE _ FileNames.Directory[fsName]; GGStateExtras.SetWorkingDirectory[ggData, directory]; } ELSE { -- filein aborted Clear[ggData, LIST[$ClearForFailedGet]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeAll => { [success, successRope] _ GGFileIn.FileinSceneAndOptions[f, ggData, TRUE, TRUE]; -- NIL if filein aborted IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeShapes => { [success, successRope] _ GGFileIn.FileinSceneOnly[f, ggData.scene, TRUE, ggData.camera]; -- NIL if filein aborted IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeOptions => { [success, successRope] _ GGFileIn.FileinOptionsOnly[f, ggData, FALSE]; IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeAlignments => { [success, successRope] _ GGFileIn.FileinOptionsOnly[f, ggData, TRUE]; IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; ENDCASE => ERROR; GGUIUtility.SafeClose[f, ggData.router]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.PutF[ggData.router, end, $Statistics, " Done in time (%r)", [integer[totalTime]]]; IF op=$Get THEN { -- update viewer name on Get GGState.GetAdvisory[ggData, fsName, versionSpecified]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; }; GGEvent.SawTextFinish[ggData, LIST[$SawTextFinish]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSceneNoBuffer, ggData: ggData, remake: triggerBag, edited: op#$Get, okToSkipCapture: FALSE]; EXITS FileinFailed => GGUIUtility.SafeClose[f, ggData.router]; END; EXITS Abort => GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSceneNoBuffer, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE]; -- needed in case of failure to read to clean out bags }; AddToGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "AddToGroup failed: no objects selected"] ELSE IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "AddToGroup failed: can't AddToGroup, no group name selected"] ELSE { AddSegments: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO duplicate: BOOL _ FALSE; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN { duplicate _ TRUE; -- already in this group EXIT; }; ENDLOOP; IF NOT duplicate THEN seg.props _ CONS[name, seg.props]; someAddition _ TRUE; ENDLOOP; }; someAddition: BOOL _ FALSE; scene: Scene _ ggData.scene; [] _ GGScene.WalkSelectedSlices[scene, first, AddSegments, normal]; Feedback.PutF[ggData.router, oneLiner, $Feedback, IF someAddition THEN "AddToGroup: added selected segments to group %g" ELSE "AddToGroup: no segments added to group %g", [rope[name]] ]; IF someAddition THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: TRUE]; }; }; SelectGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectGroup failed: can't SelectGroup, no group name selected"] ELSE { SelectSegments: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { FindProp: PROC [seg: Segment, transform: Imager.Transformation] RETURNS [keep: BOOL] = { FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; withProps: SliceDescriptor _ GGSliceOps.WalkSegments[slice, FindProp]; IF withProps#NIL THEN GGSelect.SelectSlice[withProps, ggData.scene, normal]; }; scene: Scene _ ggData.scene; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection [] _ GGScene.WalkSlices[scene, first, SelectSegments]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectGroup failed: no such group"] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectGroup: group %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; }; }; RemoveFromGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "RemoveFromGroup failed: no objects selected"] ELSE IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "RemoveFromGroup failed: can't RemoveFromGroup, no group name selected"] ELSE { RemoveSegments: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO newProps _ NIL; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps _ CONS[nextProp, newProps] ELSE someRemoval _ TRUE; ENDLOOP; seg.props _ newProps; ENDLOOP; }; someRemoval: BOOL _ FALSE; newProps: LIST OF REF ANY; scene: Scene _ ggData.scene; [] _ GGScene.WalkSelectedSlices[scene, first, RemoveSegments, normal]; Feedback.PutF[ggData.router, oneLiner, $Feedback, IF someRemoval THEN "RemoveFromGroup: removed selected segments from group %g" ELSE "RemoveFromGroup: no member segments selected to remove from group %g", [rope[name]] ]; IF someRemoval THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: TRUE]; }; }; PrintGroupsOfSelected: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowGroupsOfSelected failed: no selections to show groups"] ELSE { DoPrintGroups: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ CONS[nextProp, groupList]; ENDLOOP; ENDLOOP; }; groupList: LIST OF REF ANY; [] _ GGScene.WalkSelectedSlices[scene, first, DoPrintGroups, normal]; IF groupList#NIL THEN { Feedback.Append[ggData.router, begin, $Show, "ShowGroupsOfSelected: "]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.router, middle, $Show, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.router, end, $Show, ""]; } ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowGroupsOfSelected: no groups of selected"]; }; }; PrintAllGroups: PUBLIC UserInputProc = { groupList: LIST OF REF ANY; scene: Scene _ ggData.scene; EnumerateGroups: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { FindGroups: PROC [seg: Segment, transform: Imager.Transformation] RETURNS [keep: BOOL _ FALSE] = { FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ CONS[nextProp, groupList]; ENDLOOP; }; [] _ GGSliceOps.WalkSegments[slice, FindGroups]; }; [] _ GGScene.WalkSlices[scene, first, EnumerateGroups]; Feedback.Append[ggData.router, begin, $Show, "ShowAllGroups: "]; IF groupList#NIL THEN { FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.router, middle, $Show, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.router, end, $Show, ""]; } ELSE Feedback.Append[ggData.router, end, $Show, "no groups"]; }; Cluster: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Cluster failed: no selections to Cluster"] ELSE { AddSelectedToCluster: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { IF GGSelect.IsSelectedInPart[slice, ggData.scene, normal] THEN { justFound _ TRUE; [childList, ptr] _ GGUtility.AddSlice[slice, childList, ptr]; } ELSE { IF justFound THEN { sliceInFront _ slice; justFound _ FALSE; }; }; }; cluster: Slice _ GGSlice.CreateCluster[frozen: FALSE]; scene: Scene _ ggData.scene; childList, ptr: LIST OF Slice; sliceInFront: Slice _ NIL; priority: INT _ -1; justFound: BOOL _ FALSE; GGHistory.NewCapture["Cluster", ggData]; -- capture scene BEFORE UPDATE GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedParts: TRUE]; [childList, ptr] _ GGUtility.StartSliceList[]; [] _ GGScene.WalkSlices[scene, first, AddSelectedToCluster]; FOR list: LIST OF Slice _ childList, list.rest UNTIL list = NIL DO GGSelect.SaveSelectionsInSliceAllClasses[list.first, scene]; GGScene.DeleteSlice[scene, list.first]; GGSlice.AddChildToCluster[cluster, list.first, -1]; ENDLOOP; IF sliceInFront = NIL OR justFound THEN priority _ -1 ELSE priority _ GGScene.GetPriority[scene, sliceInFront]; GGScene.AddSlice[scene, cluster, priority]; GGSelect.ReselectSliceAllClasses[cluster, scene]; GGSelect.SelectEntireSlice[cluster, scene, normal]; GGCaret.SitOn[ggData.caret, NIL]; GGCaret.NoAttractor[ggData.caret]; GGHistory.PushCurrent[ggData]; -- push captured history event onto history list Feedback.Append[ggData.router, oneLiner, $Feedback, "Cluster: new cluster created"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; }; }; ClusterAndFreeze: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Cluster failed: no selections to Cluster"] ELSE { Cluster[ggData, event]; FreezeCluster[ggData, event]; Feedback.Append[ggData.router, oneLiner, $Feedback, "ClusterAndFreeze: new cluster created and frozen"]; }; }; UnCluster: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "UnCluster failed: no selections to UnCluster"] ELSE { BreakUpCluster: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { cluster: Slice _ sliceD.slice; childList: LIST OF Slice _ GGParent.ListChildren[cluster, first]; priority _ GGScene.GetPriority[scene, cluster]; GGSelect.SaveSelectionsInSliceAllClasses[cluster, scene]; GGScene.DeleteSlice[scene, cluster]; GGScene.AddSlices[scene, childList, priority]; FOR list: LIST OF Slice _ childList, list.rest UNTIL list = NIL DO GGSelect.ReselectSliceAllClasses[list.first, scene]; ENDLOOP; newSlices _ GGUtility.AppendSliceList[newSlices, childList]; }; priority: INT _ -1; scene: Scene _ ggData.scene; newSlices: LIST OF Slice; -- build a list then select elements after to avoid modifying selection list during WalkSelectedSlices GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGHistory.NewCapture["UnCluster", ggData]; [] _ GGScene.WalkSelectedSlices[scene, first, BreakUpCluster, normal, $Cluster]; FOR newSelections: LIST OF Slice _ newSlices, newSelections.rest UNTIL newSelections=NIL DO GGSelect.SelectEntireSlice[newSelections.first, scene, normal]; -- better be topLevel slices ENDLOOP; GGCaret.SitOn[ggData.caret, NIL]; GGCaret.NoAttractor[ggData.caret]; GGHistory.PushCurrent[ggData]; -- push captured history event onto history list Feedback.Append[ggData.router, oneLiner, $Feedback, "UnCluster: cluster unmade and components selected"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; }; }; FreezeCluster: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FreezeCluster failed: no selections to Freeze"] ELSE { DoFreeze: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSlice.SetFrozen[sliceD.slice, TRUE]; }; [] _ GGScene.WalkSelectedSlices[scene, highest, DoFreeze, normal, $Cluster]; Feedback.Append[ggData.router, oneLiner, $Complaint, "FreezeCluster failed: frozen clusters Not Yet Implemented"]; }; }; ThawCluster: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "ThawCluster failed: no selections to Thaw"] ELSE { DoThaw: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSlice.SetFrozen[sliceD.slice, FALSE]; }; [] _ GGScene.WalkSelectedSlices[scene, highest, DoThaw, normal, $Cluster]; Feedback.Append[ggData.router, oneLiner, $Feedback, "ThawCluster: selected clusters are now thawed"]; }; }; ShowFrozen: PUBLIC UserInputProc = { BEGIN Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowFrozen failed: frozen clusters Not Yet Implemented"]; RETURN; END; << frozen: BOOL _ FALSE; success: BOOL _ TRUE; sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; scene: Scene _ ggData.scene; opName: Rope.ROPE _ "ShowFrozen failed: "; DoCheckFrozen: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisFrozen: BOOL _ FALSE; IF sliceD = NIL THEN { sliceD _ thisD; frozen _ GGSlice.GetFrozen[thisD.slice]; } ELSE { thisFrozen _ GGSlice.GetFrozen[thisD.slice]; IF thisFrozen # frozen THEN done _ TRUE }; }; aborted _ GGScene.WalkSelectedSlices[scene, highest, DoCheckFrozen, normal, $Cluster]; IF aborted THEN { success _ FALSE; Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowFrozen failed: more than one frozen state is selected"]]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.Append[ggData.router, oneLiner, $Complaint, Rope.Concat["ShowFrozen: no frozen clusters are selected"]]; }; IF NOT success THEN RETURN; Feedback.PutF[ggData.router, Rope.Concat["ShowFrozen: ", GGCoreOps.BoolToRope[frozen]], oneLiner]; >> }; RGBFromRopeError: SIGNAL = CODE; CMYKFromRopeError: SIGNAL = CODE; IntensityFromRopeError: SIGNAL = CODE; ctRope: Rope.ROPE = "ColorTool operation failed: please create a ColorTool and retry"; AreaColorFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE AreaColorAux[ggData, color, GGDescribe.ColorToRope[color]]; }; }; FillHueFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE AreaColorAux[ggData, color, GGDescribe.ColorToRope[color], TRUE, $ChangeHue]; }; }; LineColorFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE LineColorAux[ggData, color, GGDescribe.ColorToRope[color]]; }; }; StrokeHueFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE LineColorAux[ggData, color, GGDescribe.ColorToRope[color], TRUE, $ChangeHue]; }; }; mapIndex: CARDINAL _ LAST[CARDINAL]; SpecialPixel: TYPE ~ ImagerDitherContext.SpecialPixel; GetSpecialColor: PROC RETURNS [color: Imager.Color _ NIL] ~ { ordinaryColor: Imager.ConstantColor; ordinaryColor _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF ordinaryColor#NIL THEN { vw: ViewersWorld.Ref _ ViewersWorld.GetViewersWorld[]; IF mapIndex=LAST[CARDINAL] THEN mapIndex _ ViewersWorld.AllocateColorMapIndex[vw, 0, NIL, NIL]; -- try to allocate a color map index to keep IF mapIndex=LAST[CARDINAL] THEN RETURN[NIL]; -- AllocateColorMapIndex failed color _ MakeSpecialColor[specialPixel: [value: mapIndex, dstFunc: null], ordinaryColor: ordinaryColor]; ColorTool.RegisterNotifyProc[$GG, TrackPatch, NIL, NIL ! ColorTool.NoColorToolViewer => CONTINUE;]; -- proc will be unregistered by SawTextFinish }; }; MakeSpecialColor: PROC [ordinaryColor: Imager.ConstantColor, specialPixel: SpecialPixel, name: Rope.ROPE _ NIL] RETURNS [Imager.SpecialColor] ~ { pixelData: REF SpecialPixel _ NEW[SpecialPixel _ specialPixel]; color: ImagerColor.SpecialColor ~ NEW[ImagerColor.ColorRep.constant.special _ [constant[special[type: $Pixel, name: name, data: pixelData, substitute: ordinaryColor]]]]; RETURN [color]; }; gamma: REAL _ 2.2; -- value stolen from Zebra ApplyGamma: PROC [v: REAL, gamma: REAL] RETURNS [BYTE] ~ { g: REAL ~ MIN[MAX[gamma, 0.01], 100.0]; uncorrected: REAL ~ MIN[MAX[v, 0.0], 1.0]; corrected: REAL ~ RealFns.Power[uncorrected, 1.0/g]; RETURN [Real.Round[MIN[MAX[corrected, 0.0], 1.0]*BYTE.LAST]]; }; TrackPatch: PROC[rgb: ImagerColor.RGB, clientData: REF] = { -- ColorTool.NotifyProc ToByte: PROC[v: REAL] RETURNS[INTEGER] = { IF v<=0.0 THEN RETURN[0]; IF v>=1.0 THEN RETURN[255]; RETURN[ApplyGamma[v, gamma]]; }; vw: ViewersWorld.Ref _ ViewersWorld.GetViewersWorld[]; IF mapIndex#LAST[CARDINAL] THEN ViewersWorld.SetColorMapEntry[vw, mapIndex, 0, ToByte[rgb.R], ToByte[rgb.G], ToByte[rgb.B] ]; }; AreaColorFollowColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; color _ GetSpecialColor[ ! ColorTool.NoColorToolViewer => CONTINUE;]; -- "animation" color; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE { ggData.refresh.areaFollowColorTool _ TRUE; AreaColorAux[ggData, color, NIL, FALSE]; Feedback.Append[ggData.router, oneLiner, $Feedback, "FollowColorTool: selected objects fill color will follow ColorTool"]; }; }; }; LineColorFollowColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; color _ GetSpecialColor[ ! ColorTool.NoColorToolViewer => CONTINUE;]; -- "animation" color; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE { ggData.refresh.lineFollowColorTool _ TRUE; LineColorAux[ggData, color, NIL, FALSE]; Feedback.Append[ggData.router, oneLiner, $Feedback, "FollowColorTool: selected objects stroke color will follow ColorTool"]; }; }; }; AreaColorToColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { success: BOOL _ FALSE; color: Imager.Color; [color, success] _ GetSelectedFillColor[ggData, "FillColorToColorTool"]; IF success THEN { noColorTool: BOOL _ FALSE; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorToColorTool: selected objects have NO fill color"] ELSE { ColorTool.SetColor[color, NIL ! ColorTool.NoColorToolViewer => { noColorTool _ TRUE; CONTINUE; };]; IF noColorTool THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "FillColorToColorTool: %g sent to ColorTool", [rope[GGDescribe.ColorToRope[color]]] ]; }; } }; }; LineColorToColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "StrokeColorToColorTool"]; IF success THEN { noColorTool: BOOL _ FALSE; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Selected objects have NO stroke color"] ELSE { ColorTool.SetColor[color, NIL ! ColorTool.NoColorToolViewer => { noColorTool _ TRUE; CONTINUE; };]; IF noColorTool THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "StrokeColorToColorTool: %g sent to ColorTool", [rope[GGDescribe.ColorToRope[color]]] ]; }; } }; }; GetSelectedFillColor: PROC [ggData: GGData, opName: Rope.ROPE] RETURNS [color: ImagerColor.Color, success: BOOL _ TRUE] = { sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; someNotFilled: BOOL _ FALSE; scene: Scene _ ggData.scene; CheckColor: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisColor: ImagerColor.Color; firstChild: Slice; IF sliceD = NIL THEN { sliceD _ thisD; [color, success] _ GGSliceOps.GetFillColor[thisD.slice, thisD.parts]; done _ NOT success; } ELSE { [thisColor, success] _ GGSliceOps.GetFillColor[thisD.slice, thisD.parts]; IF NOT success OR NOT GGCoreOps.EquivalentColors[thisColor, color] THEN done _ TRUE }; IF (GGSliceOps.GetType[thisD.slice]=$Traj AND NARROW[thisD.slice.data, TrajData].role=open) OR (GGSliceOps.GetType[thisD.slice]=$Outline AND GGSliceOps.GetType[(firstChild _ GGParent.FirstChild[thisD.slice, first])]=$Traj AND NARROW[firstChild.data, TrajData].role=open) THEN someNotFilled _ TRUE; }; aborted _ GGScene.WalkSelectedSlices[scene, first, CheckColor, normal]; IF someNotFilled THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: select only CLOSED objects to specify fill color", [rope[opName]] ]; } ELSE IF aborted THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: more than one fill colors are selected", [rope[opName]] ]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: no fill colors are selected", [rope[opName]] ]; }; }; GetSelectedStrokeColor: PROC [ggData: GGData, opName: Rope.ROPE] RETURNS [color: ImagerColor.Color, success: BOOL _ TRUE] = { sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; scene: Scene _ ggData.scene; CheckColor: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisColor: ImagerColor.Color; IF sliceD = NIL THEN { sliceD _ thisD; [color, success] _ GGSliceOps.GetStrokeColor[thisD.slice, thisD.parts]; done _ NOT success; } ELSE { [thisColor, success] _ GGSliceOps.GetStrokeColor[thisD.slice, thisD.parts]; IF NOT success OR NOT GGCoreOps.EquivalentColors[thisColor, color] THEN done _ TRUE }; }; aborted _ GGScene.WalkSelectedSlices[scene, leaf, CheckColor, normal]; IF aborted THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: more than one stroke colors are selected", [rope[opName]] ]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: no stroke colors are selected", [rope[opName]] ]; }; }; AreaColorFromSelectedName: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ParseColorName[name, ggData.router, "FillColorFromName"]; IF color#NIL THEN AreaColorAux[ggData, color, name]; }; LineColorFromSelectedName: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ParseColorName[name, ggData.router, "StrokeColorFromName"]; IF color#NIL THEN LineColorAux[ggData, color, name]; }; ParseColorName: PROC [name: Rope.ROPE, router: MsgRouter, opRope: Rope.ROPE] RETURNS [color: Imager.Color _ NIL] ~ { IF Rope.Equal[name, NIL] THEN Feedback.PutF[router, oneLiner, $Complaint, "%g failed: select a color name", [rope[opRope]] ] ELSE { IF Rope.Match["*/*", name] THEN { --try for a registered name GOTO UnImplementedColors; } ELSE color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; EXITS UnImplementedColors => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: hierarchical names UNIMPLEMENTED in PCedar", [rope[opRope]] ]; UndefinedName => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: undefined color name", [rope[opRope]] ]; BadGrammar => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: bad color name syntax", [rope[opRope]] ]; }; }; AreaColorFromSelectedRGB: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; AreaColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromRGB failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; LineColorFromSelectedRGB: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; LineColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromRGB failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; FillColorFromSelectedCMYK: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColorFns.ColorFromCMYK[CMYKFromRope[name ! CMYKFromRopeError => GOTO SyntaxError]]; AreaColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromCMYK failed: CMYK syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; FillColorFromSelectedIntensity: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; intensity: REAL _ IntensityFromRope[name ! IntensityFromRopeError => GOTO SyntaxError]; SetFillColorFromIntensity[ggData, intensity]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromIntensity failed: Intensity syntax is [0.0..1.0]"]; }; SetFillColorFromIntensity: PUBLIC PROC [ggData: GGData, intensity: REAL] = { color: Imager.Color _ ImagerColor.ColorFromGray[1.0-intensity]; name: Rope.ROPE _ GGUtility.DescribeColor[color]; AreaColorAux[ggData, color, name]; }; StrokeColorFromSelectedCMYK: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColorFns.ColorFromCMYK[CMYKFromRope[name ! CMYKFromRopeError => GOTO SyntaxError]]; LineColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromCMYK failed: CMYK syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; StrokeColorFromSelectedIntensity: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; intensity: REAL _ IntensityFromRope[name ! IntensityFromRopeError => GOTO SyntaxError]; SetStrokeColorFromIntensity[ggData, intensity]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromIntensity failed: Intensity syntax is [0.0..1.0]"]; }; SetStrokeColorFromIntensity: PUBLIC PROC [ggData: GGData, intensity: REAL] = { color: Imager.Color _ ImagerColor.ColorFromGray[1.0-intensity]; name: Rope.ROPE _ GGUtility.DescribeColor[color]; LineColorAux[ggData, color, name]; }; SelectMatchingAreaColor: PUBLIC UserInputProc = { rgb: ImagerColor.RGB; name: Rope.ROPE _ NARROW[event.rest.first]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; scene: Scene _ ggData.scene; DoSelect: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { fillColor: Imager.Color; success: BOOL _ TRUE; tallyD: SliceDescriptor; DoMatchFillColor: PROC [slice: Slice] RETURNS [visitChildren: BOOL, keep: BOOL, done: BOOL _ FALSE] = { IF GGSliceOps.GetType[slice] = $Cluster THEN { visitChildren _ TRUE; keep _ FALSE; } ELSE { visitChildren _ FALSE; fillColor _ GGSliceOps.GetFillColor[slice, NIL].color; keep _ RGBEqualsColor[rgb, fillColor, noneFlag]; }; }; tallyD _ GGParent.TallyChildren[slice, DoMatchFillColor].tallyD; IF tallyD#NIL THEN GGEvent.SelectSlice[tallyD, scene, normal, ggData]; }; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingAreaCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingAreaRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[scene, normal]; [] _ GGScene.WalkSlices[scene, first, DoSelect]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectMatchingFill: fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; UndefinedName => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: undefined color name"]; BadGrammar => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: bad color name syntax"]; }; SelectMatchingLineColor: PUBLIC UserInputProc = { rgb: ImagerColor.RGB; name: Rope.ROPE _ NARROW[event.rest.first]; scene: Scene _ ggData.scene; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; DoSelect: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { ColorProc: WalkProc = { RETURN [RGBEqualsColor[rgb, seg.color, noneFlag]]; }; sliceD: SliceDescriptor _ GGSliceOps.WalkSegments[slice, ColorProc]; -- get a descriptor of matching parts GGSelect.SelectSlice[sliceD, ggData.scene, normal]; -- and select it }; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingLineCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingLineRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[ggData.scene, normal]; [] _ GGScene.WalkSlices[scene, first, DoSelect]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectMatchingStroke: stroke color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; UndefinedName => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: undefined color name"]; BadGrammar => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: bad color name syntax"]; }; SetDefaultFillColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedFillColor[ggData, "SetDefaultFillColor"]; IF success THEN { GGState.SetDefaultFillColor[ggData, color]; ShowDefaultFillColor[ggData, NIL]; }; }; SetDefaultFillColorFromRope: PUBLIC UserInputProc = { rope: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ GGDescribe.ColorFromRope[rope]; GGState.SetDefaultFillColor[ggData, color]; }; SetDefaultLineColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "SetDefaultStrokeColor"]; IF success THEN { GGState.SetDefaultStrokeColor[ggData, color]; ShowDefaultLineColor[ggData, NIL]; }; }; SetDefaultLineColorFromRope: PUBLIC UserInputProc = { rope: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ GGDescribe.ColorFromRope[rope]; GGState.SetDefaultStrokeColor[ggData, color]; }; ShowDefaultFillColor: PUBLIC UserInputProc = { color: Imager.Color _ ggData.defaults.fillColor; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Show, "Default Fill Color: none"] ELSE Feedback.PutF[ggData.router, oneLiner, $Show, "Default Fill Color: %g", [rope[GGUtility.DescribeColor[color]]] ]; }; ShowDefaultLineColor: PUBLIC UserInputProc = { color: Imager.Color _ ggData.defaults.strokeColor; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Show, "Default Stroke Color: none"] ELSE Feedback.PutF[ggData.router, oneLiner, $Show, "Default Stroke Color: %g", [rope[GGUtility.DescribeColor[color]]] ]; }; AreaColorBlack: PUBLIC UserInputProc = { AreaColorAux[ggData, Imager.black, GGDescribe.ColorToRope[Imager.black]]; }; LineColorBlack: PUBLIC UserInputProc = { LineColorAux[ggData, Imager.black, GGDescribe.ColorToRope[Imager.black]]; }; AreaColorWhite: PUBLIC UserInputProc = { AreaColorAux[ggData, Imager.white, GGDescribe.ColorToRope[Imager.white]]; }; LineColorWhite: PUBLIC UserInputProc = { LineColorAux[ggData, Imager.white, GGDescribe.ColorToRope[Imager.white]]; }; AreaColorGray: PUBLIC UserInputProc = { AreaColorAux[ggData, GGOutline.fillColor, GGDescribe.ColorToRope[GGOutline.fillColor]]; }; LineColorGray: PUBLIC UserInputProc = { LineColorAux[ggData, GGOutline.fillColor, GGDescribe.ColorToRope[GGOutline.fillColor]]; }; AreaColorNone: PUBLIC UserInputProc = { AreaColorAux[ggData, NIL, NIL]; }; LineColorNone: PUBLIC UserInputProc = { LineColorAux[ggData, NIL, NIL]; }; CopyStrokeColor: PUBLIC UserInputProc = { currentEvent: HistoryEvent; lastSliceD: SliceDescriptor; color: Imager.Color; scene: Scene _ ggData.scene; success: BOOL _ FALSE; ApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetStrokeColor[sliceD.slice, sliceD.parts, color, $Set, currentEvent]; }; lastSliceD _ GGSelect.GetLastSelection[scene]; IF lastSliceD#NIL THEN [color, success] _ GGSliceOps.GetStrokeColor[lastSliceD.slice, lastSliceD.parts]; IF success THEN { currentEvent _ GGHistory.NewCurrent["Copy stroke color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, ApplyColor, normal]; GGHistory.PushCurrent[ggData]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "CopyStrokeColor: color copied to selected objects"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, Rope.Concat["CopyStrokeColor failed: make a final selection that has a unique stroke color to copy"]]; }; }; CopyFillColor: PUBLIC UserInputProc = { currentEvent: HistoryEvent; lastSliceD: SliceDescriptor; color: Imager.Color; scene: Scene _ ggData.scene; success: BOOL _ FALSE; ApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetFillColor[sliceD.slice, sliceD.parts, GGCoreOps.CopyColor[color], $Set, currentEvent]; }; lastSliceD _ GGSelect.GetLastSelection[scene]; IF lastSliceD#NIL THEN [color, success] _ GGSliceOps.GetFillColor[lastSliceD.slice, lastSliceD.parts]; IF success THEN { currentEvent _ GGHistory.NewCurrent["Copy fill color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, ApplyColor, normal]; GGHistory.PushCurrent[ggData]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "CopyFillColor: color copied to selected objects"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, "CopyFillColor failed: make a final selection that has a unique fill color to copy"]; }; }; ShowFillColor: UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedFillColor[ggData, "ShowFillColor"]; IF success THEN { IF color#NIL THEN Feedback.PutF[ggData.router, oneLiner, $Show, "ShowFillColor: %g", [rope[GGUtility.DescribeColor[color]]] ] ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowFillColor: no fill color"]; }; }; ShowStrokeColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "ShowStrokeColor"]; IF success THEN { IF color#NIL THEN Feedback.PutF[ggData.router, oneLiner, $Show, "ShowStrokeColor: %g", [rope[GGUtility.DescribeColor[color]]] ] ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowStrokeColor: no stroke color"]; }; }; ExtendToOutlineLevel: PROC [sliceD: SliceDescriptor] RETURNS [extendedD: SliceDescriptor] = { DoExtendSelection: PROC [sliceD: SliceDescriptor] RETURNS [visitChildren: BOOL, keepD: SliceDescriptor, done: BOOL _ FALSE] = { classType: ATOM _ GGSliceOps.GetType[sliceD.slice]; SELECT classType FROM $Cluster => { visitChildren _ TRUE; keepD _ NIL; }; ENDCASE => { visitChildren _ FALSE; keepD _ GGSliceOps.NewParts[sliceD.slice, NIL, slice]; }; }; [extendedD, ----] _ GGParent.TallyIncludedChildren[sliceD.slice, sliceD.parts, DoExtendSelection]; }; AreaColorAux: PUBLIC PROC [ggData: GGData, color: Imager.Color, name: Rope.ROPE _ NIL, noisy: BOOL _ TRUE, setHow: ATOM _ $Set] = { IF GGSelect.NoSelections[ggData.scene, normal] THEN IF noisy THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetFillColor failed: no selections to set fill color"] ELSE NULL ELSE { currentEvent: HistoryEvent; scene: Scene _ ggData.scene; newSelectList, ptr: LIST OF SliceDescriptor; extendToOutlinesD: SliceDescriptor; DoApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetFillColor[sliceD.slice, sliceD.parts, color, setHow, currentEvent]; [newSelectList, ptr] _ GGUtility.AddSliceDescriptor[sliceD, newSelectList, ptr]; }; currentEvent _ GGHistory.NewCurrent["Set fill color", ggData]; -- start new history event [newSelectList, ptr] _ GGUtility.StartSliceDescriptorList[]; [] _ GGScene.WalkSelectedSlices[scene, first, DoApplyColor, normal]; FOR list: LIST OF SliceDescriptor _ newSelectList, list.rest UNTIL list = NIL DO extendToOutlinesD _ ExtendToOutlineLevel[list.first]; GGSelect.SelectSlice[extendToOutlinesD, scene, normal]; ENDLOOP; GGHistory.PushCurrent[ggData]; IF noisy THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, "SetFillColor: fill color _ %g", IF name#NIL THEN [rope[name]] ELSE [rope["none"]]]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; }; }; LineColorAux: PUBLIC PROC [ggData: GGData, color: Imager.Color, name: Rope.ROPE, noisy: BOOL _ TRUE, setHow: ATOM _ $Set] = { IF GGSelect.NoSelections[ggData.scene, normal] THEN IF noisy THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetStrokeColor failed: no selections to set stroke color"] ELSE NULL ELSE { currentEvent: HistoryEvent; scene: Scene _ ggData.scene; DoApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetStrokeColor[sliceD.slice, sliceD.parts, color, setHow, currentEvent]; }; currentEvent _ GGHistory.NewCurrent["Set stroke color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, DoApplyColor, normal]; IF noisy THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, "SetStrokeColor: stroke color _ %g", IF name#NIL THEN [rope[name]] ELSE [rope["none"]]]; GGHistory.PushCurrent[ggData]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; }; }; RGBEqualsColor: PROC [rgb: ImagerColor.RGB, color: Imager.Color, noneFlag: BOOL] RETURNS [BOOL] = { epsilon: REAL = 1.0E-2; IF color=NIL THEN RETURN [noneFlag]; -- color is none => RETURN[looking for none] IF noneFlag THEN RETURN [FALSE] -- looking for none, but color is non-NIL ELSE { r, g, b: REAL; WITH color SELECT FROM constant: ImagerColor.ConstantColor => { [r,g,b] _ GGCoreOps.ExtractRGB[constant]; RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R] RETURN[FALSE]; }; }; RGBFromRope: PROC [name: Rope.ROPE] RETURNS [rgb: ImagerColor.RGB] = { ENABLE IO.Error, IO.EndOfStream => GOTO RGBError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL RGBFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; rgb.R _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; rgb.G _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; rgb.B _ rs.GetReal[]; Check[rgb.R]; Check[rgb.G]; Check[rgb.B]; EXITS RGBError => SIGNAL RGBFromRopeError; }; CMYKFromRope: PROC [name: Rope.ROPE] RETURNS [cmyk: ImagerColorFns.CMYK] = { ENABLE IO.Error, IO.EndOfStream => GOTO CMYKError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL CMYKFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; [] _ rs.SkipWhitespace[]; cmyk.C _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.M _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.Y _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.K _ rs.GetReal[]; Check[cmyk.C]; Check[cmyk.M]; Check[cmyk.Y]; Check[cmyk.K]; EXITS CMYKError => SIGNAL CMYKFromRopeError; }; IntensityFromRope: PROC [name: Rope.ROPE] RETURNS [intensity: REAL] = { ENABLE IO.Error, IO.EndOfStream => GOTO IntensityError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL IntensityFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; intensity _ rs.GetReal[]; Check[intensity]; EXITS IntensityError => SIGNAL IntensityFromRopeError; }; TestGravity: PUBLIC UserInputProc = { xRandomStream, yRandomStream: Random.RandomStream; desiredCount: INT _ NARROW[event.rest.first, REF INT]^; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; multiPoint: Point; normal: Vector; multiFeature: FeatureData; currentObjects: AlignBag; sceneObjects: TriggerBag; IF desiredCount<=0 OR desiredCount=LAST[INT] THEN RETURN; xRandomStream _ Random.Create[GGState.GetWidth[ggData]]; yRandomStream _ Random.Create[GGState.GetHeight[ggData]]; ggData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount >= desiredCount DO IF ggData.aborted[gravitytest] THEN { ggData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData]; ggData.refresh.spotPoint _ testPoint; currentObjects _ ggData.hitTest.alignBag; sceneObjects _ ggData.hitTest.sceneBag; [multiPoint, normal, multiFeature] _ GGMultiGravity.Map[testPoint, ggData.hitTest.t, currentObjects, sceneObjects, ggData, TRUE]; IF multiFeature = NIL THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; totalCount _ totalCount + 1; LOOP; }; multiHitCount _ multiHitCount + 1; totalCount _ totalCount + 1; ggData.refresh.hitPoint _ multiPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; ENDLOOP; Feedback.PutF[ggData.router, oneLiner, $Feedback, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity noisyTestGravity: BOOL _ FALSE; Statistics: PUBLIC UserInputProc = { f: IO.STREAM _ FeedbackOps.GetTypescriptStream[$Gargoyle]; IF f#NIL THEN CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]]; }; AppendStatistics: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; f: IO.STREAM; completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL THEN CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle] ! CodeTimer.Problem => CONTINUE;]; GGUIUtility.SafeClose[f, ggData.router]; END; }; PrintSelectedStatistic: PUBLIC UserInputProc = { intervalRope: Rope.ROPE _ NARROW[event.rest.first]; intervalName: ATOM _ Atom.MakeAtom[intervalRope]; f: IO.STREAM _ FeedbackOps.GetTypescriptStream[$Gargoyle]; IF f#NIL AND NOT Rope.Equal[intervalRope, NIL] THEN { f.PutRope["\n"]; CodeTimer.PrintInt[f, intervalName, $Gargoyle ! CodeTimer.Problem => CONTINUE;]; }; }; AppendSelectedStatistic: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; intervalName: Rope.ROPE _ NARROW[event.rest.rest.first]; atom: ATOM _ Atom.MakeAtom[intervalName]; f: IO.STREAM; completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL AND NOT Rope.Equal[intervalName, NIL] THEN CodeTimer.PrintInt[f, atom, $Gargoyle ! CodeTimer.Problem => CONTINUE;]; GGUIUtility.SafeClose[f, ggData.router]; END; }; AppendRope: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; message: Rope.ROPE _ NARROW[event.rest.rest.first]; f: IO.STREAM; completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL AND NOT Rope.Equal[message, NIL] THEN f.PutRope[message]; GGUIUtility.SafeClose[f, ggData.router]; END; }; CreateFile: PUBLIC UserInputProc = { ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g", [rope[error.explanation]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; f: IO.STREAM _ FS.StreamOpen[fileName, $create]; -- merely causes file creation GGUIUtility.SafeClose[f, ggData.router]; }; ResetStatistics: PUBLIC UserInputProc = { CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Statistics reset"]; }; DrawTouchPoints: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawBoundBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawTightBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawOutlineBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawSelectionBox: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawMovingBox: PUBLIC UserInputProc = { atom: ATOM _ NARROW[event.first]; GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DescribeCaretObject: PUBLIC UserInputProc = { description: Rope.ROPE _ "no object"; chair: SliceDescriptor _ GGCaret.GetChair[ggData.caret]; IF chair#NIL THEN description _ GGSliceOps.Describe[chair]; Feedback.PutF[ggData.router, oneLiner, $Show, "Caret is on %g", [rope[description]]]; }; CauseAnError: PUBLIC UserInputProc = { scene: GGModelTypes.Scene _ ggData.scene; firstSlice, secondSlice: GGModelTypes.Slice; index: NAT _ 0; FirstAndSecond: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { IF index = 0 THEN { firstSlice _ slice; index _ index + 1; } ELSE IF index = 1 THEN { secondSlice _ slice; done _ TRUE; }; }; [] _ GGScene.WalkSlices[scene, first, FirstAndSecond]; SIGNAL Feedback.Problem[msg: "Client requested SIGNAL"]; }; printAllInput: BOOL _ FALSE; -- controlled by Debug menu PrintAllInput: PUBLIC UserInputProc = { IF printAllInput THEN { FOR list: LIST OF REF ANY _ event, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM atom: ATOM => Feedback.PutF[ggData.router, begin, $Typescript, "%g ", [rope[Atom.GetPName[atom]]] ]; int: REF INT => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [integer[int^]] ]; real: REF REAL => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [real[real^]]]; card: REF CARD => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [cardinal[card^]]]; refChar: REF CHAR => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [character[refChar^]]]; coords: BiScrollers.ClientCoords => Feedback.PutF[ggData.router, middle, $Typescript, "(%g, %g )", [real[coords.x]], [real[coords.y]] ]; ENDCASE => Feedback.Append[ggData.router, middle, $Typescript, "Unknown input type"]; ENDLOOP; Feedback.Append[ggData.router, end, $Typescript, "" ]; }; }; PrintAllInputOn: PUBLIC UserInputProc = { printAllInput _ TRUE; }; PrintAllInputOff: PUBLIC UserInputProc = { printAllInput _ FALSE; }; Typescript: PUBLIC UserInputProc = { GGState.Typescript[ggData]; }; Init: PROC = { OPEN GGUserInput; RegisterAction[$Destroy, Destroy, none]; RegisterAction[$Clear, Clear, none]; RegisterAction[$ConfirmClear, ConfirmClear, none]; RegisterAction[$Reset, Reset, none]; RegisterAction[$ConfirmReset, ConfirmReset, none]; RegisterAction[$Get, Get, rope]; RegisterAction[$ConfirmGet, ConfirmGet, none]; RegisterAction[$MergeAll, MergeAll, rope]; RegisterAction[$MergeShapes, MergeShapes, rope]; RegisterAction[$MergeOptions, MergeOptions, rope]; RegisterAction[$MergeAlignments, MergeAlignments, rope]; RegisterAction[$Store, Store, rope]; RegisterAction[$StoreOnPlayback, Store, rope]; RegisterAction[$ConfirmStore, ConfirmStore, none]; RegisterAction[$Save, Save, none]; RegisterAction[$SaveOnPlayback, Save, none]; RegisterAction[$CleanVersion, CleanVersion, none]; RegisterAction[$AddToGroup, AddToGroup, rope]; RegisterAction[$SelectGroup, SelectGroup, rope]; RegisterAction[$RemoveFromGroup, RemoveFromGroup, rope]; RegisterAction[$PrintGroupsOfSelected, PrintGroupsOfSelected, none]; RegisterAction[$PrintAllGroups, PrintAllGroups, none]; RegisterAction[$Cluster, Cluster, none]; RegisterAction[$ClusterAndFreeze, ClusterAndFreeze, none]; RegisterAction[$UnCluster, UnCluster, none]; RegisterAction[$FreezeCluster, FreezeCluster, none]; RegisterAction[$ThawCluster, ThawCluster, none]; RegisterAction[$ShowFrozen, ShowFrozen, none]; RegisterAction[$AreaColorFromColorTool, AreaColorFromColorTool, none]; RegisterAction[$FillHueFromColorTool, FillHueFromColorTool, none]; RegisterAction[$AreaColorFollowColorTool, AreaColorFollowColorTool, none]; RegisterAction[$AreaColorToColorTool, AreaColorToColorTool, none]; RegisterAction[$AreaColorFromSelectedName, AreaColorFromSelectedName, rope]; RegisterAction[$AreaColorFromSelectedRGB, AreaColorFromSelectedRGB, rope]; RegisterAction[$FillColorFromSelectedCMYK, FillColorFromSelectedCMYK, rope]; RegisterAction[$FillColorFromSelectedIntensity, FillColorFromSelectedIntensity, rope]; RegisterAction[$PrintAreaColor, ShowFillColor, none]; RegisterAction[$SelectMatchingAreaRGB, SelectMatchingAreaColor, rope]; RegisterAction[$SelectMatchingAreaCNS, SelectMatchingAreaColor, rope]; RegisterAction[$AreaColorBlack, AreaColorBlack, none]; RegisterAction[$AreaColorWhite, AreaColorWhite, none]; RegisterAction[$AreaColorGray, AreaColorGray, none]; RegisterAction[$AreaColorNone, AreaColorNone, none]; RegisterAction[$CopyFillColor, CopyFillColor, none]; RegisterAction[$SetDefaultFillColor, SetDefaultFillColor, none]; RegisterAction[$SetDefaultFillColorFromRope, SetDefaultFillColorFromRope, rope]; RegisterAction[$ShowDefaultFillColor, ShowDefaultFillColor, none]; RegisterAction[$LineColorFromColorTool, LineColorFromColorTool, none]; RegisterAction[$StrokeHueFromColorTool, StrokeHueFromColorTool, none]; RegisterAction[$LineColorFollowColorTool, LineColorFollowColorTool, none]; RegisterAction[$LineColorToColorTool, LineColorToColorTool, none]; RegisterAction[$LineColorFromSelectedName, LineColorFromSelectedName, rope]; RegisterAction[$LineColorFromSelectedRGB, LineColorFromSelectedRGB, rope]; RegisterAction[$StrokeColorFromSelectedCMYK, StrokeColorFromSelectedCMYK, rope]; RegisterAction[$StrokeColorFromSelectedIntensity, StrokeColorFromSelectedIntensity, rope]; RegisterAction[$SelectMatchingLineRGB, SelectMatchingLineColor, rope]; RegisterAction[$SelectMatchingLineCNS, SelectMatchingLineColor, rope]; RegisterAction[$PrintLineColor, ShowStrokeColor, none]; RegisterAction[$LineColorBlack, LineColorBlack, none]; RegisterAction[$LineColorWhite, LineColorWhite, none]; RegisterAction[$LineColorGray, LineColorGray, none]; RegisterAction[$LineColorNone, LineColorNone, none]; RegisterAction[$CopyStrokeColor, CopyStrokeColor, none]; RegisterAction[$SetDefaultLineColor, SetDefaultLineColor, none]; RegisterAction[$SetDefaultLineColorFromRope, SetDefaultLineColorFromRope, rope]; RegisterAction[$ShowDefaultLineColor, ShowDefaultLineColor, none]; RegisterAction[$TestGravity, TestGravity, refInt]; RegisterAction[$Statistics, Statistics, none]; RegisterAction[$AppendStatistics, AppendStatistics, none]; RegisterAction[$PrintSelectedStatistic, PrintSelectedStatistic, rope]; RegisterAction[$AppendSelectedStatistic, AppendSelectedStatistic, none]; RegisterAction[$AppendRope, AppendRope, none]; RegisterAction[$CreateFile, CreateFile, none]; RegisterAction[$ResetStatistics, ResetStatistics, none]; RegisterAction[$DrawTightBoxes, DrawTightBoxes, none]; RegisterAction[$DrawBoundBoxes, DrawBoundBoxes, none]; RegisterAction[$DrawOutlineBoxes, DrawOutlineBoxes, none]; RegisterAction[$DrawSelectionBox, DrawSelectionBox, none]; RegisterAction[$DrawBackgroundBox, DrawMovingBox, none]; RegisterAction[$DrawOverlayBox, DrawMovingBox, none]; RegisterAction[$DrawRubberBox, DrawMovingBox, none]; RegisterAction[$DrawDragBox, DrawMovingBox, none]; RegisterAction[$Typescript, Typescript, none]; RegisterAction[$DescribeCaretObject, DescribeCaretObject, none]; RegisterAction[$PrintAllInput, PrintAllInputOn, none]; RegisterAction[$ResetAllInput, PrintAllInputOff, none]; RegisterAction[$CauseAnError, CauseAnError, none]; }; Init[]; END. æGGEventImplD.mesa Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Copyright Ó 1986, 1987, 1988, 1989, 1990 by Xerox Corporation. All rights reserved. Pier, May 14, 1992 12:21 pm PDT Kurlander, September 1, 1987 3:54:12 pm PDT Bier, March 18, 1992 6:40 pm PST Doug Wyatt, February 21, 1990 5:44 pm PST File Operations ASSERT: event is either NIL or event.first=filename ASSERT: event.first=$Get, event.rest=NIL OR filename ASSERT: event.first=$Store or $Save, event.rest=NIL OR filename Save is simply Store invoked with event.rest.first=GargoyleFileName. KAP February 17, 1986 START TIMING tell the state manager that a Store just completed called from GGUtilityImplA.GargoyleContainerDestroy tell the state manager that a Clear just completed Auto Scripting ask the state manager if a Restore is possible This proc is a mess but can't be easily sanitized DKW: if some other error.code, reject is probably better than unnamed ERROR This proc is a mess but can't be easily sanitized ggData.refresh.suppressRefresh _ FALSE; -- interferes with Clear in FastPlayback scripts ASSERT: event.first=$MergeAll, event.rest=NIL OR filename ASSERT: op=$Merge* or $Get TIMING VARIABLES START TIMING tell the state manager that a Get just completed Group Operations ggData.refresh.startBoundBox^ _ GGScene.BoundBoxOfSelected[scene, normal, TRUE]^; Feedback.Append[ggData.router, oneLiner, $Feedback, "FreezeCluster: selected clusters are now frozen"]; Fill and Line Colors Copied from ImagerDitherContextImpl, so that Gargoyle doesn't import ImagerDitherContextImpl, which isn't available for remote Viewers worlds. N.B.: this code stupidly written to get around compiler. color _ ImagerColor.Find[name]; IF color=NIL THEN color _ ImagerColor.Find[Rope.Cat["Xerox/Research/", name]]; IF color=NIL THEN GOTO UnregisteredName; UnregisteredName => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: hierarchical name not registered", [rope[opRope]] ]; WalkProc: TYPE = PROC [seg: Segment] RETURNS [keep: BOOL]; PaletteForFillColor: PUBLIC UserInputProc = { boolRope: Rope.ROPE _ NARROW[event.rest.first]; paletteForFillColorOn: BOOL _ GGCoreOps.RopeToBool[boolRope]; GGState.SetPalette[ggData, paletteForFillColorOn]; ShowPaletteForFillColor[ggData, event]; }; PaletteForStrokeColor: PUBLIC UserInputProc = { boolRope: Rope.ROPE _ NARROW[event.rest.first]; paletteForStrokeColorOn: BOOL _ GGCoreOps.RopeToBool[boolRope]; GGState.SetPalette[ggData, paletteForStrokeColorOn]; ShowPaletteForStrokeColor[ggData, event]; }; ShowPaletteForFillColor: PUBLIC UserInputProc = { paletteForFillColorOn: BOOL _ GGState.GetPalette[ggData]; Feedback.PutF[ggData.router, oneLiner, $Show, "PaletteForFillColor: %g", [rope[GGCoreOps.BoolToRope[paletteForFillColorOn] ]] ]; }; ShowPaletteForStrokeColor: PUBLIC UserInputProc = { paletteForStrokeColorOn: BOOL _ GGState.GetPalette[ggData]; Feedback.PutF[ggData.router, oneLiner, $Show, "PaletteForStrokeColor: %g", [rope[GGCoreOps.BoolToRope[paletteForStrokeColorOn] ]] ]; }; ggData.refresh.startBoundBox^ _ GGScene.BoundBoxOfSelected[ggData.scene, normal]^; ObjectChangedInPlace will provide the BoundBoxOfSelected for refresh. ggData.refresh.startBoundBox^ _ GGScene.BoundBoxOfSelected[ggData.scene, normal]^; ObjectChangedInPlace will provide the BoundBoxOfSelected for refresh. For each selected leaf of sliceD, select it in full. If a selected leaf is contained within an outline, grow the selection to the outermost such outline. ggData.refresh.startBoundBox^ _ GGScene.BoundBoxOfSelected[ggData.scene, normal]^; ObjectChangedInPlace will provide the BoundBoxOfSelected for refresh. ObjectChangedInPlace will provide the BoundBoxOfSelected for refresh. Debug Menu TestMultiGravity: PUBLIC UserInputProc = { }; Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until desiredCount points have been drawn. completeName _ Rope.Concat[ggData.originalWDir, fileName]; Prints the totals for the interval whose name is selected. completeName _ Rope.Concat[ggData.originalWDir, fileName]; completeName _ Rope.Concat[ggData.originalWDir, fileName]; f: IO.STREAM _ FS.StreamOpen[Rope.Concat[ggData.originalWDir, fileName], $create]; -- merely causes file creation FSMInfo: PUBLIC UserInputProc = { mouseMode, state: Rope.ROPE; mouseMode _ Atom.GetPName[ggData.mouseMode]; state _ Atom.GetPName[ggData.state]; Feedback.PutF[ggData.router, oneLiner, $Show, "mouseMode = %g. state = %g.", [rope[mouseMode]], [rope[state]]]; }; File Line Group Menu Fill Color Stroke Color RegisterAction[$PaletteForFillColor, PaletteForFillColor, rope]; RegisterAction[$PaletteForStrokeColor, PaletteForStrokeColor, rope]; RegisterAction[$ShowPaletteForFillColor, ShowPaletteForFillColor, none]; RegisterAction[$ShowPaletteForStrokeColor, ShowPaletteForStrokeColor, none]; Debug Menu RegisterAction[$TestMultiGravity, TestMultiGravity, none]; RegisterAction[$FSMInfo, FSMInfo, none]; ÊQ•NewlineDelimiter – "cedar" style˜Icodešœ™šÏnœx™€KšœT™TKšœ™Kšœ(Ïk™+K™ K™)—K™šž ˜ Jšœsžœížœo˜Ó—K˜š œžœž˜JšžœJžœÀžœ`˜õKšžœ,ž˜8—˜Kšœ žœ˜+Kšœ žœ˜%Kšœ žœžœ$Ïc˜[Kšœ žœ ˜1Jšœ žœ˜*Kšœžœ˜'Kšœžœ˜1Kšœžœ˜!Kšœžœ˜3Kšœžœ˜!Kšœžœžœ!˜˜ªKš žœžœžœMžœžœŸ,˜¡KšœL˜LKšœžœN˜iKšœ¡˜¡KšÏbœ<˜PKšœ;˜;K˜—K˜K˜—š(œžœžœžœ žœžœžœžœžœ žœžœžœžœžœ žœžœžœžœ žœžœ˜Kšžœžœ™3š œžœžœžœžœ žœ˜>šžœžœž˜Kšœžœžœžœ˜2Kšœžœžœ˜Kšžœžœ˜—K˜—Kšœ žœžœžœ žœžœžœžœ˜SKšžœžœžœ ž˜/Kšžœy˜}K˜—K˜šœžœ˜Kšžœžœžœ ™4Kšœžœ˜Kšœ#žœžœ˜0K•StartOfExpansion)[intervalName: ATOM, tableName: ATOM]šœ$˜$KšœŸœy˜~KšžœžœZ˜hšžœžœ žœ˜Kšœžœ˜"Kšœ žœ˜KšœC˜CKšœ˜Kšœ˜Kšœ˜Kšœ1˜1Kšœ1žœ-˜`Kšœ9Ÿ˜MKšœH˜HKšœ'Ÿ1˜XKšœžœŸ=˜\Kšœ˜—K–)[intervalName: ATOM, tableName: ATOM]šœ#˜#Kšœ˜K˜—šœžœ˜Kšžœ*žœžœ ™?KšœFžœ™[Kšœžœ˜Kšœžœžœ˜ Kšœžœ˜Kšœ#žœžœ˜0Kšœžœ˜"Kšœ žœ˜Kšœžœ˜Kšœžœ ˜Kšœ žœ˜)KšœŸœQžœJ˜¦Kšžœžœžœ žœ\˜|Kš žœžœžœžœ žœj˜™šžœžœ žœ˜Kšœžœžœ žœ˜@š œžœ"žœ žœžœ ˜Wšžœ ˜ Kšœ žœv˜‚Kšžœžœ žœ?˜TKšžœ˜ Kšœ˜—Kšœ˜—Kš œžœ˜%Kšœžœ;˜AKš œ žœžœžœ žœžœ˜VKšœ žœ:˜FKšžœžœ žœ=˜RKšžœž™ KšœžœŸ˜=Kšœ˜Kšœ6˜6K˜(Kšœ˜Kšœ1˜1Kšœ žœ3˜?Kšžœžœ žœ;˜PK™2Kšœ8˜8Kšœ7˜7Kšœ&˜&KšœžœŸ=˜\šž˜Kšœ žœ˜—Kšœ˜—Kšœ˜K˜—š œ˜ Kšœ&˜&Kšœ˜K˜—šœžœ˜KšžœžœžœžœS˜ŒKšžœk˜oKšœ˜K˜—šœžœ˜!Kšœ™3KšœžœŸ4˜KKšœŸ˜2Kšœ˜K˜—šœžœ˜Kšœ˜Kšžœžœ+˜EK™2Kšœ˜Kšœ7˜7Kšœžœ˜#KšžœžœqžœÐbkœ˜©Kšœ'Ÿ1˜XKš ™Kšœ8˜8KšœžœŸ=˜\K–M[feedback: Feedback.FeedbackData, msg: ROPE, msgType: Feedback.MsgType]šžœžœI˜cKšœ˜K˜—šÐbn œ˜KšœV˜VKšœ˜K˜—šœžœ˜K™.šžœžœ˜'Kšœžœ˜2Kšœ(˜(Kšœ˜Kšœ9Ÿ˜MKšœžœ%Ÿ˜XKšœ&˜&KšœžœŸ=˜\Kšœ'˜'K–M[feedback: Feedback.FeedbackData, msg: ROPE, msgType: Feedback.MsgType]˜JK˜—Kšœ˜K˜—š œ˜Kšœžœ˜2Kšžœžœžœi˜ŠKšžœX˜\Kšœ˜K˜—š œ˜K™1Kšœžœ˜Kšœ žœžœ˜Kšœžœ&˜9Kšžœžœžœk˜Œšžœ˜KšœŸœVžœ˜uKšžœžœ žœl˜Kšžœi˜mKšœ˜—Kšœ˜K˜—š œžœžœžœ žœžœ˜Hšœžœ˜š žœ žœžœ žœžœ˜IKšžœCž™K—Kšœ˜—Kšœ˜K˜—š œ˜K™1Kšœžœ˜Kšœ žœžœ˜Kšœžœ&˜9Kšžœžœžœm˜Žšžœ˜KšœŸœXžœ˜wKšžœžœ žœn˜Kšžœkžœžœžœ ˜¡Kšœ˜—Kšœ˜K˜—š œžœ žœžœžœžœ˜;KšœžœŸ`˜‚Kšœžœ˜!Kšœ$˜$K–K[ggData: GGInterfaceTypes.GGData, sliceD: GGModelTypes.SliceDescriptor]šœ!žœŸ˜>Kšœ!Ÿ˜>Kšœ"Ÿ˜2KšœžœŸ7˜XKšœ   œ Ÿv˜–Kšœ(Ÿ'˜OKšœ,Ÿ'˜SKšœ&Ÿ˜EKšœO˜OKšœžœžœ˜Kšœ Ïtžœ2™XKšœ£žœ˜&Kšœ£žœ˜%Kšœ£žœ˜!Kšœ#£žœ˜(Kšœ£žœ˜!Kšœ£žœ˜#Kšœ£žœ˜$Kšœ$£žœ˜+Kšœ$£žœ˜+Kšœ'˜'Kšœ'˜'Kšœ˜—K˜šœžœ˜"Kšžœ$žœžœ ™9Kšœ/˜/K˜K˜—š œžœ˜%Kšœ5˜5K˜K˜—š œžœ˜&Kšœ7˜7K˜K˜—šœžœ˜)Kš œ5˜=K˜K˜—šœžœ žœžœžœžœžœžœ˜XKšœžœ˜Kšœ#žœžœ˜0KšœŸœz˜Kšžœžœ\˜jKšžœžœ žœD˜XK˜K˜—š œžœžœžœžœžœžœžœžœžœžœ˜Kšžœ™Kšœžœžœ˜ šœ žœ˜Kš¡ ¡ ™—Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜1K˜Kšœ œ4˜VKš ˜šœžœžœžœ ˜;Kšœ‡˜‡Kšžœ˜ Kšœ˜—Kšœ žœ žœ"˜8Kš ˜Kšœ1˜1Kšœ œ3˜SK˜Kšœ œ?˜aK˜Kšžœž™ Kš ˜šž˜šžœž˜˜ Kšœ žœžœ˜+KšœCžœžœŸ˜kšžœ žœ˜Kšœ žœ˜.Kšœ5˜5K˜—šžœŸ˜Kšœžœ˜(Kšœpžœ¡œ˜ŽKšœ=˜=Kšžœ˜Kšœ˜—K˜—˜KšœCžœžœŸ˜išžœžœ žœ˜Kšœ>žœ˜PKšœ˜—K˜—˜KšœCžœŸ˜ršžœžœ žœ˜Kšœ>žœ˜PKšœ˜—K˜—šœ˜Kšœ?¡œ˜Fšžœžœ žœ˜Kšœ>žœ˜PKšœ˜—K˜—šœ˜Kšœ?¡œ˜Ešžœžœ žœ˜Kšœ>žœ˜PKšœ˜—K˜—Kšžœžœ˜—Kšœ(˜(Kš ˜Kšœ1˜1Kšœ[˜[šžœ žœŸ˜.K™0Kšœ6˜6Kšœ7˜7Kšœ˜—Kšœžœ˜4Kšœ2 œHžœ˜“šž˜Kšœ8˜8—Kšžœ˜—šž˜Kšœ; œ.žœžœŸ6˜Ñ—Kšœ˜—K˜K™š œžœ˜$Kšœ žœžœ˜+Kšžœ-žœ_˜’Kšžœžœžœžœt˜–šžœ˜š œžœžœžœžœ˜LKšœC˜Cšžœsžœžœž˜†Kšœ žœžœ˜šžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)šžœžœžœ˜+Kšœ žœŸ˜*Kšžœ˜K˜—Kšžœ˜—Kšžœžœ žœ žœ˜8Kšœžœ˜Kšžœ˜—J˜—Kšœžœžœ˜K˜Kšœ9£œ£˜CKšœ2žœžœ3žœ=˜ºKšžœžœ_žœžœ˜Kšœ˜—šœ˜K˜——š œžœ˜%Kšœ žœžœ˜+Kšžœžœžœv˜“šžœ˜š œžœžœžœžœ˜Dšœžœ2žœžœ˜Xšžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kš žœžœžœžœžœ˜7Kšžœ˜—Kšžœžœ˜Kšœ˜—KšœF˜FKšžœ žœžœ7˜LJ˜—K˜Kšœ   œ!žœžœ˜PKšœ,Ÿ˜GKšœ$£œ£˜6Kšžœ-žœZ˜Kšžœd˜hKšœjžœžœ˜‰Kšœ˜—šœ˜K˜——šœžœ˜)Kšœ žœžœ˜+Kšžœ-žœd˜—Kšžœžœžœžœ~˜ šžœ˜š œžœžœžœžœ˜OKšœC˜Cšžœsžœžœž˜†Kšœ žœ˜šžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kšžœžœžœžœ žœžœžœ˜jKšžœ˜—Kšœ˜Kšžœ˜—J˜—Kšœ žœžœ˜Kš œ žœžœžœžœ˜K˜Kšœ,£œ£œ£˜FKšœ2žœ žœ<žœX˜ÝKšžœ žœ_žœžœ˜Kšœ˜—šœ˜K˜——šœžœ˜/K˜Kšžœ&žœr˜žšžœ˜š œžœžœžœžœ˜NKšœC˜Cšžœsžœžœž˜†šžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kšœ žœžœ˜šžœžœžœžœžœžœžœž˜EKšœžœžœ˜+šžœ!žœžœ˜0Kšœ žœŸ˜.Kšžœ˜K˜—Kšžœ˜—K–4[l1: LIST OF REF ANY, l2: LIST OF REF ANY _ NIL]šžœžœ žœ žœ˜žœ‰˜ÞK˜—K˜—K˜—K˜K˜—šœžœ˜.šžœ"žœ˜*K˜Kšœ žœžœ˜KšœL˜Lšžœ žœ˜Kšœ žœžœ˜šžœžœžœ_žœ˜všœžœ#˜@Kšœžœ˜Kšžœ˜ Kšœ˜—Kšžœ žœ>žœ‹˜àK˜—K˜—K˜—K˜K˜—š œžœžœžœ%žœžœ˜{Kšœžœ˜Kšœ žœžœ˜Kšœžœžœ˜K˜–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]š œžœžœžœžœ˜JJšœ˜J˜šžœ žœžœ˜Jšœ˜JšœE˜EJšœžœ ˜J˜—šžœ˜JšœI˜IJš žœžœ žœžœ.žœž˜SJ˜—šž˜šœ'ž˜*Kšžœ(ž˜0—šœ*ž˜-KšœQž˜TKšžœ&˜,—Kšžœžœ˜—J˜—Kšœ1£œ £œ£˜Gšžœžœ˜Kšœ žœ˜Kšœƒ˜ƒK˜—šžœžœ žœ˜Kšœ žœ˜Kšœy˜yK˜—šžœžœ žœžœ˜Kšœ žœ˜Kšœn˜nK˜—K˜K˜—š œžœžœžœ%žœžœ˜}Kšœžœ˜Kšœ žœžœ˜K˜–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]š œžœžœžœžœ˜JJšœ˜šžœ žœžœ˜Jšœ˜JšœG˜GJšœžœ ˜J˜—šžœ˜JšœK˜KJš žœžœ žœžœ.žœž˜SJ˜—J˜—Kšœ<£œ£˜Fšžœ žœ˜Kšœ žœ˜Kšœ{˜{K˜—šžœžœ žœžœ˜Kšœ žœ˜Kšœp˜pK˜—K˜K˜—šœžœ˜3Kšœ žœžœ˜+KšœP˜PKšžœžœžœ#˜4K˜K˜—šœžœ˜3Kšœ žœžœ˜+KšœR˜RKšžœžœžœ#˜4K˜K˜—š œžœ žœ"žœžœžœ˜tKšžœžœžœ_˜|šžœ˜šžœžœŸ˜=Kšžœ˜Kšœ™Kšžœžœžœ=™NKšžœžœžœžœ™(K˜—šžœX˜\Kšœžœ˜0Kšœžœ ˜*K˜—šž˜Kšœ˜Kšœ€™€Kšœq˜qKšœo˜o—K˜—K˜K˜—šœžœ˜2Kšœ žœžœ˜+KšœVžœ˜iKšœ"˜"šž˜Kšœ˜—K˜K˜—šœžœ˜2Kšœ žœžœ˜+KšœVžœ˜iKšœ"˜"šž˜Kšœ‘˜‘—K˜K˜—šœžœ˜3Kšœ žœžœ˜+Kšœ\žœ˜oKšœ"˜"šž˜Kšœœ˜œ—K˜K˜—šœžœ˜8Kšœ žœžœ˜+Kšœ žœ6žœ˜WKšœ-˜-šž˜Kšœ…˜…—K˜K˜—šœžœžœžœ˜LKšœ?˜?Kšœ žœ"˜1Kšœ"˜"K˜K˜—šœžœ˜5Kšœ žœžœ˜+Kšœ\žœ˜oKšœ"˜"šž˜Kšœž˜ž—K˜K˜—š œžœ˜:Kšœ žœžœ˜+Kšœ žœ6žœ˜WKšœ/˜/šž˜Kšœ‡˜‡—K˜K˜—šœžœžœžœ˜NKšœ?˜?Kšœ žœ"˜1Kšœ"˜"K˜K˜—šœžœ˜1Kšœžœ˜Kšœ žœžœ˜+Kšœ žœžœ˜1K˜š œžœžœžœžœ˜>Kšœ˜Kšœ žœžœ˜Kšœ˜šœžœžœžœžœžœžœ˜gšžœ&žœ˜.Jšœžœ˜Jšœžœ˜ J˜—šžœ˜Kšœžœ˜Kšœ+žœ˜6Kšœ0˜0J˜—J˜—Kšœ@˜@Kšžœžœžœ4˜FJ˜—šžœžœ ž˜šœžœ ž˜šœ˜Kšœ6˜6Kšœžœ˜0Kšœžœ ˜*K˜—šœ˜Kšœ'žœ ˜8—Kšžœžœ˜——Kšœ   œ!žœžœ˜PKšœ$˜$Kšœ$£œ£˜0K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœo˜oKšœjžœžœ˜‰šž˜Kšœ‘˜‘Kšœy˜yKšœw˜w—K˜K˜—šœžœ˜1Kšœžœ˜Kšœ žœžœ˜+K˜Kšœ žœžœ˜1š œžœžœžœžœ˜>š œ˜Kš  œžœžœžœžœ™:Kšœžœ,˜3K˜—KšœEŸ%˜jK–s[sliceD: GGModelTypes.SliceDescriptor, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šœ4Ÿ˜DJ˜—š žœžœ žœžœ ž˜2šœ˜Kšœ6˜6Kšœžœ˜0Kšœžœ ˜*K˜—šœ˜Kšœ'žœ ˜8—Kšžœžœ˜—Kšœ   œ!žœžœ˜PKšœ+˜+Kšœ$£œ£˜0K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœs˜sKšœjžœžœ˜‰šž˜Kšœ“˜“Kšœ{˜{Kšœy˜y—K˜K˜—šœžœ˜-K˜Kšœ žœžœ˜KšœG˜Gšžœ žœ˜Kšœ+˜+Kšœžœ˜"K˜—K˜K˜—šœžœ˜5Kšœ žœžœ˜+Kšœ5˜5Kšœ+˜+K˜K˜—šœžœ˜-K˜Kšœ žœžœ˜KšœK˜Kšžœ žœ˜Kšœ-˜-Kšœžœ˜"K˜—K˜K˜—šœžœ˜5Kšœ žœžœ˜+Kšœ5˜5Kšœ-˜-K˜K˜—šœžœ˜.Kšœ0˜0KšžœžœžœL˜]Kšžœr˜vK˜K˜—šœžœ˜.Kšœ2˜2KšžœžœžœN˜_Kšžœt˜xK˜K˜—šœžœ™-Kšœžœžœ™/Kšœžœ"™=Kšœ2™2Kšœ'™'K™K™—šœžœ™/Kšœžœžœ™/Kšœžœ"™?Kšœ4™4Kšœ)™)K™K™—šœžœ™1Kšœžœ™9Kšœ€™€K™K™—šœžœ™3Kšœžœ™;Kšœ„™„K™—K˜šœžœ˜(KšœI˜IK˜K˜—šœžœ˜(KšœI˜IK˜K˜—šœžœ˜(KšœI˜IK˜K˜—šœžœ˜(KšœI˜IK˜K˜—š œžœ˜'KšœW˜WK˜K˜—š œžœ˜'KšœW˜WK˜K˜—š œžœ˜'Kšœžœžœ˜K˜K˜—š œžœ˜'Kšœžœžœ˜K˜K˜—šœžœ˜)Kšœ˜Kšœ˜Kšœ˜K˜Kšœ žœžœ˜š œžœžœžœžœ˜KKšœQ˜QK˜—Kšœ.˜.Kšžœ žœžœR˜hšžœ žœ˜Kšœ  œŸ˜\Kšœ,£œ £œ£˜BK–T[scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass _ normal]šœR™RKšœE™EKšœ   œ ˜Kšœg˜gKšœnžœžœ˜ŒK˜—šžœ˜Kšœ›˜›K˜—K˜K˜—š œžœ˜'Kšœ˜Kšœ˜Kšœ˜K˜Kšœ žœžœ˜š œžœžœžœžœ˜KKšœd˜dK˜—Kšœ.˜.Kšžœ žœžœP˜fšžœ žœ˜Kšœ  œŸ˜ZKšœ,£œ £œ£˜BK˜K–T[scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass _ normal]šœR™RKšœE™EKšœ   œ ˜Kšœe˜eKšœnžœžœ˜ŒK˜—šžœ˜KšœŠ˜ŠK˜—K˜K˜—š œ˜ Kšœ˜Kšœ žœžœ˜KšœA˜Ašžœ žœ˜Kšžœžœžœl˜}KšžœQ˜UK˜—K˜K˜—šœžœ˜)Kšœ˜Kšœ žœžœ˜KšœE˜Ešžœ žœ˜Kšžœžœžœn˜KšžœU˜YK˜—K˜K˜—šœžœžœ!˜]Kšœƒ  œ™šš œžœžœžœ žœžœ˜Jšœ žœ$˜3šžœ ž˜˜ Kšœžœ˜Kšœžœ˜ K˜—šžœ˜ Kšœžœ˜Kšœ*žœ ˜6Kšœ˜——J˜—Kšœ ŸœR˜bK˜K˜—š œžœžœ2žœžœ žœžœ žœ ˜ƒKš žœ-žœžœžœnžœž˜¸šžœ˜Kšœ˜K–_[gargoyleData: GGInterfaceTypes.GargoyleData, selectClass: GGInterfaceTypes.SelectionClass]˜Kšœžœžœ˜,Kšœ#˜#š œžœžœžœžœ˜MKšœQ˜QKšœP˜PJ˜—Kšœ  œŸ˜YKšœ<˜žœ˜|Kšœ(˜(Kšžœ˜—K˜K˜—š œžœ˜$Kšœžœ˜šž˜Kšžœžœ„žœ˜˜Kšœžœžœ˜/Kšœžœžœ˜3K–Ø[name: ROPE, lock: FS.Lock _ read, wantedCreatedTime: GMT _ nullGMT, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL, verifyNow: BOOL _ FALSE, checkFileType: BOOL _ FALSE, fileType: FS.FileType _ [0B (0)]]šœžœžœ˜ Kšœ:™:Kšœ˜Kšœžœ#˜)K–F[self: STREAM, r: ROPE, start: INT _ 0, len: INT _ 2147483647]š žœžœžœžœžœžœ˜BKšœ(˜(Kšžœ˜—K˜K˜—š œžœ˜$Kšžœžœjžœ˜~Kšœžœžœ˜/K–Ø[name: ROPE, lock: FS.Lock _ read, wantedCreatedTime: GMT _ nullGMT, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL, verifyNow: BOOL _ FALSE, checkFileType: BOOL _ FALSE, fileType: FS.FileType _ [0B (0)]]šœžœžœžœBŸ™qK–Ø[name: ROPE, lock: FS.Lock _ read, wantedCreatedTime: GMT _ nullGMT, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL, verifyNow: BOOL _ FALSE, checkFileType: BOOL _ FALSE, fileType: FS.FileType _ [0B (0)]]šœžœžœžœ Ÿ˜OKšœ(˜(K˜K˜—šœžœ˜)Kšœ4˜4KšœH˜HK˜K˜—šœžœ˜)Kšœjžœžœ˜ˆK˜K˜—šœžœ˜(Kšœižœžœ˜‡K˜K˜—šœžœ˜(Kšœižœžœ˜‡K˜K˜—šœžœ˜*Kšœkžœžœ˜‰K˜K˜—šœžœ˜*Kšœkžœžœ˜‰K˜K˜—š œžœ˜'Kšœžœžœ˜!Kšœ]žœžœ˜{K˜K™—šœžœ˜-Kšœžœ˜%Kšœ9˜9Kšžœžœžœ*˜;KšœU˜UK˜K˜—šœžœ™!Kšœžœ™Kšœ,™,Kšœ$™$K™pK™K™—š œžœ˜&Kšœ)˜)Kšœ,˜,Kšœžœ˜š œžœžœžœžœ˜Dšžœ žœ˜Jšœ˜Jšœ˜J˜—šžœžœ žœ˜Jšœ˜Jšœžœ˜ J˜—J˜—Jšœ$£œ£˜6Jšžœ2˜8K˜—K˜KšœžœžœŸ˜8K˜š œžœ˜'šžœžœ˜šžœžœžœžœžœžœžœž˜@Kšžœ žœž˜KšœžœZ˜dKšœžœžœO˜[KšœžœžœL˜ZKšœžœžœP˜^Kšœ žœžœT˜eKšœˆ˜ˆKšžœN˜U—Kšžœ˜Kšœ6˜6K˜—K˜K˜—šœžœ˜)Kšœžœ˜K˜K˜—šœžœ˜*Kšœžœ˜K˜K˜—š œžœ˜$Kšœ˜K˜—K˜šœžœ˜Kšžœ ˜K˜K™ Kšœ(˜(Kšœ$˜$Kšœ2˜2Kšœ$˜$Kšœ2˜2Kšœ ˜ Kšœ.˜.Kšœ*˜*Kšœ0˜0Kšœ2˜2Kšœ8˜8Kšœ$˜$Kšœ.˜.Kšœ2˜2Kšœ"˜"Kšœ,˜,Kšœ2˜2K˜K™ Kšœ.˜.Kšœ0˜0Kšœ8˜8KšœD˜DKšœ6˜6Kšœ(˜(Kšœ:˜:Kšœ,˜,Kšœ4˜4Kšœ0˜0Kšœ.˜.K˜K™ KšœF˜FKšœB˜BKšœJ˜JKšœB˜BKšœL˜LKšœJ˜JKšœL˜LKšœV˜VKšœ5˜5KšœF˜FKšœF˜FKšœ6˜6Kšœ6˜6Kšœ4˜4Kšœ4˜4Kšœ4˜4Kšœ@˜@KšœP˜PKšœB˜BK˜K™ KšœF˜FKšœF˜FKšœJ˜JKšœB˜BKšœL˜LKšœJ˜JKšœP˜PKšœZ˜ZKšœF˜FKšœF˜FKšœ7˜7Kšœ6˜6Kšœ6˜6Kšœ4˜4Kšœ4˜4Kšœ8˜8Kšœ@˜@KšœP˜PKšœB˜BK™Kšœ@™@KšœD™DKšœH™HKšœL™LK˜K™ Kšœ2˜2Kšœ:™:Kšœ.˜.Kšœ:˜:KšœF˜FKšœH˜HKšœ.˜.Kšœ.˜.Kšœ8˜8Kšœ6˜6Kšœ6˜6Kšœ:˜:Kšœ:˜:Kšœ8˜8Kšœ5˜5Kšœ4˜4Kšœ2˜2Kšœ.˜.Kšœ@˜@Kšœ(™(Kšœ6˜6Kšœ7˜7Kšœ2˜2K˜K˜—K˜K˜K˜Kšžœ˜—…—úvÿ