<> <> <> <> <> <<>> DIRECTORY --CombinePoly,-- --GGTouch,-- --PrincOpsUtils,-- Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, CubicSplines, FileNames, FS, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGError, GGEvent, GGFileIn, GGFileOut, GGGravity, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGObjects, GGSegmentTypes, GGSelect, GGSequence, GGStatistics, GGTouch, GGUtility, GGVector, GGWindow, Icons, Imager, ImagerColor, ImagerColorPrivate, IO, IPMaster, List, NamedColors, PrincOpsUtils, Random, Rope, Rosary, SlackProcess, ViewerClasses, ViewerOps, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS --CombinePoly,-- --GGTouch,-- --PrincOpsUtils,-- Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, FileNames, FS, GGAlign, GGCaret, GGError, GGEvent, GGFileIn, GGFileOut, GGGravity, GGMultiGravity, GGObjects, GGSelect, GGSequence, GGStatistics, GGTouch, GGUtility, GGVector, GGWindow, Icons, Imager, ImagerColor, ImagerColorPrivate, IO, List, NamedColors, PrincOpsUtils, Random, Rope, SlackProcess, ViewerOps, ViewerTools EXPORTS GGEvent = BEGIN BoundBox: TYPE = GGBoundBox.BoundBox; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; ObjectBag: TYPE = GGGravity.ObjectBag; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; Point: TYPE = GGBasicTypes.Point; Scene: TYPE = GGModelTypes.Scene; SegAndIndex: TYPE = GGSequence.SegAndIndex; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; TriggerBag: TYPE = GGGravity.TriggerBag; Vector: TYPE = GGBasicTypes.Vector; Viewer: TYPE = ViewerClasses.Viewer; PaintActionArea: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ViewerOps.PaintViewer[ viewer: gargoyleData.actionArea, hint: client, whatChanged: gargoyleData, clearClient: FALSE]; }; <> <<>> NotNewVersion: PROC [gargoyleData: GargoyleData] = { <> gargoyleData.outer.newVersion _ FALSE; gargoyleData.outer.icon _ cleanIcon; ViewerOps.PaintViewer[gargoyleData.outer, caption]; }; GetGargoyleFileName: PROC [event: LIST OF REF ANY, currentWDir: Rope.ROPE, feedback: Viewer, emergency: BOOL _ FALSE] RETURNS [fullName: Rope.ROPE _ NIL, success: BOOL _ TRUE, versionSpecified: 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: Rope.ROPE; fileName _ IF event#NIL AND event.first#NIL THEN RopeFromRef[event.first] ELSE ViewerTools.GetSelectionContents[]; [fullName, success, versionSpecified] _ GGUtility.GetGargoyleFileName[fileName, currentWDir, feedback, emergency]; }; <<>> Get: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; <> fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN { GGError.Append[gargoyleData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; ClearAux[event, gargoyleData]; GetMergeAux[fullName, versionSpecified, $Get, "Getting", gargoyleData]; NotNewVersion[gargoyleData]; EXITS Abort => GGError.Blink[NARROW[clientData, GargoyleData].feedback]; }; Merge: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; <> fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN { GGError.Append[gargoyleData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; GetMergeAux[fullName, versionSpecified, $Merge, "Merging", gargoyleData]; EXITS Abort => GGError.Blink[NARROW[clientData, GargoyleData].feedback]; }; GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOL _ FALSE, event: ATOM, opName: Rope.ROPE, gargoyleData: GargoyleData] = { <> f: IO.STREAM; fsName: Rope.ROPE; <> startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope: Rope.ROPE; f _ FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => { msgRope _ IO.PutFR["Could not find: %g", [rope[fullName]]]; GGError.Append[gargoyleData.feedback, msgRope, oneLiner]; GOTO Abort; };]; msgRope _ IO.PutFR["%g %g . . . ", [rope[opName]], [rope[fullName]]]; GGError.Append[gargoyleData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; GGFileIn.FileinSceneAndOptions[f, gargoyleData]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; GGError.Append[gargoyleData.feedback, msgRope, end]; <> IF event=$Get OR gargoyleData.outer.file=NIL THEN { -- update viewer name on Get or on first Merge if no Get preceeded it. fsName _ FS.FileInfo[name: fullName, wDir: gargoyleData.currentWDir].fullFName; gargoyleData.outer.file _ FileNames.StripVersionNumber[fsName]; gargoyleData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; gargoyleData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", gargoyleData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; }; GGEvent.SawTextFinish[LIST[$SawTextFinish], gargoyleData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE]; EXITS Abort => GGError.Blink[gargoyleData.feedback]; }; -- end GetMergeAux Store: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; <> <> tKeep: CARDINAL _ 0; f: IO.STREAM; fullName, fsName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; <> startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope, opName: Rope.ROPE; ofile: FS.OpenFile; emergency: BOOL _ event.first=$Emergency; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, gargoyleData.currentWDir, gargoyleData.feedback, emergency]; IF NOT success THEN RETURN; 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["Could not create: %g", [rope[fullName]]]; IF NOT emergency THEN GGError.Append[gargoyleData.feedback, msgRope, oneLiner]; GOTO Abort; };]; 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 GGError.Append[gargoyleData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; GGFileOut.FileoutSceneAndOptions[f, gargoyleData, fullName]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; IF NOT emergency THEN GGError.Append[gargoyleData.feedback, msgRope, end]; fsName _ FS.FileInfo[name: fullName, wDir: gargoyleData.currentWDir].fullFName; --latest version gargoyleData.outer.file _ FileNames.StripVersionNumber[fsName]; gargoyleData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; gargoyleData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", gargoyleData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; NotNewVersion[gargoyleData]; GGEvent.SawTextFinish[NIL, gargoyleData]; EXITS Abort => { gargoyleData: GargoyleData _ NARROW[clientData]; IF NOT event.first=$Emergency THEN GGError.Blink[gargoyleData.feedback]; }; }; Save: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF gargoyleData.outer.file#NIL THEN Store[event: LIST[$Save, gargoyleData.outer.file], clientData: clientData] ELSE { GGError.Append[gargoyleData.feedback, "Can't save an unnamed viewer: try Store", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; }; Split: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData];}; Reset: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; fileName: Rope.ROPE _ gargoyleData.outer.file; ClearAux[event, gargoyleData]; <> GetMergeAux[fileName, FALSE, $Get, "Restoring", gargoyleData]; <> NotNewVersion[gargoyleData]; }; Clear: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ClearAux[event, gargoyleData]; gargoyleData.outer.file _ NIL; gargoyleData.outer.label _ "Gargoyle"; gargoyleData.outer.name _ "Gargoyle"; GGEvent.SawTextFinish[NIL, gargoyleData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; NotNewVersion[gargoyleData]; }; -- end Clear ClearAux: PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = { gargoyleData.refresh.overlayList _ NIL; GGSelect.DeselectAllAllClasses[gargoyleData.scene]; gargoyleData.scene _ GGObjects.CreateScene[]; gargoyleData.caret _ NEW[GGInterfaceTypes.CaretObj]; gargoyleData.anchor _ NEW[GGInterfaceTypes.CaretObj]; GGEvent.StandardAlignments[LIST[$StandardAlignments], gargoyleData]; <> gargoyleData.aborted _ ALL[FALSE]; }; <> AddToGroup: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { someAddition: BOOL _ FALSE; seqGen: SequenceGenerator; gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; IF name=NIL OR Rope.Equal[name, ""] THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] 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 _ List.Append[seg.props, LIST[name]]; someAddition _ TRUE; ENDLOOP; ENDLOOP; GGError.PutF[gargoyleData.feedback, oneLiner, IF someAddition THEN "Added selected segments to group %g" ELSE "No segment selections to add to group %g", [rope[name]] ]; }; SelectGroup: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; segGen: SegmentGenerator; seq: Sequence; segsFound: BOOL; GGSelect.DeselectAll[gargoyleData.scene, normal]; -- get rid of old selection FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO segGen _ GGSequence.SegmentsInTraj[traj]; segsFound _ FALSE; FOR next: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL next.seg=NIL DO FOR prop: LIST OF REF ANY _ next.seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN { IF NOT segsFound THEN seq _ GGSequence.CreateEmpty[traj]; segsFound _ TRUE; IF NOT seq.segments[next.index] THEN { seq.segments[next.index] _ TRUE; seq.segCount _ seq.segCount + 1; }; }; ENDLOOP; -- next prop ENDLOOP; -- next segment IF segsFound THEN GGSelect.SelectSequence[seq, gargoyleData.scene, normal]; ENDLOOP; -- next trajectory GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; IF GGSelect.NoSelections[gargoyleData.scene, normal] THEN GGError.AppendHerald[gargoyleData.feedback, "No such group", oneLiner ] ELSE GGError.PutF[gargoyleData.feedback, oneLiner, "Group %g selected", [rope[name]] ]; }; RemoveFromGroup: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { someRemoval: BOOL _ FALSE; newProps: LIST OF REF ANY; seqGen: SequenceGenerator; gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; IF name=NIL OR Rope.Equal[name, ""] THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] 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 _ List.Append[newProps, LIST[nextProp]] ELSE someRemoval _ TRUE; ENDLOOP; seg.props _ newProps; ENDLOOP; ENDLOOP; GGError.PutF[gargoyleData.feedback, oneLiner, IF someRemoval THEN "Removed selected segments from group %g" ELSE "No member segments selected to remove from group %g", [rope[name]] ]; }; PrintGroupsOfSelected: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { groupList: LIST OF REF ANY; seqGen: SequenceGenerator; gargoyleData: GargoyleData _ NARROW[clientData]; IF GGSelect.NoSelections[gargoyleData.scene, normal] THEN { GGError.AppendHerald[gargoyleData.feedback, "No selections => no groups", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] 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 _ List.Append[groupList, LIST[nextProp]]; ENDLOOP; ENDLOOP; ENDLOOP; IF groupList#NIL THEN { GGError.Append[gargoyleData.feedback, "Groups of Selected: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; GGError.PutF[gargoyleData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; GGError.Append[gargoyleData.feedback, "", end]; } ELSE GGError.Append[gargoyleData.feedback, "No Groups of Selected", oneLiner]; }; PrintAllGroups: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { groupList: LIST OF REF ANY; gargoyleData: GargoyleData _ NARROW[clientData]; trajGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] 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 _ List.Append[groupList, LIST[nextProp]]; ENDLOOP; ENDLOOP; ENDLOOP; IF groupList#NIL THEN { GGError.Append[gargoyleData.feedback, "Groups: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; GGError.PutF[gargoyleData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; GGError.Append[gargoyleData.feedback, "", end]; } ELSE GGError.Append[gargoyleData.feedback, "No Groups", oneLiner]; }; <> RGBFromRopeError: SIGNAL = CODE; AreaColorFromColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { color: Imager.Color; red, green, blue: REAL; [red: red, green: green, blue: blue] _ ColorToolViewer.GetRGBValue[]; color _ ImagerColor.ColorFromRGB[rgb: [red, green, blue]]; AreaColorAux[color, gargoyleData]; }; }; LineColorFromColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { color: Imager.Color; red, green, blue: REAL; [red: red, green: green, blue: blue] _ ColorToolViewer.GetRGBValue[]; color _ ImagerColor.ColorFromRGB[rgb: [red, green, blue]]; LineColorAux[color, gargoyleData]; }; }; AreaColorFollowColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { color: Imager.Color _ ColorToolViewerExtras.GetSpecialColor[]; -- "animation" color AreaColorAux[color, gargoyleData]; }; }; LineColorFollowColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { color: Imager.Color _ ColorToolViewerExtras.GetSpecialColor[]; -- "animation" color LineColorAux[color, gargoyleData]; }; }; AreaColorToColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { red, green, blue: REAL; color: Imager.Color _ NIL; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; WITH GGObjects.NextEntity[entityGen] SELECT FROM outlineD: OutlineDescriptor => color _ outlineD.slice.class.getFillColor[outlineD.slice]; sliceD: SliceDescriptor => color _ sliceD.slice.class.getFillColor[sliceD.slice]; ENDCASE => ERROR; IF color#NIL THEN { cc: Imager.ConstantColor _ NARROW[color]; red _ ImagerColorPrivate.ComponentFromColor[cc, $Red]; green _ ImagerColorPrivate.ComponentFromColor[cc, $Green]; blue _ ImagerColorPrivate.ComponentFromColor[cc, $Blue]; ColorToolViewer.SetRGBValue[red, green, blue]; } ELSE GGError.Append[gargoyleData.feedback, ". . . Object has NIL fill color", oneLiner]; }; }; LineColorToColorTool: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF ColorToolIsBound[gargoyleData] THEN { red, green, blue: REAL; color: Imager.Color _ NIL; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; WITH GGObjects.NextEntity[entityGen] SELECT FROM outlineD: OutlineDescriptor => color _ outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]; sliceD: SliceDescriptor => color _ sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]; ENDCASE => ERROR; IF color#NIL THEN { cc: Imager.ConstantColor _ NARROW[color]; red _ ImagerColorPrivate.ComponentFromColor[cc, $Red]; green _ ImagerColorPrivate.ComponentFromColor[cc, $Green]; blue _ ImagerColorPrivate.ComponentFromColor[cc, $Blue]; ColorToolViewer.SetRGBValue[red, green, blue]; } ELSE GGError.Append[gargoyleData.feedback, ". . . Object has NIL stroke color", oneLiner]; }; }; AreaColorFromSelectedName: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; AreaColorAux[color, gargoyleData]; EXITS UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; LineColorFromSelectedName: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; LineColorAux[color, gargoyleData]; EXITS UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; AreaColorFromSelectedRGB: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; AreaColorAux[color, gargoyleData]; EXITS SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; LineColorFromSelectedRGB: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; LineColorAux[color, gargoyleData]; EXITS SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; SelectMatchingAreaColor: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; entityGen: EntityGenerator _ GGObjects.TopLevelEntitiesInScene[gargoyleData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingAreaCNS => ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingAreaRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outline: Outline => { fillColor: Imager.Color _ outline.class.getFillColor[outline]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireOutline[outline, gargoyleData.scene, normal]; }; slice: Slice => { fillColor: Imager.Color _ slice.class.getFillColor[slice]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectSlice[slice, slice.class.newParts[slice, NIL, topLevel], gargoyleData.scene, normal]; }; ENDCASE => ERROR; ENDLOOP; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; SelectMatchingLineColor: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; <> noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingLineCNS => ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingLineRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR segAndIndex: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL segAndIndex.seg = NIL DO IF RGBEqualsColor[rgb, segAndIndex.seg.color, noneFlag] THEN { seq: Sequence _ GGSequence.CreateFromSegment[traj, segAndIndex.index]; GGSelect.SelectSequence[seq, gargoyleData.scene, normal]; }; ENDLOOP; ENDLOOP; <> <> <> GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Segments with color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];}; }; RGBEqualsColor: PROC [rgb: ImagerColor.RGB, color: Imager.Color, noneFlag: BOOL] RETURNS [BOOL] = { epsilon: REAL = 1.0E-3; IF color=NIL THEN RETURN [noneFlag]; -- fillColor is none IF noneFlag THEN RETURN [color=NIL] ELSE { cc: Imager.ConstantColor _ NARROW[color]; r: REAL _ ImagerColorPrivate.ComponentFromColor[cc, $Red]; g: REAL _ ImagerColorPrivate.ComponentFromColor[cc, $Green]; b: REAL _ ImagerColorPrivate.ComponentFromColor[cc, $Blue]; RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R] color _ NARROW[outlineD.slice.class.getFillColor[outlineD.slice]]; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getFillColor[sliceD.slice]]; ENDCASE => ERROR; IF color#NIL THEN { red _ ImagerColorPrivate.ComponentFromColor[color, $Red]; green _ ImagerColorPrivate.ComponentFromColor[color, $Green]; blue _ ImagerColorPrivate.ComponentFromColor[color, $Blue]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColor.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; GGError.Append[ gargoyleData.feedback, IO.PutFR["R: %1.2f G: %1.2f B: %1.2f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColor.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE GGError.Append[gargoyleData.feedback, "No Fill Color", oneLiner]; }; }; PrintLineColor: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entity: REF ANY; isProcessBlack: Rope.ROPE; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; IF entityGen=NIL OR (entity _ GGObjects.NextEntity[entityGen])=NIL OR GGObjects.NextEntity[entityGen]#NIL THEN GGError.AppendHerald[gargoyleData.feedback, "Select exactly one entity for PrintLineColor", oneLiner] ELSE { red, green, blue: REAL; color: Imager.ConstantColor; WITH entity SELECT FROM outlineD: OutlineDescriptor => color _ NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]]; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]]; ENDCASE => ERROR; IF color#NIL THEN { red _ ImagerColorPrivate.ComponentFromColor[color, $Red]; green _ ImagerColorPrivate.ComponentFromColor[color, $Green]; blue _ ImagerColorPrivate.ComponentFromColor[color, $Blue]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColor.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; GGError.Append[ gargoyleData.feedback, IO.PutFR["R: %1.2f G: %1.2f B: %1.2f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColor.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE GGError.Append[gargoyleData.feedback, "No Stroke Color", oneLiner]; }; }; AreaColorWhite: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; AreaColorAux[Imager.white, gargoyleData]; }; LineColorWhite: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; LineColorAux[Imager.white, gargoyleData]; }; AreaColorGray: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; AreaColorAux[GGObjects.fillColor, gargoyleData]; }; LineColorGray: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; LineColorAux[GGObjects.fillColor, gargoyleData]; }; AreaColorNone: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; AreaColorAux[NIL, gargoyleData]; }; LineColorNone: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; LineColorAux[NIL, gargoyleData]; }; AreaColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outlineD: OutlineDescriptor => outlineD.slice.class.setFillColor[outlineD.slice, color]; sliceD: SliceDescriptor => sliceD.slice.class.setFillColor[sliceD.slice, color]; ENDCASE => ERROR; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; LineColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; entityGen: EntityGenerator _ GGSelect.SelectedStuff[gargoyleData.scene, normal]; FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outlineD: OutlineDescriptor => outlineD.slice.class.setStrokeColor[outlineD.slice, outlineD.parts, color]; sliceD: SliceDescriptor => sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color]; ENDCASE => ERROR; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; <<>> ColorToolIsBound: PROC [gargoyleData: GargoyleData] RETURNS [BOOL] = TRUSTED { IF PrincOpsUtils.IsBound[LOOPHOLE[ColorToolViewer.GetRGBValue]] THEN RETURN[TRUE]; GGError.AppendHerald[gargoyleData.feedback, "Please start ColorTool and retry this operation", oneLiner]; 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]; IF Ascii.Upper[rs.GetChar[]]#'R THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.R _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; IF Ascii.Upper[rs.GetChar[]]#'G THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.G _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; IF Ascii.Upper[rs.GetChar[]]#'B THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.B _ rs.GetReal[]; Check[rgb.R]; Check[rgb.G]; Check[rgb.B]; EXITS RGBError => SIGNAL RGBFromRopeError; }; <> TestMultiGravity: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < 1000 DO>> <> <> <> <<};>> <> <> <> <> <> <> <> <<[features, points, distances, count] _ GGMultiGravity.MultiMap[20, testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE];>> < 0 THEN {>> <> <> < gargoyleData.hitTest.tolerance THEN GOTO Done;>> <> <> <> < {>> <> <> <<};>> <> <<}>> <> <> <<};>> <> <> <> <<};>> <<>> TestGravity: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; <> xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; uniPoint, multiPoint: Point; uniFeature, multiFeature: FeatureData; currentObjects: ObjectBag; sceneObjects: TriggerBag; xRandomStream _ Random.Create[gargoyleData.actionArea.cw]; yRandomStream _ Random.Create[gargoyleData.actionArea.ch]; GGAlign.SetBagsForAction[gargoyleData, $CaretPos]; <> gargoyleData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount > 1000 DO IF gargoyleData.aborted[gravitytest] THEN { gargoyleData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, gargoyleData: gargoyleData]; gargoyleData.refresh.spotPoint _ testPoint; currentObjects _ gargoyleData.hitTest.currentObjectBag; sceneObjects _ gargoyleData.hitTest.sceneTriggerBag; [uniPoint, uniFeature] _ GGGravity.UniMap[testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE]; [multiPoint, multiFeature] _ GGMultiGravity.Map[testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE]; IF uniFeature = NIL AND multiFeature = NIL THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; totalCount _ totalCount + 1; LOOP; }; IF uniFeature = NIL OR multiFeature = NIL OR uniFeature # multiFeature OR uniFeature.resultType # multiFeature.resultType OR uniPoint # multiPoint THEN { ReportResultsAndPaint[testPoint, uniPoint, uniFeature, multiPoint, multiFeature, gargoyleData]; totalCount _ totalCount + 1; diffCount _ diffCount + 1; IF multiFeature # NIL THEN multiHitCount _ multiHitCount + 1; IF uniFeature # NIL THEN uniHitCount _ uniHitCount + 1; } ELSE { multiHitCount _ multiHitCount + 1; uniHitCount _ uniHitCount + 1; totalCount _ totalCount + 1; gargoyleData.refresh.hitPoint _ multiPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; GGError.PutF[gargoyleData.feedback, oneLiner, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity ReportResultsAndPaint: PROC [testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, gargoyleData: GargoyleData] = { multiMag, uniMag: REAL; IF uniFeature = NIL THEN { multiMag _ GGVector.Magnitude[GGVector.Sub[multiPoint, testPoint]]; GGError.PutFTypescript[gargoyleData.feedback, oneLiner, "No unihit at [%g, %g]. multihit distance: %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]]]; gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF multiFeature = NIL THEN { uniMag _ GGVector.Magnitude[GGVector.Sub[uniPoint, testPoint]]; GGError.PutFTypescript[gargoyleData.feedback, oneLiner, "No multihit at [%g, %g]. unihit distance: %g", [real[uniPoint.x]], [real[uniPoint.y]], [real[uniMag]]]; gargoyleData.refresh.hitPoint _ uniPoint; } ELSE IF uniFeature # multiFeature THEN { multiMag _ GGVector.Magnitude[GGVector.Sub[multiPoint, testPoint]]; uniMag _ GGVector.Magnitude[GGVector.Sub[uniPoint, testPoint]]; GGError.PutFTypescript[gargoyleData.feedback, oneLiner, "Features differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF uniFeature.resultType # multiFeature.resultType THEN { GGError.PutFTypescript[gargoyleData.feedback, oneLiner, "Feature types differ at [%g, %g]", [real[multiPoint.x]], [real[multiPoint.y]]]; gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF uniPoint # multiPoint THEN { multiMag _ GGVector.Magnitude[GGVector.Sub[multiPoint, testPoint]]; uniMag _ GGVector.Magnitude[GGVector.Sub[uniPoint, testPoint]]; GGError.PutFTypescript[gargoyleData.feedback, oneLiner, "Points differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; gargoyleData.refresh.hitPoint _ uniPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; gargoyleData.refresh.hitPoint _ multiPoint; } ELSE ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; Statistics: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGStatistics.PrintTable[gargoyleData.debug.typescriptOut, GGStatistics.GlobalTable[]]; }; ResetStatistics: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGStatistics.ResetTable[GGStatistics.GlobalTable[]]; }; DrawTouchPoints: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DescribeTouchPoints: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGTouch.DescribeAllTouchPoints[gargoyleData]; }; DrawBoundBoxes: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawTightBoxes: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawOutlineBoxes: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawSelectionBox: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawMovingBox: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintMovingBox, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; <<>> DescribeCaretObject: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; description: Rope.ROPE _ "no object"; chair: REF ANY; chair _ GGCaret.GetChair[gargoyleData.caret]; IF chair # NIL THEN { WITH chair SELECT FROM outlineD: OutlineDescriptor => { description _ outlineD.slice.class.describe[outlineD.slice, outlineD.parts]; }; sliceD: SliceDescriptor => { description _ sliceD.slice.class.describe[sliceD.slice, sliceD.parts]; }; ENDCASE => ERROR; }; GGError.Append[gargoyleData.feedback, IO.PutFR["Caret is on %g.", [rope[description]]], oneLiner]; }; Typescript: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { GGError.OpenTypescript[NARROW[clientData, GargoyleData].feedback]; }; SlackLog: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SlackProcess.OutputLog[gargoyleData.slackHandle, GGError.GetTypescriptStream[]]; }; cleanIcon: Icons.IconFlavor _ unInit; -- filled in by Init Init: PROC = { -- copied from GGWindowImpl cleanIcon _ Icons.NewIconFromFile["Gargoyle.icons", 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ }; Init[]; END.