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] = { }; 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. vGGEventImplD.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Bier on September 8, 1986 11:02:49 pm PDT Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Pier, February 2, 1987 11:09:26 am PST File Operations need to repaint the caption because viewer is no longer edited ASSERT: event is either NIL or event.first=filename ASSERT: event.first=$Get, event.rest=NIL OR filename ASSERT: event.first=$Merge, event.rest=NIL OR filename ASSERT: event=$Merge or $Get TIMING VARIABLES START TIMING here if successfully read a new GG file ASSERT: event.first=$Store or $Save, event.rest=NIL OR filename Save is simply Store invoked with event.first=gargoyleData.outer.file. KAP February 17, 1986 TIMING VARIABLES START TIMING can only reset to the latest version. No version numbers supported for resetting need to repaint the caption because viewer is no longer edited gargoyleData.refresh.suppressRefresh _ FALSE; -- moved to abort processing code Group Operations Area and Line Colors sliceGen: SliceGenerator _ GGObjects.SlicesInScene[gargoyleData.scene]; FOR slice: Slice _ GGObjects.NextSlice[sliceGen], GGObjects.NextSlice[sliceGen] UNTIL slice = NIL DO SLICES CAN'T ENUMERATE THEIR PARTS!! ENDLOOP; Debug Menu TestMultiGravity: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; 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 100 points have been drawn. xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point; x, y: INT; totalCount: NAT _ 0; features: GGMultiGravity.NearFeatures; points: GGMultiGravity.NearPoints; distances: GGMultiGravity.NearDistances; currentObjects: ObjectBag; sceneObjects: TriggerBag; count: NAT; xRandomStream _ Random.Create[gargoyleData.actionArea.cw]; yRandomStream _ Random.Create[gargoyleData.actionArea.ch]; GGAlign.SetBagsForAction[gargoyleData, $CaretPos]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintAlign, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; gargoyleData.hitTest.hitCount _ 0; 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; [features, points, distances, count] _ GGMultiGravity.MultiMap[20, testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE]; IF count > 0 THEN { FOR i: NAT IN [0..count-1] DO gargoyleData.refresh.hitPoint _ points[i]; IF distances[i] > gargoyleData.hitTest.tolerance THEN GOTO Done; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; gargoyleData.hitTest.hitCount _ gargoyleData.hitTest.hitCount + 1; REPEAT Done => { IF i = 0 THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; } ELSE { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; totalCount _ totalCount + 1; ENDLOOP; GGError.PutF[gargoyleData.feedback, oneLiner, "Tested %g total points. %g were hits", [integer[totalCount]], [integer[gargoyleData.hitTest.hitCount]]]; }; 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 100 points have been drawn. gargoyleData.hitTest.hitCount _ 0; Ê2S˜Icodešœ™Kšœ Ïmœ1™™>Kšœ žœ˜&Kšœ$˜$Kšœ3˜3Kšœ˜K˜—š Ÿœžœ žœžœžœžœžœžœžœžœžœžœ žœžœžœžœ˜ÓKšžœžœ™3š Ÿ œžœžœžœžœ žœ˜>šžœžœž˜Kšœžœžœžœ˜2Kšœžœžœ˜Kšžœžœ˜—K˜—Kšœžœ˜Kš œ žœžœžœ žœžœžœ%˜sKšœr˜rK˜K™—šŸœžœžœ žœžœžœžœžœžœ˜BKšœžœ ˜0Kšžœžœžœ ™4Kšœžœ˜Kšœžœžœ˜(Kšœy˜yšžœžœ žœ˜KšœQ˜QKšžœ˜ Kšœ˜—Kšœ˜KšœG˜GKšœ˜šž˜Kšœžœ%˜B—Kšœ˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜DKšœžœ ˜0Kšžœ!žœžœ ™6Kšœžœ˜Kšœžœžœ˜(Kšœy˜yšžœžœ žœ˜KšœQ˜QKšžœ˜ Kšœ˜—KšœI˜Išž˜Kšœžœ%˜B—Kšœ˜K˜—šŸ œžœžœžœžœ žœžœ!˜ˆKšžœ™Kšœžœžœ˜ šœ žœ˜KšÐbkÏb¡ ™—Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜K˜šœžœžœžœ ˜;Kšœ žœ/˜;Kšœ9˜9Kšžœ˜ Kšœ˜—Kšœ žœ9˜EKšœ6˜6Kšžœž™ Kš¢˜Kšœ0˜0Kšœ ˜ Kš¢˜Kšœ1˜1Kšœ žœ3˜?Kšœ4˜4Kšœ žœ™'š žœ žœžœžœ F˜zKšœ žœD˜OKšœ?˜?KšœWžœ˜]Kšœžœžœ#žœY˜²Kšœ˜—Kšœžœ ˜:Kšœžœ+žœ˜¶šž˜Kšœ.˜.—Kšœ ˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜DKšœžœ ˜0Kšžœ*žœžœ ™?KšœHžœ™]Kšœžœ˜Kšœžœžœ˜ Kšœžœ˜Kšœžœžœ˜(Kšžœž ™Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ ˜Kšœ žœ˜)Kšœ„˜„Kšžœžœ žœžœ˜Kšœžœžœ žœ˜@š œžœ"žœ žœžœ žœ ˜eKšœ žœ1˜=Kšžœžœ žœ:˜OKšžœ˜ Kšœ˜—Kšœžœ;˜AKš œ žœžœžœ žœžœ˜VKšœ žœ:˜FKšžœžœ žœ7˜LKšžœž™ Kš¢˜Kšœ<˜Kšœ>™>—Kšœ˜Kšœ˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜DKšœžœ ˜0Kšœ˜Kšœžœ˜Kšœ&˜&Kšœ%˜%Kšœžœ˜)Kšœžœ žœžœ˜®Kšœ˜Kšœ  ˜K˜—š Ÿœžœ žœžœžœžœ!˜GKšœ#žœ˜'Kšœ3˜3Kšœ-˜-Kšœžœ˜4Kšœžœ˜5Kšœžœ%˜DKšœ'žœ !™OKšœžœžœ˜"Kšœ˜—K˜K™šŸ œžœžœ žœžœžœžœžœžœ˜IKšœžœžœ˜Kšœ˜Kšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lšžœžœžœžœ˜*KšœM˜MKšžœ˜K˜—Kšœ@˜@šžœSžœžœž˜fKšœ>˜>šžœOžœžœž˜bKšœ žœžœ˜šžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)šžœžœžœ˜+Kšœ žœ ˜*Kšžœ˜K˜—Kšžœ˜—Kšžœžœ žœ$žœ˜EKšœžœ˜Kšžœ˜—Kšžœ˜—Kšœ.žœžœ'žœ<˜©šœ˜K˜——šŸ œžœžœ žœžœžœžœžœžœ˜JKšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lKšœD˜DKšœ˜K˜Kšœ žœ˜Kšœ2 ˜MšžœGžœžœž˜]Kšœ)˜)Kšœ žœ˜šžœdžœ žœž˜|šžœžœžœžœžœžœžœž˜GKšœžœžœ ˜)šžœ¢œžœžœ˜+Kšžœžœ žœ$˜9Kšœ žœ˜šžœžœžœ˜&Kšœžœ˜ Kšœ ˜ K˜—K˜—Kšžœ  ˜—Kšžœ ˜—Kšžœ žœ:˜KKšžœ ˜—Kšœyžœ žœžœ˜§Kšžœ3žœH˜KšžœS˜Wšœ˜K˜——šŸœžœžœ žœžœžœžœžœžœ˜NKšœ žœžœ˜Kš œ žœžœžœžœ˜Kšœ˜Kšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lšžœžœžœžœ˜*KšœM˜MKšžœ˜K˜—Kšœ@˜@šžœSžœžœž˜fKšœ>˜>šžœOžœžœž˜bKšœ žœ˜šžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kšžœžœžœžœ"žœ žœžœ˜wKšžœ˜—Kšœ˜Kšžœ˜—Kšžœ˜—Kšœ.žœ žœ+žœG˜·šœ˜K˜——šŸœžœžœ žœžœžœžœžœžœ˜TKš œ žœžœžœžœ˜Kšœ˜Kšœžœ ˜0šžœ3žœ˜;KšœT˜TKšžœ˜K˜—Kšœ@˜@šžœSžœžœž˜fKšœ>˜>šžœOžœžœž˜bšžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kšœ žœžœ˜šžœžœžœžœžœžœžœž˜EKšœžœžœ˜+šžœ!žœžœ˜0Kšœ žœ ˜.Kšžœ˜K˜—Kšžœ˜—K•StartOfExpansion4[l1: LIST OF REF ANY, l2: LIST OF REF ANY _ NIL]šžœžœ žœ$žœ ˜IKšžœ˜—Kšžœ˜—Kšžœ˜—šžœ žœžœ˜KšœE˜Ešžœžœžœžœžœžœžœž˜EKšœžœžœ˜+KšœG˜GKšžœ˜—Kšœ/˜/Kšœ˜—KšžœJ˜NKšœ˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜MKš œ žœžœžœžœ˜Kšœžœ ˜0KšœD˜DšžœGžœžœž˜]Kšœ;˜;šžœOžœžœž˜bšžœžœžœžœžœžœžœž˜BKšœžœžœ ˜)Kšœ žœžœ˜šžœžœžœžœžœžœžœž˜EKšœžœžœ˜+šžœ!žœžœ˜0Kšœ žœ ˜.Kšžœ˜K˜—Kšžœ˜—K–4[l1: LIST OF REF ANY, l2: LIST OF REF ANY _ NIL]šžœžœ žœ$žœ ˜IKšžœ˜—Kšžœ˜—Kšžœ˜—šžœ žœžœ˜Kšœ9˜9šžœžœžœžœžœžœžœž˜EKšœžœžœ˜+KšœG˜GKšžœ˜—Kšœ/˜/Kšœ˜—Kšžœ>˜BKšœ˜—K˜K™KšŸœžœžœ˜ šŸœžœžœ žœžœžœžœžœžœ˜UKšœžœ ˜0šžœ žœ˜(K˜Kšœžœ˜KšœE˜EK–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœ:˜:Kšœ"˜"K˜—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜UKšœžœ ˜0šžœ žœ˜(K˜Kšœžœ˜KšœE˜EK–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœ:˜:Kšœ"˜"K˜—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜WKšœžœ ˜0šžœ žœ˜(Kšœ? ˜SKšœ"˜"Kšœ˜—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜WKšœžœ ˜0šžœ žœ˜(Kšœ? ˜SKšœ"˜"Kšœ˜—K˜K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜SKšœžœ ˜0šžœ žœ˜(Kšœžœ˜Kšœžœ˜K–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœP˜Pšžœ!žœž˜0KšœY˜YKšœQ˜QKšžœžœ˜—šžœžœžœ˜Kšœžœ˜)Kšœ6˜6Kšœ:˜:Kšœ8˜8Kšœ.˜.K˜—KšžœT˜XK˜—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜SKšœžœ ˜0šžœ žœ˜(Kšœžœ˜Kšœžœ˜K–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœP˜Pšžœ!žœž˜0Kšœk˜kKšœa˜aKšžœžœ˜—šžœžœžœ˜Kšœžœ˜)Kšœ6˜6Kšœ:˜:Kšœ8˜8Kšœ.˜.K˜—KšžœV˜ZK˜—K˜K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜XKšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lšœb˜bKšœžœ˜0Kšœžœ ˜*K˜—Kšœ"˜"šž˜Kšœ'žœVžœ'˜°Kšœ$žœPžœ'˜§—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜XKšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lšœb˜bKšœžœ˜0Kšœžœ ˜*K˜—Kšœ"˜"šž˜Kšœ'žœVžœ'˜°Kšœ$žœPžœ'˜§—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜WKšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lKšœVžœ˜iKšœ"˜"šž˜Kšœ%žœyžœ'˜Ñ—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜WKšœžœ ˜0Kš œ žœžœžœžœ$žœžœ˜lKšœVžœ˜iKšœ"˜"šž˜Kšœ%žœyžœ'˜Ñ—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜VKšœžœ ˜0Kšœžœ˜Kš œ žœžœžœžœ$žœžœ˜lKšœS˜SKšœ žœžœ˜1š žœžœ žœžœ ž˜3šœ˜Kšœ3˜3Kšœžœ˜0Kšœžœ ˜*K˜—šœ˜Kšœ'žœ ˜8—Kšžœžœ˜—Kšœ1˜1š žœ žœžœDžœ žœž˜lšžœžœž˜˜Kšœ>˜>Kšžœ*žœC˜sK˜—˜Kšœ:˜:Kšžœ*žœ9žœ)˜•K˜—Kšžœžœ˜—Kšžœ˜—K–Û[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[]]]šœh˜hKšœyžœ žœžœ˜¨šž˜Kšœ%žœyžœ'˜ÑKšœ'žœVžœ'˜°Kšœ$žœPžœ'˜§—K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜VKšœžœ ˜0Kšœžœ˜Kš œ žœžœžœžœ$žœžœ˜lKšœD˜DKšœG™GKšœ žœžœ˜1š žœžœ žœžœ ž˜2šœ˜Kšœ3˜3Kšœžœ˜0Kšœžœ ˜*K˜—šœ˜Kšœ'žœ ˜8—Kšžœžœ˜—Kšœ1˜1šžœGžœžœž˜]Kšœ;˜;šžœkžœžœž˜Œšžœ6žœ˜>KšœF˜FKšœ9˜9Kšœ˜—Kšžœ˜—Kšžœ˜—šžœMžœ žœž™dKš žœžœž œžœžœ™$Kšžœ™—K–Û[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[]]]šœf˜fKšœyžœ žœžœ˜¨šž˜Kšœ%žœyžœ'˜ÑKšœ'žœVžœ'˜°Kšœ$žœPžœ'˜§—K˜K˜—K˜š Ÿœžœžœ!žœžœžœ˜cKšœ žœ ˜Kš žœžœžœžœ  ˜9š žœ žœžœžœžœ˜*Kšœžœ˜)Kšœžœ3˜:Kšœžœ5˜Kšœˆ˜ˆKšœ+˜+K˜—šžœžœžœ˜$KšœC˜CKšœ?˜?Kšœ¯˜¯Kšœ)˜)Kšœxžœ žœžœ˜§Kšœ+˜+K˜—Kšžœžœ˜ Kšœxžœ žœžœ˜§K˜K˜—šŸ œžœžœ žœžœžœžœžœžœ˜IKšœžœ ˜0KšœV˜VK˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜NKšœžœ ˜0Kšœ4˜4K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜NKšœžœ ˜0Kšœyžœ žœžœ˜§K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜RKšœžœ ˜0Kšœ-˜-K˜K˜—K˜šŸœžœžœ žœžœžœžœžœžœ˜MKšœžœ ˜0Kšœxžœ žœžœ˜¦K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜MKšœžœ ˜0Kšœxžœ žœžœ˜¦K˜K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜OKšœžœ ˜0Kšœzžœ žœžœ˜¨K˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜OKšœžœ ˜0Kšœzžœ žœžœ˜¨K˜K˜—šŸ œžœžœ žœžœžœžœžœžœ˜LKšœžœ ˜0Kšœwžœ žœžœ˜¥K˜K™—šŸœžœžœ žœžœžœžœžœžœ˜RKšœžœ ˜0Kšœžœ˜%Kšœžœžœ˜Kšœ-˜-šžœ žœžœ˜šžœžœž˜˜ KšœL˜LK˜—˜KšœF˜FK˜—Kšžœžœ˜—K˜—Kšœ&žœ:˜bK˜K˜—šŸ œžœžœ žœžœžœžœžœžœ˜IKšœžœ%˜BKšœ˜K˜—šŸœžœžœ žœžœžœžœžœžœ˜GKšœžœ ˜0KšœP˜PK˜—K˜Kšœ& ˜:K˜šŸœžœ ˜*Kšœ8 m˜¥Kšœ˜—K˜Kšœ˜K˜Kšžœ˜—…—ªìã