<> <> <> <> <> <<>> DIRECTORY --CombinePoly,-- Ascii, Atom, AtomButtonsTypes, BasicTime, CodeTimer, ColorTool, CubicSplines, Feedback, FileNames, FS, GGBasicTypes, GGBoundBox, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGOutline, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, PrincOpsUtils, Random, Rope, Rosary, Vectors2d, ViewerClasses, ViewerOps, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS ColorTool, --CombinePoly,-- PrincOpsUtils, Ascii, Atom, BasicTime, CodeTimer, Feedback, FileNames, FS, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGMultiGravity, GGOutline, GGScene, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, Random, Rope, Vectors2d, ViewerOps, ViewerTools EXPORTS GGEvent = BEGIN BoundBox: TYPE = GGBoundBox.BoundBox; WalkProc: TYPE = GGModelTypes.WalkProc; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; GGData: TYPE = GGInterfaceTypes.GGData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; AlignBag: TYPE = GGGravity.AlignBag; 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 [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; ViewerOps.PaintViewer[ viewer: ggData.actionArea, hint: client, whatChanged: ggData, clearClient: FALSE]; }; <> <<>> NotNewVersion: PROC [ggData: GGData, op: ATOM] = { <> ggData.outer.newVersion _ FALSE; ggData.outer.icon _ SELECT op FROM $clear => noNameIcon, $clean => cleanIcon, ENDCASE => ERROR; ViewerOps.PaintViewer[ggData.outer, caption]; }; GetGargoyleFileName: PROC [event: LIST OF REF ANY, currentWDir: Rope.ROPE, feedback: FeedbackData, 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 [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; <> fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback]; IF NOT success THEN { Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; ClearAux[event, ggData]; GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData]; NotNewVersion[ggData, $clean]; EXITS Abort => Feedback.Blink[NARROW[clientData, GGData].feedback]; }; Merge: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; <> fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback]; IF NOT success THEN { Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; GetMergeAux[fullName, versionSpecified, $Merge, "Merging", ggData]; EXITS Abort => Feedback.Blink[NARROW[clientData, GGData].feedback]; }; GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOL _ FALSE, event: ATOM, opName: Rope.ROPE, ggData: GGData] = { <> 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]]]; Feedback.Append[ggData.feedback, msgRope, oneLiner]; GOTO Abort; };]; msgRope _ IO.PutFR["%g %g . . . ", [rope[opName]], [rope[fullName]]]; Feedback.Append[ggData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; GGFileIn.FileinSceneAndOptions[f, ggData]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; Feedback.Append[ggData.feedback, msgRope, end]; <> IF event=$Get OR ggData.outer.file=NIL THEN { -- update viewer name on Get or on first Merge if no Get preceeded it. fsName _ FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName; ggData.outer.file _ FileNames.StripVersionNumber[fsName]; ggData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; ggData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; }; GGEvent.SawTextFinish[ggData, LIST[$SawTextFinish]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE]; EXITS Abort => Feedback.Blink[ggData.feedback]; }; -- end GetMergeAux Store: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ 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, ggData.currentWDir, ggData.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 Feedback.Append[ggData.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 Feedback.Append[ggData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; GGFileOut.FileoutSceneAndOptions[f, ggData, fullName]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, end]; fsName _ FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName; --latest version ggData.outer.file _ FileNames.StripVersionNumber[fsName]; ggData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; ggData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; NotNewVersion[ggData, $clean]; GGEvent.SawTextFinish[ggData, NIL]; EXITS Abort => { ggData: GGData _ NARROW[clientData]; IF NOT event.first=$Emergency THEN Feedback.Blink[ggData.feedback]; }; }; Save: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ggData.outer.file#NIL THEN Store[event: LIST[$Save, ggData.outer.file], clientData: clientData] ELSE { Feedback.Append[ggData.feedback, "Can't save an unnamed viewer: try Store", oneLiner]; Feedback.Blink[ggData.feedback]; }; }; Split: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData];}; Reset: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; fileName: Rope.ROPE _ ggData.outer.file; ClearAux[event, ggData]; <> GetMergeAux[fileName, FALSE, $Get, "Restoring", ggData]; <> NotNewVersion[ggData, $clean]; }; Clear: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; ClearAux[event, ggData]; ggData.outer.file _ NIL; ggData.outer.label _ "Gargoyle"; ggData.outer.name _ "Gargoyle"; GGEvent.SawTextFinish[ggData, NIL]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; NotNewVersion[ggData, $clear]; }; -- end Clear ClearAux: PROC [event: LIST OF REF ANY, ggData: GGData] = { ggData.refresh.overlayList _ NIL; GGSelect.DeselectAllAllClasses[ggData.scene]; ggData.scene _ GGScene.CreateScene[]; ggData.caret _ NEW[GGInterfaceTypes.CaretObj]; ggData.anchor _ NEW[GGInterfaceTypes.CaretObj]; GGEvent.StandardAlignments[ggData, LIST[$StandardAlignments]]; <> ggData.aborted _ ALL[FALSE]; }; <> AddToGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { someAddition: BOOL _ FALSE; seqGen: SequenceGenerator; ggData: GGData _ 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 { Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.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; Feedback.PutF[ggData.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 [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; segGen: SegmentGenerator; seq: Sequence; segsFound: BOOL; GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.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, ggData.scene, normal]; ENDLOOP; -- next trajectory GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.AppendHerald[ggData.feedback, "No such group", oneLiner ] ELSE Feedback.PutF[ggData.feedback, oneLiner, "Group %g selected", [rope[name]] ]; }; RemoveFromGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { someRemoval: BOOL _ FALSE; newProps: LIST OF REF ANY; seqGen: SequenceGenerator; ggData: GGData _ 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 { Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.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; Feedback.PutF[ggData.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 [clientData: REF ANY, event: LIST OF REF ANY] = { groupList: LIST OF REF ANY; seqGen: SequenceGenerator; ggData: GGData _ NARROW[clientData]; IF GGSelect.NoSelections[ggData.scene, normal] THEN { Feedback.AppendHerald[ggData.feedback, "No selections => no groups", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.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 { Feedback.Append[ggData.feedback, "Groups of Selected: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.feedback, "", end]; } ELSE Feedback.Append[ggData.feedback, "No Groups of Selected", oneLiner]; }; PrintAllGroups: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { groupList: LIST OF REF ANY; ggData: GGData _ NARROW[clientData]; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.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 { Feedback.Append[ggData.feedback, "Groups: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.feedback, "", end]; } ELSE Feedback.Append[ggData.feedback, "No Groups", oneLiner]; }; <> RGBFromRopeError: SIGNAL = CODE; AreaColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN AreaColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData]; }; LineColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN LineColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData]; }; AreaColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { color: Imager.Color _ GGUtility.GetSpecialColor[]; -- "animation" color; IF color#NIL THEN { ggData.refresh.areaFollowColorTool _ TRUE; AreaColorAux[color, ggData]; } ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner]; }; }; LineColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { color: Imager.Color _ GGUtility.GetSpecialColor[]; -- "animation" color; IF color#NIL THEN { ggData.refresh.lineFollowColorTool _ TRUE; LineColorAux[color, ggData]; } ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner]; }; }; AreaColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { red, green, blue: REAL; color: Imager.Color; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; color _ sliceD.slice.class.getFillColor[sliceD.slice]; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; ColorTool.SetRGBValue[[red, green, blue], NIL]; } ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL fill color", oneLiner]; }; }; LineColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { red, green, blue: REAL; color: Imager.Color; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; color _ sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; ColorTool.SetRGBValue[[red, green, blue], NIL]; } ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL stroke color", oneLiner]; }; }; AreaColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; AreaColorAux[color, ggData]; EXITS UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; LineColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; LineColorAux[color, ggData]; EXITS UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; AreaColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ 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, ggData]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; LineColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ 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, ggData]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; <> <> <> <> <> <> <> <<$SelectMatchingAreaCNS =>>> <> < GOTO UndefinedName;>> < GOTO BadGrammar;>> <<]],>> <<$SelectMatchingAreaRGB =>>> < GOTO SyntaxError]>> < ERROR;>> <> <> <> < {>> <> <> <<};>> < {>> <> <> <<};>> < ERROR;>> <> <> <> <> < {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};>> < {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};>> < {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};>> <<};>> <<>> SelectMatchingAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; sliceGen: SliceGenerator _ GGScene.TopLevelSlicesInScene[ggData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; 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; GGSelect.DeselectAll[ggData.scene, normal]; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO fillColor: Imager.Color _ slice.class.getFillColor[slice]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireSlice[slice, ggData.scene, normal]; ENDLOOP; Feedback.PutFHerald[ggData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; SelectMatchingLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; <> sliceGen: SliceGenerator _ GGScene.SlicesInScene[ggData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; 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; GGSelect.DeselectAll[ggData.scene, normal]; <> <> <> <> <> <> <<};>> <> <> FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO -- for every slice in the scene ColorProc: WalkProc = { <> RETURN [RGBEqualsColor[rgb, seg.color, noneFlag]]; }; sliceD: SliceDescriptor _ GGSlice.WalkSegments[slice, ColorProc]; -- get a descriptor of matching parts GGSelect.SelectSlice[sliceD, ggData.scene, normal]; -- and select it ENDLOOP; Feedback.PutFHerald[ggData.feedback, oneLiner, "Segments with color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; SetDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceD: SliceDescriptor; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; IF sliceDescGen=NIL OR (sliceD _ GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for setting default line color", oneLiner] ELSE { isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner]; ggData.defaults.strokeColor _ color; }; }; SetDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceD: SliceDescriptor; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; IF sliceDescGen=NIL OR (sliceD _ GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one filled object for setting default fill color", oneLiner] ELSE { isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor; IF sliceD.slice.class.type=$Outline AND GGOutline.FenceOfOutline[sliceD.slice].role=open THEN { Feedback.AppendHerald[ggData.feedback, "Select one FILLED object for setting default fill color", oneLiner]; RETURN; } ELSE color _ NARROW[sliceD.slice.class.getFillColor[sliceD.slice]]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner]; ggData.defaults.fillColor _ color; }; }; ShowDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[ggData.defaults.strokeColor]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner]; }; ShowDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[ggData.defaults.fillColor]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner]; }; AreaColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[Imager.black, ggData]; }; LineColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[Imager.black, ggData]; }; PrintAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceD: SliceDescriptor; isProcessBlack: Rope.ROPE; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; IF sliceDescGen=NIL OR (sliceD _ GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for PrintFillColor", oneLiner] ELSE { red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[sliceD.slice.class.getFillColor[sliceD.slice]]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "No Fill Color", oneLiner]; }; }; PrintLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceD: SliceDescriptor; isProcessBlack: Rope.ROPE; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; IF sliceDescGen=NIL OR (sliceD _ GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for PrintLineColor", oneLiner] ELSE { red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]]; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "No Stroke Color", oneLiner]; }; }; AreaColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[Imager.white, ggData]; }; LineColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[Imager.white, ggData]; }; AreaColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[GGOutline.fillColor, ggData]; }; LineColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[GGOutline.fillColor, ggData]; }; AreaColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[NIL, ggData]; }; LineColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[NIL, ggData]; }; AreaColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO sliceD.slice.class.setFillColor[sliceD.slice, color]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; LineColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { ggData: GGData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[ggData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color]; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; <<>> ColorToolIsBound: PROC [ggData: GGData] RETURNS [BOOL _ FALSE] = TRUSTED { IF PrincOpsUtils.IsBound[LOOPHOLE[ColorTool.GetRGBValue]] THEN RETURN[TRUE]; Feedback.AppendHerald[ggData.feedback, "Please start ColorTool and retry this operation", oneLiner]; }; 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; [r,g,b] _ GGUtility.ExtractRGB[color]; RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R] 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 [clientData: REF ANY, event: LIST OF REF ANY] = { }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < 1000 DO>> <> <> <> <<};>> <> <> <> <> <> <> <> <<[features, points, distances, count] _ GGMultiGravity.MultiMap[20, testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE];>> < 0 THEN {>> <> <> < ggData.hitTest.tolerance THEN GOTO Done;>> <> <> <> < {>> <> <> <<};>> <> <<}>> <> <> <<};>> <> <> <> <<};>> <<>> TestGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; <> xRandomStream, yRandomStream: Random.RandomStream; desiredCount: INT _ NARROW[event.rest.first, REF INT]^; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; uniPoint, multiPoint: Point; uniFeature, multiFeature: FeatureData; currentObjects: AlignBag; sceneObjects: TriggerBag; IF desiredCount < 0 THEN RETURN; xRandomStream _ Random.Create[ggData.actionArea.cw]; yRandomStream _ Random.Create[ggData.actionArea.ch]; <> <> 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; [uniPoint, uniFeature] _ GGGravity.UniMap[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; [multiPoint, multiFeature] _ GGMultiGravity.Map[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; IF uniFeature = NIL AND multiFeature = NIL THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; totalCount _ totalCount + 1; LOOP; }; IF uniFeature = NIL OR multiFeature = NIL OR uniFeature # multiFeature OR uniFeature.type # multiFeature.type OR uniPoint # multiPoint THEN { ReportResultsAndPaint[testPoint, uniPoint, uniFeature, multiPoint, multiFeature, ggData]; 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; ggData.refresh.hitPoint _ multiPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity noisyTestGravity: BOOL _ FALSE; ReportResultsAndPaint: PROC [testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, ggData: GGData] = { multiMag, uniMag: REAL; IF uniFeature = NIL THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No unihit at [%g, %g]. multihit distance: %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF multiFeature = NIL THEN { uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No multihit at [%g, %g]. unihit distance: %g", [real[uniPoint.x]], [real[uniPoint.y]], [real[uniMag]]]; ggData.refresh.hitPoint _ uniPoint; } ELSE IF uniFeature # multiFeature THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Features differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF uniFeature.type # multiFeature.type THEN { IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Feature types differ at [%g, %g]", [real[multiPoint.x]], [real[multiPoint.y]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF uniPoint # multiPoint THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Points differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; ggData.refresh.hitPoint _ uniPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.refresh.hitPoint _ multiPoint; } ELSE ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; Statistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; f: IO.STREAM _ Feedback.GetTypescriptStream[$Gargoyle]; CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]]; }; PrintSelectedStatistic: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; intervalName: Rope.ROPE _ NARROW[event.rest.first]; atom: ATOM _ Atom.MakeAtom[intervalName]; f: IO.STREAM _ Feedback.GetTypescriptStream[$Gargoyle]; CodeTimer.PrintInt[f, atom, $Gargoyle]; }; ResetStatistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]]; }; DrawTouchPoints: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawBoundBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawTightBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawOutlineBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawSelectionBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawMovingBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; atom: ATOM _ NARROW[event.first]; GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; <<>> DescribeCaretObject: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; description: Rope.ROPE _ "no object"; chair: REF ANY; chair _ GGCaret.GetChair[ggData.caret]; IF chair # NIL THEN { WITH chair SELECT FROM outlineD: OutlineDescriptor => { description _ outlineD.slice.class.describe[outlineD]; }; sliceD: SliceDescriptor => { description _ sliceD.slice.class.describe[sliceD]; }; ENDCASE => ERROR; }; Feedback.Append[ggData.feedback, IO.PutFR["Caret is on %g.", [rope[description]]], oneLiner]; }; SlackLog: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; <> }; Typescript: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { [] _ Feedback.OpenTypescript["Gargoyle Typescript", $Gargoyle, 120]; }; cleanIcon: Icons.IconFlavor _ unInit; -- filled in by Init noNameIcon: Icons.IconFlavor _ unInit; -- filled in by Init Init: PROC = { -- copied from GGWindowImpl noNameIcon _ Icons.NewIconFromFile["Gargoyle.icons", 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ cleanIcon _ Icons.NewIconFromFile["Gargoyle.icons", 3]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ }; Init[]; END.