GGCaretImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by Bier on January 14, 1987 11:29:07 pm PST
Contents: Facilities for moving the caret and storing information about the neighborhood it inhabits (such as what trajectory it is sitting on).
Pier, August 22, 1986 5:01:17 pm PDT
DIRECTORY
GGBasicTypes, GGBoundBox, GGCaret, GGInterfaceTypes, GGModelTypes, GGOutline, GGSegmentTypes, GGTraj;
GGCaretImpl: CEDAR PROGRAM
IMPORTS GGBoundBox, GGOutline, GGTraj
EXPORTS GGCaret = BEGIN
Caret: TYPE = REF CaretObj;
CaretObj: TYPE = GGInterfaceTypes.CaretObj;
CaretOn: TYPE = GGInterfaceTypes.CaretOn;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
Joint: TYPE = GGModelTypes.Joint;
OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor;
Point: TYPE = GGBasicTypes.Point;
Segment: TYPE = GGSegmentTypes.Segment;
Sequence: TYPE = GGModelTypes.Sequence;
Traj: TYPE = GGModelTypes.Traj;
TrajPartType: TYPE = GGModelTypes.TrajPartType;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
NotYetImplemented: PUBLIC SIGNAL = CODE;
Copy: PUBLIC PROC [to, from: Caret] = {
Used for dropping the anchor.
to.exists ← from.exists;
to.point ← from.point;
to.chair ← from.chair;
to.attractor ← from.attractor;
to.onOverlay ← from.onOverlay;
};
Kill: PUBLIC PROC [caret: Caret] = {
This caret no longer exists. It should disappear from the screen.
caret.exists ← FALSE;
};
Exists: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = {
RETURN[caret.exists];
};
BoundBoxOfCaret: PUBLIC PROC [caret: Caret, gargoyleData: GargoyleData] RETURNS [box: GGBoundBox.BoundBox ← NIL] = {
leftOffset, rightOffset, topOffset, bottomOffset: REAL ← 0.0;
IF caret=NIL OR gargoyleData=NIL THEN ERROR;
SELECT TRUE FROM
caret=gargoyleData.caret => {
leftOffset ← GGCaret.caretWidth/2.0;
rightOffset ← leftOffset;
topOffset ← 0.0;
bottomOffset ← GGCaret.caretHeight;
};
caret=gargoyleData.anchor => {
leftOffset ← GGCaret.anchorWidth/2.0;
rightOffset ← leftOffset;
topOffset ← GGCaret.anchorHeight/2.0;
bottomOffset ← topOffset;
};
ENDCASE => RETURN[NIL];
leftOffset ← leftOffset+fudge;
rightOffset ← rightOffset+fudge;
bottomOffset ← bottomOffset+fudge;
topOffset ← topOffset+fudge;
RETURN[GGBoundBox.CreateBoundBox[ caret.point.x-leftOffset, caret.point.y-bottomOffset, caret.point.x+rightOffset, caret.point.y+topOffset ]];
};
fudge: REAL ← 4.0; -- needed to make control points erase properly
For use by GGRefreshImpl.
TellOnOverlay: PUBLIC PROC [caret: Caret, onOverlay: BOOL] = {
caret.onOverlay ← onOverlay;
};
IsOnOverlay: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = {
RETURN[caret.onOverlay];
};
The Chair.
SitOn: PUBLIC PROC [caret: Caret, chair: REF ANYNIL] = {
caret.chairchair;
};
GetChair: PUBLIC PROC [caret: Caret] RETURNS [chair: REF ANY, on: CaretOn, joint: Joint ← NIL, jointNum: NAT ← 999, cp: Point, cpNum: NAT ← 999, seg: Segment ← NIL, segNum: NAT ← 999] = {
chair ← caret.chair;
on ← caret.chairOn;
jointNum ← caret.chairJointNum;
cpNum ← caret.chairCPNum;
segNum ← caret.chairSegNum;
IF chair#NIL THEN WITH chair SELECT FROM
traj: Traj => SELECT on FROM
nothing => NULL;
joint => joint ← GGTraj.FetchJoint[traj, jointNum];
seg => seg ← GGTraj.FetchSegment[traj, segNum];
cp => {
seg ← GGTraj.FetchSegment[traj, segNum];
cp ← seg.class.controlPointGet[seg, cpNum];
};
slice => ERROR;
ENDCASE;
outlineD: OutlineDescriptor => SELECT on FROM
nothing => NULL;
slice => NULL; -- may do something more clever in the future
joint, seg, cp=> ERROR;
ENDCASE;
sliceD: SliceDescriptor => SELECT on FROM
nothing => NULL;
slice => NULL; -- may do something more clever in the future
joint, seg, cp=> ERROR;
ENDCASE;
ENDCASE => ERROR; -- chairs can only be trajs and sliceDescriptors
};
GetChair: PUBLIC PROC [caret: Caret] RETURNS [chair: REF ANY] = {
chair ← caret.chair;
};
SittingOnEnd: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = {
success: BOOL;
partType: TrajPartType;
jointNum: NAT;
traj: Traj;
IF caret.chair = NIL THEN RETURN[FALSE];
WITH caret.chair SELECT FROM
outlineD: OutlineDescriptor => {
[success, partType, traj, ----, jointNum] ← GGOutline.UnpackSimpleDescriptorOld[outlineD];
IF NOT success OR partType # joint THEN RETURN[FALSE];
RETURN[GGTraj.IsEndJoint[traj, jointNum]];
};
sliceD: SliceDescriptor => {
IF sliceD.slice.class.type # $Outline THEN RETURN[FALSE];
[success, partType, traj, ----, jointNum] ← GGOutline.UnpackSimpleDescriptor[sliceD];
IF NOT success OR partType # joint THEN RETURN[FALSE];
RETURN[GGTraj.IsEndJoint[traj, jointNum]];
};
ENDCASE => ERROR;
};
The Attractor.
NoAttractor: PUBLIC PROC [caret: Caret] = {
caret.attractor ← NIL;
};
SetAttractor: PUBLIC PROC [caret: Caret, point: Point, attractor: REF ANY] = {
caret.exists ← TRUE;
caret.point ← point;
caret.attractor ← attractor;
};
GetAttractor: PUBLIC PROC [caret: Caret] RETURNS [attractor: REF ANY] = {
attractor ← caret.attractor;
};
GetAttractor: PUBLIC PROC [caret: Caret] RETURNS [attractor: REF ANY] = {
attractor ← caret.attractor;
on ← caret.attractorOn;
jointNum ← caret.attractorJointNum;
cpNum ← caret.attractorCPNum;
segNum ← caret.attractorSegNum;
IF attractor#NIL THEN WITH attractor SELECT FROM
traj: Traj => SELECT on FROM
nothing => NULL;
joint => joint ← GGTraj.FetchJoint[traj, jointNum];
seg => seg ← GGTraj.FetchSegment[traj, segNum];
cp => {
seg ← GGTraj.FetchSegment[traj, segNum];
cp ← seg.class.controlPointGet[seg, cpNum];
};
slice => ERROR;
ENDCASE;
sliceD: SliceDescriptor => SELECT on FROM
nothing => NULL;
slice => NULL; -- may do something more clever in the future
joint, seg, cp=> ERROR;
ENDCASE;
ENDCASE => ERROR; -- chairs can only be trajs and sliceDescriptors
};
GetPoint: PUBLIC PROC [caret: Caret] RETURNS [point: Point] = {
point ← caret.point;
};
Touching.
MakeJointTouchJoint: PROC [traj1, traj2: Traj, joint1, joint2: Joint, point: Point, gargoyleData: GargoyleData] = {
touchGroup, group1, group2: TouchGroup;
IF joint1.touchItem # NIL AND joint2.touchItem = NIL THEN {
joint1 already belongs to a group. Add joint2 to this group.
touchGroup ← GGTouch.TouchGroupOfItem[joint1.touchItem];
joint2.touchItem ← GGTouch.AddJoint[traj2, joint2, touchGroup];
}
ELSE IF joint1.touchItem = NIL AND joint2.touchItem # NIL THEN {
touchGroup ← GGTouch.TouchGroupOfItem[joint2.touchItem];
joint1.touchItem ← GGTouch.AddJoint[traj1, joint1, touchGroup];
}
ELSE IF joint1.touchItem # NIL AND joint2.touchItem # NIL THEN {
Merge the two groups.
group1 ← GGTouch.TouchGroupOfItem[joint1.touchItem];
group2 ← GGTouch.TouchGroupOfItem[joint2.touchItem];
GGTouch.MergeGroups[group1, group2, gargoyleData];
}
ELSE {
touchGroup ← GGTouch.CreateTouchGroup[gargoyleData, point];
joint1.touchItem ← GGTouch.AddJoint[traj1, joint1, touchGroup];
joint2.touchItem ← GGTouch.AddJoint[traj2, joint2, touchGroup];
};
};
RatherClose: PROC [p1, p2: Point] RETURNS [BOOL] = {
epsilon: REAL = 1.0e-5;
RETURN[ABS[p1.x - p2.x] < epsilon OR ABS[p1.y - p2.y] < epsilon];
};
FindItemAtPoint: PROC [point: Point, touchItemList: LIST OF TouchItem] RETURNS [TouchItem] = {
FOR list: LIST OF TouchItem ← touchItemList, list.rest UNTIL list = NIL DO
IF RatherClose[list.first.segPoint, point] THEN RETURN[list.first]
ENDLOOP;
RETURN[NIL];
};
MakeJointTouchSegment: PROC [traj1, traj2: Traj, joint: Joint, seg: Segment, point: Point, gargoyleData: GargoyleData] = {
samePointItem: TouchItem;
touchGroup, group1, group2: TouchGroup;
samePointItem ← FindItemAtPoint[point, seg.touchItemList];
IF joint.touchItem # NIL AND samePointItem = NIL THEN {
touchGroup ← GGTouch.TouchGroupOfItem[joint.touchItem];
seg.touchItemList ← CONS[GGTouch.AddSegment[traj2, seg, point, touchGroup], seg.touchItemList];
}
ELSE IF joint.touchItem = NIL AND samePointItem # NIL THEN {
touchGroup ← GGTouch.TouchGroupOfItem[samePointItem];
joint.touchItem ← GGTouch.AddJoint[traj1, joint, touchGroup];
}
ELSE IF joint.touchItem # NIL AND samePointItem # NIL THEN {
group1 ← GGTouch.TouchGroupOfItem[joint.touchItem];
group2 ← GGTouch.TouchGroupOfItem[samePointItem];
GGTouch.MergeGroups[group1, group2, gargoyleData];
}
ELSE {
touchGroup ← GGTouch.CreateTouchGroup[gargoyleData, point];
joint.touchItem ← GGTouch.AddJoint[traj1, joint, touchGroup];
seg.touchItemList ←
CONS[GGTouch.AddSegment[traj2, seg, point, touchGroup], seg.touchItemList];
};
};
MakeSegmentTouchSegment: PROC [chair, attractor: Traj, chairSeg, attractorSeg: Segment, point: Point, gargoyleData: GargoyleData] = {
Not yet implemented.
};
MakeChairTouchAttractor: PUBLIC PROC [caret: Caret, gargoyleData: GargoyleData] = {
};
MakeChairTouchTrajJoint: PUBLIC PROC [caret: Caret, gargoyleData: GargoyleData, traj: Traj, jointNum: NAT] = {
};
END.