<> <> <> <> <<>> DIRECTORY Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, FS, GGError, GGEvent, GGFileIn, GGFileOut, FileNames, Imager, ImagerColor, ImagerColorPrivate, GGInterfaceTypes, GGModelTypes, GGObjects, GGSelect, GGSegmentTypes, GGSequence, GGUtility, GGWindow, Icons, IO, List, NamedColors, PrincOpsUtils, Rope, ViewerClasses, ViewerOps, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, FileNames, FS, GGError, GGFileIn, GGFileOut, GGEvent, GGObjects, GGSelect, GGSequence, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorPrivate, Icons, IO, List, NamedColors, PrincOpsUtils, Rope, ViewerOps, ViewerTools EXPORTS GGEvent = BEGIN EntityGenerator: TYPE = GGModelTypes.EntityGenerator; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; Segment: TYPE = GGSegmentTypes.Segment; SegAndIndex: TYPE = GGSequence.SegAndIndex; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; 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; }; 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.