GGEventImplD.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on April 20, 1987 6:00:17 pm PDT
Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module.
Pier, May 12, 1987 5:32:05 pm PDT
DIRECTORY
--CombinePoly,-- Ascii, Atom, AtomButtonsTypes, BasicTime, CodeTimer, ColorTool, CubicSplines, Feedback, FileNames, FS, GGBasicTypes, GGBoundBox, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGOutline, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, PrincOpsUtils, Random, Rope, Rosary, Vectors2d, ViewerClasses, ViewerOps, ViewerTools;
GGEventImplD: CEDAR PROGRAM
IMPORTS ColorTool, --CombinePoly,-- PrincOpsUtils, Ascii, Atom, BasicTime, CodeTimer, Feedback, FileNames, FS, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGMultiGravity, GGOutline, GGScene, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, Random, Rope, Vectors2d, ViewerOps, ViewerTools
EXPORTS GGEvent = BEGIN
BoundBox: TYPE = GGBoundBox.BoundBox;
WalkProc: TYPE = GGModelTypes.WalkProc;
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
FeatureData: TYPE = GGInterfaceTypes.FeatureData;
FeedbackData: TYPE = AtomButtonsTypes.FeedbackData;
GGData: TYPE = GGInterfaceTypes.GGData;
Joint: TYPE = GGModelTypes.Joint;
JointGenerator: TYPE = GGModelTypes.JointGenerator;
AlignBag: TYPE = GGGravity.AlignBag;
Outline: TYPE = GGModelTypes.Outline;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
Point: TYPE = GGBasicTypes.Point;
Scene: TYPE = GGModelTypes.Scene;
SegAndIndex: TYPE = GGSequence.SegAndIndex;
Segment: TYPE = GGSegmentTypes.Segment;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator;
Slice: TYPE = GGModelTypes.Slice;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceParts: TYPE = GGModelTypes.SliceParts;
Traj: TYPE = GGModelTypes.Traj;
TrajGenerator: TYPE = GGModelTypes.TrajGenerator;
TriggerBag: TYPE = GGGravity.TriggerBag;
Vector: TYPE = GGBasicTypes.Vector;
Viewer: TYPE = ViewerClasses.Viewer;
PaintActionArea: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ViewerOps.PaintViewer[
viewer: ggData.actionArea,
hint: client,
whatChanged: ggData,
clearClient: FALSE];
};
File Operations
NotNewVersion: PROC [ggData: GGData, op: ATOM] = {
need to repaint the caption because viewer is no longer edited
ggData.outer.newVersion ← FALSE;
ggData.outer.icon ← SELECT op FROM
$clear => noNameIcon,
$clean => cleanIcon,
ENDCASE => ERROR;
ViewerOps.PaintViewer[ggData.outer, caption];
};
GetGargoyleFileName: PROC [event: LIST OF REF ANY, currentWDir: Rope.ROPE, feedback: FeedbackData, emergency: BOOLFALSE] RETURNS [fullName: Rope.ROPENIL, success: BOOLTRUE, versionSpecified: BOOLFALSE] = {
ASSERT: event is either NIL or event.first=filename
RopeFromRef: PROC [ref: REF ANY] RETURNS [rope: Rope.ROPE] ~ {
WITH ref SELECT FROM
text: REF TEXT => RETURN[Rope.FromRefText[text] ];
r: Rope.ROPE => RETURN[r];
ENDCASE => ERROR;
};
fileName: Rope.ROPE;
fileName ← IF event#NIL AND event.first#NIL THEN RopeFromRef[event.first] ELSE ViewerTools.GetSelectionContents[];
[fullName, success, versionSpecified] ← GGUtility.GetGargoyleFileName[fileName, currentWDir, feedback, emergency];
};
Get: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ASSERT: event.first=$Get, event.rest=NIL OR filename
fullName: Rope.ROPE;
success, versionSpecified: BOOLFALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback];
IF NOT success THEN {
Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
ClearAux[event, ggData];
GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData];
NotNewVersion[ggData, $clean];
EXITS
Abort => Feedback.Blink[NARROW[clientData, GGData].feedback];
};
Merge: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ASSERT: event.first=$Merge, event.rest=NIL OR filename
fullName: Rope.ROPE;
success, versionSpecified: BOOLFALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback];
IF NOT success THEN {
Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
GetMergeAux[fullName, versionSpecified, $Merge, "Merging", ggData];
EXITS
Abort => Feedback.Blink[NARROW[clientData, GGData].feedback];
};
GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOLFALSE, event: ATOM, opName: Rope.ROPE, ggData: GGData] = {
ASSERT: event=$Merge or $Get
f: IO.STREAM;
fsName: Rope.ROPE;
TIMING VARIABLES
startTime: BasicTime.GMT;
endTime: BasicTime.GMT;
totalTime: INT;
msgRope: Rope.ROPE;
f ← FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => {
msgRope ← IO.PutFR["Could not find: %g", [rope[fullName]]];
Feedback.Append[ggData.feedback, msgRope, oneLiner];
GOTO Abort;
};];
msgRope ← IO.PutFR["%g %g . . . ", [rope[opName]], [rope[fullName]]];
Feedback.Append[ggData.feedback, msgRope, begin];
START TIMING
startTime ← BasicTime.Now[];
GGFileIn.FileinSceneAndOptions[f, ggData];
f.Close[];
endTime ← BasicTime.Now[];
totalTime ← BasicTime.Period[startTime, endTime];
msgRope ← IO.PutFR[" Done in time (%r)", [integer[totalTime]]];
Feedback.Append[ggData.feedback, msgRope, end];
here if successfully read a new GG file
IF event=$Get OR ggData.outer.file=NIL THEN { -- update viewer name on Get or on first Merge if no Get preceeded it.
fsName ← FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName;
ggData.outer.file ← FileNames.StripVersionNumber[fsName];
ggData.outer.label ← FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE];
ggData.outer.name ← IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"];
};
GGEvent.SawTextFinish[ggData, LIST[$SawTextFinish]];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE];
EXITS
Abort => Feedback.Blink[ggData.feedback];
}; -- end GetMergeAux
Store: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ASSERT: event.first=$Store or $Save, event.rest=NIL OR filename
Save is simply Store invoked with event.first=ggData.outer.file. KAP February 17, 1986
tKeep: CARDINAL ← 0;
f: IO.STREAM;
fullName, fsName: Rope.ROPE;
success, versionSpecified: BOOLFALSE;
TIMING VARIABLES
startTime: BasicTime.GMT;
endTime: BasicTime.GMT;
totalTime: INT;
msgRope, opName: Rope.ROPE;
ofile: FS.OpenFile;
emergency: BOOL ← event.first=$Emergency;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback, emergency];
IF NOT success THEN RETURN;
tKeep ← FS.FileInfo[name: fullName ! FS.Error => CONTINUE].keep;
ofile ← FS.Create[name: fullName, setPages: FALSE, setKeep: TRUE, keep: MAX[tKeep, 2] ! FS.Error => {
msgRope ← IO.PutFR["Could not create: %g", [rope[fullName]]];
IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, oneLiner];
GOTO Abort;
};];
f ← FS.StreamFromOpenFile[openFile: ofile, accessRights: $write];
opName ← IF event.first = NIL THEN "someSave" ELSE Atom.GetPName[NARROW[event.first]];
msgRope ← IO.PutFR["%g: %g . . . ", [rope[opName]], [rope[fullName]]];
IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, begin];
START TIMING
startTime ← BasicTime.Now[];
GGFileOut.FileoutSceneAndOptions[f, ggData, fullName];
f.Close[];
endTime ← BasicTime.Now[];
totalTime ← BasicTime.Period[startTime, endTime];
msgRope ← IO.PutFR[" Done in time (%r)", [integer[totalTime]]];
IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, end];
fsName ← FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName; --latest version
ggData.outer.file ← FileNames.StripVersionNumber[fsName];
ggData.outer.label ← FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE];
ggData.outer.name ← IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"];
NotNewVersion[ggData, $clean];
GGEvent.SawTextFinish[ggData, NIL];
EXITS
Abort => {
ggData: GGData ← NARROW[clientData];
IF NOT event.first=$Emergency THEN Feedback.Blink[ggData.feedback];
};
};
Save: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ggData.outer.file#NIL THEN Store[event: LIST[$Save, ggData.outer.file], clientData: clientData]
ELSE {
Feedback.Append[ggData.feedback, "Can't save an unnamed viewer: try Store", oneLiner];
Feedback.Blink[ggData.feedback];
};
};
Split: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];};
Reset: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
fileName: Rope.ROPE ← ggData.outer.file;
ClearAux[event, ggData];
can only reset to the latest version. No version numbers supported for resetting
GetMergeAux[fileName, FALSE, $Get, "Restoring", ggData];
need to repaint the caption because viewer is no longer edited
NotNewVersion[ggData, $clean];
};
Clear: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ClearAux[event, ggData];
ggData.outer.file ← NIL;
ggData.outer.label ← "Gargoyle";
ggData.outer.name ← "Gargoyle";
GGEvent.SawTextFinish[ggData, NIL];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE];
NotNewVersion[ggData, $clear];
}; -- end Clear
ClearAux: PROC [event: LIST OF REF ANY, ggData: GGData] = {
ggData.refresh.overlayList ← NIL;
GGSelect.DeselectAllAllClasses[ggData.scene];
ggData.scene ← GGScene.CreateScene[];
ggData.caret ← NEW[GGInterfaceTypes.CaretObj];
ggData.anchor ← NEW[GGInterfaceTypes.CaretObj];
GGEvent.StandardAlignments[ggData, LIST[$StandardAlignments]];
ggData.refresh.suppressRefresh ← FALSE; -- moved to abort processing code
ggData.aborted ← ALL[FALSE];
};
Group Operations
AddToGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
someAddition: BOOLFALSE;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=NIL OR Rope.Equal[name, ""] THEN {
Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO
duplicate: BOOLFALSE;
FOR prop: LIST OF REF ANY ← seg.props, prop.rest UNTIL prop=NIL DO
nextProp: Rope.ROPENARROW[prop.first];
IF Rope.Equal[name, nextProp, FALSE] THEN {
duplicate ← TRUE; -- already in this group
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN seg.props ← List.Append[seg.props, LIST[name]];
someAddition ← TRUE;
ENDLOOP;
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, IF someAddition THEN "Added selected segments to group %g" ELSE "No segment selections to add to group %g", [rope[name]] ];
};
SelectGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
trajGen: TrajGenerator ← GGScene.TrajsInScene[ggData.scene];
segGen: SegmentGenerator;
seq: Sequence;
segsFound: BOOL;
GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO
segGen ← GGSequence.SegmentsInTraj[traj];
segsFound ← FALSE;
FOR next: SegAndIndex ← GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL next.seg=NIL DO
FOR prop: LIST OF REF ANY ← next.seg.props, prop.rest UNTIL prop=NIL DO
nextProp: Rope.ROPENARROW[prop.first];
IF Rope.Equal[name, nextProp, FALSE] THEN {
IF NOT segsFound THEN seq ← GGSequence.CreateEmpty[traj];
segsFound ← TRUE;
IF NOT seq.segments[next.index] THEN {
seq.segments[next.index] ← TRUE;
seq.segCount ← seq.segCount + 1;
};
};
ENDLOOP; -- next prop
ENDLOOP; -- next segment
IF segsFound THEN GGSelect.SelectSequence[seq, ggData.scene, normal];
ENDLOOP; -- next trajectory
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.AppendHerald[ggData.feedback, "No such group", oneLiner ]
ELSE Feedback.PutF[ggData.feedback, oneLiner, "Group %g selected", [rope[name]] ];
};
RemoveFromGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
someRemoval: BOOLFALSE;
newProps: LIST OF REF ANY;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=NIL OR Rope.Equal[name, ""] THEN {
Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO
newProps ← NIL;
FOR prop: LIST OF REF ANY ← seg.props, prop.rest UNTIL prop=NIL DO
nextProp: Rope.ROPENARROW[prop.first];
IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps ← List.Append[newProps, LIST[nextProp]] ELSE someRemoval ← TRUE;
ENDLOOP;
seg.props ← newProps;
ENDLOOP;
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, IF someRemoval THEN "Removed selected segments from group %g" ELSE "No member segments selected to remove from group %g", [rope[name]] ];
};
PrintGroupsOfSelected: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
groupList: LIST OF REF ANY;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
IF GGSelect.NoSelections[ggData.scene, normal] THEN {
Feedback.AppendHerald[ggData.feedback, "No selections => no groups", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO
FOR prop: LIST OF REF ANY ← seg.props, prop.rest UNTIL prop=NIL DO
nextProp: Rope.ROPENARROW[prop.first];
duplicate: BOOLFALSE;
FOR group: LIST OF REF ANY ← groupList, group.rest UNTIL group=NIL DO
nextGroup: Rope.ROPENARROW[group.first];
IF Rope.Equal[nextGroup, nextProp, FALSE] THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#NIL THEN {
Feedback.Append[ggData.feedback, "Groups of Selected: ", begin];
FOR group: LIST OF REF ANY ← groupList, group.rest UNTIL group=NIL DO
nextGroup: Rope.ROPENARROW[group.first];
Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
Feedback.Append[ggData.feedback, "", end];
}
ELSE Feedback.Append[ggData.feedback, "No Groups of Selected", oneLiner];
};
PrintAllGroups: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
groupList: LIST OF REF ANY;
ggData: GGData ← NARROW[clientData];
trajGen: TrajGenerator ← GGScene.TrajsInScene[ggData.scene];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO
segGen: SegmentGenerator ← GGSequence.SegmentsInTraj[traj];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO
FOR prop: LIST OF REF ANY ← seg.props, prop.rest UNTIL prop=NIL DO
nextProp: Rope.ROPENARROW[prop.first];
duplicate: BOOLFALSE;
FOR group: LIST OF REF ANY ← groupList, group.rest UNTIL group=NIL DO
nextGroup: Rope.ROPENARROW[group.first];
IF Rope.Equal[nextGroup, nextProp, FALSE] THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#NIL THEN {
Feedback.Append[ggData.feedback, "Groups: ", begin];
FOR group: LIST OF REF ANY ← groupList, group.rest UNTIL group=NIL DO
nextGroup: Rope.ROPENARROW[group.first];
Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
Feedback.Append[ggData.feedback, "", end];
}
ELSE Feedback.Append[ggData.feedback, "No Groups", oneLiner];
};
Area and Line Colors
RGBFromRopeError: SIGNAL = CODE;
AreaColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN AreaColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData];
};
LineColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN LineColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData];
};
AreaColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN {
color: Imager.Color ← GGUtility.GetSpecialColor[]; -- "animation" color;
IF color#NIL THEN {
ggData.refresh.areaFollowColorTool ← TRUE;
AreaColorAux[color, ggData];
}
ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner];
};
};
LineColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN {
color: Imager.Color ← GGUtility.GetSpecialColor[]; -- "animation" color;
IF color#NIL THEN {
ggData.refresh.lineFollowColorTool ← TRUE;
LineColorAux[color, ggData];
}
ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner];
};
};
AreaColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN {
red, green, blue: REAL;
color: Imager.Color;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen];
color ← sliceD.slice.class.getFillColor[sliceD.slice];
IF color#NIL THEN {
[red, green, blue] ← GGUtility.ExtractRGB[color];
ColorTool.SetRGBValue[[red, green, blue], NIL];
}
ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL fill color", oneLiner];
};
};
LineColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
IF ColorToolIsBound[ggData] THEN {
red, green, blue: REAL;
color: Imager.Color;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen];
color ← sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts];
IF color#NIL THEN {
[red, green, blue] ← GGUtility.ExtractRGB[color];
ColorTool.SetRGBValue[[red, green, blue], NIL];
}
ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL stroke color", oneLiner];
};
};
AreaColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
AreaColorAux[color, ggData];
EXITS
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
LineColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
LineColorAux[color, ggData];
EXITS
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
AreaColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
AreaColorAux[color, ggData];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
LineColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
LineColorAux[color, ggData];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
SelectMatchingAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
entityGen: EntityGenerator ← GGScene.TopLevelEntitiesInScene[ggData.scene];
noneFlag: BOOL ← Rope.Equal[name, "none", FALSE];
IF NOT noneFlag THEN rgb ← SELECT event.first FROM
$SelectMatchingAreaCNS =>
ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]],
$SelectMatchingAreaRGB =>
RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]
ENDCASE => ERROR;
GGSelect.DeselectAll[ggData.scene, normal];
FOR entity: REF ANY ← GGScene.NextEntity[entityGen], GGScene.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, ggData.scene, normal];
};
slice: Slice => {
fillColor: Imager.Color ← slice.class.getFillColor[slice];
IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectSlice[slice.class.newParts[slice, NIL, topLevel], ggData.scene, normal];
};
ENDCASE => ERROR;
ENDLOOP;
Feedback.PutFHerald[ggData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ];
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
SelectMatchingAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
sliceGen: SliceGenerator ← GGScene.TopLevelSlicesInScene[ggData.scene];
noneFlag: BOOL ← Rope.Equal[name, "none", FALSE];
IF NOT noneFlag THEN rgb ← SELECT event.first FROM
$SelectMatchingAreaCNS =>
ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]],
$SelectMatchingAreaRGB =>
RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]
ENDCASE => ERROR;
GGSelect.DeselectAll[ggData.scene, normal];
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO
fillColor: Imager.Color ← slice.class.getFillColor[slice];
IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireSlice[slice, ggData.scene, normal];
ENDLOOP;
Feedback.PutFHerald[ggData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ];
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
SelectMatchingLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPEIF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
trajGen: TrajGenerator ← GGScene.TrajsInScene[ggData.scene];
sliceGen: SliceGenerator ← GGScene.SlicesInScene[ggData.scene];
noneFlag: BOOL ← Rope.Equal[name, "none", FALSE];
IF NOT noneFlag THEN rgb ← SELECT event.first FROM
$SelectMatchingLineCNS =>
ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]],
$SelectMatchingLineRGB =>
RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]
ENDCASE => ERROR;
GGSelect.DeselectAll[ggData.scene, normal];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.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, ggData.scene, normal];
};
ENDLOOP;
ENDLOOP;
FOR slice: Slice ← GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO -- for every slice in the scene
ColorProc: WalkProc = {
WalkProc: TYPE = PROC [seg: Segment] RETURNS [keep: BOOL];
RETURN [RGBEqualsColor[rgb, seg.color, noneFlag]];
};
sliceD: SliceDescriptor ← GGSlice.WalkSegments[slice, ColorProc]; -- get a descriptor of matching parts
GGSelect.SelectSlice[sliceD, ggData.scene, normal]; -- and select it
ENDLOOP;
Feedback.PutFHerald[ggData.feedback, oneLiner, "Segments with color %g selected", [rope[name]] ];
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
SetDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceD: SliceDescriptor;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
IF sliceDescGen=NIL OR (sliceD ← GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for setting default line color", oneLiner]
ELSE {
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor ← NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]];
IF color#NIL THEN {
[red,green,blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner];
ggData.defaults.strokeColor ← color;
};
};
SetDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceD: SliceDescriptor;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
IF sliceDescGen=NIL OR (sliceD ← GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one filled object for setting default fill color", oneLiner]
ELSE {
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor;
IF sliceD.slice.class.type=$Outline AND GGOutline.FenceOfOutline[sliceD.slice].role=open THEN {
Feedback.AppendHerald[ggData.feedback, "Select one FILLED object for setting default fill color", oneLiner];
RETURN;
}
ELSE color ← NARROW[sliceD.slice.class.getFillColor[sliceD.slice]];
IF color#NIL THEN {
[red,green,blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner];
ggData.defaults.fillColor ← color;
};
};
ShowDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor ← NARROW[ggData.defaults.strokeColor];
IF color#NIL THEN {
[red,green,blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner];
};
ShowDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor ← NARROW[ggData.defaults.fillColor];
IF color#NIL THEN {
[red,green,blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner];
};
AreaColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
AreaColorAux[Imager.black, ggData];
};
LineColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
LineColorAux[Imager.black, ggData];
};
PrintAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceD: SliceDescriptor;
isProcessBlack: Rope.ROPE;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
IF sliceDescGen=NIL OR (sliceD ← GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for PrintFillColor", oneLiner]
ELSE {
red, green, blue: REAL;
color: Imager.ConstantColor ← NARROW[sliceD.slice.class.getFillColor[sliceD.slice]];
IF color#NIL THEN {
[red,green,blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "No Fill Color", oneLiner];
};
};
PrintLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceD: SliceDescriptor;
isProcessBlack: Rope.ROPE;
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
IF sliceDescGen=NIL OR (sliceD ← GGSelect.NextSliceDescriptor[sliceDescGen])=NIL OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one object for PrintLineColor", oneLiner]
ELSE {
red, green, blue: REAL;
color: Imager.ConstantColor ← NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]];
IF color#NIL THEN {
[red, green, blue] ← GGUtility.ExtractRGB[color];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
Feedback.Append[
ggData.feedback,
IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE Feedback.Append[ggData.feedback, "No Stroke Color", oneLiner];
};
};
AreaColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
AreaColorAux[Imager.white, ggData];
};
LineColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
LineColorAux[Imager.white, ggData];
};
AreaColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
AreaColorAux[GGOutline.fillColor, ggData];
};
LineColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
LineColorAux[GGOutline.fillColor, ggData];
};
AreaColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
AreaColorAux[NIL, ggData];
};
LineColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
LineColorAux[NIL, ggData];
};
AreaColorAux: PROC [color: Imager.Color, clientData: REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
FOR sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO
sliceD.slice.class.setFillColor[sliceD.slice, color];
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
LineColorAux: PROC [color: Imager.Color, clientData: REF ANY] = {
ggData: GGData ← NARROW[clientData];
sliceDescGen: SliceDescriptorGenerator ← GGSelect.SelectedSlices[ggData.scene, normal];
FOR sliceD: SliceDescriptor ← GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO
sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color];
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
ColorToolIsBound: PROC [ggData: GGData] RETURNS [BOOLFALSE] = TRUSTED {
IF PrincOpsUtils.IsBound[LOOPHOLE[ColorTool.GetRGBValue]] THEN RETURN[TRUE];
Feedback.AppendHerald[ggData.feedback, "Please start ColorTool and retry this operation", oneLiner];
};
RGBEqualsColor: PROC [rgb: ImagerColor.RGB, color: Imager.Color, noneFlag: BOOL] RETURNS [BOOL] = {
epsilon: REAL = 1.0E-2;
IF color=NIL THEN RETURN [noneFlag]; -- color is none => RETURN[looking for none]
IF noneFlag THEN RETURN [FALSE] -- looking for none, but color is non-NIL
ELSE {
r, g, b: REAL;
[r,g,b] ← GGUtility.ExtractRGB[color];
RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R]<epsilon AND ABS[g-rgb.G]<epsilon AND ABS[b-rgb.B]<epsilon ) ];
};
};
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.STREAMIO.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;
};
Debug Menu
TestMultiGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
};
TestMultiGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until 100 points have been drawn.
xRandomStream, yRandomStream: Random.RandomStream;
testPoint: Point;
x, y: INT;
totalCount: NAT ← 0;
features: GGMultiGravity.NearFeatures;
points: GGMultiGravity.NearPoints;
distances: GGMultiGravity.NearDistances;
currentObjects: AlignBag;
sceneObjects: TriggerBag;
count: NAT;
xRandomStream ← Random.Create[ggData.actionArea.cw];
yRandomStream ← Random.Create[ggData.actionArea.ch];
GGAlign.SetBagsForAction[ggData, $CaretPos];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintAlign, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
ggData.hitTest.hitCount ← 0;
ggData.aborted[gravitytest] ← FALSE; -- in case there was one left over from prior abort
UNTIL totalCount > 1000 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;
[features, points, distances, count] ← GGMultiGravity.MultiMap[20, testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE];
IF count > 0 THEN {
FOR i: NAT IN [0..count-1] DO
ggData.refresh.hitPoint ← points[i];
IF distances[i] > ggData.hitTest.tolerance THEN GOTO Done;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
ggData.hitTest.hitCount ← ggData.hitTest.hitCount + 1;
REPEAT
Done => {
IF i = 0 THEN
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
ENDLOOP;
}
ELSE {
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
totalCount ← totalCount + 1;
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g were hits", [integer[totalCount]], [integer[ggData.hitTest.hitCount]]];
};
TestGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until 100 points have been drawn.
xRandomStream, yRandomStream: Random.RandomStream;
desiredCount: INTNARROW[event.rest.first, REF INT]^;
testPoint: Point;
x, y: INT;
totalCount, multiHitCount, uniHitCount, diffCount: NAT ← 0;
uniPoint, multiPoint: Point;
uniFeature, multiFeature: FeatureData;
currentObjects: AlignBag;
sceneObjects: TriggerBag;
IF desiredCount < 0 THEN RETURN;
xRandomStream ← Random.Create[ggData.actionArea.cw];
yRandomStream ← Random.Create[ggData.actionArea.ch];
GGAlign.SetStaticBags[ggData];
ggData.hitTest.hitCount ← 0;
ggData.aborted[gravitytest] ← FALSE; -- in case there was one left over from prior abort
UNTIL totalCount >= desiredCount DO
IF ggData.aborted[gravitytest] THEN {
ggData.aborted[gravitytest] ← FALSE;
EXIT;
};
x ← Random.NextInt[xRandomStream];
y ← Random.NextInt[yRandomStream];
testPoint ← [x, y];
testPoint ← GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData];
ggData.refresh.spotPoint ← testPoint;
currentObjects ← ggData.hitTest.alignBag;
sceneObjects ← ggData.hitTest.sceneBag;
[uniPoint, uniFeature] ← GGGravity.UniMap[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE];
[multiPoint, multiFeature] ← GGMultiGravity.Map[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE];
IF uniFeature = NIL AND multiFeature = NIL THEN {
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
totalCount ← totalCount + 1;
LOOP;
};
IF uniFeature = NIL OR multiFeature = NIL OR uniFeature # multiFeature OR uniFeature.type # multiFeature.type OR uniPoint # multiPoint THEN {
ReportResultsAndPaint[testPoint, uniPoint, uniFeature, multiPoint, multiFeature, ggData];
totalCount ← totalCount + 1;
diffCount ← diffCount + 1;
IF multiFeature # NIL THEN multiHitCount ← multiHitCount + 1;
IF uniFeature # NIL THEN uniHitCount ← uniHitCount + 1;
}
ELSE {
multiHitCount ← multiHitCount + 1;
uniHitCount ← uniHitCount + 1;
totalCount ← totalCount + 1;
ggData.refresh.hitPoint ← multiPoint;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]];
}; -- end TestGravity
noisyTestGravity: BOOLFALSE;
ReportResultsAndPaint: PROC [testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, ggData: GGData] = {
multiMag, uniMag: REAL;
IF uniFeature = NIL THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No unihit at [%g, %g]. multihit distance: %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE IF multiFeature = NIL THEN {
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No multihit at [%g, %g]. unihit distance: %g", [real[uniPoint.x]], [real[uniPoint.y]], [real[uniMag]]];
ggData.refresh.hitPoint ← uniPoint;
}
ELSE IF uniFeature # multiFeature THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Features differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE IF uniFeature.type # multiFeature.type THEN {
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Feature types differ at [%g, %g]", [real[multiPoint.x]], [real[multiPoint.y]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE IF uniPoint # multiPoint THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Points differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]];
ggData.refresh.hitPoint ← uniPoint;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE ERROR;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
Statistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
f: IO.STREAM ← Feedback.GetTypescriptStream[$Gargoyle];
CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]];
};
PrintSelectedStatistic: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
intervalName: Rope.ROPENARROW[event.rest.first];
atom: ATOM ← Atom.MakeAtom[intervalName];
f: IO.STREAM ← Feedback.GetTypescriptStream[$Gargoyle];
CodeTimer.PrintInt[f, atom, $Gargoyle];
};
ResetStatistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]];
};
DrawTouchPoints: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawBoundBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawTightBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawOutlineBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawSelectionBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawMovingBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
atom: ATOMNARROW[event.first];
GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DescribeCaretObject: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
description: Rope.ROPE ← "no object";
chair: REF ANY;
chair ← GGCaret.GetChair[ggData.caret];
IF chair # NIL THEN {
WITH chair SELECT FROM
outlineD: OutlineDescriptor => {
description ← outlineD.slice.class.describe[outlineD];
};
sliceD: SliceDescriptor => {
description ← sliceD.slice.class.describe[sliceD];
};
ENDCASE => ERROR;
};
Feedback.Append[ggData.feedback, IO.PutFR["Caret is on %g.", [rope[description]]], oneLiner];
};
SlackLog: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
SlackProcess.OutputLog[ggData.slackHandle, Feedback.GetTypescriptStream[$Gargoyle]];
};
Typescript: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
[] ← Feedback.OpenTypescript["Gargoyle Typescript", $Gargoyle, 120];
};
cleanIcon: Icons.IconFlavor ← unInit; -- filled in by Init
noNameIcon: Icons.IconFlavor ← unInit; -- filled in by Init
Init: PROC = { -- copied from GGWindowImpl
noNameIcon ← Icons.NewIconFromFile["Gargoyle.icons", 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/
cleanIcon ← Icons.NewIconFromFile["Gargoyle.icons", 3]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/
};
Init[];
END.