GGEventImplD.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on September 8, 1986 11:02:49 pm PDT
Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module.
DIRECTORY
Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, FS, GGError, GGEvent, GGFileIn, GGFileOut, FileNames, Imager, ImagerColor, ImagerColorPrivate, GGInterfaceTypes, GGModelTypes, GGObjects, GGSelect, GGSegmentTypes, GGSequence, GGUtility, GGWindow, Icons, IO, List, NamedColors, PrincOpsUtils, Rope, ViewerClasses, ViewerOps, ViewerTools;
GGEventImplD:
CEDAR
PROGRAM
IMPORTS Ascii, Atom, BasicTime, ColorToolViewer, ColorToolViewerExtras, FileNames, FS, GGError, GGFileIn, GGFileOut, GGEvent, GGObjects, GGSelect, GGSequence, GGUtility, GGWindow, Imager, ImagerColor, ImagerColorPrivate, Icons, IO, List, NamedColors, PrincOpsUtils, Rope, ViewerOps, ViewerTools
EXPORTS GGEvent = BEGIN
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
Outline: TYPE = GGModelTypes.Outline;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
Slice: TYPE = GGModelTypes.Slice;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
Segment: TYPE = GGSegmentTypes.Segment;
SegAndIndex: TYPE = GGSequence.SegAndIndex;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator;
Traj: TYPE = GGModelTypes.Traj;
TrajGenerator: TYPE = GGModelTypes.TrajGenerator;
Viewer: TYPE = ViewerClasses.Viewer;
PaintActionArea:
PUBLIC PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
ViewerOps.PaintViewer[
viewer: gargoyleData.actionArea,
hint: client,
whatChanged: gargoyleData,
clearClient: FALSE];
};
File Operations
NotNewVersion:
PROC [gargoyleData: GargoyleData] = {
need to repaint the caption because viewer is no longer edited
gargoyleData.outer.newVersion ← FALSE;
gargoyleData.outer.icon ← cleanIcon;
ViewerOps.PaintViewer[gargoyleData.outer, caption];
};
GetGargoyleFileName:
PROC [event:
LIST
OF
REF
ANY, currentWDir: Rope.
ROPE, feedback: Viewer, emergency:
BOOL ←
FALSE]
RETURNS [fullName: Rope.
ROPE ←
NIL, success:
BOOL ←
TRUE, versionSpecified:
BOOL ←
FALSE] = {
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 [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
ASSERT: event.first=$Get, event.rest=NIL OR filename
fullName: Rope.ROPE;
success, versionSpecified: BOOL ← FALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, gargoyleData.currentWDir, gargoyleData.feedback];
IF
NOT success
THEN {
GGError.Append[gargoyleData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
ClearAux[event, gargoyleData];
GetMergeAux[fullName, versionSpecified, $Get, "Getting", gargoyleData];
NotNewVersion[gargoyleData];
EXITS
Abort => GGError.Blink[NARROW[clientData, GargoyleData].feedback];
};
Merge:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
ASSERT: event.first=$Merge, event.rest=NIL OR filename
fullName: Rope.ROPE;
success, versionSpecified: BOOL ← FALSE;
[fullName, success, versionSpecified] ← GetGargoyleFileName[event.rest, gargoyleData.currentWDir, gargoyleData.feedback];
IF
NOT success
THEN {
GGError.Append[gargoyleData.feedback, "Could not find requested file", oneLiner];
GOTO Abort;
};
GetMergeAux[fullName, versionSpecified, $Merge, "Merging", gargoyleData];
EXITS
Abort => GGError.Blink[NARROW[clientData, GargoyleData].feedback];
};
GetMergeAux:
PROC [fullName: Rope.
ROPE, versionSpecified:
BOOL ←
FALSE, event:
ATOM, opName: Rope.
ROPE, gargoyleData: GargoyleData] = {
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]]];
GGError.Append[gargoyleData.feedback, msgRope, oneLiner];
GOTO Abort;
};];
msgRope ← IO.PutFR["%g %g . . . ", [rope[opName]], [rope[fullName]]];
GGError.Append[gargoyleData.feedback, msgRope, begin];
START TIMING
startTime ← BasicTime.Now[];
GGFileIn.FileinSceneAndOptions[f, gargoyleData];
f.Close[];
endTime ← BasicTime.Now[];
totalTime ← BasicTime.Period[startTime, endTime];
msgRope ← IO.PutFR[" Done in time (%r)", [integer[totalTime]]];
GGError.Append[gargoyleData.feedback, msgRope, end];
here if successfully read a new GG file
IF event=$Get
OR gargoyleData.outer.file=
NIL
THEN {
-- update viewer name on Get or on first Merge if no Get preceeded it.
fsName ← FS.FileInfo[name: fullName, wDir: gargoyleData.currentWDir].fullFName;
gargoyleData.outer.file ← FileNames.StripVersionNumber[fsName];
gargoyleData.outer.label ← FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE];
gargoyleData.outer.name ← IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", gargoyleData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"];
};
GGEvent.SawTextFinish[LIST[$SawTextFinish], gargoyleData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE];
EXITS
Abort => GGError.Blink[gargoyleData.feedback];
}; -- end GetMergeAux
Store:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
ASSERT: event.first=$Store or $Save, event.rest=NIL OR filename
Save is simply Store invoked with event.first=gargoyleData.outer.file. KAP February 17, 1986
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, gargoyleData.currentWDir, gargoyleData.feedback, emergency];
IF NOT success THEN RETURN;
tKeep ← FS.FileInfo[name: fullName ! FS.Error => CONTINUE].keep;
ofile ←
FS.Create[name: fullName, setPages:
FALSE, setKeep:
TRUE, keep:
MAX[tKeep, 2] !
FS.Error => {
msgRope ← IO.PutFR["Could not create: %g", [rope[fullName]]];
IF NOT emergency THEN GGError.Append[gargoyleData.feedback, msgRope, oneLiner];
GOTO Abort;
};];
f ← FS.StreamFromOpenFile[openFile: ofile, accessRights: $write];
opName ← IF event.first = NIL THEN "someSave" ELSE Atom.GetPName[NARROW[event.first]];
msgRope ← IO.PutFR["%g: %g . . . ", [rope[opName]], [rope[fullName]]];
IF NOT emergency THEN GGError.Append[gargoyleData.feedback, msgRope, begin];
START TIMING
startTime ← BasicTime.Now[];
GGFileOut.FileoutSceneAndOptions[f, gargoyleData, fullName];
f.Close[];
endTime ← BasicTime.Now[];
totalTime ← BasicTime.Period[startTime, endTime];
msgRope ← IO.PutFR[" Done in time (%r)", [integer[totalTime]]];
IF NOT emergency THEN GGError.Append[gargoyleData.feedback, msgRope, end];
fsName ← FS.FileInfo[name: fullName, wDir: gargoyleData.currentWDir].fullFName; --latest version
gargoyleData.outer.file ← FileNames.StripVersionNumber[fsName];
gargoyleData.outer.label ← FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE];
gargoyleData.outer.name ← IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", gargoyleData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"];
NotNewVersion[gargoyleData];
GGEvent.SawTextFinish[NIL, gargoyleData];
EXITS
Abort => {
gargoyleData: GargoyleData ← NARROW[clientData];
IF NOT event.first=$Emergency THEN GGError.Blink[gargoyleData.feedback];
};
};
Save:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF gargoyleData.outer.file#NIL THEN Store[event: LIST[$Save, gargoyleData.outer.file], clientData: clientData]
ELSE {
GGError.Append[gargoyleData.feedback, "Can't save an unnamed viewer: try Store", oneLiner];
GGError.Blink[gargoyleData.feedback];
};
};
Split:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];};
Reset:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
fileName: Rope.ROPE ← gargoyleData.outer.file;
ClearAux[event, gargoyleData];
can only reset to the latest version. No version numbers supported for resetting
GetMergeAux[fileName,
FALSE, $Get, "Restoring", gargoyleData];
need to repaint the caption because viewer is no longer edited
NotNewVersion[gargoyleData];
};
Clear:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
ClearAux[event, gargoyleData];
gargoyleData.outer.file ← NIL;
gargoyleData.outer.label ← "Gargoyle";
gargoyleData.outer.name ← "Gargoyle";
GGEvent.SawTextFinish[NIL, gargoyleData];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE];
NotNewVersion[gargoyleData];
}; -- end Clear
ClearAux:
PROC [event:
LIST
OF
REF
ANY, gargoyleData: GargoyleData] = {
gargoyleData.refresh.overlayList ← NIL;
GGSelect.DeselectAllAllClasses[gargoyleData.scene];
gargoyleData.scene ← GGObjects.CreateScene[];
gargoyleData.caret ← NEW[GGInterfaceTypes.CaretObj];
gargoyleData.anchor ← NEW[GGInterfaceTypes.CaretObj];
GGEvent.StandardAlignments[LIST[$StandardAlignments], gargoyleData];
gargoyleData.refresh.suppressRefresh ← FALSE; -- moved to abort processing code
gargoyleData.aborted ← ALL[FALSE];
};
Group Operations
AddToGroup:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
someAddition: BOOL ← FALSE;
seqGen: SequenceGenerator;
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=
NIL
OR Rope.Equal[name, ""]
THEN {
GGError.AppendHerald[gargoyleData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[gargoyleData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
duplicate: BOOL ← FALSE;
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF Rope.Equal[name, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already in this group
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN seg.props ← List.Append[seg.props, LIST[name]];
someAddition ← TRUE;
ENDLOOP;
ENDLOOP;
GGError.PutF[gargoyleData.feedback, oneLiner, IF someAddition THEN "Added selected segments to group %g" ELSE "No segment selections to add to group %g", [rope[name]] ];
SelectGroup:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
trajGen: TrajGenerator ← GGObjects.TrajsInScene[gargoyleData.scene];
segGen: SegmentGenerator;
seq: Sequence;
segsFound: BOOL;
GGSelect.DeselectAll[gargoyleData.scene, normal]; -- get rid of old selection
FOR traj: Traj ← GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen]
UNTIL traj =
NIL
DO
segGen ← GGSequence.SegmentsInTraj[traj];
segsFound ← FALSE;
FOR next: SegAndIndex ← GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen]
UNTIL next.seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← next.seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF
Rope.Equal[name, nextProp,
FALSE]
THEN {
IF NOT segsFound THEN seq ← GGSequence.CreateEmpty[traj];
segsFound ← TRUE;
IF
NOT seq.segments[next.index]
THEN {
seq.segments[next.index] ← TRUE;
seq.segCount ← seq.segCount + 1;
};
};
ENDLOOP; -- next prop
ENDLOOP; -- next segment
IF segsFound THEN GGSelect.SelectSequence[seq, gargoyleData.scene, normal];
ENDLOOP; -- next trajectory
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE];
IF GGSelect.NoSelections[gargoyleData.scene, normal] THEN GGError.AppendHerald[gargoyleData.feedback, "No such group", oneLiner ]
ELSE GGError.PutF[gargoyleData.feedback, oneLiner, "Group %g selected", [rope[name]] ];
RemoveFromGroup:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
someRemoval: BOOL ← FALSE;
newProps: LIST OF REF ANY;
seqGen: SequenceGenerator;
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
IF name=
NIL
OR Rope.Equal[name, ""]
THEN {
GGError.AppendHerald[gargoyleData.feedback, "Select a group name", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[gargoyleData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen]
UNTIL seg=
NIL
DO
newProps ← NIL;
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps ← List.Append[newProps, LIST[nextProp]] ELSE someRemoval ← TRUE;
ENDLOOP;
seg.props ← newProps;
ENDLOOP;
ENDLOOP;
GGError.PutF[gargoyleData.feedback, oneLiner, IF someRemoval THEN "Removed selected segments from group %g" ELSE "No member segments selected to remove from group %g", [rope[name]] ];
PrintGroupsOfSelected:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
groupList: LIST OF REF ANY;
seqGen: SequenceGenerator;
gargoyleData: GargoyleData ← NARROW[clientData];
IF GGSelect.NoSelections[gargoyleData.scene, normal]
THEN {
GGError.AppendHerald[gargoyleData.feedback, "No selections => no groups", oneLiner];
RETURN;
};
seqGen ← GGSelect.SelectedSequences[gargoyleData.scene, normal];
FOR seq: Sequence ← GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen]
UNTIL seq=
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInSequence[seq];
FOR seg: Segment ← GGSequence.
NextSegment[segGen], GGSequence.
NextSegment[segGen]
UNTIL seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
duplicate: BOOL ← FALSE;
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
IF Rope.Equal[nextGroup, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#
NIL
THEN {
GGError.Append[gargoyleData.feedback, "Groups of Selected: ", begin];
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
GGError.PutF[gargoyleData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
GGError.Append[gargoyleData.feedback, "", end];
}
ELSE GGError.Append[gargoyleData.feedback, "No Groups of Selected", oneLiner];
};
PrintAllGroups:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
groupList: LIST OF REF ANY;
gargoyleData: GargoyleData ← NARROW[clientData];
trajGen: TrajGenerator ← GGObjects.TrajsInScene[gargoyleData.scene];
FOR traj: Traj ← GGObjects.
NextTraj[trajGen], GGObjects.
NextTraj[trajGen]
UNTIL traj =
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInTraj[traj];
FOR seg: Segment ← GGSequence.
NextSegment[segGen], GGSequence.
NextSegment[segGen]
UNTIL seg=
NIL
DO
FOR prop:
LIST
OF
REF
ANY ← seg.props, prop.rest
UNTIL prop=
NIL
DO
nextProp: Rope.ROPE ← NARROW[prop.first];
duplicate: BOOL ← FALSE;
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
IF Rope.Equal[nextGroup, nextProp,
FALSE]
THEN {
duplicate ← TRUE; -- already on the group list
EXIT;
};
ENDLOOP;
IF NOT duplicate THEN groupList ← List.Append[groupList, LIST[nextProp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF groupList#
NIL
THEN {
GGError.Append[gargoyleData.feedback, "Groups: ", begin];
FOR group:
LIST
OF
REF
ANY ← groupList, group.rest
UNTIL group=
NIL
DO
nextGroup: Rope.ROPE ← NARROW[group.first];
GGError.PutF[gargoyleData.feedback, middle, "%g ", [rope[nextGroup]] ];
ENDLOOP;
GGError.Append[gargoyleData.feedback, "", end];
}
ELSE GGError.Append[gargoyleData.feedback, "No Groups", oneLiner];
};
Area and Line Colors
RGBFromRopeError: SIGNAL = CODE;
AreaColorFromColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
color: Imager.Color;
red, green, blue: REAL;
[red: red, green: green, blue: blue] ← ColorToolViewer.GetRGBValue[];
color ← ImagerColor.ColorFromRGB[rgb: [red, green, blue]];
AreaColorAux[color, gargoyleData];
};
};
LineColorFromColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
color: Imager.Color;
red, green, blue: REAL;
[red: red, green: green, blue: blue] ← ColorToolViewer.GetRGBValue[];
color ← ImagerColor.ColorFromRGB[rgb: [red, green, blue]];
LineColorAux[color, gargoyleData];
};
};
AreaColorFollowColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
color: Imager.Color ← ColorToolViewerExtras.GetSpecialColor[]; -- "animation" color
AreaColorAux[color, gargoyleData];
};
};
LineColorFollowColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
color: Imager.Color ← ColorToolViewerExtras.GetSpecialColor[]; -- "animation" color
LineColorAux[color, gargoyleData];
};
};
AreaColorToColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
red, green, blue: REAL;
color: Imager.Color ← NIL;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
WITH GGObjects.NextEntity[entityGen]
SELECT
FROM
outlineD: OutlineDescriptor => color ← outlineD.slice.class.getFillColor[outlineD.slice];
sliceD: SliceDescriptor => color ← sliceD.slice.class.getFillColor[sliceD.slice];
ENDCASE => ERROR;
IF color#
NIL
THEN {
cc: Imager.ConstantColor ← NARROW[color];
red ← ImagerColorPrivate.ComponentFromColor[cc, $Red];
green ← ImagerColorPrivate.ComponentFromColor[cc, $Green];
blue ← ImagerColorPrivate.ComponentFromColor[cc, $Blue];
ColorToolViewer.SetRGBValue[red, green, blue];
}
ELSE GGError.Append[gargoyleData.feedback, ". . . Object has NIL fill color", oneLiner];
};
};
LineColorToColorTool:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
IF ColorToolIsBound[gargoyleData]
THEN {
red, green, blue: REAL;
color: Imager.Color ← NIL;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
WITH GGObjects.NextEntity[entityGen]
SELECT
FROM
outlineD: OutlineDescriptor => color ← outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts];
sliceD: SliceDescriptor => color ← sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts];
ENDCASE => ERROR;
IF color#
NIL
THEN {
cc: Imager.ConstantColor ← NARROW[color];
red ← ImagerColorPrivate.ComponentFromColor[cc, $Red];
green ← ImagerColorPrivate.ComponentFromColor[cc, $Green];
blue ← ImagerColorPrivate.ComponentFromColor[cc, $Blue];
ColorToolViewer.SetRGBValue[red, green, blue];
}
ELSE GGError.Append[gargoyleData.feedback, ". . . Object has NIL stroke color", oneLiner];
};
};
AreaColorFromSelectedName:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
AreaColorAux[color, gargoyleData];
EXITS
UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
LineColorFromSelectedName:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]]];
LineColorAux[color, gargoyleData];
EXITS
UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
AreaColorFromSelectedRGB:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
AreaColorAux[color, gargoyleData];
EXITS
SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
LineColorFromSelectedRGB:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
color: Imager.Color ← ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]];
LineColorAux[color, gargoyleData];
EXITS
SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
SelectMatchingAreaColor:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
entityGen: EntityGenerator ← GGObjects.TopLevelEntitiesInScene[gargoyleData.scene];
noneFlag: BOOL ← Rope.Equal[name, "none", FALSE];
IF
NOT noneFlag
THEN rgb ←
SELECT event.first
FROM
$SelectMatchingAreaCNS =>
ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]],
$SelectMatchingAreaRGB =>
RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]
ENDCASE => ERROR;
GGSelect.DeselectAll[gargoyleData.scene, normal];
FOR entity:
REF
ANY ← GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen]
UNTIL entity =
NIL
DO
WITH entity
SELECT
FROM
outline: Outline => {
fillColor: Imager.Color ← outline.class.getFillColor[outline];
IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireOutline[outline, gargoyleData.scene, normal];
};
slice: Slice => {
fillColor: Imager.Color ← slice.class.getFillColor[slice];
IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectSlice[slice, slice.class.newParts[slice, NIL, topLevel], gargoyleData.scene, normal];
};
ENDCASE => ERROR;
ENDLOOP;
GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ];
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
EXITS
SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
SelectMatchingLineColor:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
rgb: ImagerColor.RGB;
name: Rope.ROPE ← IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first];
trajGen: TrajGenerator ← GGObjects.TrajsInScene[gargoyleData.scene];
sliceGen: SliceGenerator ← GGObjects.SlicesInScene[gargoyleData.scene];
noneFlag: BOOL ← Rope.Equal[name, "none", FALSE];
IF
NOT noneFlag
THEN rgb ←
SELECT event.first
FROM
$SelectMatchingLineCNS =>
ImagerColor.RGBFromHSL[NamedColors.RopeToHSL[name !
NamedColors.UndefinedName => GOTO UndefinedName;
NamedColors.BadGrammar => GOTO BadGrammar;
]],
$SelectMatchingLineRGB =>
RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]
ENDCASE => ERROR;
GGSelect.DeselectAll[gargoyleData.scene, normal];
FOR traj: Traj ← GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen]
UNTIL traj =
NIL
DO
segGen: SegmentGenerator ← GGSequence.SegmentsInTraj[traj];
FOR segAndIndex: SegAndIndex ← GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen]
UNTIL segAndIndex.seg =
NIL
DO
IF RGBEqualsColor[rgb, segAndIndex.seg.color, noneFlag]
THEN {
seq: Sequence ← GGSequence.CreateFromSegment[traj, segAndIndex.index];
GGSelect.SelectSequence[seq, gargoyleData.scene, normal];
};
ENDLOOP;
ENDLOOP;
FOR slice: Slice ← GGObjects.NextSlice[sliceGen], GGObjects.NextSlice[sliceGen] UNTIL slice = NIL DO
SLICES CAN'T ENUMERATE THEIR PARTS!!
ENDLOOP;
GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Segments with color %g selected", [rope[name]] ];
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
EXITS
SyntaxError => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
UndefinedName => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Undefined Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
BadGrammar => {GGError.AppendHerald[NARROW[clientData, GargoyleData].feedback, "Bad Color Name", oneLiner]; GGError.Blink[NARROW[clientData, GargoyleData].feedback];};
};
RGBEqualsColor:
PROC [rgb: ImagerColor.
RGB, color: Imager.Color, noneFlag:
BOOL]
RETURNS [
BOOL] = {
epsilon: REAL = 1.0E-3;
IF color=NIL THEN RETURN [noneFlag]; -- fillColor is none
IF noneFlag
THEN
RETURN [color=
NIL]
ELSE {
cc: Imager.ConstantColor ← NARROW[color];
r: REAL ← ImagerColorPrivate.ComponentFromColor[cc, $Red];
g: REAL ← ImagerColorPrivate.ComponentFromColor[cc, $Green];
b: REAL ← ImagerColorPrivate.ComponentFromColor[cc, $Blue];
RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R]<epsilon AND ABS[g-rgb.G]<epsilon AND ABS[b-rgb.B]<epsilon ) ];
};
};
AreaColorBlack:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
AreaColorAux[Imager.black, gargoyleData];
};
LineColorBlack:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
LineColorAux[Imager.black, gargoyleData];
};
PrintAreaColor:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
entity: REF ANY;
isProcessBlack: Rope.ROPE;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
IF entityGen=NIL OR (entity ← GGObjects.NextEntity[entityGen])=NIL OR GGObjects.NextEntity[entityGen]#NIL THEN GGError.AppendHerald[gargoyleData.feedback, "Select exactly one entity for 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 ← ImagerColorPrivate.ComponentFromColor[color, $Red];
green ← ImagerColorPrivate.ComponentFromColor[color, $Green];
blue ← ImagerColorPrivate.ComponentFromColor[color, $Blue];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColor.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
GGError.Append[
gargoyleData.feedback,
IO.PutFR["R: %1.2f G: %1.2f B: %1.2f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColor.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE GGError.Append[gargoyleData.feedback, "No Fill Color", oneLiner];
};
};
PrintLineColor:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
entity: REF ANY;
isProcessBlack: Rope.ROPE;
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
IF entityGen=NIL OR (entity ← GGObjects.NextEntity[entityGen])=NIL OR GGObjects.NextEntity[entityGen]#NIL THEN GGError.AppendHerald[gargoyleData.feedback, "Select exactly one entity for PrintLineColor", oneLiner]
ELSE {
red, green, blue: REAL;
color: Imager.ConstantColor;
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => color ← NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]];
sliceD: SliceDescriptor => color ← NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]];
ENDCASE => ERROR;
IF color#
NIL
THEN {
red ← ImagerColorPrivate.ComponentFromColor[color, $Red];
green ← ImagerColorPrivate.ComponentFromColor[color, $Green];
blue ← ImagerColorPrivate.ComponentFromColor[color, $Blue];
IF color = Imager.black THEN isProcessBlack ← " (process black)"
ELSE IF ImagerColor.GrayFromColor[color]=1.0 THEN isProcessBlack ← " (CMY black)"
ELSE isProcessBlack ← "";
GGError.Append[
gargoyleData.feedback,
IO.PutFR["R: %1.2f G: %1.2f B: %1.2f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColor.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ],
oneLiner];
}
ELSE GGError.Append[gargoyleData.feedback, "No Stroke Color", oneLiner];
};
};
AreaColorWhite:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
AreaColorAux[Imager.white, gargoyleData];
};
LineColorWhite:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
LineColorAux[Imager.white, gargoyleData];
};
AreaColorGray:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
AreaColorAux[GGObjects.fillColor, gargoyleData];
};
LineColorGray:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
LineColorAux[GGObjects.fillColor, gargoyleData];
};
AreaColorNone:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
AreaColorAux[NIL, gargoyleData];
};
LineColorNone:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
LineColorAux[NIL, gargoyleData];
};
AreaColorAux:
PROC [color: Imager.Color, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
FOR entity:
REF
ANY ← GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen]
UNTIL entity =
NIL
DO
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => outlineD.slice.class.setFillColor[outlineD.slice, color];
sliceD: SliceDescriptor => sliceD.slice.class.setFillColor[sliceD.slice, color];
ENDCASE => ERROR;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
LineColorAux:
PROC [color: Imager.Color, clientData:
REF
ANY] = {
gargoyleData: GargoyleData ← NARROW[clientData];
entityGen: EntityGenerator ← GGSelect.SelectedStuff[gargoyleData.scene, normal];
FOR entity:
REF
ANY ← GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen]
UNTIL entity =
NIL
DO
WITH entity
SELECT
FROM
outlineD: OutlineDescriptor => outlineD.slice.class.setStrokeColor[outlineD.slice, outlineD.parts, color];
sliceD: SliceDescriptor => sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color];
ENDCASE => ERROR;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE];
};
ColorToolIsBound:
PROC [gargoyleData: GargoyleData]
RETURNS [
BOOL] =
TRUSTED {
IF PrincOpsUtils.IsBound[LOOPHOLE[ColorToolViewer.GetRGBValue]] THEN RETURN[TRUE];
GGError.AppendHerald[gargoyleData.feedback, "Please start ColorTool and retry this operation", oneLiner];
RETURN[FALSE];
};
RGBFromRope:
PROC [name: Rope.
ROPE]
RETURNS [rgb: ImagerColor.
RGB] = {
ENABLE IO.Error, IO.EndOfStream => GOTO RGBError;
Check:
PROC [x:
REAL] = {
IF x NOT IN [0.0..1.0] THEN SIGNAL RGBFromRopeError;
};
rs: IO.STREAM ← IO.RIS[name];
IF Ascii.Upper[rs.GetChar[]]#'R THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.R ← rs.GetReal[]; [] ← rs.SkipWhitespace[];
IF Ascii.Upper[rs.GetChar[]]#'G THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.G ← rs.GetReal[]; [] ← rs.SkipWhitespace[];
IF Ascii.Upper[rs.GetChar[]]#'B THEN GOTO RGBError;
IF rs.GetChar[]#': THEN GOTO RGBError;
rgb.B ← rs.GetReal[];
Check[rgb.R]; Check[rgb.G]; Check[rgb.B];
EXITS
RGBError => SIGNAL RGBFromRopeError;
};
cleanIcon: Icons.IconFlavor ← unInit; -- filled in by Init
Init:
PROC = {
-- copied from GGWindowImpl
cleanIcon ← Icons.NewIconFromFile["Gargoyle.icons", 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/
};
Init[];
END.