DIRECTORY
BasicTime, CubicSplines, FS, GGAlign, GGButtons, GGCaret, GGDescribe, GGDrawProcess, GGError, GGEvent, GGGraphicsButton, GGGravity, GGInterfaceTypes, GGModelTypes, GGObjects, GGRefresh, GGSegment, GGSelect, GGTouch, GGVector, GGViewerOps, GGWindow, Imager, ImagerColor, ImagerInterpress, IO, Random, Real, Rope, Rosary, TiogaButtons, ViewerClasses, ViewerIO, ViewerOps, ViewerTools;

GGEventImpl: CEDAR PROGRAM
IMPORTS BasicTime, FS, GGAlign, GGButtons, GGCaret, GGDescribe, GGDrawProcess, GGError, GGGraphicsButton, GGGravity, GGObjects, GGRefresh, GGSegment, GGSelect, GGTouch, GGVector, GGViewerOps, GGWindow, Imager, ImagerColor, ImagerInterpress, IO, Random, Real, Rope, Rosary, TiogaButtons, ViewerIO, ViewerOps, ViewerTools
EXPORTS GGEvent =
BEGIN

Cluster: TYPE = GGModelTypes.Cluster;
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
Outline: TYPE = GGModelTypes.Outline;
Point: TYPE = GGModelTypes.Point;
ScalarButtonClient: TYPE = GGInterfaceTypes.ScalarButtonClient;
Segment: TYPE = GGModelTypes.Segment;
Sequence: TYPE = GGModelTypes.Sequence;
Traj: TYPE = GGModelTypes.Traj;
TrajGenerator: TYPE = GGModelTypes.TrajGenerator;
TwoState: TYPE = GGInterfaceTypes.TwoState;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator;
Vector: TYPE = GGModelTypes.Vector;
Viewer: TYPE = ViewerClasses.Viewer;

Clear: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};
Reset: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};
Get: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};
Store: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};
Split: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};
Interpress: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
ipRef: ImagerInterpress.Ref;
wdir, ipName, fullName: Rope.ROPE;
success: BOOL;
pixelsPerMeter: REAL _ 0.0254 / 72.0;
startTime: BasicTime.GMT;
endTime: BasicTime.GMT;
totalTime: INT;
msgRope: Rope.ROPE;
DoMakeInterpress: PROC [dc: Imager.Context] = {
Imager.ScaleT[dc, pixelsPerMeter];
GGRefresh.InterpressEntireScene[dc, gargoyleData];
};

ipName _ ViewerTools.GetSelectionContents[];
IF Rope.Length[ipName] = 0 THEN RETURN;
wdir _ gargoyleData.originalWorkingDirectory;
success _ TRUE;
[fullName,,] _ FS.ExpandName[ipName, wdir
! FS.Error => IF error.group = user THEN {
success _ FALSE;
CONTINUE;
}
];
IF NOT success THEN RETURN;
ipRef _ ImagerInterpress.Create[fullName];
msgRope _ IO.PutFR["Writing to interpress file: %g . . . ", [rope[fullName]]];
GGError.Append[msgRope, begin];
startTime _ BasicTime.Now[];
ImagerInterpress.DoPage[ipRef, DoMakeInterpress, 1.0];
ImagerInterpress.Close[ipRef];
endTime _ BasicTime.Now[];
totalTime _ BasicTime.Period[startTime, endTime];
msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]];
GGError.Append[msgRope, end];
};



Delete: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
parentOutline: Outline;
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
GGSelect.DeselectEntity[entity, gargoyleData, normal];
GGSelect.DeselectEntity[entity, gargoyleData, copy];
GGSelect.DeselectEntity[entity, gargoyleData, hot];
GGSelect.DeselectEntity[entity, gargoyleData, active];
WITH entity SELECT FROM
cluster: Cluster => ERROR NotYetImplemented;
outline: Outline => {
GGObjects.DeleteOutline[gargoyleData.scene, outline];
GGTouch.OutlineDeleted[outline, gargoyleData];
};
seq: Sequence => {
parentOutline _ GGObjects.OutlineOfTraj[seq.traj];
IF GGObjects.HasHoles[parentOutline] THEN {
SELECT seq.traj.role FROM
hole => ERROR NotYetImplemented;
open => ERROR; -- impossible since the outline has holes
fence => {
GGError.Append["You can't delete the fence trajectory of an outline with holes.", oneLiner];
LOOP;
};
ENDCASE => ERROR;
}
ELSE {
IF seq.all THEN { -- the whole trajectory is selected
GGObjects.DeleteOutline[gargoyleData.scene, parentOutline];
GGTouch.OutlineDeleted[parentOutline, gargoyleData];
}
ELSE { -- part of a trajectory is selected.  Remove the parts in a sensible fashion.  This may require breaking up the trajectory into pieces.  Remove all of the pieces from touching lists.
ERROR NotYetImplemented;
};
};
};
ENDCASE => ERROR;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};

SelectAll: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGSelect.DeselectAll[gargoyleData, normal];
GGSelect.SelectAll[gargoyleData, normal];
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};

NotYetImplemented: PUBLIC SIGNAL = CODE;
SetStraight: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segmentGen: SegmentGenerator;
traj: Traj;
newSeg: Segment;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR seq: Sequence _ GGObjects.NextSequence[seqGen], GGObjects.NextSequence[seqGen] UNTIL seq = NIL DO
segmentGen _ GGObjects.SegmentsInSequence[seq];
traj _ seq.traj;
FOR next: GGObjects.SegAndIndex _ GGObjects.NextSegmentAndIndex[segmentGen], GGObjects.NextSegmentAndIndex[segmentGen] UNTIL next.seg = NIL DO
newSeg _ GGSegment.MakeLine[next.seg.lo, next.seg.hi];
AddSegment[traj, newSeg, next];
ENDLOOP;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};
SetArc: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segmentGen: SegmentGenerator;
traj: Traj;
newSeg: Segment;
p0, p1, p2: Point;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR seq: Sequence _ GGObjects.NextSequence[seqGen], GGObjects.NextSequence[seqGen] UNTIL seq = NIL DO
segmentGen _ GGObjects.SegmentsInSequence[seq];
traj _ seq.traj;
FOR next: GGObjects.SegAndIndex _ GGObjects.NextSegmentAndIndex[segmentGen], GGObjects.NextSegmentAndIndex[segmentGen] UNTIL next.seg = NIL DO
p0 _ next.seg.lo;
p2 _ next.seg.hi;
p1 _ GetPt[p0, GGVector.Sub[p2,p0], GGVector.Distance[p0,p1]];
newSeg _ GGSegment.MakeArc[p0, p1, p2];
AddSegment[traj, newSeg, next];
ENDLOOP;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};
SetConic: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segmentGen: SegmentGenerator;
traj: Traj;
newSeg: Segment;
p0, p1, p2: Point;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR seq: Sequence _ GGObjects.NextSequence[seqGen], GGObjects.NextSequence[seqGen] UNTIL seq = NIL DO
segmentGen _ GGObjects.SegmentsInSequence[seq];
traj _ seq.traj;
FOR next: GGObjects.SegAndIndex _ GGObjects.NextSegmentAndIndex[segmentGen], GGObjects.NextSegmentAndIndex[segmentGen] UNTIL next.seg = NIL DO
p0 _ next.seg.lo;
p2 _ next.seg.hi;
p1 _ GetPt[p0, GGVector.Sub[p2,p0], GGVector.Distance[p0,p1]];
newSeg _ GGSegment.MakeConic[p0, p1, p2, 0.7];
AddSegment[traj, newSeg, next];
ENDLOOP;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};

random: Random.RandomStream _ Random.Create[10000,0];
NewV: PROC RETURNS[REAL] = {RETURN[Random.NextInt[random]/10000.0]};

GetPt: PROC[p0, dir: Point, maxL: REAL] RETURNS [pt: Point] = {
scale1: REAL _ NewV[]*maxL;
angle: REAL _ 180*NewV[]-90;	--range -90..90
pt _ GGVector.Add[GGVector.Scale[GGVector.VectorPlusAngle[dir,angle], scale1], p0];
};


GetPtSequence: PROC[p0,p1: Point, n: NAT] RETURNS [CubicSplines.KnotSequence] ={
points: CubicSplines.KnotSequence _ NEW[CubicSplines.KnotSequenceRec[n+2]];
dir: Point _ GGVector.Sub[p1,p0];
inc: REAL _ GGVector.Distance[p0,p1]/(n-2);
maxL: REAL _ inc;
points[0] _ p0;
FOR i: NAT IN [1..points.length-1) DO
points[i] _ GetPt[p0, dir, maxL];
maxL _ maxL+inc;
ENDLOOP;
points[points.length-1] _ p1;
RETURN[points];
};

AddSegment: PROC[traj: Traj, newSeg: Segment, next: GGObjects.SegAndIndex] = {
traj.segments _ Rosary.Cat[ Rosary.Substr[traj.segments, 0, next.index], Rosary.FromItem[newSeg], Rosary.Substr[traj.segments, next.index+1, GGObjects.HiSegment[traj]-next.index] ];
};

SetBezier: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segmentGen: SegmentGenerator;
traj: Traj;
newSeg: Segment;
p0, p1, p2, p3: Point;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR seq: Sequence _ GGObjects.NextSequence[seqGen], GGObjects.NextSequence[seqGen] UNTIL seq = NIL DO
segmentGen _ GGObjects.SegmentsInSequence[seq];
traj _ seq.traj;
FOR next: GGObjects.SegAndIndex _ GGObjects.NextSegmentAndIndex[segmentGen], GGObjects.NextSegmentAndIndex[segmentGen] UNTIL next.seg = NIL DO
length: REAL _ GGVector.Distance[next.seg.lo, next.seg.hi];
dir: Point _ GGVector.Sub[p3,p0];
p0 _ next.seg.lo;
p1 _ GetPt[p0, dir,length*0.7];
p2 _ GetPt[p0, dir,length];
p3 _ next.seg.hi;
newSeg _ GGSegment.MakeBezier[p0, p1, p2, p3];
AddSegment[traj, newSeg, next];
ENDLOOP;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};
SetSpline: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segmentGen: SegmentGenerator;
traj: Traj;
newSeg: Segment;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR seq: Sequence _ GGObjects.NextSequence[seqGen], GGObjects.NextSequence[seqGen] UNTIL seq = NIL DO
segmentGen _ GGObjects.SegmentsInSequence[seq];
traj _ seq.traj;
FOR next: GGObjects.SegAndIndex _ GGObjects.NextSegmentAndIndex[segmentGen], GGObjects.NextSegmentAndIndex[segmentGen] UNTIL next.seg = NIL DO
length: REAL _ GGVector.Distance[next.seg.lo, next.seg.hi];
type: CubicSplines.SplineType _ naturalAL;
nKnots: INT _ Real.RoundLI[10*NewV[]];
cps: CubicSplines.KnotSequence _ GetPtSequence[next.seg.lo, next.seg.hi, nKnots];
newSeg _ GGSegment.MakeCubicSpline[cps, type];
AddSegment[traj, newSeg, next];
ENDLOOP;
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};
Close: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
traj: Traj;
firstPoint, lastPoint: Point;
seg: Segment;
[traj,----,----,----,----] _ GGCaret.GetChair[gargoyleData.caret];
IF traj = NIL THEN {
GGError.Append["There is no caret trajectory to close.", oneLiner];
GGError.Blink[];
RETURN;
};
GGError.Append["The caret trajectory will be closed.", oneLiner];
firstPoint _ GGObjects.FetchJointPos[traj, 0];
lastPoint _ GGObjects.LastJointPos[traj];
seg _ GGSegment.MakeLine[lastPoint, firstPoint];
GGObjects.CloseWithSegment[traj, seg, lo];
GGObjects.SetFillColor[GGObjects.OutlineOfTraj[traj], Imager.MakeGray[0.5]];
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};


TestGravity: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
xRandomStream, yRandomStream: Random.RandomStream;
testPoint: Point;
x, y: INT;
totalCount: NAT _ 0;
s: IO.STREAM;
resultPoint: Point;
feature: REF ANY;
countRope: Rope.ROPE;
environ: GGGravity.ObjectBag;
xRandomStream _ Random.Create[gargoyleData.actionArea.cw];
yRandomStream _ Random.Create[gargoyleData.actionArea.ch];
environ _ GGGravity.CreateObjectBag[];
GGAlign.AddItemsForAction[gargoyleData, environ, $SelectPoint];
IF environ = NIL THEN {
GGError.Append["Add some trajectories to test gravity.", oneLiner];
GGError.Blink[];
RETURN;
};
gargoyleData.hitTest.environ _ environ;
GGWindow.Painter[$PaintAlign, gargoyleData];
gargoyleData.hitTest.hitCount _ 0;
UNTIL totalCount > 1000 DO
IF gargoyleData.aborted THEN {
gargoyleData.aborted _ FALSE;
EXIT;
};
x _ Random.NextInt[xRandomStream];
y _ Random.NextInt[yRandomStream];
testPoint _ [x, y];
testPoint _ GGWindow.ScreenToWorld[testPoint, gargoyleData.camera];
gargoyleData.refresh.spotPoint _ testPoint;
[resultPoint, feature] _ GGGravity.Map[testPoint, gargoyleData.hitTest.tolerance, environ, gargoyleData];
IF feature # NIL THEN {
gargoyleData.refresh.hitPoint _ resultPoint;
GGWindow.Painter[$PaintHitLine, gargoyleData];
gargoyleData.hitTest.hitCount _ gargoyleData.hitTest.hitCount + 1;
}
ELSE {
GGWindow.Painter[$PaintSpot, gargoyleData];
};
totalCount _ totalCount + 1;
ENDLOOP;
s _ IO.ROS[];
s.PutF["Tested %g total points.  %g were hits", [integer[totalCount]], [integer[gargoyleData.hitTest.hitCount]]];
countRope _ IO.RopeFromROS[s];
GGError.Append[countRope, oneLiner];
};

DrawTouchPoints: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGWindow.Painter[$PaintTouchPoints, gargoyleData];
};
DescribeTouchPoints: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGTouch.DescribeAllTouchPoints[gargoyleData];
};
DrawBoundBoxes: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGWindow.Painter[$PaintBoundBoxes, gargoyleData];
};
DrawSelectionBox: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGWindow.Painter[$PaintSelectionBox, gargoyleData];
};
Typescript: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
newViewer: Viewer;
inHandle, outHandle: IO.STREAM;
[inHandle, outHandle, newViewer] _ MakeNewViewerAndHandle[];
GGError.SetErrorStream[outHandle];
gargoyleData.debug.typescript _ newViewer;
};

MakeNewViewerAndHandle: PRIVATE PROC [] RETURNS [in, out: IO.STREAM, newViewer: Viewer] = {
newViewer _ ViewerOps.CreateViewer[
flavor: $TypeScript,
info: [
name: "Gargoyle Script",
menu: NIL,
data: NIL,
iconic: TRUE,
column: right,
scrollable: TRUE,
icon: unInit
],
paint: FALSE];
ViewerOps.SetOpenHeight[newViewer, 120];
ViewerOps.OpenIcon[icon: newViewer, closeOthers: FALSE, bottom: TRUE, paint: TRUE];
[in, out] _ ViewerIO.CreateViewerStreams["gargoyle script", newViewer, NIL, TRUE];
};

SlackLog: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGDrawProcess.OutputLog[];
};

DescribeCaretObject: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
chair: Traj;
description, msgRope: Rope.ROPE;
isJoint: BOOL;
jointNum: NAT;
seg: Segment;
[chair, isJoint, ----, jointNum, seg] _ GGCaret.GetChair[gargoyleData.caret];
IF isJoint THEN {
description _ GGDescribe.DescribeJoint[chair, jointNum];
}
ELSE {
segNum: INT;
segNum _ GGObjects.IndexOfSegment[seg, chair];
IF segNum = -1 THEN description _ Rope.Concat["Nonexistent segment of ", GGDescribe.DescribeTraj[chair]]
ELSE description _ GGDescribe.DescribeSegment[chair, segNum];
};
msgRope _ IO.PutFR["Caret is on %g.", [rope[description]]];
GGError.Append[msgRope, oneLiner];
};
LineWidth: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
strokeWidth: REAL;
msgRope: Rope.ROPE;
sequenceGen: SequenceGenerator;
widthRef: REF INT _ NARROW[event.rest.first];
width: NAT _ widthRef^;
strokeWidth _ width;
msgRope _ IO.PutFR["Selected objects will have line width %g.", [real[strokeWidth]]];
GGError.Append[msgRope, oneLiner];
sequenceGen _ GGSelect.SelectedSequences[gargoyleData, normal];
FOR sequence: Sequence _ GGObjects.NextSequence[sequenceGen], GGObjects.NextSequence[sequenceGen] UNTIL sequence = NIL DO
GGObjects.SetStrokeWidth[sequence, strokeWidth];
ENDLOOP;
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};

AreaColorBlack: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
outline: Outline;
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
seq: Sequence => outline _ GGObjects.OutlineOfTraj[seq.traj];
traj: Traj => outline _ GGObjects.OutlineOfTraj[traj];
o: Outline => outline _ o;
cluster: Cluster => ERROR NotYetImplemented;
ENDCASE => ERROR;
GGObjects.SetFillColor[outline, Imager.black];
ENDLOOP;
};

AreaColorWhite: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
outline: Outline;
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
seq: Sequence => outline _ GGObjects.OutlineOfTraj[seq.traj];
traj: Traj => outline _ GGObjects.OutlineOfTraj[traj];
o: Outline => outline _ o;
cluster: Cluster => ERROR NotYetImplemented;
ENDCASE => ERROR;
GGObjects.SetFillColor[outline, Imager.white];
ENDLOOP;
};
AreaColorGray: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
outline: Outline;
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
WITH entity SELECT FROM
seq: Sequence => outline _ GGObjects.OutlineOfTraj[seq.traj];
traj: Traj => outline _ GGObjects.OutlineOfTraj[traj];
o: Outline => outline _ o;
cluster: Cluster => ERROR NotYetImplemented;
ENDCASE => ERROR;
GGObjects.SetFillColor[outline, ImagerColor.ColorFromGray[0.5]];
ENDLOOP;
};
MakeHot: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
GGSelect.SelectEntity[entity, gargoyleData, hot];
ENDLOOP;
};
MakeCold: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
entityGen: EntityGenerator;
entityGen _ GGSelect.SelectedEntities[gargoyleData, normal];
FOR entity: REF ANY _ GGObjects.NextEntity[entityGen], GGObjects.NextEntity[entityGen] UNTIL entity = NIL DO
GGSelect.DeselectEntity[entity, gargoyleData, hot];
ENDLOOP;
};

DropAnchor: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGCaret.Copy[gargoyleData.anchor, gargoyleData.caret];
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};

KillAnchor: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGCaret.Kill[gargoyleData.anchor];
GGWindow.Painter[$PaintEntireScene, gargoyleData];
};
GravityChoiceChange: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
info: GGInterfaceTypes.EnumTypeRef _ gargoyleData.hitTest.gravityTypeMenu;
name: Rope.ROPE;
IF event.rest.first = $FlipForward THEN
GGButtons.TimeToFlipThru[LIST[$FlipForward, info]]
ELSE 
GGButtons.TimeToFlipThru[LIST[$FlipBackward, info]];
name _ info.flipLabel.name;
SELECT TRUE FROM
Rope.Equal[name, "StrictDistance", TRUE] => gargoyleData.hitTest.gravityType _ strictDistance;
Rope.Equal[name, "PointsPreferred", TRUE] => gargoyleData.hitTest.gravityType _ innerCircle;
Rope.Equal[name, "Sectors", TRUE] => gargoyleData.hitTest.gravityType _ sectors;
Rope.Equal[name, "None", TRUE] => gargoyleData.hitTest.gravityType _ none;
ENDCASE => ERROR;
};

GravityExtentChange: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
value: REAL;
msgRope: Rope.ROPE;
graphicsState: GGGraphicsButton.GraphicsState _ gargoyleData.hitTest.gravityExtentButton;
value _ GGGraphicsButton.GetValue[graphicsState];
SELECT event.rest.first FROM
$ValueUp => {
value _ value*2.0;
msgRope _ IO.PutFR["Gravity extent is now %g screen dots.", [real[value]] ];
GGError.Append[msgRope, oneLiner];
GGGraphicsButton.SetButtonValueAndPaint[graphicsState, value];
};
$ValueDown => {
value _ value/2.0;
msgRope _ IO.PutFR["Gravity extent is now %g screen dots.", [real[value]] ];
GGError.Append[msgRope, oneLiner];
GGGraphicsButton.SetButtonValueAndPaint[graphicsState, value];
};
$InitialValue => {};
ENDCASE => ERROR;
gargoyleData.hitTest.tolerance _ value;
gargoyleData.hitTest.criticalR _ value;
gargoyleData.hitTest.innerR _ value;
};

ToggleAlwaysOn: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
stateInfo: TwoState _ gargoyleData.hitTest.linesAlwaysOn;
GGButtons.SwitchState[stateInfo];
};
ToggleDoubleBuffer: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
stateInfo: TwoState _ gargoyleData.refresh.doubleBuffer;
GGButtons.SwitchState[stateInfo];
};

SlopePrompt: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
viewer: Viewer _ gargoyleData.hitTest.slopeText;
ViewerTools.SetSelection[viewer];
};

AddSlope: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
slope: REAL;
thisButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
slope _ GGViewerOps.GetReal[gargoyleData.hitTest.slopeText, 90.0];
thisButton _ gargoyleData.hitTest.slopeButtons;
UNTIL thisButton.next = NIL DO thisButton _ thisButton.next ENDLOOP;
tiogaButton _ thisButton.button;
[] _ GGButtons.AddScalarButton[tiogaButton, slope, LIST[$ToggleSlope, NEW[REAL _ slope]], FALSE, gargoyleData];
};

GetSlope: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segGen: SegmentGenerator;
seq, next: Sequence;
direction: Vector;
degrees: REAL;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
seq _ GGObjects.NextSequence[seqGen];
next _ GGObjects.NextSequence[seqGen];
IF next # NIL THEN {
GGError.Append["Select a single sequence for a GetSlope.", oneLiner];
GGError.Blink[];
};
segGen _ GGObjects.SegmentsInSequence[seq];
FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO
direction _ GGVector.VectorFromPoints[seg.lo, seg.hi];
degrees _ GGVector.AngleFromVector[direction];
IF degrees < 0.0 THEN degrees _ degrees + 180.0;
BEGIN
thisButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
thisButton _ gargoyleData.hitTest.slopeButtons;
UNTIL thisButton.next = NIL DO thisButton _ thisButton.next ENDLOOP;
tiogaButton _ thisButton.button;
[] _ GGButtons.AddScalarButton[tiogaButton, degrees, LIST[$ToggleSlope, NEW[REAL _ degrees]], FALSE, gargoyleData];
END
ENDLOOP;
};


ToggleSlope: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
slope: REAL;
firstButton, pushedButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
WITH event.rest.first SELECT FROM
int: REF INT => slope _ int^;
real: REF REAL => slope _ real^;
ENDCASE => ERROR;
firstButton _ gargoyleData.hitTest.slopeButtons;
FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO
IF thisButton.value = slope THEN {
pushedButton _ thisButton;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
tiogaButton _ pushedButton.button;
IF pushedButton.on THEN {
pushedButton.on _ FALSE;
TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"];
}
ELSE {
pushedButton.on _ TRUE;
TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""];
};
};

DeleteSlope: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};

RadiusPrompt: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
viewer: Viewer _ gargoyleData.hitTest.radiusText;
ViewerTools.SetSelection[viewer];
};

AddRadius: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
radius: REAL;
thisButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
radius _ GGViewerOps.GetReal[gargoyleData.hitTest.radiusText, 72.0];
thisButton _ gargoyleData.hitTest.radiusButtons;
UNTIL thisButton.next = NIL DO thisButton _ thisButton.next ENDLOOP;
tiogaButton _ thisButton.button;
[] _ GGButtons.AddScalarButton[tiogaButton, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], FALSE, gargoyleData];
};
GetRadius: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
seqGen: SequenceGenerator;
segGen: SegmentGenerator;
seq, next: Sequence;
radius: REAL;
seqGen _ GGSelect.SelectedSequences[gargoyleData, normal];
seq _ GGObjects.NextSequence[seqGen];
next _ GGObjects.NextSequence[seqGen];
IF next # NIL THEN {
GGError.Append["Select a single sequence for a GetRadius.", oneLiner];
GGError.Blink[];
};
segGen _ GGObjects.SegmentsInSequence[seq];
FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO
radius _ GGVector.Distance[seg.lo, seg.hi];
BEGIN
thisButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
thisButton _ gargoyleData.hitTest.radiusButtons;
UNTIL thisButton.next = NIL DO thisButton _ thisButton.next ENDLOOP;
tiogaButton _ thisButton.button;
[] _ GGButtons.AddScalarButton[tiogaButton, radius, LIST[$ToggleRadius, NEW[REAL _ radius]], FALSE, gargoyleData];
END
ENDLOOP;
};
ToggleRadius: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
radius: REAL;
firstButton, pushedButton: ScalarButtonClient;
tiogaButton: TiogaButtons.TiogaButton;
WITH event.rest.first SELECT FROM
int: REF INT => radius _ int^;
real: REF REAL => radius _ real^;
ENDCASE => ERROR;
firstButton _ gargoyleData.hitTest.radiusButtons;
FOR thisButton: ScalarButtonClient _ firstButton, thisButton.next UNTIL thisButton = NIL DO
IF thisButton.value = radius THEN {
pushedButton _ thisButton;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
tiogaButton _ pushedButton.button;
IF pushedButton.on THEN {
pushedButton.on _ FALSE;
TiogaButtons.ChangeButtonLooks[tiogaButton, "", "b"];
}
ELSE {
pushedButton.on _ TRUE;
TiogaButtons.ChangeButtonLooks[tiogaButton, "b", ""];
};
};


DeleteRadius: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {};


Erase: PUBLIC PROC [event: LIST OF REF ANY, gargoyleData: GargoyleData] = {
GGWindow.Painter[$EraseAll, gargoyleData];
};


END.

��¦��GGEventImpl.mesa
Last edited by Bier on August 19, 1985 4:19:09 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.
Stone, August 9, 1985 2:38:57 pm PDT


File Operations

TIMING VARIABLES
The Painting Call
START TIMING

Master Menu
Hierarchy Menu

Curve Menu
Choose a random p1:
Choose a random p near the line p0, p2:
Choose a random p1 and p2:
Choose a random number of knots and positions:

Edit Curve Menu

Debug Menu
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.

Style Operations



Alignment Operations


Doesn't properly handle end conditions.  Assumes that some buttons already exist.
Doesn't properly handle end conditions.  Assumes that some buttons already exist.
Miscellaneous

�ÊÛ��˜�Ihead1™J™5™€Icode™$—J™�šÏk	˜	Jšœþ˜þJ˜�—šœ
œ˜Jšœ¸˜¿Jšœ
˜—Jš˜J˜�Jšœ	œ˜%Jšœœ ˜5Jšœœ!˜3Jšœ	œ˜%Jšœœ˜!Jšœœ'˜?Jšœ	œ˜%Jšœ
œ˜'Jšœœ˜Jšœœ˜1Jšœ
œ˜+Jšœœ!˜7Jšœœ"˜9Jšœœ˜#J˜$J˜�J™�J™J™�JšÏnœœœ	œœœœ#˜MJšžœœœ	œœœœ#˜MJšžœœœ	œœœœ#˜KJšžœœœ	œœœœ#˜MJšžœœœ	œœœœ#˜MšÐbn
œœœ	œœœœ!˜PIprocšœ˜Mšœœ˜"Mšœ	œ˜M˜%Jšœ™Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜M™šžœœ˜/M˜"Mšœ2˜2M˜M˜�—Mšœ,˜,Jšœœœ˜'JšÏbœ)˜-Jšœ
œ˜šœ œœ˜)šœœ
œœ˜*Jšœ
œ˜Jšœ˜	J˜—Jšœ˜—Jšœœ	œœ˜Jšœ*˜*Jšœ
œB˜NJšœ˜Jšœ™Jš ˜Jšœ6˜6Jšœ˜Jš ˜Jšœ1˜1Jšœ
œ3˜?Jšœ˜M˜J˜�J˜�—J™�J™J˜�J™šžœœœ	œœœœ!˜LM˜Mšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœ6˜6Mšœ4˜4Mšœ3˜3Mšœ6˜6Mšœœ˜Mšœœ˜,šœ˜Mšœ5˜5Mšœ.˜.M˜—šœ˜Mšœ2˜2šœ#œ˜+Mšœ˜Mšœœ˜ MšœœÏc)˜8šœ
˜
Mšœ\˜\Mšœ˜M˜—Mšœœ˜Mšœ˜—šœ˜šœ	œ¡#˜5Mšœ;˜;Mšœ4˜4M˜—šœ¡¶˜½Mšœ˜M˜—M˜—M˜—Mšœœ˜—Mšœ˜Jšœ2˜2J˜J˜�—šž	œœ	œœœœ!˜OMšœ+˜+Mšœ)˜)Jšœ2˜2M˜J˜�—Jšœœœœ˜(J™�J™
šžœœ	œœœœ!˜QJ˜J˜J˜J˜Jšœ:˜:šœPœœ˜eJšœ/˜/Jšœ˜šœtœœ˜ŽJšœžœ˜6J˜—Jšœ˜—Jšœ˜Jšœ2˜2Jšœ˜—šžœœœ	œœœœ!˜LJ˜J˜J˜J˜J˜Jšœ:˜:šœPœœ˜eJšœ/˜/Jšœ˜Jšœtœœ˜Ž™J˜J˜Jšœ>˜>Jšœžœ
˜'J˜—Jšœ˜—Jšœ˜Jšœ2˜2J˜—šžœœ	œœœœ!˜NJ˜J˜J˜J˜J˜Jšœ:˜:šœPœœ˜eJšœ/˜/Jšœ˜šœtœœ˜ŽJ˜J˜Jšœ>˜>Jšœž	œ˜.J˜—Jšœ˜—Jšœ˜Jšœ2˜2Jšœ˜—J˜�J˜5Jš
žœœœœœ"˜DJ˜�šžœœœœ˜?J™'Jšœœ˜Jšœœ¡˜,J˜SJ˜—J˜�J˜�šž
œœœœ˜PJšœ$œ$˜KJšœ!˜!Jšœœ"˜+Jšœœ˜J˜šœœœ˜%Jšœ!˜!J˜Jšœ˜—Jšœ˜Jšœ	˜J˜J˜�—šž
œœ>˜NJšœµ˜µJ˜J˜�—šŸ	œœ	œœœœ!˜OJ˜J˜J˜J˜J˜Jšœ:˜:šœPœœ˜eJšœ/˜/Jšœ˜Jšœtœœ˜Ž™Jšœœ/˜;Jšœ!˜!J˜Jšœ˜Jšœ˜J˜Jšœž
œ˜.J˜—Jšœ˜—Jšœ˜Jšœ2˜2J˜—šž	œœ	œœœœ!˜OJ˜J˜J˜J˜Jšœ:˜:šœPœœ˜eJšœ/˜/Jšœ˜Jšœtœœ˜Ž™.Jšœœ/˜;J˜*Jšœœ˜&JšœQ˜QJšœžœ˜.J˜—Jšœ˜—Jšœ˜Jšœ2˜2Jšœ˜—J™�J™šžœœœ	œœœœ!˜KMšœ˜Mšœ˜M˜
MšœB˜Bšœœœ˜MšœC˜CMšœ˜Mšœ˜M˜—MšœA˜AMšœ.˜.Mšœ)˜)Mšœ0˜0Mšœ*˜*MšœL˜LJšœ2˜2M˜J˜�—J˜�J™�J™
šžœœœ	œœœœ!˜QM™ÄMšœ2˜2Mšœ˜Mšœœ˜
Mšœœ˜Mšœœœ˜
Jšœ˜Jšœ	œœ˜Mšœœ˜Mšœ˜Mšœ:˜:Mšœ:˜:Mšœ&˜&Mšœ?˜?šœœœ˜MšœC˜CM˜Mšœ˜M˜—Mšœ'˜'Mšœ,˜,Mšœ"˜"šœ˜šœœ˜Mšœœ˜Mšœ˜M˜—Mšœ"˜"Mšœ"˜"M˜MšœC˜CMšœ+˜+Mšœi˜išœœœ˜Mšœ,˜,Mšœ.˜.MšœB˜BM˜—šœ˜Mšœ+˜+M˜—M˜—Mšœ˜Mšœœœ˜
Mšœq˜qMšœœ˜Mšœ$˜$M˜M˜�—šžœœœ	œœœœ!˜UJšœ2˜2J˜—šžœœœ	œœœœ!˜YJšœ-˜-J˜—šžœœœ	œœœœ!˜TJšœ1˜1J˜—šžœœœ	œœœœ!˜VJšœ3˜3J˜—šž
œœœ	œœœœ!˜PJšœ˜Jšœœœ˜Jšœ<˜<Jšœ"˜"Jšœ*˜*Jšœ˜—šžœœœœœœ˜[˜#J˜Jšœ'œœ
œœœ˜„—Jšœ(˜(Jšœ1œ
œ	œ˜SJšœGœœ˜RJšœ˜J˜�—šžœœ	œœœœ!˜NJšœ˜J˜J˜�—šžœœœ	œœœœ!˜YJ˜Jšœœ˜ Jšœ	œ˜Jšœ
œ˜J˜
Jšœ¡œ8˜Mšœ	œ˜Jšœ8˜8J˜—šœ˜Jšœœ˜Jšœ.˜.Jšœ
œU˜hJšœ9˜=J˜—Jšœ
œ/˜;Jšœ"˜"J˜—J™�J™J™�šž	œœœ	œœœœ!˜OMšœ
œ˜Mšœœ˜M˜Mšœ
œœœ˜-Mšœœ
˜Mšœ˜Mšœ
œI˜UMšœ"˜"Mšœ?˜?šœ_œœ˜yMšœ0˜0—Mšœ˜Jšœ2˜2J˜J˜�—M™�šžœœœ	œœœœ!˜TM˜Mšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœœ˜M˜=M˜6M˜Mšœœ˜,Mšœœ˜Mšœ.˜.—Mšœ˜M˜J˜�—šžœœ	œœœœ!˜TM˜Mšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœœ˜M˜=M˜6M˜Mšœœ˜,Mšœœ˜Mšœ.˜.—Mšœ˜M˜—šž
œœ	œœœœ!˜SM˜Mšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœœ˜M˜=M˜6M˜Mšœœ˜,Mšœœ˜Mšœ@˜@—Mšœ˜M˜—M™�M™M™�šžœœœ	œœœœ!˜MMšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœ1˜1—Mšœ˜M˜—šžœœ	œœœœ!˜NMšœ˜Mšœ<˜<šœ	œœDœ
œ˜lMšœ3˜3—Mšœ˜M˜M˜�—šž
œœ	œœœœ!˜PJšœ6˜6Jšœ2˜2J˜J˜�—šž
œœ	œœœœ!˜PJšœ"˜"Jšœ2˜2J˜—J™�šžœœœ	œœœœ!˜YMšœJ˜JMšœœ˜šœ!˜'Mšœœ˜2—šœ˜Mšœœ˜4—Mšœ˜Mšœœ˜Mšœ#œ7˜^Mšœ$œ4˜\Mšœœ0˜PMšœœ-˜JMšœœ˜M˜M˜�—šžœœœ	œœœœ!˜YMšœœ˜Mšœœ˜MšœY˜YMšœ1˜1Mšœ˜šœ	œ˜
Mšœ˜Mšœ
œ@˜LM˜"Mšœ>˜>M˜—šœ˜Mšœ˜Mšœ
œ@˜LM˜"Mšœ>˜>M˜—M˜Mš
œœ˜Mšœ'˜'Mšœ'˜'Mšœ$˜$M˜M˜�—šžœœ	œœœœ!˜TMšœ9˜9Mšœ!˜!M˜—šžœœœ	œœœœ!˜XMšœ8˜8Mšœ!˜!M˜—M˜�šžœœ	œœœœ!˜QMšœ0˜0Mšœ!˜!Mšœ˜M˜�—šžœœ	œœœœ!˜NM™QMšœœ˜Mšœ˜Mšœ&˜&MšœB˜BMšœ/˜/Mšœœœœ˜DMšœ ˜ Mš	œ3œœœœ˜oM˜M˜�—šžœœœ	œœœœ!˜NMšœ˜Mšœ˜Mšœ˜M˜Mšœ	œ˜Mšœ:˜:Mšœ%˜%Mšœ&˜&šœœœ˜M˜EM˜M˜—Mšœ+˜+šœMœœ˜bM˜6Mšœ.˜.Mšœœ˜0š˜Mšœ˜Mšœ&˜&Mšœ/˜/Mšœœœœ˜DMšœ ˜ Mš	œ5œœœœ˜s—Mš˜—Mšœ˜˜M˜�—M˜�—šžœœœ	œœœœ!˜QMšœœ˜Mšœ.˜.Mšœ&˜&Mšœœ˜!Mšœœœ˜Mšœœœ˜ Mšœœ˜Mšœ0˜0šœ?œœ˜[šœœ˜"Mšœ˜Mšœ˜M˜——š˜Mšœœ˜—Mšœ˜Mšœ"˜"šœœ˜Mšœœ˜Mšœ5˜5M˜—šœ˜Mšœœ˜Mšœ5˜5M˜—M˜M˜�—Mšžœœ	œœœœ#˜SM˜�šžœœ	œœœœ!˜RMšœ1˜1Mšœ!˜!M˜M˜�—šž	œœœ	œœœœ!˜OM™QMšœœ˜
Mšœ˜Mšœ&˜&MšœD˜DMšœ0˜0Mšœœœœ˜DMšœ ˜ Mš	œ4œœœ
œ˜rM˜—šž	œœ	œœœœ!˜OMšœ˜Mšœ˜Mšœ˜Mšœœ˜
Mšœ:˜:Mšœ%˜%Mšœ&˜&šœœœ˜M˜FM˜M˜—Mšœ+˜+šœMœœ˜bMšœ+˜+š˜Mšœ˜Mšœ&˜&Mšœ0˜0Mšœœœœ˜DMšœ ˜ Mš	œ4œœœ
œ˜r—Mš˜—Mšœ˜Mšœ˜—šžœœœ	œœœœ!˜RMšœœ˜
Mšœ.˜.Mšœ&˜&Mšœœ˜!Mšœœœ˜Mšœœœ˜!Mšœœ˜Mšœ1˜1šœ?œœ˜[šœœ˜#Mšœ˜Mšœ˜M˜——š˜Mšœœ˜—Mšœ˜Mšœ"˜"šœœ˜Mšœœ˜Mšœ5˜5M˜—šœ˜Mšœœ˜Mšœ5˜5M˜—M˜M˜�M˜�—Mšžœœœ	œœœœ#˜T˜�M˜�—J™
J™�šžœœœ	œœœœ!˜KJšœ*˜*Jšœ˜M˜�—J˜�Jšœ˜J˜�—�…—����b����