GGEventImplB.mesa
Copyright Ó 1988, 1991, 1992 by Xerox Corporation. All rights reserved.
Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module.
Pier, October 2, 1992 5:28 pm PDT
Bier, June 23, 1993 9:47 pm PDT
Doug Wyatt, April 16, 1992 4:33 pm PDT
DIRECTORY
BiScrollersTransformsTypes, CodeTimer, CubicSplines, Feedback, FeedbackTypes, Geom2D, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGCoreOps, GGCoreTypes, GGDescribe, GGEmbedTypes, GGEvent, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGMeasure, GGModelTypes, GGMouseEvent, GGParent, GGParseIn, GGRefresh, GGRefreshTypes, GGScene, GGScrollMonitor, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUIUtility, GGUserInput, GGViewerOps, GGWindow, Imager, ImagerBox, ImagerTransformation, IO, Real, Rope, Vector2, Vectors2d;
GGEventImplB: CEDAR PROGRAM
IMPORTS CodeTimer, Feedback, Geom2D, GGAlign, GGBoundBox, GGCaret, GGCoreOps, GGDescribe, GGHistory, GGMeasure, GGMouseEvent, GGParent, GGParseIn, GGRefresh, GGScene, GGScrollMonitor, GGSelect, GGSequence, GGSlice, GGSliceOps, GGState, GGTraj, GGUIUtility, GGUserInput, GGViewerOps, GGWindow, ImagerBox, ImagerTransformation, IO, Rope, Vectors2d
EXPORTS GGEvent, GGHistoryTypes, GGInterfaceTypes = BEGIN
AlignBag: TYPE = GGInterfaceTypes.AlignBag;
Axis: TYPE = BiScrollersTransformsTypes.Axis;
BoundBox: TYPE = GGModelTypes.BoundBox;
Camera: TYPE = GGModelTypes.Camera;
Caret: TYPE = GGInterfaceTypes.Caret;
Change: PUBLIC TYPE = GGHistory.Change; -- exported to GGHistoryTypes
DisplayStyle: TYPE = GGModelTypes.DisplayStyle;
EmbedDataObj: PUBLIC TYPE = GGEmbedTypes.EmbedDataObj; -- exported to GGInterfaceTypes
FeatureData: TYPE = GGInterfaceTypes.FeatureData;
MsgRouter: TYPE = FeedbackTypes.MsgRouter;
FilterLists: TYPE = GGAlign.FilterLists;
GGData: TYPE = GGInterfaceTypes.GGData;
GravityType: TYPE = GGInterfaceTypes.GravityType;
HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent;
Point: TYPE = GGBasicTypes.Point;
RefreshDataObj: PUBLIC TYPE = GGRefreshTypes.RefreshDataObj;
Scene: TYPE = GGModelTypes.Scene;
SegAndIndex: TYPE = GGSequence.SegAndIndex;
Segment: TYPE = GGSegmentTypes.Segment;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SequenceOfReal: TYPE = REF SequenceOfRealObj;
SequenceOfRealObj: TYPE = GGCoreTypes.SequenceOfRealObj;
Slice: TYPE = GGModelTypes.Slice;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceParts: TYPE = GGModelTypes.SliceParts;
StrokeEnd: TYPE = Imager.StrokeEnd;
StrokeJoint: TYPE = Imager.StrokeJoint;
Traj: TYPE = GGModelTypes.Traj;
TrajData: TYPE = GGModelTypes.TrajData;
TrajEnd: TYPE = GGModelTypes.TrajEnd;
TrajParts: TYPE = GGModelTypes.TrajParts;
TriggerBag: TYPE = GGInterfaceTypes.TriggerBag;
Transformation: TYPE = ImagerTransformation.Transformation;
UserInputProc: TYPE = GGEvent.UserInputProc;
Vector: TYPE = GGBasicTypes.Vector;
Vec: TYPE = Vector2.VEC;
WalkProc: TYPE = GGModelTypes.WalkProc;
pointsPerIn: REAL = 72.0;
pointsPerCm: REAL = 72.0/2.54;
reallyBigReal: REAL = 1.0e37;
multipleValues: Rope.ROPE = "multiple values - Aborted!!";
complainAboutIconic: Rope.ROPE = "Viewing transformations not allowed on iconic viewer";
Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem;
BiScrollers Operations
GetArg: PROC [diffOK: BOOL ¬ FALSE, sel: Rope.ROPE, router: MsgRouter] RETURNS [valid: BOOL, arg, arg2: REAL ¬ 0.0] ~ {
s: IO.STREAM;
valid ¬ SELECT sel.Length[] FROM
> 1 => TRUE,
> 0 => sel.Fetch[0] IN ['0 .. '9],
ENDCASE => FALSE;
IF NOT valid THEN RETURN;
s ¬ IO.RIS[sel];
{
ENABLE IO.Error, IO.EndOfStream => {
valid ¬ FALSE;
Feedback.PutF[router, oneLiner, $Complaint, "Select a number, not %g", IO.refAny[sel]];
CONTINUE};
arg ¬ arg2 ¬ s.GetReal[];
IF diffOK AND (NOT s.EndOf[]) AND s.PeekChar[]=': THEN {
IF NOT s.GetChar[]=': THEN ERROR;
arg2 ¬ s.GetReal[];
valid ¬ valid};
IF NOT s.EndOf[] THEN IO.Error[ec: SyntaxError, stream: s];
};
s.Close[];
};
WindowBigEnough: PROC [ggData: GGData] RETURNS [BOOL] = {
iconW, iconH: INT ¬ 0;
w: INT ¬ GGState.GetWidth[ggData];
h: INT ¬ GGState.GetHeight[ggData];
[iconW, iconH] ¬ GGViewerOps.GetIconSize[];
RETURN [w>iconW AND h>iconH];
};
GetBiScroller: PROC [ggData: GGData] RETURNS [bs: BiScrollers.BiScroller] = {
RETURN [IF WindowBigEnough[ggData] THEN GGState.GetBiScroller[ggData] ELSE NIL]; -- NIL means viewer is iconic or pathologically small
};
ScalePop: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
key: REF ¬ event.rest.first;
sel: Rope.ROPE ¬ NARROW[event.rest.rest.first];
valid: BOOL;
op: GGState.ScaleOp;
arg, arg2: REAL;
[valid, arg, arg2] ¬ GetArg[TRUE, sel, ggData.router];
IF NOT valid THEN arg ¬ arg2 ¬ 2.0;
IF key=$Shrink THEN {arg ¬ 1.0/arg; arg2 ¬ 1.0/arg2};
op ← SELECT key FROM
$Magnify, $Shrink => IF arg=arg2 THEN [byArg[arg]] ELSE [diff[arg, arg2]],
$Reset => [reset[]],
ENDCASE => ERROR;
GGState.BiScrollersScale[ggData, op];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
RotatePop: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
key: REF ¬ event.rest.first;
sel: Rope.ROPE ¬ NARROW[event.rest.rest.first];
valid: BOOL;
op: GGState.RotateOp;
arg: REAL;
[valid, arg] ¬ GetArg[FALSE, sel, ggData.router];
IF NOT valid THEN arg ¬ 90;
op ← SELECT key FROM
$Left => [byArg[arg]],
$Right => [byArg[-arg]],
$Half => [byArg[180]],
$Reset => [reset[]],
ENDCASE => ERROR;
GGState.BiScrollersRotate[ggData, op];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
FitPop: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
key: REF ¬ event.rest.first;
uniformly: BOOL ~ SELECT key FROM
$FitUniformly => TRUE,
$FitXY => FALSE,
ENDCASE => ERROR;
BiScrollersFit[ggData, uniformly];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
Norm: PROC [t: Transformation, axis: Axis] RETURNS [norm: Vec] = {
tn: Geom2D.Trans ¬ Geom2D.ToTrans[t];
SELECT axis FROM
X => norm ¬ [tn.dxdx, tn.dxdy];
Y => norm ¬ [tn.dydx, tn.dydy];
ENDCASE => ERROR;
};
BiScrollersFit: PROC [ggData: GGData, uniformly: BOOL] = {
old: Transformation = GGState.GetBiScrollersTransform[ggData];
viewport: Imager.Rectangle ¬ GGState.GetViewport[ggData];
cw: REAL ← viewport.w;
ch: REAL ← viewport.h;
normX: Vec ¬ Norm[old, X];
normY: Vec ¬ Norm[old, Y];
minX, maxX: Vec;
minY, maxY: Vec;
limits: Imager.Box;
from, to: Geom2D.Rect;
[minX, maxX] ← GGExtremaProc[ggData, normX];
[minY, maxY] ← GGExtremaProc[ggData, normY];
[limits.xmin, limits.xmax] ¬ ViewLimitsOfImage[old, minX, maxX, X];
[limits.ymin, limits.ymax] ¬ ViewLimitsOfImage[old, minY, maxY, Y];
from ¬ ImagerBox.RectangleFromBox[limits];
to ¬ [0, 0, cw, ch];
GGState.BiScrollersBoxScale[ggData, from, to, uniformly];
};
ViewLimitsOfImage: PROC [t: Transformation, min, max: Vec, axis: Axis] RETURNS [vmin, vmax: REAL] = {
min ¬ t.Transform[min];
max ¬ t.Transform[max];
SELECT axis FROM
X => {vmin ¬ min.x; vmax ¬ max.x};
Y => {vmin ¬ min.y; vmax ¬ max.y};
ENDCASE => ERROR;
};
GGExtremaProc: PROC [ggData: GGData, direction: Vec] RETURNS [min, max: Vec] = {
Mostly copied from GGWindowImpl.GGExtremaProc
area: Geom2D.Rect;
bigBox: BoundBox ¬ GGBoundBox.BoundBoxOfBoxes[GGScene.BoundBoxesInScene[ggData.scene].list];
area ¬ IF bigBox#NIL THEN [x: bigBox.loX, y: bigBox.loY, w: bigBox.hiX-bigBox.loX, h: bigBox.hiY-bigBox.loY] ELSE [0.0, 0.0, 1.0, 1.0];
[min, max] ¬ Geom2D.ExtremaOfRect[r: area, n: direction];
};
paperHeight: REAL = 11.0*72.0;
paperWidth: REAL = 8.5*72.0;
ResetPop: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
key: REF ¬ event.rest.first;
SELECT key FROM
$Vanilla => {
viewport: Imager.Rectangle ¬ GGState.GetViewport[ggData];
cw: REAL ← viewport.w;
ch: REAL ← viewport.h;
vanilla: Transformation;
vanilla ← ImagerTransformation.Translate[[(cw-paperWidth)/2.0, (ch-paperHeight)/2.0]];
bs.style.ChangeTransform[bs: bs, new: vanilla, ageOp: remember, paint: FALSE];
GGState.SetBiScrollersTransform[ggData, vanilla, FALSE, remember];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE]; -- paint properly
};
$VanillaAndCenter => {
viewport: Imager.Rectangle ¬ GGState.GetViewport[ggData];
cw: REAL ← viewport.w;
ch: REAL ← viewport.h;
vanilla: Transformation;
vanilla ← ImagerTransformation.Translate[[(cw-paperWidth)/2.0, (ch-paperHeight)/2.0]];
bs.style.ChangeTransform[bs: bs, new: bs.class.common.vanilla[bs], ageOp: remember, paint: FALSE];
GGState.SetBiScrollersTransform[ggData, vanilla, FALSE, remember];
};
$Center => NULL;
ENDCASE => ERROR;
SELECT key FROM
$Center, $VanillaAndCenter => {
GGState.BiScrollersAlign[
ggData: ggData,
client: [fraction[0.5, 0.5]],
viewer: [fraction[0.5, 0.5]],
doX: TRUE,
doY: TRUE,
ageOp: remember];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
IF key = $Center THEN remember ELSE ignore -- can't express this in BiScrollers.Align
$Vanilla => NULL;
ENDCASE => ERROR;
};
};
EdgePop: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
key: REF ¬ event.rest.first;
loc: fraction BiScrollersTransformsTypes.Location ¬ [fraction[0, 0]];
doX, doY: BOOL ¬ TRUE;
SELECT key FROM
$Left => {loc.fx ¬ 0; doY ¬ FALSE};
$Right => {loc.fx ¬ 1; doY ¬ FALSE};
$Bottom => {loc.fy ¬ 0; doX ¬ FALSE};
$Top => {loc.fy ¬ 1; doX ¬ FALSE};
$BotLeft => loc ¬ [fraction[0, 0]];
$MidLeft => loc ¬ [fraction[0, 0.5]];
$TopLeft => loc ¬ [fraction[0, 1]];
$BotMiddle => loc ¬ [fraction[0.5, 0]];
$BotRight => loc ¬ [fraction[1, 0]];
$MidRight => loc ¬ [fraction[1, 0.5]];
$TopRight => loc ¬ [fraction[1, 1]];
$TopMiddle => loc ¬ [fraction[0.5, 1]];
ENDCASE => ERROR;
GGState.BiScrollersAlign[
ggData: ggData,
client: loc,
viewer: loc,
doX: doX,
doY: doY,
ageOp: remember];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
CenterSel: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
bBox: BoundBox ¬ GGScene.BoundBoxOfSelected[ggData.scene, normal];
IF bBox.null THEN {
IF GGCaret.Exists[ggData.caret] THEN {
caretPos: Point ¬ GGCaret.GetPoint[ggData.caret];
GGState.BiScrollersAlign[
ggData: ggData,
client: [variant: coord[x: caretPos.x, y: caretPos.y]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
doX: TRUE,
doY: TRUE,
ageOp: remember];
BiScrollers.Align[
bs: bs,
client: [variant: coord[x: caretPos.x, y: caretPos.y]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
paint: FALSE];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
}
ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "CenterSel failed: either a selection or a caret is required to center"];
}
ELSE {
BiScrollers.Align[
bs: bs,
client: [variant: coord[x: (bBox.loX+bBox.hiX)/2.0, y: (bBox.loY+bBox.hiY)/2.0]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
paint: FALSE];
GGState.BiScrollersAlign[
ggData: ggData,
client: [variant: coord[x: (bBox.loX+bBox.hiX)/2.0, y: (bBox.loY+bBox.hiY)/2.0]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
doX: TRUE,
doY: TRUE,
ageOp: remember];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
};
CenterCaret: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
IF GGCaret.Exists[ggData.caret] THEN {
caretPos: Point ¬ GGCaret.GetPoint[ggData.caret];
BiScrollers.Align[
bs: bs,
client: [variant: coord[x: caretPos.x, y: caretPos.y]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
paint: FALSE];
GGState.BiScrollersAlign[
ggData: ggData,
client: [variant: coord[x: caretPos.x, y: caretPos.y]],
viewer: [variant: fraction[fx: 0.5, fy: 0.5]],
doX: TRUE,
doY: TRUE,
ageOp: remember];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
}
ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "CenterCaret failed: a caret is required to center"];
};
};
FitSel: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
tbBox, vBox, tvBox: Geom2D.Rect;
cToV: Transformation;
bBox: BoundBox ¬ GGScene.BoundBoxOfSelected[scene: ggData.scene, selectClass: normal];
IF bBox.null THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "FitSel failed: a selection is required to fit"]
ELSE {
cToV ¬ BiScrollers.GetStyle[].GetTransforms[bs].clientToViewer;
cToV ¬ GGState.GetBiScrollersTransform[ggData];
tbBox ¬ ImagerTransformation.TransformRectangle[cToV, GGBoundBox.RectangleFromBoundBox[bBox] ];
vBox ¬ BiScrollers.ViewportBox[bs];
vBox ¬ GGState.GetViewport[ggData];
tvBox ¬ ImagerTransformation.TransformRectangle[cToV, vBox];
BiScrollers.BoxScale[bs: bs, from: tbBox, to: tvBox, paint: FALSE];
Change scale and offsets so that client data previously in `from' covers as much as possible of `to' (from and to in viewer coords).
GGState.BiScrollersBoxScale[ggData: ggData, from: tbBox, to: tvBox, uniformly: TRUE];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
};
PrevTransform: PUBLIC UserInputProc = {
bigEnough: BOOL ¬ WindowBigEnough[ggData];
IF NOT bigEnough THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, complainAboutIconic];
}
ELSE {
bs.style.ChangeTransform[
bs: bs,
new: bs.style.GetTransforms[bs, previous].clientToViewer,
ageOp: remember,
paint: FALSE];
GGState.BiScrollersPreviousTransform[ggData];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
};
SetBiScrollersTransform: PUBLIC UserInputProc = {
rope: Rope.ROPE ¬ NARROW[event.rest.first];
clientToViewer: Transformation ¬ GGDescribe.FactoredTransformationFromRope[rope ! GGParseIn.SyntaxError => GOTO SyntaxError];
GGState.SetBiScrollersTransform[ggData, clientToViewer];
EXITS
SyntaxError => Feedback.Append[ggData.router, oneLiner, $Complaint, "SetBiScrollersTransform failed: select a legal factored transformation for SetBiScrollersTransform"];
};
ShowBiScrollersTransform: PUBLIC UserInputProc = {
clientToViewer: Imager.Transformation ¬ GGState.GetBiScrollersTransform[ggData];
Feedback.PutF[ggData.router, oneLiner, $Show, "BiScrollers transform: %g", [rope[GGDescribe.FactoredTransformationToRope[clientToViewer] ]] ];
};
ScrollBar: UserInputProc = {
newEvent: LIST OF REF ¬ CONS[$First, event]; -- so no paint occurs with clearClient = TRUE
BiScrollers.DoBSUserAction[bs, newEvent];
GGState.DoBSUserAction[ggData, newEvent];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
OneZoom: UserInputProc = {
ggData.embed.scrollDue is updated in GGUserImpl.ProcessAndQueueEvent.
IF IsIdentity[ggData.embed.scrollDue] THEN RETURN;
GGState.BiScrollersTransform[ggData, ggData.embed.scrollDue];
ggData.embed.scrollDue ¬ ImagerTransformation.Scale[1.0];
GGScrollMonitor.UpdateBiScrollersTransformAndClearDue[ggData];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
ggData.embed.scrollDue is updated in GGUserImpl.ProcessAndQueueEvent.
identity: Transformation = ImagerTransformation.Scale[1.0];
IsIdentity: PROC [m: Transformation] RETURNS [BOOL] = {
RETURN[ImagerTransformation.Equal[m, identity]];
};
OneScroll: UserInputProc = {
this code implements the following behavior: scrolling while DuringCaretPos leaves the caret at the same place in the viewer while the scroll happens.
clientToViewer, viewerToClient: Transformation;
caretPoint: Point;
caretViewer: Point;
caretClient: Point;
IF IsIdentity[ggData.embed.scrollDue] THEN RETURN;
clientToViewer ¬ GGState.GetBiScrollersTransform[ggData];
caretPoint ¬ GGCaret.GetPoint[ggData.caret];
caretViewer ¬ ImagerTransformation.Transform[clientToViewer, caretPoint];
GGState.BiScrollersTransform[ggData, ggData.embed.scrollDue];
ggData.embed.scrollDue ¬ ImagerTransformation.Scale[1.0];
GGScrollMonitor.UpdateBiScrollersTransformAndClearDue[ggData];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
viewerToClient ¬ GGState.GetBiScrollersTransforms[ggData].viewerToClient;
caretClient ¬ ImagerTransformation.Transform[viewerToClient, caretViewer];
GGMouseEvent.HandleMouse[ggData, LIST[$During, NEW[Point ¬ caretClient]]];
};
ViewersPaintEntireScene: PUBLIC UserInputProc = {
PROC [ggData: GGData, event: LIST OF REF];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, FALSE, TRUE];
};
ViewersPaintAllPlanes: PUBLIC UserInputProc = {
PROC [ggData: GGData, event: LIST OF REF];
GGWindow.RestoreScreenAndInvariants[$ViewersPaintAllPlanes, ggData, none, FALSE, FALSE, TRUE];
};
Alignment Operations
MakeHot: PUBLIC UserInputProc = {
IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "MakeHot failed: select some objects for MakeHot"]
ELSE {
MakeSliceHot: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
GGSelect.SelectSlice[sliceD, ggData.scene, hot];
};
UpdateTriggerAndAlignBags: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
sliceFeature: FeatureData ¬ GGAlign.AddSliceFeature[sliceD, triggerBag];
alignObjects: LIST OF FeatureData;
alignObjects ¬ GGAlign.IncrementalNewTrigger[sliceFeature, filterLists, NOT showAlignments, alignBag];
GGRefresh.NoteNewForeground[ggData, alignObjects]; -- fix foreground plane
};
showAlignments: BOOL ¬ GGState.GetShowAlignments[ggData];
triggerBag: TriggerBag ¬ ggData.hitTest.triggerBag;
alignBag: AlignBag ¬ ggData.hitTest.alignBag;
filterLists: FilterLists ¬ GGState.GetFilterLists[ggData];
CodeTimer.StartInt[$MakeHot, $Gargoyle];
Make all normal selected slices hot.
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceHot, normal];
Fix the trigger bags, object bags, and Foreground plane (for efficiency).
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, first, UpdateTriggerAndAlignBags, hot];
Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeHot: selected objects made hot"];
GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: FALSE];
CodeTimer.StopInt[$MakeHot, $Gargoyle];
};
};
MakeAllHot: PUBLIC UserInputProc = {
MakeSliceHot: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = {
GGSelect.SelectEntireSlice[slice, ggData.scene, hot];
};
triggerBag: TriggerBag ¬ ggData.hitTest.triggerBag;
alignBag: AlignBag ¬ ggData.hitTest.alignBag;
CodeTimer.StartInt[$MakeAllHot, $Gargoyle];
Make all slices hot.
[] ¬ GGScene.WalkSlices[ggData.scene, first, MakeSliceHot];
Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeAllHot: all objects made hot"];
GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, ggData: ggData, remake: triggerBagNotSceneBag, edited: FALSE, okToSkipCapture: FALSE];
CodeTimer.StopInt[$MakeAllHot, $Gargoyle];
};
MakeCold: PUBLIC UserInputProc = {
IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "MakeCold failed: select some objects for MakeCold"]
ELSE {
MakeSliceCold: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, ggData.scene, hot];
};
CodeTimer.StartInt[$MakeCold, $Gargoyle];
Make all normal selected slices cold.
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceCold, normal];
Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeCold: selected objects made cold"];
GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE];
CodeTimer.StopInt[$MakeCold, $Gargoyle];
};
};
MakeAllCold: PUBLIC UserInputProc = {
MakeSliceCold: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, ggData.scene, hot];
};
CodeTimer.StartInt[$MakeAllCold, $Gargoyle];
Find all hot slices and make them cold.
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, first, MakeSliceCold, hot];
Feedback.Append[ggData.router, oneLiner, $Feedback, "MakeCold: all objects made cold"];
GGWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: FALSE];
CodeTimer.StopInt[$MakeAllCold, $Gargoyle];
};
DropAnchor: PUBLIC UserInputProc = {
IF GGCaret.Exists[ggData.caret] THEN {
IF GGCaret.Exists[ggData.anchor] THEN GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, anchor: TRUE]
ELSE GGRefresh.NullStartBox[ggData];
GGCaret.Copy[to: ggData.anchor, from: ggData.caret];
[] ¬ GGAlign.CreateAnchorTrigger[ggData.anchor, ggData.hitTest.triggerBag];
Feedback.Append[ggData.router, oneLiner, $Feedback, "DropAnchor: anchor dropped"];
GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorAdded, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
}
ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "DropAnchor failed: caret needed to drop anchor"];
};
LiftAnchor: PUBLIC UserInputProc = {
IF GGCaret.Exists[ggData.anchor] THEN {
GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, anchor: TRUE, alignments: TRUE];
GGCaret.Kill[ggData.anchor];
Feedback.Append[ggData.router, oneLiner, $Feedback, "LiftAnchor: anchor lifted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $AnchorRemoved, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: TRUE];
}
ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "LiftAnchor failed: no anchor"];
};
StandardAlignments: PUBLIC UserInputProc = {
StandardSlopes[ggData, event];
StandardAngles[ggData, event];
StandardRadii[ggData, event];
StandardDistances[ggData, event];
IF event.first = $StandardAlignments THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "StandardAlignments: standard alignments set"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
ClearAlignments: PUBLIC UserInputProc = {
ClearSlopes[ggData, event];
ClearAngles[ggData, event];
ClearRadii[ggData, event];
ClearDistances[ggData, event];
IF event.first = $ClearAlignments THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "ClearAlignments: alignments cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
AllAlignmentsOff: PUBLIC UserInputProc = {
SlopePrompt[ggData, event];
AnglePrompt[ggData, event];
RadiusPrompt[ggData, event];
DistancePrompt[ggData, event];
GGState.SetMidpoints[ggData, FALSE];
IF event.first = $AllAlignmentsOff THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "AllAlignmentsOff: all alignments off"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
InitializeAlignments: PUBLIC UserInputProc = {
Does AllAlignmentsOff, turns alignment processing on, sets the gravity extent to a default value, turns gravity on, sets gravity type to PreferPoints, resets the radius unit and turns heuristics on. This is done before creating or playing a session log to get repeatable results.
AllAlignmentsOff[ggData, event];
IF event.first = $InitializeAlignments THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "InitializeAlignments: alignments initialized"];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
Screen style
DisplayStyleChange: PUBLIC UserInputProc = {
forward: BOOL ¬ event.rest.first = $FlipForward;
camera: Camera ¬ ggData.camera;
SetTextDisplayStyle: PROC [slice: Slice] RETURNS [done: BOOL ¬ FALSE] = {
GGSlice.SetTextDisplayStyle[slice, camera.displayStyle, NIL];
};
GGState.CycleDisplayStyle[ggData, forward];
[] ¬ GGScene.WalkSlices[scene: ggData.scene, level: leaf, walkProc: SetTextDisplayStyle, classType: $Text];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Display style changed"];
GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: none, edited: FALSE, okToSkipCapture: TRUE];
};
ToggleShowAlignments: PUBLIC UserInputProc = {
GGState.SetShowAlignments[ggData, NOT GGState.GetShowAlignments[ggData]];
IF event.first = $ToggleShowAlignments THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE];
};
SetShowAlignments: PUBLIC UserInputProc = {
boolRope: Rope.ROPE ¬ NARROW[event.rest.first];
showAlignments: BOOL ¬ GGCoreOps.RopeToBool[boolRope];
GGState.SetShowAlignments[ggData, showAlignments];
};
ToggleMidpoints: PUBLIC UserInputProc = {
GGState.SetMidpoints[ggData, NOT GGState.GetMidpoints[ggData]];
IF event.first = $ToggleMidpoints THEN GGWindow.RestoreScreenAndInvariants[paintAction: $None, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE];
};
SetMidpoints: PUBLIC UserInputProc = {
boolRope: Rope.ROPE ¬ NARROW[event.rest.first];
setMidpoints: BOOL ¬ GGCoreOps.RopeToBool[boolRope];
GGState.SetMidpoints[ggData, setMidpoints];
};
ToggleHeuristics: PUBLIC UserInputProc = {
GGState.SetHeuristics[ggData, NOT GGState.GetHeuristics[ggData]];
IF event.first = $ToggleHeuristics THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, edited: FALSE, okToSkipCapture: TRUE];
};
SetHeuristics: PUBLIC UserInputProc = {
boolRope: Rope.ROPE ¬ NARROW[event.rest.first];
setHeuristics: BOOL ¬ GGCoreOps.RopeToBool[boolRope];
GGState.SetHeuristics[ggData, setHeuristics];
};
SetDisplayStyle: PUBLIC UserInputProc = {
styleRope: Rope.ROPE ¬ NARROW[event.rest.first];
style: DisplayStyle ¬ GGUIUtility.DisplayStyleFromRope[styleRope];
GGState.SetDisplayStyle[ggData, style];
};
Units Menu
ScaleUnitAux: PROC [ggData: GGData, distance: REAL, noisy: BOOL] = {
IF distance <=0.0 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "SetUnits failed: zero or illegal unit value"]
ELSE {
currentEvent: HistoryEvent ¬ GGHistory.NewCurrent["Set scale unit", ggData]; -- start new history event;
GGState.SetScaleUnit[ggData, distance, currentEvent]; -- in screen dots
GGHistory.PushCurrent[ggData];
IF noisy THEN PrintScaleUnit[ggData, NIL];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
ScaleUnitFromSegment: PUBLIC UserInputProc = {
IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]#1 THEN GOTO NoNoNoNoNO
ELSE {
distance: REAL ¬ 0.0; -- illegal scale unit
firstSliceD: SliceDescriptor ¬ GGScene.FirstSelectedSlice[ggData.scene, leaf, normal];
segGen: SegmentGenerator ¬ GGSliceOps.SegmentsInDescriptor[firstSliceD];
firstSeg: Segment ¬ GGSliceOps.NextSegment[firstSliceD.slice, segGen].seg;
nextSeg: Segment ¬ GGSliceOps.NextSegment[firstSliceD.slice, segGen].seg;
IF firstSeg=NIL OR nextSeg#NIL THEN GOTO NoNoNoNoNO;
distance ¬ Vectors2d.Distance[firstSeg.lo, firstSeg.hi];
ScaleUnitAux[ggData, distance, TRUE];
};
EXITS
NoNoNoNoNO => {
Feedback.Append[ggData.router, oneLiner, $Complaint, "UnitsFromSegment failed: select a single segment to set Units"];
};
};
ScaleUnitFromValue: PUBLIC UserInputProc = {
radius: REAL;
success: BOOL ¬ FALSE;
[radius, success] ¬ GGState.GetRadiusValue[ggData];
IF success THEN ScaleUnitAux[ggData, radius*ggData.hitTest.scaleUnit, TRUE];
};
ScaleUnitFromSelection: PUBLIC UserInputProc = {
distance: REAL ¬ WITH event.rest.first SELECT FROM
real: REF REAL => real­,
int: REF INT => REAL[int­],
ENDCASE => -1.0;
IF distance>reallyBigReal OR distance=LAST[INT] OR distance <= 0.0 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "UnitsFromSelection failed: select a positive real number (in inches) for unit"]
ELSE ScaleUnitAux[ggData, distance*72.0, TRUE]; -- screen dots
};
SetScaleUnit: PUBLIC UserInputProc = {
points: REAL ¬ NARROW[event.rest.first, REF REAL]­;
noisy: ATOM ¬ NARROW[event.rest.rest.first];
ScaleUnitAux[ggData, points, noisy = $Noisy];
};
InchScaleUnit: PUBLIC UserInputProc = {
SetScaleUnit[ggData, LIST[$SetScaleUnit, NEW[REAL ¬ pointsPerIn], $Quiet]];
};
PrintScaleUnit: PUBLIC UserInputProc = {
scale: REAL ¬ GGState.GetScaleUnit[ggData: ggData];
Feedback.PutFL[ggData.router, oneLiner, $Show, "Current scale is %g points = %g inches = %g centimeters", LIST[[real[scale]], [real[scale/pointsPerIn]], [real[scale/pointsPerCm]]] ];
};
Slope Line
standardSlopeDegrees: LIST OF REAL ¬ LIST[150.0, 135.0, 120.0, 90.0, 60.0, 45.0, 30.0, 0.0];
StandardSlopes: PUBLIC UserInputProc = {
GGState.NewSlopeList[ggData, standardSlopeDegrees];
IF event.first = $StandardSlopes THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard slopes installed"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
SetSlopes: PUBLIC UserInputProc = {
slopeRope: Rope.ROPE;
values: LIST OF REAL;
on: LIST OF BOOL;
slopeRope ¬ IF ISTYPE[event.rest.first, REF TEXT] THEN Rope.FromRefText[NARROW[event.rest.first]] ELSE NARROW[event.rest.first];
[----, values, on] ¬ GGDescribe.ScalarButtonValuesFromRope[slopeRope];
FOR nextValues: LIST OF REAL ¬ values, nextValues.rest UNTIL nextValues = NIL DO
AddSlopeInternal[ggData, nextValues.first, on.first];
on ¬ on.rest;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
ClearSlopes: PROC [ggData: GGData, event: LIST OF REF] = {
GGState.NewSlopeList[ggData, NIL];
IF event.first = $ClearSlopes THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: FALSE, okToSkipCapture: TRUE];
};
};
SlopePrompt: PUBLIC UserInputProc = {
GGState.SetAllAlignmentStates[ggData, slope, FALSE];
IF event.first = $SlopePrompt THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
AddSlope: PUBLIC UserInputProc = {
adds slope from angle viewer in measure line
If slopeViewValue was set internally, viewer and value will be consistent.
If SlopeValue viewer was set by typein, viewer and value will be inconsistent.
slope: REAL;
success: BOOL;
[slope, success] ¬ GGState.GetSlopeValue[ggData];
IF NOT success THEN RETURN;
[] ¬ GGState.AddSlope[ggData, slope];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Slope added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
AddSlopeInternal: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL ¬ FALSE] = {
only positive slopes, please
IF degrees<0.0 THEN degrees ¬ degrees+180.0;
IF degrees=360.0 THEN degrees ¬ 0.0;
ggData.measure.slopeViewValue ¬ degrees;
[] ¬ GGState.AddSlope[ggData, degrees, on];
};
DeleteSlope: PUBLIC UserInputProc = {
GGState.DeleteSelectedAlignments[ggData, slope];
ggData.measure.slopeViewValue ¬ Real.LargestNumber; -- invalidate cached value
Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes deleted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
GetSlope: PUBLIC UserInputProc = {
Gets selected segment slopes, adds to slope menu and turns it on
IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetSlope"]
ELSE {
DoGetSlope: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
segGen: SegmentGenerator ¬ GGSliceOps.SegmentsInDescriptor[sliceD];
FOR nextSeg: Segment ¬ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO
[] ¬ GGState.AddSlope[ggData, GGMeasure.SlopeOfSegment[nextSeg]];
ENDLOOP;
};
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetSlope, normal];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Slopes added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
ToggleSlope: PUBLIC UserInputProc = {
menuValue: REAL;
changedToOn: BOOL ¬ FALSE;
paintAction: ATOM;
remake: GGWindow.ForegroundParts ¬ alignBag;
CodeTimer.StartInt[$ToggleSlope, $Gargoyle];
[menuValue, changedToOn, paintAction] ¬ ToggleAux[ggData, event, slope];
IF changedToOn THEN {
alignObjects: LIST OF FeatureData;
hideAlignments: BOOL ¬ NOT GGState.GetShowAlignments[ggData];
alignObjects ¬ GGAlign.IncrementalNewFilter[menuValue, slope, ggData.hitTest.triggerBag, hideAlignments, ggData.hitTest.alignBag];
GGRefresh.NoteNewForeground[ggData, alignObjects];
remake ¬ none;
}
ELSE remake ¬ alignBag;
GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE];
CodeTimer.StopInt[$ToggleSlope, $Gargoyle];
};
ToggleAux: PROC [ggData: GGData, event: LIST OF REF, type: GGState.AlignmentType] RETURNS [menuValue: REAL ¬ 777.0, changedToOn: BOOL ¬ FALSE, paintAction: ATOM] = {
argValue: REAL ¬ WITH event.rest.first SELECT FROM
real: REF REAL => real­,
int: REF INT => REAL[int­],
ENDCASE => Real.LargestNumber;
IF argValue>reallyBigReal OR argValue=LAST[INT] THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, "ToggleAux: Unreasonable real argument"];
RETURN;
};
[menuValue, changedToOn] ¬ GGState.ToggleAlignment[ggData, argValue, type];
IF changedToOn THEN paintAction ¬ $NewAlignmentsSelected
ELSE paintAction ¬ $NewAlignmentsDeselected;
};
Angle Line
standardAngles: LIST OF REAL ¬ LIST[90.0, 60.0, 45.0, 30.0, 0.0, -30.0, -45.0, -60.0, -90.0];
StandardAngles: PUBLIC UserInputProc = {
GGState.NewAngleList[ggData, standardAngles];
IF event.first = $StandardAngles THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard angles installed"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
SetAngles: PUBLIC UserInputProc = {
angleRope: Rope.ROPE;
values: LIST OF REAL;
on: LIST OF BOOL;
angleRope ¬ IF ISTYPE[event.rest.first, REF TEXT] THEN Rope.FromRefText[NARROW[event.rest.first]] ELSE NARROW[event.rest.first];
[----, values, on] ¬ GGDescribe.ScalarButtonValuesFromRope[angleRope];
FOR nextValues: LIST OF REAL ¬ values, nextValues.rest UNTIL nextValues = NIL DO
AddAngleInternal[ggData, nextValues.first, on.first];
on ¬ on.rest;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
ClearAngles: PROC [ggData: GGData, event: LIST OF REF] = {
GGState.NewAngleList[ggData, NIL];
IF event.first = $ClearAngles THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
AnglePrompt: PUBLIC UserInputProc = {
GGState.SetAllAlignmentStates[ggData, angle, FALSE];
IF event.first = $AnglePrompt THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
AddAngle: PUBLIC UserInputProc = {
adds angle from angle viewer in measure line
See comments in AddSlope
angle: REAL;
success: BOOL;
[angle, success] ¬ GGState.GetAngleValue[ggData];
IF NOT success THEN RETURN;
[] ¬ GGState.AddAngle[ggData, angle];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Angle added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
AddAngleInternal: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL ¬ FALSE] = {
IF degrees=360.0 THEN degrees ¬ 0.0;
ggData.measure.angleViewValue ¬ degrees;
[] ¬ GGState.AddAngle[ggData, degrees, on];
};
DeleteAngle: PUBLIC UserInputProc = {
GGState.DeleteSelectedAlignments[ggData, angle];
ggData.measure.angleViewValue ¬ Real.LargestNumber; -- invalidate cached value
Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles deleted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
GetAngle: PUBLIC UserInputProc = {
Gets selected segment angles, adds to angle menu and turns it on
IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN
Feedback.Append[ggData.router, oneLiner, $Complaint, "Select two or more segments for GetAngle"]
ELSE {
DoGetAngle: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
segGen: SegmentGenerator ¬ GGSliceOps.SegmentsInDescriptor[sliceD];
firstSeg, secondSeg: Segment ¬ NIL;
degrees: REAL ¬ 0.0;
FOR seg: Segment ¬ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL seg = NIL DO
IF firstSeg=NIL THEN {firstSeg ¬ seg; LOOP;};
IF secondSeg=NIL THEN secondSeg ¬ seg;
degrees ¬ GGMeasure.CounterClockwiseBetweenSegments[firstSeg, secondSeg];
[] ¬ GGState.AddAngle[ggData, degrees];
firstSeg ¬ secondSeg;
secondSeg¬ NIL;
ENDLOOP;
};
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetAngle, normal];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Angles added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
ToggleAngle: PUBLIC UserInputProc = {
menuValue: REAL;
changedToOn: BOOL ¬ FALSE;
paintAction: ATOM;
remake: GGWindow.ForegroundParts ¬ alignBag;
[menuValue, changedToOn, paintAction] ¬ ToggleAux[ggData, event, angle];
IF changedToOn THEN {
remake ¬ alignBag;
}
ELSE remake ¬ alignBag;
GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE];
};
Radius Line
standardRadii: LIST OF REAL ¬ LIST[1.0/18.0, 1.0/9.0, 0.125, 0.25, 1.0/3.0, 0.5, 2.0/3.0, 0.75, 1.0, 2.0, 4.0];
standardRadiiNames: LIST OF Rope.ROPE ¬ LIST["1/18", "1/9", "1/8", "1/4", "1/3", "1/2", "2/3", "3/4", "1", "2", "4"];
StandardRadii: PUBLIC UserInputProc = {
GGState.NewRadiusList[ggData, standardRadiiNames, standardRadii];
IF event.first = $StandardRadii THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard radii installed"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
SetRadii: PUBLIC UserInputProc = {
radiiRope: Rope.ROPE;
values: LIST OF REAL;
on: LIST OF BOOL;
names: LIST OF Rope.ROPE;
radiiRope ¬ IF ISTYPE[event.rest.first, REF TEXT] THEN Rope.FromRefText[NARROW[event.rest.first]] ELSE NARROW[event.rest.first];
[names, values, on] ¬ GGDescribe.ScalarButtonValuesFromRope[radiiRope];
FOR nextValues: LIST OF REAL ¬ values, nextValues.rest UNTIL nextValues = NIL DO
AddRadiusInternal[ggData, names.first, nextValues.first, on.first];
on ¬ on.rest;
names ¬ names.rest;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
ClearRadii: PROC [ggData: GGData, event: LIST OF REF] = {
GGState.NewRadiusList[ggData, NIL, NIL];
IF event.first = $ClearRadii THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
RadiusPrompt: PUBLIC UserInputProc = {
GGState.SetAllAlignmentStates[ggData, radius, FALSE];
IF event.first = $RadiusPrompt THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
AddRadius: PUBLIC UserInputProc = {
adds radius from Radius viewer in measure line
See comments in AddSlope
radius: REAL;
success: BOOL;
[radius, success] ¬ GGState.GetRadiusValue[ggData];
IF NOT success THEN RETURN;
[] ¬ GGState.AddRadius[ggData, NIL, radius];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Radius added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
AddRadiusInternal: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, radius: REAL, on: BOOL ¬ FALSE] = {
ggData.measure.radiusViewValue ¬ radius;
[] ¬ GGState.AddRadius[ggData, name, radius, on];
};
DeleteRadius: PUBLIC UserInputProc = {
GGState.DeleteSelectedAlignments[ggData, radius];
ggData.measure.radiusViewValue ¬ Real.LargestNumber; -- invalidate cached value
Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii deleted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
GetRadius: PUBLIC UserInputProc = {
IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN
Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetRadius"]
ELSE {
DoGetRadius: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
segGen: SegmentGenerator ¬ GGSliceOps.SegmentsInDescriptor[sliceD];
FOR nextSeg: Segment ¬ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO
radius: REAL ¬ GGMeasure.DistanceBetweenPoints[nextSeg.lo, nextSeg.hi]/ggData.hitTest.scaleUnit;
[] ¬ GGState.AddRadius[ggData, NIL, radius];
ENDLOOP;
};
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetRadius, normal];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Radii added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
ToggleRadius: PUBLIC UserInputProc = {
menuValue: REAL;
changedToOn: BOOL ¬ FALSE;
paintAction: ATOM;
remake: GGWindow.ForegroundParts ¬ alignBag;
[menuValue, changedToOn, paintAction] ¬ ToggleAux[ggData, event, radius];
IF changedToOn THEN {
remake ¬ alignBag;
}
ELSE remake ¬ alignBag;
GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE];
};
Distance Line
standardDistances: LIST OF REAL = LIST [0.0, 1.0/18.0, 1.0/9.0, 0.5, 1.0];
standardDistanceNames: LIST OF Rope.ROPE = LIST ["0", "1/18", "1/9", "1/2", "1"];
StandardDistances: PUBLIC UserInputProc = {
GGState.NewLineDistanceList[ggData, standardDistanceNames, standardDistances];
IF event.first = $StandardDistances THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Standard distances installed"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
SetDistances: PUBLIC UserInputProc = {
distanceRope: Rope.ROPE;
values: LIST OF REAL;
on: LIST OF BOOL;
names: LIST OF Rope.ROPE;
distanceRope ¬ IF ISTYPE[event.rest.first, REF TEXT] THEN Rope.FromRefText[NARROW[event.rest.first]] ELSE NARROW[event.rest.first];
[names, values, on] ¬ GGDescribe.ScalarButtonValuesFromRope[distanceRope];
FOR nextValues: LIST OF REAL ¬ values, nextValues.rest UNTIL nextValues = NIL DO
AddDistanceInternal[ggData, names.first, nextValues.first, on.first];
on ¬ on.rest;
names ¬ names.rest;
ENDLOOP;
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
ClearDistances: PROC [ggData: GGData, event: LIST OF REF] = {
GGState.NewLineDistanceList[ggData, NIL, NIL];
IF event.first = $ClearDistances THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
DistancePrompt: PUBLIC UserInputProc = {
GGState.SetAllAlignmentStates[ggData, lineDistance, FALSE];
IF event.first = $DistancePrompt THEN {
Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances cleared"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
AddDistance: PUBLIC UserInputProc = {
adds distance from LineDistance viewer in measure line
See comments in AddSlope
distance: REAL;
success: BOOL;
[distance, success] ¬ GGState.GetLineDistanceValue[ggData];
IF NOT success THEN RETURN;
[] ¬ GGState.AddLineDistance[ggData, NIL, distance];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Distance added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
AddDistanceInternal: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, distance: REAL, on: BOOL ¬ FALSE] = {
ggData.measure.lineDistViewValue ¬ distance;
[] ¬ GGState.AddLineDistance[ggData, name, distance, on];
};
DeleteDistance: PUBLIC UserInputProc = {
GGState.DeleteSelectedAlignments[ggData, lineDistance];
ggData.measure.lineDistViewValue ¬ Real.LargestNumber; -- invalidate cached value
Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances deleted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
GetDistance: PUBLIC UserInputProc = {
IF GGScene.CountSelectedSlices[ggData.scene, leaf, normal]<1 THEN
Feedback.Append[ggData.router, oneLiner, $Complaint, "Select one or more segments for GetDistance"]
ELSE {
DoGetDist: PROC [sliceD: SliceDescriptor] RETURNS [done: BOOL ¬ FALSE] = {
segGen: SegmentGenerator ¬ GGSliceOps.SegmentsInDescriptor[sliceD];
FOR nextSeg: Segment ¬ GGSliceOps.NextSegment[sliceD.slice, segGen].seg, GGSliceOps.NextSegment[sliceD.slice, segGen].seg UNTIL nextSeg=NIL DO
distance: REAL ¬ GGMeasure.LengthOfSegment[nextSeg]/ggData.hitTest.scaleUnit;
[] ¬ GGState.AddLineDistance[ggData, NIL, distance];
ENDLOOP
};
[] ¬ GGScene.WalkSelectedSlices[ggData.scene, leaf, DoGetDist, normal];
Feedback.Append[ggData.router, oneLiner, $Feedback, "Distances added"];
GGWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, ggData: ggData, remake: alignBag, edited: TRUE, okToSkipCapture: TRUE];
};
};
ToggleDistance: PUBLIC UserInputProc = {
menuValue: REAL;
changedToOn: BOOL ¬ FALSE;
paintAction: ATOM;
remake: GGWindow.ForegroundParts ¬ alignBag;
[menuValue, changedToOn, paintAction] ¬ ToggleAux[ggData, event, lineDistance];
IF changedToOn THEN {
remake ¬ alignBag;
}
ELSE remake ¬ alignBag;
GGWindow.RestoreScreenAndInvariants[paintAction: paintAction, ggData: ggData, remake: remake, edited: TRUE, okToSkipCapture: TRUE];
};
Coordinate/Measure Line
MeasureSlopeHit: PUBLIC UserInputProc = {
[] ¬ GGState.SelectSlope[ggData];
};
MeasureSlopeFromSelection: PUBLIC UserInputProc = {
slope: REAL ¬ NARROW[event.rest.first, REF REAL]­;
IF slope>reallyBigReal THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, "SlopeFromSelection failed: select a reasonable value for slope"];
RETURN;
};
GGState.SetSlopeValue[ggData, slope];
AddSlope[ggData, LIST[$AddSlope]];
};
MeasureAngleHit: PUBLIC UserInputProc = {
[] ¬ GGState.SelectAngle[ggData];
};
MeasureAngleFromSelection: PUBLIC UserInputProc = {
angle: REAL ¬ NARROW[event.rest.first, REF REAL]­;
IF angle>reallyBigReal THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, "AngleFromSelection failed: select a reasonable value for angle"];
RETURN;
};
GGState.SetAngleValue[ggData, angle];
AddAngle[ggData, LIST[$AddAngle]];
};
MeasureRadiusHit: PUBLIC UserInputProc = {
[] ¬ GGState.SelectRadius[ggData];
};
MeasureRadiusFromSelection: PUBLIC UserInputProc = {
radius: REAL ¬ NARROW[event.rest.first, REF REAL]­;
IF radius>reallyBigReal THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, "RadiusFromSelection failed: select a reasonable value for radius"];
RETURN;
};
GGState.SetRadiusValue[ggData, radius];
AddRadius[ggData, LIST[$AddRadius]];
};
MeasureLineDistHit: PUBLIC UserInputProc = {
[] ¬ GGState.SelectLineDistance[ggData];
};
MeasureLineDistFromSelection: PUBLIC UserInputProc = {
lineDist: REAL ¬ NARROW[event.rest.first, REF REAL]­;
IF lineDist>reallyBigReal THEN {
Feedback.Append[ggData.router, oneLiner, $Complaint, "DistanceFromSelection failed: select a reasonable value for line distance"];
RETURN;
};
GGState.SetLineDistanceValue[ggData, lineDist];
AddDistance[ggData, LIST[$AddDistance]];
};
Miscellaneous
DeleteCaretSegment: PUBLIC UserInputProc = {
jointNum, newEndJoint: NAT;
traj, shortTraj, smallerOutline: Slice;
smallerOutlines: LIST OF Slice;
trajEnd: TrajEnd;
chairD, trajD: SliceDescriptor;
delSeq: TrajParts;
bBoxOfTraj: BoundBox;
point: Point;
normal: Vector;
caret: Caret ¬ ggData.caret;
scene: Scene ¬ ggData.scene;
IF GGCaret.SittingOnEnd[caret] THEN { -- delete the joint and segment near the caret
success, isHot: BOOL ¬ FALSE;
delD: SliceDescriptor;
oldOutline: Slice;
chairD ¬ GGCaret.GetChair[caret];
[success, trajD, jointNum] ¬ GGSliceOps.UnpackJoint[chairD];
IF NOT success THEN ERROR Problem[msg: "Chair not simple descriptor"];
traj ¬ trajD.slice;
oldOutline ¬ GGParent.GetParent[traj];
bBoxOfTraj ¬ GGSliceOps.GetBoundBox[traj];
isHot ¬ GGSelect.IsSelectedInPart[traj, ggData.scene, hot];
SELECT jointNum FROM
0 => {newEndJoint ¬ 1; trajEnd ¬ lo};
GGTraj.HiJoint[traj] => {newEndJoint ¬ jointNum -1; trajEnd ¬ hi};
ENDCASE => ERROR Problem[msg: "failed assertion"];
point ¬ GGTraj.FetchJointPos[traj, newEndJoint];
normal ¬ GGTraj.FetchJointNormal[traj, newEndJoint];
delSeq ¬ GGSequence.LastSegAndJoint[NARROW[traj.data, TrajData], trajEnd];
GGHistory.NewCapture["Backspace segment", ggData]; -- capture scene BEFORE UPDATE
GGRefresh.SetStartBox[ggData: ggData, dragInProgress: FALSE, selectedCPs: TRUE, caret: TRUE, attractor: TRUE, hotCPs: isHot, alignments: isHot];
since the attractor is the outline containing the trajectory, this is all the startBox we should need.
GGSelect.SaveSelectionsInSliceAllClasses[chairD.slice, scene];
delD ¬ GGSlice.DescriptorFromParts[traj, delSeq];
smallerOutlines ¬ GGTraj.DeleteSequence[delD].openTrajOutlines;
smallerOutline ¬ IF smallerOutlines = NIL THEN NIL ELSE smallerOutlines.first;
IF smallerOutline = NIL THEN { -- we removed the last segment
GGCaret.SetAttractor[ggData.caret, point, normal, NIL];
GGCaret.SitOn[caret, NIL];
IF GGScene.IsTopLevel[oldOutline] THEN {
GGScene.DeleteSlice[scene, oldOutline];
}
ELSE {
cluster: Slice ¬ GGParent.GetParent[oldOutline];
smallerCluster: Slice ¬ GGSlice.RemoveChild[cluster, oldOutline];
IF smallerCluster = NIL THEN GGSlice.PruneNullClusters[scene, cluster];
};
}
ELSE {
jointParts: TrajParts;
jointD, outD: SliceDescriptor;
priority: INT;
IF GGScene.IsTopLevel[oldOutline] THEN {
priority ¬ GGScene.GetPriority[scene, oldOutline];
GGScene.DeleteSlice[scene, oldOutline];
GGScene.AddSlice[scene, smallerOutline, priority];
GGSelect.ReselectSliceAllClasses[smallerOutline, scene];
}
ELSE {
cluster: Slice ¬ GGParent.GetParent[oldOutline];
priority ¬ GGParent.GetChildPriority[cluster, oldOutline];
[] ¬ GGSlice.RemoveChild[cluster, oldOutline];
GGSlice.AddChildToCluster[cluster, smallerOutline, priority];
GGSelect.ReselectSliceAllClasses[cluster, scene];
};
Build a descriptor for the new chair.
shortTraj ¬ GGParent.FirstChild[smallerOutline, first, $Traj];
jointParts ¬ GGSequence.CreateFromJoint[NARROW[shortTraj.data], IF trajEnd = lo THEN 0 ELSE newEndJoint];
jointD ¬ GGSlice.DescriptorFromParts[shortTraj, jointParts]; -- traj descriptor
outD ¬ GGParent.TopLevelDescriptorFromChildDescriptor[jointD];
GGSelect.SelectSlice[outD, ggData.scene, normal];
GGCaret.SitOn[ggData.caret, outD];
GGCaret.SetAttractor[ggData.caret, point, normal, outD];
};
ggData.refresh.startBoundBox­ ¬ bBoxOfTraj­;
see comment in GGRefresh.SetStartBox call, above
GGHistory.PushCurrent[ggData]; -- push captured history event onto history list
Feedback.Append[ggData.router, oneLiner, $Feedback, "Backspace segment: caret segment deleted"];
GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, ggData: ggData, remake: triggerBag, edited: TRUE, okToSkipCapture: FALSE];
}
ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, "Delete segment failed: \"joint select\" the end of an open trajectory to delete"];
};
Nop: UserInputProc ~ {
};
RegisterEventProcs: PROC = {
OPEN GGUserInput;
Trackball Actions
RegisterAction[$OneScroll, OneScroll, rope2, FALSE, FALSE];
RegisterAction[$OneZoom, OneZoom, rope, FALSE, FALSE];
BiScrollers Menu
RegisterAction[$ScalePop, ScalePop, rope2];
RegisterAction[$RotatePop, RotatePop, rope2];
RegisterAction[$FitPop, FitPop, none];
RegisterAction[$ResetPop, ResetPop, none];
RegisterAction[$EdgePop, EdgePop, none];
RegisterAction[$PrevTransform, PrevTransform, none];
RegisterAction[$CenterSel, CenterSel, none];
RegisterAction[$CenterCaret, CenterCaret, none];
RegisterAction[$FitSel, FitSel, none];
RegisterAction[$SetBiScrollersTransform, SetBiScrollersTransform, rope];
RegisterAction[$ShowBiScrollersTransform, ShowBiScrollersTransform, none];
RegisterAction[$AlignFracs, ScrollBar, none];
RegisterAction[$Shift, ScrollBar, none];
RegisterAction[$ViewersPaintEntireScene, ViewersPaintEntireScene, none];
RegisterAction[$ViewersPaintAllPlanes, ViewersPaintAllPlanes, none];
Alignment Operations
RegisterAction[$MakeHot, MakeHot, none];
RegisterAction[$MakeAllHot, MakeAllHot, none];
RegisterAction[$MakeCold, MakeCold, none];
RegisterAction[$MakeAllCold, MakeAllCold, none];
RegisterAction[$DropAnchor, DropAnchor, none];
RegisterAction[$LiftAnchor, LiftAnchor, none];
RegisterAction[$StandardAlignments, StandardAlignments, none];
RegisterAction[$ClearAlignments, ClearAlignments, none];
RegisterAction[$AllAlignmentsOff, AllAlignmentsOff, none];
RegisterAction[$InitializeAlignments, InitializeAlignments, none];
Setting Parts of the Gargoyle State
RegisterAction[$ScreenChoiceChange, DisplayStyleChange, none];
RegisterAction[$ToggleShowColors, Nop, none, FALSE];
RegisterAction[$SetShowColors, Nop, none, FALSE];
RegisterAction[$ToggleMidpoints, ToggleMidpoints, none];
RegisterAction[$SetMidpoints, SetMidpoints, none, FALSE];
RegisterAction[$ToggleHeuristics, ToggleHeuristics, none];
RegisterAction[$SetHeuristics, SetHeuristics, none, FALSE];
RegisterAction[$ToggleShowAlignments, ToggleShowAlignments, none];
RegisterAction[$SetShowAlignments, SetShowAlignments, none];
RegisterAction[$SetDisplayStyle, SetDisplayStyle, rope];
Unit Line
RegisterAction[$RadiusUnitFromSegment, ScaleUnitFromSegment, none];
RegisterAction[$RadiusUnitFromValue, ScaleUnitFromValue, none];
RegisterAction[$RadiusUnitFromSelection, ScaleUnitFromSelection, refReal];
RegisterAction[$InchScaleUnit, InchScaleUnit, none];
RegisterAction[$SetScaleUnit, SetScaleUnit, none];
RegisterAction[$PrintScaleUnit, PrintScaleUnit, none];
Slope Line
RegisterAction[$SlopePrompt, SlopePrompt, none];
RegisterAction[$SetSlopes, SetSlopes, none];
RegisterAction[$AddSlope, AddSlope, none];
RegisterAction[$GetSlope, GetSlope, none];
RegisterAction[$ToggleSlope, ToggleSlope, none];
RegisterAction[$DeleteSlope, DeleteSlope, none];
Angle Line
RegisterAction[$AnglePrompt, AnglePrompt, none];
RegisterAction[$SetAngles, SetAngles, none];
RegisterAction[$AddAngle, AddAngle, none];
RegisterAction[$GetAngle, GetAngle, none];
RegisterAction[$ToggleAngle, ToggleAngle, none];
RegisterAction[$DeleteAngle, DeleteAngle, none];
Radius Line
RegisterAction[$RadiusPrompt, RadiusPrompt, none];
RegisterAction[$SetRadii, SetRadii, none];
RegisterAction[$AddRadius, AddRadius, none];
RegisterAction[$GetRadius, GetRadius, none];
RegisterAction[$ToggleRadius, ToggleRadius, none];
RegisterAction[$DeleteRadius, DeleteRadius, none];
Distance Line
RegisterAction[$DistancePrompt, DistancePrompt, none];
RegisterAction[$SetDistances, SetDistances, none];
RegisterAction[$AddDistance, AddDistance, none];
RegisterAction[$GetDistance, GetDistance, none];
RegisterAction[$ToggleDistance, ToggleDistance, none];
RegisterAction[$DeleteDistance, DeleteDistance, none];
Coordinate Line
RegisterAction[$MeasureSlopeHit, MeasureSlopeHit, none];
RegisterAction[$MeasureSlopeFromSelection, MeasureSlopeFromSelection, refReal];
RegisterAction[$MeasureAngleHit, MeasureAngleHit, none];
RegisterAction[$MeasureAngleFromSelection, MeasureAngleFromSelection, refReal];
RegisterAction[$MeasureRadiusHit, MeasureRadiusHit, none];
RegisterAction[$MeasureRadiusFromSelection, MeasureRadiusFromSelection, refReal];
RegisterAction[$MeasureLineDistHit, MeasureLineDistHit, none];
RegisterAction[$MeasureLineDistFromSelection, MeasureLineDistFromSelection, refReal];
RegisterAction[$DeleteCaretSegment, DeleteCaretSegment, none];
};
TBox: PROC RETURNS [b, t: BoundBox] = {
if: InputFocus.Focus ← InputFocus.GetInputFocus[];
ggData: GGData ¬ NARROW[BiScrollers.ClientDataOfViewer[if.owner]];
sliceD: SliceDescriptor ¬ GGScene.FirstSelectedSlice[ggData.scene, first, normal, $Text];
b ← GGSliceOps.GetBoundBox[sliceD.slice, NIL];
t ← GGSliceOps.GetTightBox[sliceD.slice, NIL];
IF TRUE THEN RETURN;
};
RegisterEventProcs[];
END.