<> <> <> <> <> <> <> <<>> DIRECTORY Atom, BasicTime, BiScrollers, CodeTimer, ColorTool, CubicSplines, Feedback, FeedbackOps, FeedbackTypes, FileNames, FS, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGControlPanelTypes, GGCoreOps, GGDescribe, GGEvent, GGEventExtras, GGFileIn, GGFileOps, GGFileOut, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGRefreshTypes, GGScene, GGSegmentTypes, GGSelect, GGSessionLog, GGShapes, GGSlice, GGSliceOps, GGState, GGStateExtras, GGUIUtility, GGUserInput, GGUserProfile, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorFns, ImagerDitherContext, IO, NamedColors, Random, Real, RealFns, Rope, SlackProcess, SystemNames, TiogaOpsDefs, ViewersWorld, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS Atom, BasicTime, CodeTimer, ColorTool, Feedback, FeedbackOps, FileNames, FS, GGAlign, GGCaret, GGCoreOps, GGDescribe, GGEvent, GGFileIn, GGFileOps, GGFileOut, GGHistory, GGMultiGravity, GGOutline, GGParent, GGRefresh, GGScene, GGSelect, GGSessionLog, GGSlice, GGSliceOps, GGState, GGStateExtras, GGUIUtility, GGUserInput, GGUserProfile, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorFns, IO, NamedColors, Random, Real, RealFns, Rope, SlackProcess, SystemNames, ViewersWorld, ViewerTools EXPORTS GGEvent, GGEventExtras, GGInterfaceTypes = BEGIN AlignBag: TYPE = GGInterfaceTypes.AlignBag; BoundBox: TYPE = GGBoundBox.BoundBox; ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes FeatureData: TYPE = GGInterfaceTypes.FeatureData; MsgRouter: TYPE = FeedbackTypes.MsgRouter; GGData: TYPE = GGInterfaceTypes.GGData; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; Point: TYPE = GGBasicTypes.Point; RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj; ROPE: TYPE = Rope.ROPE; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; Sequence: TYPE = GGModelTypes.Sequence; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajData: TYPE = GGModelTypes.TrajData; TriggerBag: TYPE = GGInterfaceTypes.TriggerBag; UserInputProc: TYPE = GGEvent.UserInputProc; Vector: TYPE = GGBasicTypes.Vector; WalkProc: TYPE = GGModelTypes.WalkProc; <> <<>> OpenAutoScript: PUBLIC PROC [ggData: GGData, openNoMatterWhat: BOOL _ FALSE] = { IF GGUserProfile.GetAutoScriptingOn[] THEN { time: BasicTime.Unpacked _ BasicTime.Unpack[BasicTime.Now[]]; userName: Rope.ROPE _ SystemNames.UserName[]; name: Rope.ROPE _ IO.PutFR["%g%02g%02g%02g-%02g-", [rope[userName]], [integer[time.year-1900]], [integer[ORD[time.month]+1]], [integer[time.day]], [integer[time.hour]] ]; IF NOT openNoMatterWhat AND ggData.debug.autoScriptActionCount = ggData.debug.lastAutoScriptActionCount THEN RETURN; -- the user is just repeatedly hitting Clear ggData.debug.lastAutoScriptActionCount _ ggData.debug.autoScriptActionCount; name _ Rope.Concat[name, IO.PutFR["%02g-%02g.script", [integer[time.minute]], [integer[time.second]] ] ]; [ggData.debug.autoScriptStream, ggData.debug.autoScriptName] _ GGSessionLog.OpenScript[name, ggData, ggData.debug.autoScriptStream, ggData.debug.autoScriptName]; GGCoreOps.AppendRope[ggData.debug.autoScriptName, ggData.debug.autoScriptNames]; [] _ SlackProcess.EnableSessionLogging[ggData.slackHandle]; }; }; FileNameFromEvent: PUBLIC PROC [opName: Rope.ROPE, event: LIST OF REF ANY, currentWDir: Rope.ROPE, router: MsgRouter, emergency: BOOL _ FALSE] RETURNS [fileName, fullName: Rope.ROPE _ NIL, success: BOOL _ FALSE, versionSpecified: BOOL _ FALSE, noName: BOOL _ FALSE] = { <> RopeFromRef: PROC [ref: REF ANY] RETURNS [rope: Rope.ROPE] ~ { WITH ref SELECT FROM text: REF TEXT => RETURN[Rope.FromRefText[text] ]; r: Rope.ROPE => RETURN[r]; ENDCASE => ERROR; }; fileName _ IF event#NIL AND event.first#NIL THEN RopeFromRef[event.first] ELSE NIL; IF Rope.Equal[fileName, NIL] THEN noName _ TRUE ELSE [fullName, success, versionSpecified] _ GGFileOps.GetGargoyleFileName[opName, fileName, currentWDir, router, emergency]; }; Get: PUBLIC UserInputProc = { <> fullName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; CodeTimer.StartInt[$Get, $Gargoyle]; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent["Get", event.rest, ggData.currentWDir, ggData.router]; IF noName THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: no filename specified"] ELSE IF success THEN { startTime, endTime: BasicTime.GMT; totalTime: INT; Feedback.Append[ggData.router, begin, $Statistics, "Clearing ..."]; startTime _ BasicTime.Now[]; ClearAux[event, ggData]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.Append[ggData.router, end, $Statistics, IO.PutFR[" done (%r)", [integer[totalTime]] ]]; ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; -- clear script list GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData, event]; GGState.NotNewVersion[ggData, $clean]; -- could be folded in to GGState.ClearAdvisory ?? OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. }; CodeTimer.StopInt[$Get, $Gargoyle]; }; Store: PUBLIC UserInputProc = { <> <> tKeep: CARDINAL _ 0; f: IO.STREAM; fullName, fsName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; startTime, endTime: BasicTime.GMT; totalTime: INT; msgRope, opName: Rope.ROPE; ofile: FS.OpenFile; emergency: BOOL _ event.first=$Emergency; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent[Atom.GetPName[NARROW[event.first]], event.rest, ggData.currentWDir, ggData.router, emergency]; IF noName AND NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: no filename specified"] ELSE IF versionSpecified AND NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: store to explicit version forbidden"] ELSE IF success THEN { tKeep _ FS.FileInfo[name: fullName ! FS.Error => CONTINUE].keep; ofile _ FS.Create[name: fullName, setPages: FALSE, setKeep: TRUE, keep: MAX[tKeep, 2] ! FS.Error => { msgRope _ IO.PutFR["%g failed: could not create: %g [FS.Error: %g]", [rope[opName]], [rope[fullName]], [rope[error.explanation]]]; IF NOT emergency THEN Feedback.Append[ggData.router, oneLiner, $Complaint, msgRope]; GOTO Abort; }; ]; fsName _ FS.GetName[ofile].fullFName; f _ FS.StreamFromOpenFile[openFile: ofile, accessRights: $write]; opName _ IF event.first = NIL THEN "someSave" ELSE Atom.GetPName[NARROW[event.first]]; msgRope _ IO.PutFR["%g: %g . . . ", [rope[opName]], [rope[fullName]]]; IF NOT emergency THEN Feedback.Append[ggData.router, begin, $Statistics, msgRope]; <> GGEvent.SawTextFinish[ggData, NIL]; -- do this before fileout startTime _ BasicTime.Now[]; GGFileOut.FileoutSceneAndOptions[f, ggData, fullName]; GGUIUtility.SafeClose[f, ggData.router]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; IF NOT emergency THEN Feedback.Append[ggData.router, end, $Statistics, msgRope]; <> GGState.StoreAdvisory[ggData, fsName, versionSpecified]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; GGState.NotNewVersion[ggData, $clean]; OpenAutoScript[ggData, FALSE]; -- close the current script. Open a new one and add to list. EXITS Abort => NULL; }; }; CleanVersion: UserInputProc = { GGState.NotNewVersion[ggData, $clean]; }; Save: PUBLIC UserInputProc = { IF GGState.GetFullName[ggData]#NIL THEN Store[event: LIST[$Save, FileNames.StripVersionNumber[GGState.GetFullName[ggData]]], ggData: ggData] ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "Save failed: can't save unnamed viewer; try Store"]; }; Destroy: PUBLIC UserInputProc = { <> ggData.controls _ NIL; -- prevent unwanted actions on active control panels ClearAux[event, ggData]; -- for garbage collection }; Clear: PUBLIC UserInputProc = { ClearAux[event, ggData]; IF event.first=$Clear THEN GGEvent.StandardAlignments[ggData, event]; <> GGState.ClearAdvisory[ggData]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; GGEvent.SawTextFinish[ggData, NIL]; IF event.first=$Clear THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; GGState.NotNewVersion[ggData, $clear]; -- could be folded in to GGState.ClearAdvisory ?? <> ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. IF event.first=$Clear THEN Feedback.Append[ggData.router, oneLiner, $Feedback, "Clear: completed"]; }; ConfirmClear: UserInputProc = { Feedback.Append[ggData.router, oneLiner, $Confirm, "Confirm deletion of all objects"]; }; Reset: PUBLIC UserInputProc = { <> IF GGState.AdviseRestore[ggData] THEN { fileName: Rope.ROPE _ GGState.GetFullName[ggData]; CodeTimer.StartInt[$Restore, $Gargoyle]; ClearAux[event, ggData]; ggData.debug.autoScriptNames _ GGCoreOps.NewRopeListt[]; -- clear script list GetMergeAux[fileName, FALSE, $Get, "Restoring", ggData, event]; -- makes new script list GGState.NotNewVersion[ggData, $clean]; OpenAutoScript[ggData, FALSE]; -- close the last script and open a new one. Add it to list. CodeTimer.StopInt[$Restore, $Gargoyle]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Restore: completed"]; }; }; ConfirmReset: UserInputProc = { filename: Rope.ROPE _ GGState.GetFullName[ggData]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Restore failed: no file loaded. Do not confirm."] ELSE Feedback.Append[ggData.router, oneLiner, $Confirm, "Confirm restore to original file"]; }; ConfirmGet: UserInputProc = { <> fullName: Rope.ROPE; success: BOOL _ FALSE; filename: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: no filename specified. Do not confirm."] ELSE { [fullName, success, ----] _ GGFileOps.GetGargoyleFileName["Get", filename, ggData.currentWDir, ggData.router, FALSE]; IF NOT success THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Get failed: bad filename specified. Do not confirm."] ELSE Feedback.PutF[ggData.router, oneLiner, $Confirm, "Confirm Get of %g as a new scene", [rope[fullName]] ]; }; }; FileExists: PROC [fileName: Rope.ROPE] RETURNS [answer: BOOL _ TRUE] = { [] _ FS.FileInfo[fileName ! FS.Error => IF error.code=$unknownFile THEN { answer _ FALSE; CONTINUE }; <> ]; }; ConfirmStore: UserInputProc = { <> fullName: Rope.ROPE; success: BOOL _ FALSE; filename: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Equal[filename, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: no filename specified. Do not confirm."] ELSE { [fullName, success, ----] _ GGFileOps.GetGargoyleFileName["Store", filename, ggData.currentWDir, ggData.router, FALSE]; IF NOT success THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Store failed: bad filename specified. Do not confirm."] ELSE Feedback.PutF[ggData.router, oneLiner, $Confirm, "Confirm Store to %g [%g File]", [rope[fullName]], [rope[IF FileExists[fullName] THEN "Old" ELSE "New"]] ]; }; }; ClearAux: PROC [event: LIST OF REF ANY, ggData: GGData] = { GGState.SetActive[ggData, FALSE]; -- for now. This will prevent most (but not all) race conditions with the Input Notify process. ggData.refresh.overlayList _ NIL; GGState.SetExtendMode[ggData, none]; GGState.SetSliceToExtend[ggData, NIL]; -- forget sliceToExtend ggData.caret _ GGCaret.Create[]; -- forget caret and attractor ggData.anchor _ GGCaret.Create[]; -- forget anchor ggData.behavior.activeDoc _ NIL; -- next time this field is needed it will be recomputed GGHistory.ResetHistory[ggData]; -- do this before MakeSceneGarbage, in order to synchronize with any outstanding advance captures by history mechanism GGScene.MakeSceneGarbage[ggData.scene]; -- important unlink of circular garbage GGAlign.MakeFiltersGarbage[ggData.hitTest]; -- important unlink of circular garbage ggData.scene _ GGScene.CreateScene[]; -- drop old scene refs on floor ggData.rootSlice _ GGSlice.MakeCircleSlice[[999.0, 999.0], [99.0, 99.0]].slice; ggData.aborted _ ALL[FALSE]; <> ggData.refresh.dragInProgress _ FALSE; ggData.refresh.caretIsMoving _ FALSE; ggData.refresh.overlayList _ NIL; ggData.refresh.orderedOverlayList _ NIL; ggData.refresh.addedObject _ NIL; ggData.refresh.recentFeature _ NIL; ggData.refresh.textInProgress _ NIL; ggData.refresh.areaFollowColorTool _ FALSE; ggData.refresh.lineFollowColorTool _ FALSE; GGRefresh.InvalidateForeground[ggData]; GGRefresh.InvalidateBackground[ggData]; }; MergeAll: PUBLIC UserInputProc = { <> MergeAux[event, ggData, $MergeAll, "MergeAll"]; }; MergeShapes: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeShapes, "MergeShapes"]; }; MergeOptions: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeOptions, "MergeOptions"]; }; MergeAlignments: PUBLIC UserInputProc = { MergeAux[event, ggData, $MergeAlignments, "MergeAlignments"]; }; MergeAux: PROC [event: LIST OF REF ANY, ggData: GGData, op: ATOM, opName: Rope.ROPE] = { fullName: Rope.ROPE; success, versionSpecified, noName: BOOL _ FALSE; [----, fullName, success, versionSpecified, noName] _ FileNameFromEvent[opName, event.rest, ggData.currentWDir, ggData.router]; IF noName THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Merge failed: no filename specified"] ELSE IF success THEN GetMergeAux[fullName, versionSpecified, op, opName, ggData, event]; }; GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOL _ FALSE, op: ATOM, opName: Rope.ROPE, ggData: GGData, event: LIST OF REF ANY] = { <> f: IO.STREAM; fsName: Rope.ROPE; <> startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; success: BOOL _ FALSE; successRope: Rope.ROPE; failedRope: Rope.ROPE = "failed: malformed file"; Feedback.PutF[ggData.router, begin, $Statistics, " Opening %g ...", [rope[fullName]]]; startTime _ BasicTime.Now[]; f _ FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => { Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: could not find %g (FS or IO Error)", [rope[opName]], [rope[fullName]]]; GOTO Abort; };]; fsName _ FS.GetName[FS.OpenFileFromStream[f]].fullFName; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.PutF[ggData.router, end, $Statistics, " done (%r)", [integer[totalTime]]]; Feedback.PutF[ggData.router, begin, $Statistics, "%g %g . . . ", [rope[opName]], [rope[fsName]]]; <> startTime _ BasicTime.Now[]; BEGIN SELECT op FROM $Get => { GGEvent.ClearAlignments[ggData, LIST[NIL]]; [success, successRope] _ GGFileIn.FileinSceneAndOptions[f, ggData, FALSE, FALSE]; -- NIL if filein aborted IF success THEN { directory: ROPE _ FileNames.Directory[fsName]; GGStateExtras.SetWorkingDirectory[ggData, directory]; } ELSE { -- filein aborted Clear[ggData, LIST[$ClearForFailedGet]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE]; Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeAll => { [success, successRope] _ GGFileIn.FileinSceneAndOptions[f, ggData, TRUE, TRUE]; -- NIL if filein aborted IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeShapes => { [success, successRope] _ GGFileIn.FileinSceneOnly[f, ggData.scene, TRUE, ggData.camera]; -- NIL if filein aborted IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeOptions => { [success, successRope] _ GGFileIn.FileinOptionsOnly[f, ggData, FALSE]; IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; $MergeAlignments => { [success, successRope] _ GGFileIn.FileinOptionsOnly[f, ggData, TRUE]; IF NOT success THEN { Feedback.Append[ggData.router, end, $Statistics, failedRope]; GOTO FileinFailed; }; }; ENDCASE => ERROR; GGUIUtility.SafeClose[f, ggData.router]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.PutF[ggData.router, end, $Statistics, " Done in time (%r)", [integer[totalTime]]]; IF op=$Get THEN { -- update viewer name on Get <> GGState.GetAdvisory[ggData, fsName, versionSpecified]; GGHistory.CapTool[GGState.GetFullName[ggData], ggData]; }; GGEvent.SawTextFinish[ggData, LIST[$SawTextFinish]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSceneNoBuffer, ggData: ggData, remake: triggerBag, edited: op#$Get, okToSkipCapture: FALSE]; EXITS FileinFailed => GGUIUtility.SafeClose[f, ggData.router]; END; EXITS Abort => GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSceneNoBuffer, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE]; -- needed in case of failure to read to clean out bags }; <> AddToGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "AddToGroup failed: no objects selected"] ELSE IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "AddToGroup failed: can't AddToGroup, no group name selected"] ELSE { AddSegments: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO duplicate: BOOL _ FALSE; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN { duplicate _ TRUE; -- already in this group EXIT; }; ENDLOOP; IF NOT duplicate THEN seg.props _ CONS[name, seg.props]; someAddition _ TRUE; ENDLOOP; }; someAddition: BOOL _ FALSE; scene: Scene _ ggData.scene; [] _ GGScene.WalkSelectedSlices[scene, first, AddSegments, normal]; Feedback.PutF[ggData.router, oneLiner, $Feedback, IF someAddition THEN "AddToGroup: added selected segments to group %g" ELSE "AddToGroup: no segments added to group %g", [rope[name]] ]; IF someAddition THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: TRUE]; }; }; SelectGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectGroup failed: can't SelectGroup, no group name selected"] ELSE { SelectSegments: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { FindProp: PROC [seg: Segment, transform: Imager.Transformation] RETURNS [keep: BOOL] = { FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; withProps: SliceDescriptor _ GGSliceOps.WalkSegments[slice, FindProp]; IF withProps#NIL THEN GGSelect.SelectSlice[withProps, ggData.scene, normal]; }; scene: Scene _ ggData.scene; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection [] _ GGScene.WalkSlices[scene, first, SelectSegments]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectGroup failed: no such group"] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectGroup: group %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; }; }; RemoveFromGroup: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "RemoveFromGroup failed: no objects selected"] ELSE IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "RemoveFromGroup failed: can't RemoveFromGroup, no group name selected"] ELSE { RemoveSegments: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO newProps _ NIL; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps _ CONS[nextProp, newProps] ELSE someRemoval _ TRUE; ENDLOOP; seg.props _ newProps; ENDLOOP; }; someRemoval: BOOL _ FALSE; newProps: LIST OF REF ANY; scene: Scene _ ggData.scene; [] _ GGScene.WalkSelectedSlices[scene, first, RemoveSegments, normal]; Feedback.PutF[ggData.router, oneLiner, $Feedback, IF someRemoval THEN "RemoveFromGroup: removed selected segments from group %g" ELSE "RemoveFromGroup: no member segments selected to remove from group %g", [rope[name]] ]; IF someRemoval THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: TRUE]; }; }; PrintGroupsOfSelected: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowGroupsOfSelected failed: no selections to show groups"] ELSE { DoPrintGroups: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { segGen: SegmentGenerator _ GGSliceOps.SegmentsInDescriptor[sliceD]; FOR seg: Segment _ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg=NIL DO FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ CONS[nextProp, groupList]; ENDLOOP; ENDLOOP; }; groupList: LIST OF REF ANY; [] _ GGScene.WalkSelectedSlices[scene, first, DoPrintGroups, normal]; IF groupList#NIL THEN { Feedback.Append[ggData.router, begin, $Show, "ShowGroupsOfSelected: "]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.router, middle, $Show, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.router, end, $Show, ""]; } ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowGroupsOfSelected: no groups of selected"]; }; }; PrintAllGroups: PUBLIC UserInputProc = { groupList: LIST OF REF ANY; scene: Scene _ ggData.scene; EnumerateGroups: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { FindGroups: PROC [seg: Segment, transform: Imager.Transformation] RETURNS [keep: BOOL _ FALSE] = { FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ CONS[nextProp, groupList]; ENDLOOP; }; [] _ GGSliceOps.WalkSegments[slice, FindGroups]; }; [] _ GGScene.WalkSlices[scene, first, EnumerateGroups]; Feedback.Append[ggData.router, begin, $Show, "ShowAllGroups: "]; IF groupList#NIL THEN { FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.router, middle, $Show, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.router, end, $Show, ""]; } ELSE Feedback.Append[ggData.router, end, $Show, "no groups"]; }; Cluster: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Cluster failed: no selections to Cluster"] ELSE { AddSelectedToCluster: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { IF GGSelect.IsSelectedInPart[slice, ggData.scene, normal] THEN { justFound _ TRUE; [childList, ptr] _ GGUtility.AddSlice[slice, childList, ptr]; } ELSE { IF justFound THEN { sliceInFront _ slice; justFound _ FALSE; }; }; }; cluster: Slice _ GGSlice.CreateCluster[frozen: FALSE]; scene: Scene _ ggData.scene; childList, ptr: LIST OF Slice; sliceInFront: Slice _ NIL; priority: INT _ -1; justFound: BOOL _ FALSE; GGHistory.NewCapture["Cluster", ggData]; -- capture scene BEFORE UPDATE <> GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedParts: TRUE]; [childList, ptr] _ GGUtility.StartSliceList[]; [] _ GGScene.WalkSlices[scene, first, AddSelectedToCluster]; FOR list: LIST OF Slice _ childList, list.rest UNTIL list = NIL DO GGSelect.SaveSelectionsInSliceAllClasses[list.first, scene]; GGScene.DeleteSlice[scene, list.first]; GGSlice.AddChildToCluster[cluster, list.first, -1]; ENDLOOP; IF sliceInFront = NIL OR justFound THEN priority _ -1 ELSE priority _ GGScene.GetPriority[scene, sliceInFront]; GGScene.AddSlice[scene, cluster, priority]; GGSelect.ReselectSliceAllClasses[cluster, scene]; GGSelect.SelectEntireSlice[cluster, scene, normal]; GGCaret.SitOn[ggData.caret, NIL]; GGCaret.NoAttractor[ggData.caret]; GGHistory.PushCurrent[ggData]; -- push captured history event onto history list Feedback.Append[ggData.router, oneLiner, $Feedback, "Cluster: new cluster created"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; }; }; ClusterAndFreeze: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Cluster failed: no selections to Cluster"] ELSE { Cluster[ggData, event]; FreezeCluster[ggData, event]; Feedback.Append[ggData.router, oneLiner, $Feedback, "ClusterAndFreeze: new cluster created and frozen"]; }; }; UnCluster: PUBLIC UserInputProc = { IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "UnCluster failed: no selections to UnCluster"] ELSE { BreakUpCluster: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { cluster: Slice _ sliceD.slice; childList: LIST OF Slice _ GGParent.ListChildren[cluster, first]; priority _ GGScene.GetPriority[scene, cluster]; GGSelect.SaveSelectionsInSliceAllClasses[cluster, scene]; GGScene.DeleteSlice[scene, cluster]; GGScene.AddSlices[scene, childList, priority]; FOR list: LIST OF Slice _ childList, list.rest UNTIL list = NIL DO GGSelect.ReselectSliceAllClasses[list.first, scene]; ENDLOOP; newSlices _ GGUtility.AppendSliceList[newSlices, childList]; }; priority: INT _ -1; scene: Scene _ ggData.scene; newSlices: LIST OF Slice; -- build a list then select elements after to avoid modifying selection list during WalkSelectedSlices GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGHistory.NewCapture["UnCluster", ggData]; [] _ GGScene.WalkSelectedSlices[scene, first, BreakUpCluster, normal, $Cluster]; FOR newSelections: LIST OF Slice _ newSlices, newSelections.rest UNTIL newSelections=NIL DO GGSelect.SelectEntireSlice[newSelections.first, scene, normal]; -- better be topLevel slices ENDLOOP; GGCaret.SitOn[ggData.caret, NIL]; GGCaret.NoAttractor[ggData.caret]; GGHistory.PushCurrent[ggData]; -- push captured history event onto history list Feedback.Append[ggData.router, oneLiner, $Feedback, "UnCluster: cluster unmade and components selected"]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE]; }; }; FreezeCluster: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FreezeCluster failed: no selections to Freeze"] ELSE { DoFreeze: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSlice.SetFrozen[sliceD.slice, TRUE]; }; [] _ GGScene.WalkSelectedSlices[scene, highest, DoFreeze, normal, $Cluster]; <> Feedback.Append[ggData.router, oneLiner, $Complaint, "FreezeCluster failed: frozen clusters Not Yet Implemented"]; }; }; ThawCluster: PUBLIC UserInputProc = { scene: Scene _ ggData.scene; IF GGSelect.NoSelections[scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "ThawCluster failed: no selections to Thaw"] ELSE { DoThaw: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSlice.SetFrozen[sliceD.slice, FALSE]; }; [] _ GGScene.WalkSelectedSlices[scene, highest, DoThaw, normal, $Cluster]; Feedback.Append[ggData.router, oneLiner, $Feedback, "ThawCluster: selected clusters are now thawed"]; }; }; ShowFrozen: PUBLIC UserInputProc = { BEGIN Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowFrozen failed: frozen clusters Not Yet Implemented"]; RETURN; END; << frozen: BOOL _ FALSE; success: BOOL _ TRUE; sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; scene: Scene _ ggData.scene; opName: Rope.ROPE _ "ShowFrozen failed: "; DoCheckFrozen: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisFrozen: BOOL _ FALSE; IF sliceD = NIL THEN { sliceD _ thisD; frozen _ GGSlice.GetFrozen[thisD.slice]; } ELSE { thisFrozen _ GGSlice.GetFrozen[thisD.slice]; IF thisFrozen # frozen THEN done _ TRUE }; }; aborted _ GGScene.WalkSelectedSlices[scene, highest, DoCheckFrozen, normal, $Cluster]; IF aborted THEN { success _ FALSE; Feedback.Append[ggData.router, oneLiner, $Complaint, "ShowFrozen failed: more than one frozen state is selected"]]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.Append[ggData.router, oneLiner, $Complaint, Rope.Concat["ShowFrozen: no frozen clusters are selected"]]; }; IF NOT success THEN RETURN; Feedback.PutF[ggData.router, Rope.Concat["ShowFrozen: ", GGCoreOps.BoolToRope[frozen]], oneLiner]; >> }; <> <<>> RGBFromRopeError: SIGNAL = CODE; CMYKFromRopeError: SIGNAL = CODE; IntensityFromRopeError: SIGNAL = CODE; ctRope: Rope.ROPE = "ColorTool operation failed: please create a ColorTool and retry"; AreaColorFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE AreaColorAux[ggData, color, GGDescribe.ColorToRope[color]]; }; }; FillHueFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE AreaColorAux[ggData, color, GGDescribe.ColorToRope[color], TRUE, $ChangeHue]; }; }; LineColorFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE LineColorAux[ggData, color, GGDescribe.ColorToRope[color]]; }; }; StrokeHueFromColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: ImagerColor.Color; color _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE LineColorAux[ggData, color, GGDescribe.ColorToRope[color], TRUE, $ChangeHue]; }; }; mapIndex: CARDINAL _ LAST[CARDINAL]; SpecialPixel: TYPE ~ ImagerDitherContext.SpecialPixel; GetSpecialColor: PROC RETURNS [color: Imager.Color _ NIL] ~ { ordinaryColor: Imager.ConstantColor; ordinaryColor _ ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[NIL ! ColorTool.NoColorToolViewer => CONTINUE;]]; IF ordinaryColor#NIL THEN { vw: ViewersWorld.Ref _ ViewersWorld.GetViewersWorld[]; IF mapIndex=LAST[CARDINAL] THEN mapIndex _ ViewersWorld.AllocateColorMapIndex[vw, 0, NIL, NIL]; -- try to allocate a color map index to keep IF mapIndex=LAST[CARDINAL] THEN RETURN[NIL]; -- AllocateColorMapIndex failed color _ MakeSpecialColor[specialPixel: [value: mapIndex, dstFunc: null], ordinaryColor: ordinaryColor]; ColorTool.RegisterNotifyProc[$GG, TrackPatch, NIL, NIL ! ColorTool.NoColorToolViewer => CONTINUE;]; -- proc will be unregistered by SawTextFinish }; }; MakeSpecialColor: PROC [ordinaryColor: Imager.ConstantColor, specialPixel: SpecialPixel, name: Rope.ROPE _ NIL] RETURNS [Imager.SpecialColor] ~ { <> pixelData: REF SpecialPixel _ NEW[SpecialPixel _ specialPixel]; color: ImagerColor.SpecialColor ~ NEW[ImagerColor.ColorRep.constant.special _ [constant[special[type: $Pixel, name: name, data: pixelData, substitute: ordinaryColor]]]]; RETURN [color]; }; gamma: REAL _ 2.2; -- value stolen from Zebra ApplyGamma: PROC [v: REAL, gamma: REAL] RETURNS [BYTE] ~ { g: REAL ~ MIN[MAX[gamma, 0.01], 100.0]; uncorrected: REAL ~ MIN[MAX[v, 0.0], 1.0]; corrected: REAL ~ RealFns.Power[uncorrected, 1.0/g]; RETURN [Real.Round[MIN[MAX[corrected, 0.0], 1.0]*BYTE.LAST]]; }; TrackPatch: PROC[rgb: ImagerColor.RGB, clientData: REF] = { -- ColorTool.NotifyProc ToByte: PROC[v: REAL] RETURNS[INTEGER] = { <> IF v<=0.0 THEN RETURN[0]; IF v>=1.0 THEN RETURN[255]; RETURN[ApplyGamma[v, gamma]]; }; vw: ViewersWorld.Ref _ ViewersWorld.GetViewersWorld[]; IF mapIndex#LAST[CARDINAL] THEN ViewersWorld.SetColorMapEntry[vw, mapIndex, 0, ToByte[rgb.R], ToByte[rgb.G], ToByte[rgb.B] ]; }; AreaColorFollowColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; color _ GetSpecialColor[ ! ColorTool.NoColorToolViewer => CONTINUE;]; -- "animation" color; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE { ggData.refresh.areaFollowColorTool _ TRUE; AreaColorAux[ggData, color, NIL, FALSE]; Feedback.Append[ggData.router, oneLiner, $Feedback, "FollowColorTool: selected objects fill color will follow ColorTool"]; }; }; }; LineColorFollowColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; color _ GetSpecialColor[ ! ColorTool.NoColorToolViewer => CONTINUE;]; -- "animation" color; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE { ggData.refresh.lineFollowColorTool _ TRUE; LineColorAux[ggData, color, NIL, FALSE]; Feedback.Append[ggData.router, oneLiner, $Feedback, "FollowColorTool: selected objects stroke color will follow ColorTool"]; }; }; }; AreaColorToColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { success: BOOL _ FALSE; color: Imager.Color; [color, success] _ GetSelectedFillColor[ggData, "FillColorToColorTool"]; IF success THEN { noColorTool: BOOL _ FALSE; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorToColorTool: selected objects have NO fill color"] ELSE { ColorTool.SetColor[color, NIL ! ColorTool.NoColorToolViewer => { noColorTool _ TRUE; CONTINUE; };]; IF noColorTool THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "FillColorToColorTool: %g sent to ColorTool", [rope[GGDescribe.ColorToRope[color]]] ]; }; } }; }; LineColorToColorTool: PUBLIC UserInputProc = { IF GGState.ColorToolIsBound[ggData] THEN { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "StrokeColorToColorTool"]; IF success THEN { noColorTool: BOOL _ FALSE; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Selected objects have NO stroke color"] ELSE { ColorTool.SetColor[color, NIL ! ColorTool.NoColorToolViewer => { noColorTool _ TRUE; CONTINUE; };]; IF noColorTool THEN Feedback.Append[ggData.router, oneLiner, $Complaint, ctRope] ELSE Feedback.PutF[ggData.router, oneLiner, $Feedback, "StrokeColorToColorTool: %g sent to ColorTool", [rope[GGDescribe.ColorToRope[color]]] ]; }; } }; }; GetSelectedFillColor: PROC [ggData: GGData, opName: Rope.ROPE] RETURNS [color: ImagerColor.Color, success: BOOL _ TRUE] = { sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; someNotFilled: BOOL _ FALSE; scene: Scene _ ggData.scene; CheckColor: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisColor: ImagerColor.Color; firstChild: Slice; IF sliceD = NIL THEN { sliceD _ thisD; [color, success] _ GGSliceOps.GetFillColor[thisD.slice, thisD.parts]; done _ NOT success; } ELSE { [thisColor, success] _ GGSliceOps.GetFillColor[thisD.slice, thisD.parts]; IF NOT success OR NOT GGCoreOps.EquivalentColors[thisColor, color] THEN done _ TRUE }; IF (GGSliceOps.GetType[thisD.slice]=$Traj AND NARROW[thisD.slice.data, TrajData].role=open) OR (GGSliceOps.GetType[thisD.slice]=$Outline AND GGSliceOps.GetType[(firstChild _ GGParent.FirstChild[thisD.slice, first])]=$Traj AND NARROW[firstChild.data, TrajData].role=open) THEN someNotFilled _ TRUE; }; aborted _ GGScene.WalkSelectedSlices[scene, first, CheckColor, normal]; IF someNotFilled THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: select only CLOSED objects to specify fill color", [rope[opName]] ]; } ELSE IF aborted THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: more than one fill colors are selected", [rope[opName]] ]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: no fill colors are selected", [rope[opName]] ]; }; }; GetSelectedStrokeColor: PROC [ggData: GGData, opName: Rope.ROPE] RETURNS [color: ImagerColor.Color, success: BOOL _ TRUE] = { sliceD: SliceDescriptor _ NIL; aborted: BOOL _ FALSE; scene: Scene _ ggData.scene; CheckColor: PROC [thisD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { thisColor: ImagerColor.Color; IF sliceD = NIL THEN { sliceD _ thisD; [color, success] _ GGSliceOps.GetStrokeColor[thisD.slice, thisD.parts]; done _ NOT success; } ELSE { [thisColor, success] _ GGSliceOps.GetStrokeColor[thisD.slice, thisD.parts]; IF NOT success OR NOT GGCoreOps.EquivalentColors[thisColor, color] THEN done _ TRUE }; }; aborted _ GGScene.WalkSelectedSlices[scene, leaf, CheckColor, normal]; IF aborted THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: more than one stroke colors are selected", [rope[opName]] ]; } ELSE IF sliceD = NIL THEN { success _ FALSE; Feedback.PutF[ggData.router, oneLiner, $Complaint, "%g failed: no stroke colors are selected", [rope[opName]] ]; }; }; AreaColorFromSelectedName: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ParseColorName[name, ggData.router, "FillColorFromName"]; IF color#NIL THEN AreaColorAux[ggData, color, name]; }; LineColorFromSelectedName: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ParseColorName[name, ggData.router, "StrokeColorFromName"]; IF color#NIL THEN LineColorAux[ggData, color, name]; }; ParseColorName: PROC [name: Rope.ROPE, router: MsgRouter, opRope: Rope.ROPE] RETURNS [color: Imager.Color _ NIL] ~ { IF Rope.Equal[name, NIL] THEN Feedback.PutF[router, oneLiner, $Complaint, "%g failed: select a color name", [rope[opRope]] ] ELSE { IF Rope.Match["*/*", name] THEN { --try for a registered name GOTO UnImplementedColors; <> <> <> } ELSE color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; EXITS UnImplementedColors => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: hierarchical names UNIMPLEMENTED in PCedar", [rope[opRope]] ]; < Feedback.PutF[router, oneLiner, $Complaint, "%g failed: hierarchical name not registered", [rope[opRope]] ];>> UndefinedName => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: undefined color name", [rope[opRope]] ]; BadGrammar => Feedback.PutF[router, oneLiner, $Complaint, "%g failed: bad color name syntax", [rope[opRope]] ]; }; }; AreaColorFromSelectedRGB: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; AreaColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromRGB failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; LineColorFromSelectedRGB: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; LineColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromRGB failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; FillColorFromSelectedCMYK: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColorFns.ColorFromCMYK[CMYKFromRope[name ! CMYKFromRopeError => GOTO SyntaxError]]; AreaColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromCMYK failed: CMYK syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; FillColorFromSelectedIntensity: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; intensity: REAL _ IntensityFromRope[name ! IntensityFromRopeError => GOTO SyntaxError]; SetFillColorFromIntensity[ggData, intensity]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "FillColorFromIntensity failed: Intensity syntax is [0.0..1.0]"]; }; SetFillColorFromIntensity: PUBLIC PROC [ggData: GGData, intensity: REAL] = { color: Imager.Color _ ImagerColor.ColorFromGray[1.0-intensity]; name: Rope.ROPE _ GGUtility.DescribeColor[color]; AreaColorAux[ggData, color, name]; }; StrokeColorFromSelectedCMYK: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ ImagerColorFns.ColorFromCMYK[CMYKFromRope[name ! CMYKFromRopeError => GOTO SyntaxError]]; LineColorAux[ggData, color, name]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromCMYK failed: CMYK syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; }; StrokeColorFromSelectedIntensity: PUBLIC UserInputProc = { name: Rope.ROPE _ NARROW[event.rest.first]; intensity: REAL _ IntensityFromRope[name ! IntensityFromRopeError => GOTO SyntaxError]; SetStrokeColorFromIntensity[ggData, intensity]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "StrokeColorFromIntensity failed: Intensity syntax is [0.0..1.0]"]; }; SetStrokeColorFromIntensity: PUBLIC PROC [ggData: GGData, intensity: REAL] = { color: Imager.Color _ ImagerColor.ColorFromGray[1.0-intensity]; name: Rope.ROPE _ GGUtility.DescribeColor[color]; LineColorAux[ggData, color, name]; }; SelectMatchingAreaColor: PUBLIC UserInputProc = { rgb: ImagerColor.RGB; name: Rope.ROPE _ NARROW[event.rest.first]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; scene: Scene _ ggData.scene; DoSelect: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { fillColor: Imager.Color; success: BOOL _ TRUE; tallyD: SliceDescriptor; DoMatchFillColor: PROC [slice: Slice] RETURNS [visitChildren: BOOL, keep: BOOL, done: BOOL _ FALSE] = { IF GGSliceOps.GetType[slice] = $Cluster THEN { visitChildren _ TRUE; keep _ FALSE; } ELSE { visitChildren _ FALSE; fillColor _ GGSliceOps.GetFillColor[slice, NIL].color; keep _ RGBEqualsColor[rgb, fillColor, noneFlag]; }; }; tallyD _ GGParent.TallyChildren[slice, DoMatchFillColor].tallyD; IF tallyD#NIL THEN GGEvent.SelectSlice[tallyD, scene, normal, ggData]; }; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingAreaCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingAreaRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[scene, normal]; [] _ GGScene.WalkSlices[scene, first, DoSelect]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectMatchingFill: fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; UndefinedName => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: undefined color name"]; BadGrammar => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingFill failed: bad color name syntax"]; }; SelectMatchingLineColor: PUBLIC UserInputProc = { rgb: ImagerColor.RGB; name: Rope.ROPE _ NARROW[event.rest.first]; scene: Scene _ ggData.scene; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; DoSelect: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { ColorProc: WalkProc = { <> RETURN [RGBEqualsColor[rgb, seg.color, noneFlag]]; }; sliceD: SliceDescriptor _ GGSliceOps.WalkSegments[slice, ColorProc]; -- get a descriptor of matching parts GGSelect.SelectSlice[sliceD, ggData.scene, normal]; -- and select it }; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingLineCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingLineRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE]; GGSelect.DeselectAll[ggData.scene, normal]; [] _ GGScene.WalkSlices[scene, first, DoSelect]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "SelectMatchingStroke: stroke color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE]; EXITS SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: RGB syntax is [0.0..1.0] [0.0..1.0] [0.0..1.0]"]; UndefinedName => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: undefined color name"]; BadGrammar => Feedback.Append[ggData.router, oneLiner, $Complaint, "SelectMatchingStroke failed: bad color name syntax"]; }; SetDefaultFillColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedFillColor[ggData, "SetDefaultFillColor"]; IF success THEN { GGState.SetDefaultFillColor[ggData, color]; ShowDefaultFillColor[ggData, NIL]; }; }; SetDefaultFillColorFromRope: PUBLIC UserInputProc = { rope: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ GGDescribe.ColorFromRope[rope]; GGState.SetDefaultFillColor[ggData, color]; }; SetDefaultLineColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "SetDefaultStrokeColor"]; IF success THEN { GGState.SetDefaultStrokeColor[ggData, color]; ShowDefaultLineColor[ggData, NIL]; }; }; SetDefaultLineColorFromRope: PUBLIC UserInputProc = { rope: Rope.ROPE _ NARROW[event.rest.first]; color: Imager.Color _ GGDescribe.ColorFromRope[rope]; GGState.SetDefaultStrokeColor[ggData, color]; }; ShowDefaultFillColor: PUBLIC UserInputProc = { color: Imager.Color _ ggData.defaults.fillColor; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Show, "Default Fill Color: none"] ELSE Feedback.PutF[ggData.router, oneLiner, $Show, "Default Fill Color: %g", [rope[GGUtility.DescribeColor[color]]] ]; }; ShowDefaultLineColor: PUBLIC UserInputProc = { color: Imager.Color _ ggData.defaults.strokeColor; IF color=NIL THEN Feedback.Append[ggData.router, oneLiner, $Show, "Default Stroke Color: none"] ELSE Feedback.PutF[ggData.router, oneLiner, $Show, "Default Stroke Color: %g", [rope[GGUtility.DescribeColor[color]]] ]; }; <> <> <> <> <> <<};>> <<>> <> <> <> <> <> <<};>> <<>> <> <> <> <<};>> <<>> <> <> <> <<};>> AreaColorBlack: PUBLIC UserInputProc = { AreaColorAux[ggData, Imager.black, GGDescribe.ColorToRope[Imager.black]]; }; LineColorBlack: PUBLIC UserInputProc = { LineColorAux[ggData, Imager.black, GGDescribe.ColorToRope[Imager.black]]; }; AreaColorWhite: PUBLIC UserInputProc = { AreaColorAux[ggData, Imager.white, GGDescribe.ColorToRope[Imager.white]]; }; LineColorWhite: PUBLIC UserInputProc = { LineColorAux[ggData, Imager.white, GGDescribe.ColorToRope[Imager.white]]; }; AreaColorGray: PUBLIC UserInputProc = { AreaColorAux[ggData, GGOutline.fillColor, GGDescribe.ColorToRope[GGOutline.fillColor]]; }; LineColorGray: PUBLIC UserInputProc = { LineColorAux[ggData, GGOutline.fillColor, GGDescribe.ColorToRope[GGOutline.fillColor]]; }; AreaColorNone: PUBLIC UserInputProc = { AreaColorAux[ggData, NIL, NIL]; }; LineColorNone: PUBLIC UserInputProc = { LineColorAux[ggData, NIL, NIL]; }; CopyStrokeColor: PUBLIC UserInputProc = { currentEvent: HistoryEvent; lastSliceD: SliceDescriptor; color: Imager.Color; scene: Scene _ ggData.scene; success: BOOL _ FALSE; ApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetStrokeColor[sliceD.slice, sliceD.parts, color, $Set, currentEvent]; }; lastSliceD _ GGSelect.GetLastSelection[scene]; IF lastSliceD#NIL THEN [color, success] _ GGSliceOps.GetStrokeColor[lastSliceD.slice, lastSliceD.parts]; IF success THEN { currentEvent _ GGHistory.NewCurrent["Copy stroke color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, ApplyColor, normal]; <> <> GGHistory.PushCurrent[ggData]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "CopyStrokeColor: color copied to selected objects"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, Rope.Concat["CopyStrokeColor failed: make a final selection that has a unique stroke color to copy"]]; }; }; CopyFillColor: PUBLIC UserInputProc = { currentEvent: HistoryEvent; lastSliceD: SliceDescriptor; color: Imager.Color; scene: Scene _ ggData.scene; success: BOOL _ FALSE; ApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetFillColor[sliceD.slice, sliceD.parts, GGCoreOps.CopyColor[color], $Set, currentEvent]; }; lastSliceD _ GGSelect.GetLastSelection[scene]; IF lastSliceD#NIL THEN [color, success] _ GGSliceOps.GetFillColor[lastSliceD.slice, lastSliceD.parts]; IF success THEN { currentEvent _ GGHistory.NewCurrent["Copy fill color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, ApplyColor, normal]; <> <> GGHistory.PushCurrent[ggData]; Feedback.PutF[ggData.router, oneLiner, $Feedback, "CopyFillColor: color copied to selected objects"]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; } ELSE { Feedback.Append[ggData.router, oneLiner, $Complaint, "CopyFillColor failed: make a final selection that has a unique fill color to copy"]; }; }; ShowFillColor: UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedFillColor[ggData, "ShowFillColor"]; IF success THEN { IF color#NIL THEN Feedback.PutF[ggData.router, oneLiner, $Show, "ShowFillColor: %g", [rope[GGUtility.DescribeColor[color]]] ] ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowFillColor: no fill color"]; }; }; ShowStrokeColor: PUBLIC UserInputProc = { color: Imager.Color; success: BOOL _ FALSE; [color, success] _ GetSelectedStrokeColor[ggData, "ShowStrokeColor"]; IF success THEN { IF color#NIL THEN Feedback.PutF[ggData.router, oneLiner, $Show, "ShowStrokeColor: %g", [rope[GGUtility.DescribeColor[color]]] ] ELSE Feedback.Append[ggData.router, oneLiner, $Show, "ShowStrokeColor: no stroke color"]; }; }; ExtendToOutlineLevel: PROC [sliceD: SliceDescriptor] RETURNS [extendedD: SliceDescriptor] = { <> DoExtendSelection: PROC [sliceD: SliceDescriptor] RETURNS [visitChildren: BOOL, keepD: SliceDescriptor, done: BOOL _ FALSE] = { classType: ATOM _ GGSliceOps.GetType[sliceD.slice]; SELECT classType FROM $Cluster => { visitChildren _ TRUE; keepD _ NIL; }; ENDCASE => { visitChildren _ FALSE; keepD _ GGSliceOps.NewParts[sliceD.slice, NIL, slice]; }; }; [extendedD, ----] _ GGParent.TallyIncludedChildren[sliceD.slice, sliceD.parts, DoExtendSelection]; }; AreaColorAux: PUBLIC PROC [ggData: GGData, color: Imager.Color, name: Rope.ROPE _ NIL, noisy: BOOL _ TRUE, setHow: ATOM _ $Set] = { IF GGSelect.NoSelections[ggData.scene, normal] THEN IF noisy THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetFillColor failed: no selections to set fill color"] ELSE NULL ELSE { currentEvent: HistoryEvent; scene: Scene _ ggData.scene; newSelectList, ptr: LIST OF SliceDescriptor; extendToOutlinesD: SliceDescriptor; DoApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetFillColor[sliceD.slice, sliceD.parts, color, setHow, currentEvent]; [newSelectList, ptr] _ GGUtility.AddSliceDescriptor[sliceD, newSelectList, ptr]; }; currentEvent _ GGHistory.NewCurrent["Set fill color", ggData]; -- start new history event [newSelectList, ptr] _ GGUtility.StartSliceDescriptorList[]; [] _ GGScene.WalkSelectedSlices[scene, first, DoApplyColor, normal]; FOR list: LIST OF SliceDescriptor _ newSelectList, list.rest UNTIL list = NIL DO extendToOutlinesD _ ExtendToOutlineLevel[list.first]; GGSelect.SelectSlice[extendToOutlinesD, scene, normal]; ENDLOOP; <> <> GGHistory.PushCurrent[ggData]; IF noisy THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, "SetFillColor: fill color _ %g", IF name#NIL THEN [rope[name]] ELSE [rope["none"]]]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; }; }; LineColorAux: PUBLIC PROC [ggData: GGData, color: Imager.Color, name: Rope.ROPE, noisy: BOOL _ TRUE, setHow: ATOM _ $Set] = { IF GGSelect.NoSelections[ggData.scene, normal] THEN IF noisy THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetStrokeColor failed: no selections to set stroke color"] ELSE NULL ELSE { currentEvent: HistoryEvent; scene: Scene _ ggData.scene; DoApplyColor: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL _ FALSE] = { GGSliceOps.SetStrokeColor[sliceD.slice, sliceD.parts, color, setHow, currentEvent]; }; currentEvent _ GGHistory.NewCurrent["Set stroke color", ggData]; -- start new history event [] _ GGScene.WalkSelectedSlices[scene, first, DoApplyColor, normal]; IF noisy THEN Feedback.PutF[ggData.router, oneLiner, $Feedback, "SetStrokeColor: stroke color _ %g", IF name#NIL THEN [rope[name]] ELSE [rope["none"]]]; GGHistory.PushCurrent[ggData]; <> GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, edited: TRUE, okToSkipCapture: FALSE]; }; }; <<>> RGBEqualsColor: PROC [rgb: ImagerColor.RGB, color: Imager.Color, noneFlag: BOOL] RETURNS [BOOL] = { epsilon: REAL = 1.0E-2; IF color=NIL THEN RETURN [noneFlag]; -- color is none => RETURN[looking for none] IF noneFlag THEN RETURN [FALSE] -- looking for none, but color is non-NIL ELSE { r, g, b: REAL; WITH color SELECT FROM constant: ImagerColor.ConstantColor => { [r,g,b] _ GGCoreOps.ExtractRGB[constant]; RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R] RETURN[FALSE]; }; }; RGBFromRope: PROC [name: Rope.ROPE] RETURNS [rgb: ImagerColor.RGB] = { ENABLE IO.Error, IO.EndOfStream => GOTO RGBError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL RGBFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; rgb.R _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; rgb.G _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; rgb.B _ rs.GetReal[]; Check[rgb.R]; Check[rgb.G]; Check[rgb.B]; EXITS RGBError => SIGNAL RGBFromRopeError; }; CMYKFromRope: PROC [name: Rope.ROPE] RETURNS [cmyk: ImagerColorFns.CMYK] = { ENABLE IO.Error, IO.EndOfStream => GOTO CMYKError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL CMYKFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; [] _ rs.SkipWhitespace[]; cmyk.C _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.M _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.Y _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; cmyk.K _ rs.GetReal[]; Check[cmyk.C]; Check[cmyk.M]; Check[cmyk.Y]; Check[cmyk.K]; EXITS CMYKError => SIGNAL CMYKFromRopeError; }; IntensityFromRope: PROC [name: Rope.ROPE] RETURNS [intensity: REAL] = { ENABLE IO.Error, IO.EndOfStream => GOTO IntensityError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL IntensityFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; intensity _ rs.GetReal[]; Check[intensity]; EXITS IntensityError => SIGNAL IntensityFromRopeError; }; <> <<>> <> <<};>> <<>> TestGravity: PUBLIC UserInputProc = { <> xRandomStream, yRandomStream: Random.RandomStream; desiredCount: INT _ NARROW[event.rest.first, REF INT]^; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; multiPoint: Point; normal: Vector; multiFeature: FeatureData; currentObjects: AlignBag; sceneObjects: TriggerBag; IF desiredCount<=0 OR desiredCount=LAST[INT] THEN RETURN; xRandomStream _ Random.Create[GGState.GetWidth[ggData]]; yRandomStream _ Random.Create[GGState.GetHeight[ggData]]; ggData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount >= desiredCount DO IF ggData.aborted[gravitytest] THEN { ggData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData]; ggData.refresh.spotPoint _ testPoint; currentObjects _ ggData.hitTest.alignBag; sceneObjects _ ggData.hitTest.sceneBag; [multiPoint, normal, multiFeature] _ GGMultiGravity.Map[testPoint, ggData.hitTest.t, currentObjects, sceneObjects, ggData, TRUE]; IF multiFeature = NIL THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; totalCount _ totalCount + 1; LOOP; }; multiHitCount _ multiHitCount + 1; totalCount _ totalCount + 1; ggData.refresh.hitPoint _ multiPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; ENDLOOP; Feedback.PutF[ggData.router, oneLiner, $Feedback, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity noisyTestGravity: BOOL _ FALSE; Statistics: PUBLIC UserInputProc = { f: IO.STREAM _ FeedbackOps.GetTypescriptStream[$Gargoyle]; IF f#NIL THEN CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]]; }; AppendStatistics: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; f: IO.STREAM; <> completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL THEN CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle] ! CodeTimer.Problem => CONTINUE;]; GGUIUtility.SafeClose[f, ggData.router]; END; }; PrintSelectedStatistic: PUBLIC UserInputProc = { <> intervalRope: Rope.ROPE _ NARROW[event.rest.first]; intervalName: ATOM _ Atom.MakeAtom[intervalRope]; f: IO.STREAM _ FeedbackOps.GetTypescriptStream[$Gargoyle]; IF f#NIL AND NOT Rope.Equal[intervalRope, NIL] THEN { f.PutRope["\n"]; CodeTimer.PrintInt[f, intervalName, $Gargoyle ! CodeTimer.Problem => CONTINUE;]; }; }; AppendSelectedStatistic: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; intervalName: Rope.ROPE _ NARROW[event.rest.rest.first]; atom: ATOM _ Atom.MakeAtom[intervalName]; f: IO.STREAM; <> completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL AND NOT Rope.Equal[intervalName, NIL] THEN CodeTimer.PrintInt[f, atom, $Gargoyle ! CodeTimer.Problem => CONTINUE;]; GGUIUtility.SafeClose[f, ggData.router]; END; }; AppendRope: PUBLIC UserInputProc = { completeName: Rope.ROPE; BEGIN ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g: %g", [rope[error.explanation]], [rope[completeName]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; message: Rope.ROPE _ NARROW[event.rest.rest.first]; f: IO.STREAM; <> completeName _ fileName; f _ FS.StreamOpen[completeName, $append]; IF f#NIL AND NOT Rope.Equal[message, NIL] THEN f.PutRope[message]; GGUIUtility.SafeClose[f, ggData.router]; END; }; CreateFile: PUBLIC UserInputProc = { ENABLE FS.Error => {Feedback.PutF[ggData.router, oneLiner, $Complaint, "FS.Error %g", [rope[error.explanation]] ]; CONTINUE }; fileName: Rope.ROPE _ NARROW[event.rest.first]; <> f: IO.STREAM _ FS.StreamOpen[fileName, $create]; -- merely causes file creation GGUIUtility.SafeClose[f, ggData.router]; }; ResetStatistics: PUBLIC UserInputProc = { CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Statistics reset"]; }; DrawTouchPoints: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawBoundBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawTightBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawOutlineBoxes: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawSelectionBox: PUBLIC UserInputProc = { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; DrawMovingBox: PUBLIC UserInputProc = { atom: ATOM _ NARROW[event.first]; GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE]; }; <<>> DescribeCaretObject: PUBLIC UserInputProc = { description: Rope.ROPE _ "no object"; chair: SliceDescriptor _ GGCaret.GetChair[ggData.caret]; IF chair#NIL THEN description _ GGSliceOps.Describe[chair]; Feedback.PutF[ggData.router, oneLiner, $Show, "Caret is on %g", [rope[description]]]; }; <> <> <> <> <> <<};>> <<>> CauseAnError: PUBLIC UserInputProc = { scene: GGModelTypes.Scene _ ggData.scene; firstSlice, secondSlice: GGModelTypes.Slice; index: NAT _ 0; FirstAndSecond: PROC [slice: Slice] RETURNS [done: BOOL _ FALSE] = { IF index = 0 THEN { firstSlice _ slice; index _ index + 1; } ELSE IF index = 1 THEN { secondSlice _ slice; done _ TRUE; }; }; [] _ GGScene.WalkSlices[scene, first, FirstAndSecond]; SIGNAL Feedback.Problem[msg: "Client requested SIGNAL"]; }; printAllInput: BOOL _ FALSE; -- controlled by Debug menu PrintAllInput: PUBLIC UserInputProc = { IF printAllInput THEN { FOR list: LIST OF REF ANY _ event, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM atom: ATOM => Feedback.PutF[ggData.router, begin, $Typescript, "%g ", [rope[Atom.GetPName[atom]]] ]; int: REF INT => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [integer[int^]] ]; real: REF REAL => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [real[real^]]]; card: REF CARD => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [cardinal[card^]]]; refChar: REF CHAR => Feedback.PutF[ggData.router, middle, $Typescript, "%g ", [character[refChar^]]]; coords: BiScrollers.ClientCoords => Feedback.PutF[ggData.router, middle, $Typescript, "(%g, %g )", [real[coords.x]], [real[coords.y]] ]; ENDCASE => Feedback.Append[ggData.router, middle, $Typescript, "Unknown input type"]; ENDLOOP; Feedback.Append[ggData.router, end, $Typescript, "" ]; }; }; PrintAllInputOn: PUBLIC UserInputProc = { printAllInput _ TRUE; }; PrintAllInputOff: PUBLIC UserInputProc = { printAllInput _ FALSE; }; Typescript: PUBLIC UserInputProc = { GGState.Typescript[ggData]; }; Init: PROC = { OPEN GGUserInput; <> RegisterAction[$Destroy, Destroy, none]; RegisterAction[$Clear, Clear, none]; RegisterAction[$ConfirmClear, ConfirmClear, none]; RegisterAction[$Reset, Reset, none]; RegisterAction[$ConfirmReset, ConfirmReset, none]; RegisterAction[$Get, Get, rope]; RegisterAction[$ConfirmGet, ConfirmGet, none]; RegisterAction[$MergeAll, MergeAll, rope]; RegisterAction[$MergeShapes, MergeShapes, rope]; RegisterAction[$MergeOptions, MergeOptions, rope]; RegisterAction[$MergeAlignments, MergeAlignments, rope]; RegisterAction[$Store, Store, rope]; RegisterAction[$StoreOnPlayback, Store, rope]; RegisterAction[$ConfirmStore, ConfirmStore, none]; RegisterAction[$Save, Save, none]; RegisterAction[$SaveOnPlayback, Save, none]; RegisterAction[$CleanVersion, CleanVersion, none]; <> RegisterAction[$AddToGroup, AddToGroup, rope]; RegisterAction[$SelectGroup, SelectGroup, rope]; RegisterAction[$RemoveFromGroup, RemoveFromGroup, rope]; RegisterAction[$PrintGroupsOfSelected, PrintGroupsOfSelected, none]; RegisterAction[$PrintAllGroups, PrintAllGroups, none]; RegisterAction[$Cluster, Cluster, none]; RegisterAction[$ClusterAndFreeze, ClusterAndFreeze, none]; RegisterAction[$UnCluster, UnCluster, none]; RegisterAction[$FreezeCluster, FreezeCluster, none]; RegisterAction[$ThawCluster, ThawCluster, none]; RegisterAction[$ShowFrozen, ShowFrozen, none]; <> RegisterAction[$AreaColorFromColorTool, AreaColorFromColorTool, none]; RegisterAction[$FillHueFromColorTool, FillHueFromColorTool, none]; RegisterAction[$AreaColorFollowColorTool, AreaColorFollowColorTool, none]; RegisterAction[$AreaColorToColorTool, AreaColorToColorTool, none]; RegisterAction[$AreaColorFromSelectedName, AreaColorFromSelectedName, rope]; RegisterAction[$AreaColorFromSelectedRGB, AreaColorFromSelectedRGB, rope]; RegisterAction[$FillColorFromSelectedCMYK, FillColorFromSelectedCMYK, rope]; RegisterAction[$FillColorFromSelectedIntensity, FillColorFromSelectedIntensity, rope]; RegisterAction[$PrintAreaColor, ShowFillColor, none]; RegisterAction[$SelectMatchingAreaRGB, SelectMatchingAreaColor, rope]; RegisterAction[$SelectMatchingAreaCNS, SelectMatchingAreaColor, rope]; RegisterAction[$AreaColorBlack, AreaColorBlack, none]; RegisterAction[$AreaColorWhite, AreaColorWhite, none]; RegisterAction[$AreaColorGray, AreaColorGray, none]; RegisterAction[$AreaColorNone, AreaColorNone, none]; RegisterAction[$CopyFillColor, CopyFillColor, none]; RegisterAction[$SetDefaultFillColor, SetDefaultFillColor, none]; RegisterAction[$SetDefaultFillColorFromRope, SetDefaultFillColorFromRope, rope]; RegisterAction[$ShowDefaultFillColor, ShowDefaultFillColor, none]; <> RegisterAction[$LineColorFromColorTool, LineColorFromColorTool, none]; RegisterAction[$StrokeHueFromColorTool, StrokeHueFromColorTool, none]; RegisterAction[$LineColorFollowColorTool, LineColorFollowColorTool, none]; RegisterAction[$LineColorToColorTool, LineColorToColorTool, none]; RegisterAction[$LineColorFromSelectedName, LineColorFromSelectedName, rope]; RegisterAction[$LineColorFromSelectedRGB, LineColorFromSelectedRGB, rope]; RegisterAction[$StrokeColorFromSelectedCMYK, StrokeColorFromSelectedCMYK, rope]; RegisterAction[$StrokeColorFromSelectedIntensity, StrokeColorFromSelectedIntensity, rope]; RegisterAction[$SelectMatchingLineRGB, SelectMatchingLineColor, rope]; RegisterAction[$SelectMatchingLineCNS, SelectMatchingLineColor, rope]; RegisterAction[$PrintLineColor, ShowStrokeColor, none]; RegisterAction[$LineColorBlack, LineColorBlack, none]; RegisterAction[$LineColorWhite, LineColorWhite, none]; RegisterAction[$LineColorGray, LineColorGray, none]; RegisterAction[$LineColorNone, LineColorNone, none]; RegisterAction[$CopyStrokeColor, CopyStrokeColor, none]; RegisterAction[$SetDefaultLineColor, SetDefaultLineColor, none]; RegisterAction[$SetDefaultLineColorFromRope, SetDefaultLineColorFromRope, rope]; RegisterAction[$ShowDefaultLineColor, ShowDefaultLineColor, none]; <<>> <> <> <> <> <> RegisterAction[$TestGravity, TestGravity, refInt]; <> RegisterAction[$Statistics, Statistics, none]; RegisterAction[$AppendStatistics, AppendStatistics, none]; RegisterAction[$PrintSelectedStatistic, PrintSelectedStatistic, rope]; RegisterAction[$AppendSelectedStatistic, AppendSelectedStatistic, none]; RegisterAction[$AppendRope, AppendRope, none]; RegisterAction[$CreateFile, CreateFile, none]; RegisterAction[$ResetStatistics, ResetStatistics, none]; RegisterAction[$DrawTightBoxes, DrawTightBoxes, none]; RegisterAction[$DrawBoundBoxes, DrawBoundBoxes, none]; RegisterAction[$DrawOutlineBoxes, DrawOutlineBoxes, none]; RegisterAction[$DrawSelectionBox, DrawSelectionBox, none]; RegisterAction[$DrawBackgroundBox, DrawMovingBox, none]; RegisterAction[$DrawOverlayBox, DrawMovingBox, none]; RegisterAction[$DrawRubberBox, DrawMovingBox, none]; RegisterAction[$DrawDragBox, DrawMovingBox, none]; RegisterAction[$Typescript, Typescript, none]; RegisterAction[$DescribeCaretObject, DescribeCaretObject, none]; <> RegisterAction[$PrintAllInput, PrintAllInputOn, none]; RegisterAction[$ResetAllInput, PrintAllInputOff, none]; RegisterAction[$CauseAnError, CauseAnError, none]; }; Init[]; END.