GGMouseEventImplB.mesa
Last edited by Pier on November 21, 1986 3:10:19 pm PST
Contents: Once a mouse event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module.
Bier, January 27, 1987 1:07:13 am PST
Kurlander July 17, 1986 2:40:45 pm PDT
DIRECTORY
GGBasicTypes, GGCaret, GGDescribe, GGError, GGGravity, GGInterfaceTypes, GGModelTypes, GGMouseEvent, GGMultiGravity, GGObjects, GGOutline, GGRefresh, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUtility, GGVector, GGWindow, ImagerTransformation, InputFocus, Menus, Rope;
GGMouseEventImplB:
CEDAR
PROGRAM
IMPORTS GGCaret, GGDescribe, GGError, GGGravity, GGMouseEvent, GGMultiGravity, GGObjects, GGOutline, GGRefresh, GGSelect, GGSequence, GGTraj, GGVector, GGWindow, ImagerTransformation, InputFocus
EXPORTS GGMouseEvent = BEGIN
AlignmentPoint: TYPE = GGInterfaceTypes.AlignmentPoint;
BoundBox: TYPE = GGModelTypes.BoundBox;
Caret: TYPE = GGInterfaceTypes.Caret;
EntityGenerator: TYPE = GGModelTypes.EntityGenerator;
FeatureData: TYPE = GGInterfaceTypes.FeatureData;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
Joint: TYPE = GGModelTypes.Joint;
MouseButton: TYPE = Menus.MouseButton;
MouseProc: TYPE = GGMouseEvent.MouseProc;
ObjectBag: TYPE = GGInterfaceTypes.ObjectBag;
Outline: TYPE = GGModelTypes.Outline;
OutlineDescriptor: TYPE = REF OutlineDescriptorObj;
OutlineDescriptorObj: TYPE = GGModelTypes.OutlineDescriptorObj;
Point: TYPE = GGBasicTypes.Point;
ResultFeatureType: TYPE = GGModelTypes.ResultFeatureType;
Scene: TYPE = GGModelTypes.Scene;
SelectMode: TYPE = GGModelTypes.SelectMode;
Segment: TYPE = GGSegmentTypes.Segment;
Sequence: TYPE = GGModelTypes.Sequence;
Slice: TYPE = GGModelTypes.Slice;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceClass: TYPE = GGModelTypes.SliceClass;
SliceParts: TYPE = GGModelTypes.SliceParts;
StartProc: TYPE = GGMouseEvent.StartProc;
TouchGroup: TYPE = GGSegmentTypes.TouchGroup;
Traj: TYPE = GGModelTypes.Traj;
TrajEnd: TYPE = GGModelTypes.TrajEnd;
TrajGenerator: TYPE = GGModelTypes.TrajGenerator;
Vector: TYPE = GGBasicTypes.Vector;
Problem: SIGNAL [msg: Rope.ROPE] = GGError.Problem;
SaveSavedState:
PROC [gargoyleData: GargoyleData] = {
GGObjects.SaveSelections[gargoyleData.scene];
GGWindow.SaveCaretPos[gargoyleData];
GGCaret.Copy[from: gargoyleData.caret, to: gargoyleData.drag.savedCaret];
};
DescribeSelectionAction:
PUBLIC
PROC [gargoyleData: GargoyleData, feature: FeatureData, selectMode: SelectMode, action: Rope.
ROPE] = {
GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[action]], [rope[GGDescribe.DescribeFeature[feature, gargoyleData]]]];
};
SetCaretAttractorEndpoint:
PUBLIC
PROC [gargoyleData: GargoyleData, mapPoint: Point, feature: FeatureData] = {
IF feature=
NIL
THEN GGCaret.SetAttractor[gargoyleData.caret, mapPoint,
NIL]
ELSE {
resultType: ResultFeatureType ← feature.resultType;
shape: REF ANY ← feature.shape;
SELECT resultType
FROM
outline => {
traj: Traj;
hitType: GGModelTypes.TrajPartType;
segNum, cpNum, jointNum: INT;
hitPoint, thisPoint: Point;
jointSeq: Sequence;
jointParts: SliceParts;
jointD: OutlineDescriptor;
outlineD: OutlineDescriptor ← NARROW[shape];
[traj, hitType, segNum, cpNum, jointNum, hitPoint] ← GGOutline.UnpackHitData[feature.hitPart];
SELECT hitType
FROM
joint => {
jointSeq ← GGSequence.CreateFromJoint[traj, jointNum];
thisPoint ← mapPoint;
};
controlPoint => {
jointSeq ← GGSequence.CreateFromControlPoint[traj, segNum, cpNum];
thisPoint ← mapPoint;
};
segment => {
success: BOOL;
jointPoint, cpPoint: Point;
seg: Segment ← GGTraj.FetchSegment[traj, segNum];
[jointNum, ----] ← GGOutline.NearestJointToHitData[feature.hitPart];
jointPoint ← GGTraj.FetchJointPos[traj, jointNum];
[cpPoint, cpNum, success] ← seg.class.closestControlPoint[seg, mapPoint, GGUtility.plusInfinity];
IF
NOT success
THEN {
-- its a joint for sure
jointSeq ← GGSequence.CreateFromJoint[traj, jointNum];
thisPoint ← jointPoint;
}
ELSE {
-- could be a cp instead of a joint
cpDist: REAL ← GGVector.DistanceSquared[cpPoint, mapPoint];
jointDist: REAL ← GGVector.DistanceSquared[jointPoint, mapPoint];
tisAJoint: BOOL ← jointDist <= cpDist;
IF tisAJoint
THEN {
jointSeq ← GGSequence.CreateFromJoint[traj, jointNum];
thisPoint ← jointPoint;
}
ELSE {
jointSeq ← GGSequence.CreateFromControlPoint[traj, segNum, cpNum];
thisPoint ← cpPoint;
};
};
};
ENDCASE => ERROR;
jointParts ← GGOutline.PartsFromSequence[outlineD.slice, jointSeq];
jointD ← NEW[OutlineDescriptorObj ← [outlineD.slice, jointParts]];
GGCaret.SetAttractor[gargoyleData.caret, thisPoint, jointD];
};
slice => {
pos: Point;
sliceD: SliceDescriptor ← NARROW[shape];
IF sliceD.slice.class.type = $Outline THEN ERROR Problem[msg: "Outlines are Slices"];
[pos, ----, ----, ----] ← sliceD.slice.class.closestPoint[sliceD, mapPoint, GGUtility.plusInfinity];
GGCaret.SetAttractor[gargoyleData.caret, pos, sliceD];
};
ENDCASE => GGCaret.SetAttractor[gargoyleData.caret, mapPoint, NIL];
};
};
Deselection Procs
StartDeselectJoint:
PUBLIC StartProc = {
Use the StrictDistance gravity function. Find the nearest segment to the cursor. Snap the caret to the nearest endpoint of that segment. Feedback during the operation will be to deselect hightlight the joint which the caret is snapped to. The final result is to deselect a single joint selection. If the final position of the cursor is too far from any line, do nothing.
Refresh strategy: the selections are moved to the overlay, then DuringDeselect the hit joints are deselected. Since the selection is on the overlay, it's joints will be highlighted, preserving selection feedback, except for the transiently deselected joint.
gargoyleData.drag.selectState ← joint;
GGAlign.SetBagsForAction[gargoyleData, $Select];
Common Deselect Operations.
StartDeselectAux[gargoyleData, worldPt, NIL];
DuringDeselect[NIL, gargoyleData, worldPt];
};
StartDeselectSegment:
PUBLIC StartProc = {
Use the StrictDistance gravity function. Find the nearest segment to the cursor. Snap the caret to the nearest endpoint of that segment. Feedback during the operation will be to select hightlight the endjoints of the segment which the caret is snapped to. The final result is to deselect a single segment selection. If the final position of the cursor is too far from any line, do nothing.
Refresh strategy: the selections are moved to the overlay, then DuringDeselect the hit segments are deselected. Since the selection is on the overlay, it's segments will be highlighted, preserving selection feedback, except for the transiently deselected segments.
gargoyleData.drag.selectState ← segment;
Common Deselect Operations.
StartDeselectAux[gargoyleData, worldPt, NIL];
DuringDeselect[NIL, gargoyleData, worldPt];
};
StartDeselectTrajectory:
PUBLIC StartProc = {
Use the StrictDistance gravity function. Find the nearest trajectory to the cursor. Snap the caret to the nearest endjoint of that trajectory. Feedback during the operation will be to select hightlight the endjoints of the trajectory which the caret is snapped to. The final result is to deselect a single trajectory selection. If the final position of the cursor is too far from any line, do nothing.
Refresh strategy: the selections are moved to the overlay, then DuringDeselect the hit trajectories are deselected. Since the selection is on the overlay, it's trajectories will be highlighted, preserving selection feedback, except for the transiently deselected trajectories.
gargoyleData.drag.selectState ← traj;
GGAlign.SetBagsForAction[gargoyleData, $Select];
Common Deselect Operations.
StartDeselectAux[gargoyleData, worldPt, NIL];
DuringDeselect[NIL, gargoyleData, worldPt];
};
StartDeselectTopLevel:
PUBLIC StartProc = {
gargoyleData.drag.selectState ← topLevel;
GGAlign.SetBagsForAction[gargoyleData, $SelectTopLevel];
Common Deselect Operations.
StartDeselectAux[gargoyleData, worldPt, NIL];
DuringDeselect[NIL, gargoyleData, worldPt];
};
StartDeselectAux:
PROC [gargoyleData: GargoyleData, worldPt: Point, startBox: BoundBox] = {
Check overlay invariant and grab input focus.
IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR; -- nothing on overlay
[] ← InputFocus.SetInputFocus[gargoyleData.actionArea];
Measure caret coordinates.
SaveSavedState[gargoyleData];
gargoyleData.drag.currentPoint ← worldPt; -- this line moved from individual Start code
gargoyleData.drag.transform ← ImagerTransformation.Scale[1.0]; -- needed for DuringDeselect to work properly
};
DuringDeselect:
PUBLIC MouseProc = {
While a joint, cp, segment, traj, or top level object is being deselected, gravity is forced to be StrictDistance. The object bag should consist only of trajectories and slices. The caret is moved to the segment endpoint of the nearest segment or traj as appropriate or tracks the cursor if none are nearby. Feedback is in the form of removing highlighted joints or cps.
resultPoint: Point;
feature: FeatureData;
Use StrictDistance gravity except for DeselectJoint.
gargoyleData.drag.currentPoint ← worldPt;
IF gargoyleData.drag.selectState = joint
THEN
[resultPoint, feature] ← GGMultiGravity.InnerCircle[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.innerR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, FALSE]
ELSE [resultPoint, feature] ← GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData];
Put Caret on a joint (if any).
SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature];
DescribeSelectionAction[gargoyleData, feature, gargoyleData.drag.selectState, "Deselecting"];
Reselect all.
GGObjects.RestoreSelections[gargoyleData.scene];
IF feature =
NIL
THEN {
-- no near trajectories, do nothing
}
ELSE {
DuringDeselectAux[feature, resultPoint, gargoyleData.scene, gargoyleData.drag.selectState];
};
GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end DuringDeselect
DuringDeselectAux:
PROC [feature: FeatureData, caretPt: Point, scene: Scene, mode: GGModelTypes.SelectMode] = {
SELECT feature.resultType
FROM
outline => {
[] ← OutlineDeselectAux[feature, mode, scene];
};
slice => {
[] ← SliceDeselectAux[feature, mode, scene];
};
midpoint => NULL; -- temporarily ignore midpoints in bags. KAP. June 26, 1986
slopeLine, angleLine, distanceLine, intersectionPoint, radiiCircle, midpoint => ERROR;
ENDCASE => ERROR;
};
SliceDeselectAux:
PROC [feature: FeatureData, mode: GGModelTypes.SelectMode, scene: Scene]
RETURNS [deselectedParts: SliceParts] = {
sliceD: SliceDescriptor ← GGSelect.FindSelectedSlice[NARROW[feature.shape, SliceDescriptor].slice, scene, normal];
IF sliceD#
NIL
THEN {
class: SliceClass ← sliceD.slice.class;
newP: SliceParts ← class.newParts[sliceD.slice, feature.hitPart, mode];
diffP: SliceParts ← class.differenceParts[sliceD.slice, sliceD.parts, newP];
GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, scene, normal];
IF NOT class.emptyParts[sliceD.slice, diffP] THEN GGSelect.SelectSlice[sliceD.slice, diffP, scene, normal];
deselectedParts ← newP;
};
};
OutlineDeselectAux:
PROC [feature: FeatureData, mode: GGModelTypes.SelectMode, scene: Scene]
RETURNS [deselectedParts: SliceParts] = {
sliceD: OutlineDescriptor ← GGSelect.FindSelectedOutline[NARROW[feature.shape, OutlineDescriptor].slice, scene, normal];
IF sliceD#
NIL
THEN {
class: GGModelTypes.OutlineClass ← sliceD.slice.class;
newP: SliceParts ← class.newParts[sliceD.slice, feature.hitPart, mode];
diffP: SliceParts ← class.differenceParts[sliceD.slice, sliceD.parts, newP];
GGSelect.DeselectOutline[sliceD.slice, sliceD.parts, scene, normal];
IF NOT class.emptyParts[sliceD.slice, diffP] THEN GGSelect.SelectOutline[sliceD.slice, diffP, scene, normal];
deselectedParts ← newP;
};
};
EndDeselect:
PUBLIC MouseProc = {
resultPoint: Point;
feature: FeatureData;
IF gargoyleData.drag.selectState = joint
THEN
[resultPoint, feature] ← GGMultiGravity.InnerCircle[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.innerR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, FALSE]
ELSE [resultPoint, feature] ← GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData];
Put Caret on a joint (if any).
SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature];
GGWindow.NewCaretPos[gargoyleData];
Clear the overlay plane.
GGRefresh.
MoveOverlayToBackground[gargoyleData];
And Dispatch to the proper EndDeselect handler.
SELECT gargoyleData.drag.selectState
FROM
joint => EndDeselectJoint[gargoyleData, resultPoint, feature];
segment => EndDeselectSegment[gargoyleData, resultPoint, feature];
traj => EndDeselectTrajectory[gargoyleData, resultPoint, feature];
topLevel => EndDeselectTopLevel[gargoyleData, resultPoint, feature];
ENDCASE => ERROR;
gargoyleData.drag.selectState ← none; -- added to help DescribeFeature work. KAP.
};
EndDeselectJoint:
PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = {
GGCaret.SitOn[gargoyleData.caret, NIL];
IF feature =
NIL
THEN {
GGError.AppendHerald[gargoyleData.feedback, "No near joint found.", oneLiner];
}
ELSE {
SELECT feature.resultType
FROM
outline => {
gone: SliceParts ← OutlineDeselectAux[feature, joint, gargoyleData.scene];
sliceD: OutlineDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
slice => {
gone: SliceParts ← SliceDeselectAux[feature, joint, gargoyleData.scene];
sliceD: SliceDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect joint."];
};
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end EndDeselectJoint
EndDeselectSegment:
PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = {
GGCaret.SitOn[gargoyleData.caret, NIL];
IF feature =
NIL
THEN {
-- do nothing
GGError.AppendHerald[gargoyleData.feedback, "No near segment found.", oneLiner];
}
ELSE {
SELECT feature.resultType
FROM
outline => {
gone: SliceParts ← OutlineDeselectAux[feature, segment, gargoyleData.scene];
sliceD: OutlineDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
slice => {
gone: SliceParts ← SliceDeselectAux[feature, segment, gargoyleData.scene];
sliceD: SliceDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect segment."];
};
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end EndDeselectSegment
EndDeselectTrajectory:
PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = {
GGCaret.SitOn[gargoyleData.caret, NIL];
IF feature =
NIL
THEN {
GGError.AppendHerald[gargoyleData.feedback, "No near trajectory found.", oneLiner];
}
ELSE {
SELECT feature.type
FROM
outline => {
gone: SliceParts ← OutlineDeselectAux[feature, traj, gargoyleData.scene];
sliceD: OutlineDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
slice => {
gone: SliceParts ← SliceDeselectAux[feature, traj, gargoyleData.scene];
sliceD: SliceDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect trajectory."];
};
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end EndDeselectTrajectory
EndDeselectTopLevel:
PROC [gargoyleData: GargoyleData, resultPoint: Point, feature: FeatureData] = {
GGCaret.SitOn[gargoyleData.caret, NIL];
IF feature =
NIL
THEN {
GGError.AppendHerald[gargoyleData.feedback, "No near object found.", oneLiner];
}
ELSE {
SELECT feature.resultType
FROM
outline => {
gone: SliceParts ← OutlineDeselectAux[feature, topLevel, gargoyleData.scene];
sliceD: OutlineDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
slice => {
gone: SliceParts ← SliceDeselectAux[feature, topLevel, gargoyleData.scene];
sliceD: SliceDescriptor ← NARROW[feature.shape];
IF gone#NIL THEN GGError.PutFHerald[gargoyleData.feedback, oneLiner, "%g %g", [rope[sliceD.slice.class.describe[sliceD.slice, gone]]], [rope[" deselected"]]];
};
ENDCASE => SIGNAL Problem [msg: "Unexpected feature type for deselect top level."];
};
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
};
Extend selection procs.
StartExtend
SelectJoint:
PUBLIC StartProc = {
gargoyleData.drag.extendMode ← joint;
RETURN[StartExtendSelection[input, gargoyleData, worldPt]];
};
StartExtend
SelectSegment:
PUBLIC StartProc = {
gargoyleData.drag.extendMode ← segment;
RETURN[StartExtendSelection[input, gargoyleData, worldPt]];
};
StartExtend
SelectTraj:
PUBLIC StartProc = {
gargoyleData.drag.extendMode ← traj;
RETURN[StartExtendSelection[input, gargoyleData, worldPt]];
};
StartExtend
SelectTopLevel:
PUBLIC StartProc = {
gargoyleData.drag.extendMode ← topLevel;
RETURN[StartExtendSelection[input, gargoyleData, worldPt]];
};
StartExtendSelection:
PUBLIC StartProc = {
IF NOT GGRefresh.EmptyOverlay[gargoyleData] THEN ERROR;
[] ← InputFocus.SetInputFocus[gargoyleData.actionArea];
SaveSavedState[gargoyleData]; -- must do this before any possible aborts occur
gargoyleData.drag.currentPoint ← worldPt;
gargoyleData.drag.transform ← ImagerTransformation.Scale[1.0];
DuringExtendSelection[NIL, gargoyleData, worldPt];
};
DuringExtendSelection:
PUBLIC MouseProc= {
resultPoint: Point;
feature: FeatureData;
IF gargoyleData.drag.extendMode = joint
THEN
[resultPoint, feature] ← GGMultiGravity.InnerCircle[worldPt, gargoyleData.hitTest.criticalR, gargoyleData.hitTest.innerR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData, FALSE]
ELSE [resultPoint, feature] ← GGMultiGravity.StrictDistance[worldPt, gargoyleData.hitTest.criticalR, GGGravity.emptyObjectBag, gargoyleData.hitTest.sceneTriggerBag, gargoyleData];
Put Caret on a joint (if any).
SetCaretAttractorEndpoint[gargoyleData, resultPoint, feature];
DescribeSelectionAction[gargoyleData, feature, gargoyleData.drag.extendMode, "Extending to"];
Reselect all.
GGSelect.DeselectAll[gargoyleData.scene, normal]; -- MUST CLEAR OUT TRANSIENT SELECTIONS!
GGObjects.RestoreSelections[gargoyleData.scene];
IF feature =
NIL
THEN {
-- no near trajectories, do nothing
}
ELSE {
SELECT gargoyleData.drag.extendMode
FROM
joint, segment, segmentRange, traj, topLevel => DuringExtendSelectionFeedback[feature, resultPoint, gargoyleData];
outline, slice, none => NULL; -- NoOp
ENDCASE => ERROR;
};
GGWindow.RestoreScreenAndInvariants[paintAction: $DuringSelect, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end DuringExtendSelection
DuringExtendSelectionFeedback:
PROC [feature: FeatureData, caretPt: Point, gargoyleData: GargoyleData] = {
depending on extend mode, check if feature is in that mode, then select the new feature.
SELECT gargoyleData.drag.extendMode
FROM
joint => GGMouseEvent.SelectJointOrCP[feature, caretPt, gargoyleData];
segment => GGMouseEvent.SelectSegment[feature, caretPt, gargoyleData];
segmentRange => {
IF feature.resultType = outline
THEN {
traj, trajToExtend: Traj;
hitType: GGModelTypes.TrajPartType;
segNum, cpNum, jointNum, segToExtendNum: INT;
hitPoint: Point;
[traj, hitType, segNum, cpNum, jointNum, hitPoint] ← GGOutline.UnpackHitData[feature.hitPart];
IF (hitType = segment
OR hitType = controlPoint)
THEN {
[trajToExtend, segToExtendNum] ← GGOutline.UnpackOneSegmentDescriptorOld[gargoyleData.drag.outlineToExtend];
IF trajToExtend = traj
THEN {
-- we're extending segments in the same trajectory
seq: Sequence ← GGSequence.CreateFromSegments[traj, segToExtendNum, segNum];
[] ← GGSelect.SelectSequence[seq, gargoyleData.scene, normal]; -- select current hit
}
ELSE GOTO RegularSelectMechanism;
}
ELSE GOTO RegularSelectMechanism;
}
ELSE GOTO RegularSelectMechanism;
EXITS
RegularSelectMechanism => GGMouseEvent.SelectSegment[feature, caretPt, gargoyleData];
};
traj => GGMouseEvent.SelectTraj[feature: feature, caretPt: caretPt, gargoyleData: gargoyleData];
topLevel => GGMouseEvent.SelectTopLevel[feature: feature, caretPt: caretPt, gargoyleData: gargoyleData];
ENDCASE => ERROR; -- should have been weeded about before calling this Proc
};
End
ExtendSelection:
PUBLIC MouseProc = {
GGCaret.DoNotSit[gargoyleData.caret]; -- simple but not always correct thing to do
simply paint new selections directly
GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE];
}; -- end EndExtendSelection
END.