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 5, 1987 6:44: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:
BOOL ←
FALSE]
RETURNS [fullName: Rope.
ROPE ←
NIL, success:
BOOL ←
TRUE, versionSpecified:
BOOL ←
FALSE] = {
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: BOOL ← FALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback];
IF
NOT success
THEN {
Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
ClearAux[event, ggData];
GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData];
NotNewVersion[ggData, $clean];
EXITS
Abort => Feedback.Blink[NARROW[clientData, GGData].feedback];
};
Merge:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
ASSERT: event.first=$Merge, event.rest=NIL OR filename
fullName: Rope.ROPE;
success, versionSpecified: BOOL ← FALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback];
IF
NOT success
THEN {
Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
GetMergeAux[fullName, versionSpecified, $Merge, "Merging", ggData];
EXITS
Abort => Feedback.Blink[NARROW[clientData, GGData].feedback];
};
GetMergeAux:
PROC [fullName: Rope.
ROPE, versionSpecified:
BOOL ←
FALSE, event:
ATOM, opName: Rope.
ROPE, ggData: GGData] = {
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: BOOL ← FALSE;
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: BOOL ← FALSE;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=
NIL
OR Rope.Equal[name, ""]
THEN {
Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
duplicate: BOOL ← FALSE;
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF Rope.Equal[name, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already in this group
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN seg.props ← List.Append[seg.props, LIST[name]];
someAddition ← TRUE;
ENDLOOP;
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, IF someAddition THEN "Added selected segments to group %g" ELSE "No segment selections to add to group %g", [rope[name]] ];
SelectGroup:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
trajGen: TrajGenerator ← GGScene.TrajsInScene[ggData.scene];
segGen: SegmentGenerator;
seq: Sequence;
segsFound: BOOL;
GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen]
UNTIL traj =
NIL
DO
segGen ← GGSequence.SegmentsInTraj[traj];
segsFound ← FALSE;
FOR next: SegAndIndex ← GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen]
UNTIL next.seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← next.seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF
Rope.Equal[name, nextProp,
FALSE]
THEN {
IF NOT segsFound THEN seq ← GGSequence.CreateEmpty[traj];
segsFound ← TRUE;
IF
NOT seq.segments[next.index]
THEN {
seq.segments[next.index] ← TRUE;
seq.segCount ← seq.segCount + 1;
};
};
ENDLOOP; -- next prop
ENDLOOP; -- next segment
IF segsFound THEN GGSelect.SelectSequence[seq, ggData.scene, normal];
ENDLOOP; -- next trajectory
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.AppendHerald[ggData.feedback, "No such group", oneLiner ]
ELSE Feedback.PutF[ggData.feedback, oneLiner, "Group %g selected", [rope[name]] ];
RemoveFromGroup:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
someRemoval: BOOL ← FALSE;
newProps: LIST OF REF ANY;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=
NIL
OR Rope.Equal[name, ""]
THEN {
Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
newProps ← NIL;
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps ← List.Append[newProps, LIST[nextProp]] ELSE someRemoval ← TRUE;
ENDLOOP;
seg.props ← newProps;
ENDLOOP;
ENDLOOP;
Feedback.PutF[ggData.feedback, oneLiner, IF someRemoval THEN "Removed selected segments from group %g" ELSE "No member segments selected to remove from group %g", [rope[name]] ];
PrintGroupsOfSelected:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
groupList: LIST OF REF ANY;
seqGen: SequenceGenerator;
ggData: GGData ← NARROW[clientData];
IF GGSelect.NoSelections[ggData.scene, normal]
THEN {
Feedback.AppendHerald[ggData.feedback, "No selections => no groups", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[ggData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
duplicate: BOOL ← FALSE;
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
IF Rope.Equal[nextGroup, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#
NIL
THEN {
Feedback.Append[ggData.feedback, "Groups of Selected: ", begin];
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
Feedback.Append[ggData.feedback, "", end];
}
ELSE Feedback.Append[ggData.feedback, "No Groups of Selected", oneLiner];
};
PrintAllGroups:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
groupList: LIST OF REF ANY;
ggData: GGData ← NARROW[clientData];
trajGen: TrajGenerator ← GGScene.TrajsInScene[ggData.scene];
FOR traj: Traj ← GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen]
UNTIL traj =
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInTraj[traj];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
duplicate: BOOL ← FALSE;
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
IF Rope.Equal[nextGroup, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#
NIL
THEN {
Feedback.Append[ggData.feedback, "Groups: ", begin];
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
Feedback.Append[ggData.feedback, "", end];
}
ELSE Feedback.Append[ggData.feedback, "No Groups", oneLiner];
};
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 ← NIL;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
WITH GGScene.NextEntity[entityGen]
SELECT
FROM
outlineD: OutlineDescriptor => color ← outlineD.slice.class.getFillColor[outlineD.slice];
sliceD: SliceDescriptor => color ← sliceD.slice.class.getFillColor[sliceD.slice];
ENDCASE => ERROR;
IF color#
NIL
THEN {
[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 ← NIL;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
WITH GGScene.NextEntity[entityGen]
SELECT
FROM
outlineD: OutlineDescriptor => color ← outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts];
sliceD: SliceDescriptor => color ← sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts];
ENDCASE => ERROR;
IF color#
NIL
THEN {
[red, green, blue] ← GGUtility.ExtractRGB[color];
ColorTool.SetRGBValue[[red, green, blue], NIL];
}
ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL stroke color", oneLiner];
};
};
AreaColorFromSelectedName:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
AreaColorAux[color, ggData];
EXITS
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
LineColorFromSelectedName:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
LineColorAux[color, ggData];
EXITS
UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
AreaColorFromSelectedRGB:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
AreaColorAux[color, ggData];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
LineColorFromSelectedRGB:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
LineColorAux[color, ggData];
EXITS
SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];};
};
SelectMatchingAreaColor:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
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];};
};
SelectMatchingLineColor:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
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];
entity: REF ANY;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
IF entityGen=NIL OR (entity ← GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for setting default line color", oneLiner]
ELSE {
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor;
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => color ← NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]];
sliceD: SliceDescriptor => color ← NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]];
ENDCASE => ERROR;
IF color#
NIL
THEN {
[red,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];
entity: REF ANY;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
IF entityGen=NIL OR (entity ← GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for setting default fill color", oneLiner]
ELSE {
isProcessBlack: Rope.ROPE;
red, green, blue: REAL;
color: Imager.ConstantColor;
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => {
IF GGOutline.FenceOfOutline[outlineD.slice].role#open
THEN color ←
NARROW[outlineD.slice.class.getFillColor[outlineD.slice]]
ELSE {
Feedback.AppendHerald[ggData.feedback, "Select exactly one filled entity for setting default fill color", oneLiner];
RETURN;
};
};
sliceD: SliceDescriptor => color ← NARROW[sliceD.slice.class.getFillColor[sliceD.slice]];
ENDCASE => ERROR;
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];
entity: REF ANY;
isProcessBlack: Rope.ROPE;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
IF entityGen=NIL OR (entity ← GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for PrintFillColor", oneLiner]
ELSE {
red, green, blue: REAL;
color: Imager.ConstantColor;
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => color ← NARROW[outlineD.slice.class.getFillColor[outlineD.slice]];
sliceD: SliceDescriptor => color ← NARROW[sliceD.slice.class.getFillColor[sliceD.slice]];
ENDCASE => ERROR;
IF color#
NIL
THEN {
[red,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];
entity: REF ANY;
isProcessBlack: Rope.ROPE;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
IF entityGen=NIL OR (entity ← GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for PrintLineColor", oneLiner]
ELSE {
red, green, blue: REAL;
color: Imager.ConstantColor;
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => color ← NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]];
sliceD: SliceDescriptor => color ← NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]];
ENDCASE => ERROR;
IF color#
NIL
THEN {
[red, 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];
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
FOR entity:
REF
ANY ← GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen]
UNTIL entity =
NIL
DO
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => outlineD.slice.class.setFillColor[outlineD.slice, color];
sliceD: SliceDescriptor => sliceD.slice.class.setFillColor[sliceD.slice, color];
ENDCASE => ERROR;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
LineColorAux:
PROC [color: Imager.Color, clientData:
REF
ANY] = {
ggData: GGData ← NARROW[clientData];
entityGen: EntityGenerator ← GGSelect.SelectedStuff[ggData.scene, normal];
FOR entity:
REF
ANY ← GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen]
UNTIL entity =
NIL
DO
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => outlineD.slice.class.setStrokeColor[outlineD.slice, outlineD.parts, color];
sliceD: SliceDescriptor => sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color];
ENDCASE => ERROR;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
ColorToolIsBound:
PROC [ggData: GGData]
RETURNS [
BOOL ←
FALSE] =
TRUSTED {
IF PrincOpsUtils.IsBound[LOOPHOLE[ColorTool.GetRGBValue]] THEN RETURN[TRUE];
Feedback.AppendHerald[ggData.feedback, "Please start ColorTool and retry this operation", oneLiner];
};
RGBEqualsColor:
PROC [rgb: ImagerColor.
RGB, color: Imager.Color, noneFlag:
BOOL]
RETURNS [
BOOL] = {
epsilon: REAL = 1.0E-2;
IF color=NIL THEN RETURN [noneFlag]; -- fillColor is 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.STREAM ← IO.RIS[name];
IF Ascii.Upper[rs.GetChar[]]#'R THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.R ← rs.GetReal[]; [] ← rs.SkipWhitespace[];
IF Ascii.Upper[rs.GetChar[]]#'G THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.G ← rs.GetReal[]; [] ← rs.SkipWhitespace[];
IF Ascii.Upper[rs.GetChar[]]#'B THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.B ← rs.GetReal[];
Check[rgb.R]; Check[rgb.G]; Check[rgb.B];
EXITS
RGBError => SIGNAL RGBFromRopeError;
};
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: INT ← NARROW[event.rest.first, REF INT]^;
testPoint: Point;
x, y: INT;
totalCount, multiHitCount, uniHitCount, diffCount: NAT ← 0;
uniPoint, multiPoint: Point;
uniFeature, multiFeature: FeatureData;
currentObjects: AlignBag;
sceneObjects: TriggerBag;
IF desiredCount < 0 THEN RETURN;
xRandomStream ← Random.Create[ggData.actionArea.cw];
yRandomStream ← Random.Create[ggData.actionArea.ch];
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: BOOL ← FALSE;
ReportResultsAndPaint:
PROC [testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, ggData: GGData] = {
multiMag, uniMag: REAL;
IF uniFeature =
NIL
THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No unihit at [%g, %g]. multihit distance: %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE
IF multiFeature =
NIL
THEN {
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No multihit at [%g, %g]. unihit distance: %g", [real[uniPoint.x]], [real[uniPoint.y]], [real[uniMag]]];
ggData.refresh.hitPoint ← uniPoint;
}
ELSE
IF uniFeature # multiFeature
THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Features differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE
IF uniFeature.type # multiFeature.type
THEN {
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Feature types differ at [%g, %g]", [real[multiPoint.x]], [real[multiPoint.y]]];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE
IF uniPoint # multiPoint
THEN {
multiMag ← Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]];
uniMag ← Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]];
IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Points differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]];
ggData.refresh.hitPoint ← uniPoint;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
ggData.refresh.hitPoint ← multiPoint;
}
ELSE ERROR;
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
Statistics:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
f: IO.STREAM ← Feedback.GetTypescriptStream[$Gargoyle];
CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]];
};
PrintSelectedStatistic:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
intervalName: Rope.ROPE ← NARROW[event.rest.first];
atom: ATOM ← Atom.MakeAtom[intervalName];
f: IO.STREAM ← Feedback.GetTypescriptStream[$Gargoyle];
CodeTimer.PrintInt[f, atom, $Gargoyle];
};
ResetStatistics:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]];
};
DrawTouchPoints:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawBoundBoxes:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawTightBoxes:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawOutlineBoxes:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawSelectionBox:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DrawMovingBox:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
atom: ATOM ← NARROW[event.first];
GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
};
DescribeCaretObject:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
description: Rope.ROPE ← "no object";
chair: REF ANY;
chair ← GGCaret.GetChair[ggData.caret];
IF chair #
NIL
THEN {
WITH chair
SELECT
FROM
outlineD: OutlineDescriptor => {
description ← outlineD.slice.class.describe[outlineD];
};
sliceD: SliceDescriptor => {
description ← sliceD.slice.class.describe[sliceD];
};
ENDCASE => ERROR;
};
Feedback.Append[ggData.feedback, IO.PutFR["Caret is on %g.", [rope[description]]], oneLiner];
};
SlackLog:
PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = {
ggData: GGData ← NARROW[clientData];
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.