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
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;
File Operations
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;
TIMING VARIABLES
startTime: BasicTime.GMT;
endTime: BasicTime.GMT;
totalTime: INT;
msgRope: Rope.ROPE;
The Painting Call
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];
START TIMING
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];
};
Master Menu
Hierarchy Menu
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;
Curve Menu
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
Choose a random p1:
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] = {
Choose a random p near the line p0, p2:
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
Choose a random p1 and p2:
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
Choose a random number of knots and positions:
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];
};
Edit Curve Menu
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];
};
Debug Menu
TestGravity:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, gargoyleData: GargoyleData] = {
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;
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];
};
Style Operations
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;
};
Alignment Operations
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] = {
Doesn't properly handle end conditions. Assumes that some buttons already exist.
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] = {
Doesn't properly handle end conditions. Assumes that some buttons already exist.
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] = {};
Miscellaneous
Erase:
PUBLIC
PROC [event:
LIST
OF
REF
ANY, gargoyleData: GargoyleData] = {
GGWindow.Painter[$EraseAll, gargoyleData];
};
END.