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; GGData: TYPE = GGInterfaceTypes.GGData; 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] = { to.exists _ from.exists; to.point _ from.point; to.chair _ from.chair; to.attractor _ from.attractor; }; Kill: PUBLIC PROC [caret: Caret] = { caret.exists _ FALSE; }; Exists: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = { RETURN[caret.exists]; }; BoundBoxOfCaret: PUBLIC PROC [caret: Caret, ggData: GGData] RETURNS [box: GGBoundBox.BoundBox _ NIL] = { leftOffset, rightOffset, topOffset, bottomOffset: REAL _ 0.0; IF caret=NIL OR ggData=NIL THEN ERROR; SELECT TRUE FROM caret=ggData.caret => { leftOffset _ GGCaret.caretWidth/2.0; rightOffset _ leftOffset; topOffset _ 0.0; bottomOffset _ GGCaret.caretHeight; }; caret=ggData.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 SitOn: PUBLIC PROC [caret: Caret, chair: SliceDescriptor _ NIL] = { caret.chair _ chair; }; GetChair: PUBLIC PROC [caret: Caret] RETURNS [chair: SliceDescriptor] = { chair _ caret.chair; }; SittingOnEnd: PUBLIC PROC [caret: Caret] RETURNS [BOOL] = { success: BOOL; partType: TrajPartType; jointNum: NAT; traj: Traj; IF caret.chair = NIL OR caret.chair.slice.class.type # $Outline THEN RETURN[FALSE]; [success, partType, traj, ----, jointNum] _ GGOutline.UnpackSimpleDescriptor[caret.chair]; RETURN[IF (NOT success OR partType # joint) THEN FALSE ELSE GGTraj.IsEndJoint[traj, jointNum] ]; }; NoAttractor: PUBLIC PROC [caret: Caret] = { caret.attractor _ NIL; }; SetAttractor: PUBLIC PROC [caret: Caret, point: Point, attractor: SliceDescriptor] = { caret.exists _ TRUE; caret.point _ point; caret.attractor _ attractor; }; GetAttractor: PUBLIC PROC [caret: Caret] RETURNS [attractor: SliceDescriptor] = { attractor _ caret.attractor; }; GetPoint: PUBLIC PROC [caret: Caret] RETURNS [point: Point] = { point _ caret.point; }; END. ‚GGCaretImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by Bier on April 6, 1987 9:45:01 pm PDT Contents: Facilities for moving the caret and storing information about the neighborhood it inhabits (such as what trajectory it is sitting on). Pier, May 13, 1987 1:26:11 pm PDT Used for dropping the anchor. to.onOverlay _ from.onOverlay; This caret no longer exists. It should disappear from the screen. 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. SittingOnEndOLDD: 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. Touching. MakeJointTouchJoint: PROC [traj1, traj2: Traj, joint1, joint2: Joint, point: Point, ggData: GGData] = { 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, ggData]; } ELSE { touchGroup _ GGTouch.CreateTouchGroup[ggData, 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, ggData: GGData] = { 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, ggData]; } ELSE { touchGroup _ GGTouch.CreateTouchGroup[ggData, 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, ggData: GGData] = { Not yet implemented. }; MakeChairTouchAttractor: PUBLIC PROC [caret: Caret, ggData: GGData] = { }; MakeChairTouchTrajJoint: PUBLIC PROC [caret: Caret, ggData: GGData, traj: Traj, jointNum: NAT] = { }; Κ&˜code™Kšœ Οmœ1™Kšœ™K™K™—š Ÿ œžœžœžœžœ™:Kšžœ™K™—K˜™ K™—šŸœžœžœ)žœ˜CKšœΟtœ‘˜K˜K˜—šŸœžœžœžœ˜IKšœ˜K˜K˜—š Ÿœžœžœžœžœ™?Kšœ žœ™Kšœ™Kšœ žœ™K™ Kš žœžœžœžœžœ™(šžœ žœž™™ Kšœ œ<™ZKš žœžœ žœžœžœžœ™6Kšžœ$™*K™—™Kšžœ$žœžœžœ™9Kšœ œ7™UKš žœžœ žœžœžœžœ™6Kšžœ$™*K™—Kšžœžœ™—K™K™—š Ÿ œžœžœžœžœ˜;Kšœ žœ˜Kšœ˜Kšœ žœ˜K˜ Kš žœžœžœ)žœžœžœ˜SKšœ œΟb œ˜ZKšžœžœžœ žœžœžœžœ%˜`K˜—K™™K˜—šŸ œžœžœ˜+Kšœžœ˜K˜K˜—šŸ œžœžœ=˜VKšœžœ˜Kšœ˜Kšœ˜K˜K˜—šŸ œžœžœžœ!˜QKšœ˜K˜K˜—K˜šŸœžœžœžœ˜?Kšœ˜K˜—K˜™ K™—šŸœžœN™gKšœ'™'š žœžœžœžœžœ™;Kšœ=™=Kšœ8™8Kšœ?™?K™—š žœžœžœžœžœžœ™@Kšœ8™8Kšœ?™?K™—š žœžœžœžœžœžœ™@K™Kšœ4™4Kšœ4™4Kšœ,™,K™—šžœ™Kšœ5™5Kšœ?™?Kšœ?™?K™—K™K™—šŸ œžœžœžœ™4Kšœ žœ ™Kšžœžœžœžœ™AK™K™—š Ÿœžœžœžœ žœ™^š žœžœžœ&žœžœž™JKšžœ)žœžœ ™B—Kšžœ™Kšžœžœ™ K™K™—šŸœžœS™nK™Kšœ'™'Kšœ:™:š žœžœžœžœžœ™7Kšœ7™7KšœžœG™_K™—š žœžœžœžœžœžœ™