TrcManualImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Eric Nickell, September 22, 1986 8:40:31 pm PDT
DIRECTORY
Abutters,
Buttons USING [ButtonProc, Create],
Convert USING [RealFromRope],
Imager USING [MaskVector, SetStrokeWidth],
ImagerBackdoor USING [GetReal],
IO,
Real USING [CompareREAL],
RedBlackTree, --using lots...
Rope USING [Equal, ROPE],
Trc,
Vector2 USING [InlineAdd, Length, Sub, VEC],
ViewerClasses USING [Viewer, ViewerRec],
ViewerOps,
ViewerTools;
TrcManualImpl: CEDAR PROGRAM
IMPORTS Abutters, Buttons, Convert, Imager, ImagerBackdoor, IO, Real, RedBlackTree, Rope, Trc, Vector2, ViewerOps, ViewerTools
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector2.VEC;
margin: NAT ~ 10;
ManualInstance: TYPE ~ REF ManualInstanceRep;
ManualInstanceRep: TYPE ~ RECORD [
xScale, yScale: REAL ← 1.0,
pins: RedBlackTree.Table ← RedBlackTree.Create[getKey: TrcManualGet, compare: TrcManualCompare]
];
Pin: TYPE ~ REF PinRep;
PinRep: TYPE ~ RECORD [
vec: Vector2.VEC
];
ManualControlData: TYPE ~ REF ManualControlDataRep;
ManualControlDataRep: TYPE ~ RECORD [
container, childControl: ViewerClasses.Viewer ← NIL,
trc: Trc.TRCNIL,
y: INTEGER
];
ManualFcn: Trc.Fcn = {
[trc: TRC, a: REAL] RETURNS [b: REAL]
VecFromRef: PROC [ref: REF] RETURNS [vec: VEC] ~ {
WITH ref SELECT FROM
p: Pin => RETURN [p^];  --This will return NIL as well
ENDCASE => ERROR;
};
instance: ManualInstance ~ NARROW[trc.instance];
left, equal, right: REF;
[left, equal, right] ← RedBlackTree.Lookup3[self: instance.pins, lookupKey: RealToRef[a]];
SELECT TRUE FROM
equal#NIL => RETURN [VecFromRef[equal].y];
left=NIL AND right=NIL => RETURN [a];
left=NIL => RETURN [NARROW[right, Pin].y];
right=NIL => RETURN [NARROW[left, Pin].y]
ENDCASE => { --We're between two pins, at least one of which is a fixed Pin.
vLeft: VEC ~ VecFromRef[left];
vRight: VEC ~ VecFromRef[right];
alpha: REAL ~ (a-vLeft.x)/(vRight.x-vLeft.x);
RETURN [(alpha*(vRight.y) + (1.0-alpha)*(vLeft.y))]
};
};
ManualBackground: Trc.BackgroundProc = {
[trc: TRC, context: Imager.Context, rectangle: ImagerTransformation.Rectangle, whatChanged: REF ← NIL]
Mark: PROC [vec: VEC] ~ INLINE {
Imager.MaskVector[context: context, p1: vec.InlineAdd[[-d,-d]], p2: vec.InlineAdd[[d,d]]];
Imager.MaskVector[context: context, p1: vec.InlineAdd[[d,-d]], p2: vec.InlineAdd[[-d,d]]];
};
instance: ManualInstance ~ NARROW[trc.instance];
w: REAL ~ ImagerBackdoor.GetReal[context: context, key: strokeWidth];
d: REAL ~ 3*w;
Imager.SetStrokeWidth[context: context, strokeWidth: w/2];
IF whatChanged=NIL THEN {
XMarksTheSpot: RedBlackTree.EachNode = {
[data: RedBlackTree.UserData] RETURNS [stop: BOOL ← FALSE]
WITH data SELECT FROM
pin: Pin => Mark[pin^];
ENDCASE => ERROR;
};
RedBlackTree.EnumerateIncreasing[self: instance.pins, procToApply: XMarksTheSpot];
}
ELSE {
WITH whatChanged SELECT FROM
atom: ATOM => NULL;  --Somebody has us layered
ENDCASE => ERROR;
};
};
ManualPickle: Trc.PickleProc = {
[trc: TRC, stream: STREAM, indentation: ROPE ← NIL]
instance: ManualInstance ~ NARROW[trc.instance];
IO.PutRope[self: stream, r: " {"];
PutValuesToStream[instance, stream, indentation];
IO.PutF[stream: stream, format: "\n%g}", v1: [rope[indentation]]];
};
ManualDepickle: Trc.DepickleProc = {
[class: Trc.Class, stream: STREAM] RETURNS [trc: TRC]
instance: ManualInstance ~ NEW[ManualInstanceRep];
token: ROPE;
tokenKind: IO.TokenKind;
trc ← NEW[Trc.TRCRep ← [class: class, instance: instance, listener: NIL]];
IF ~IO.GetCedarTokenRope[stream: stream].token.Equal["{"] THEN ERROR;
[tokenKind: tokenKind, token: token] ← IO.GetCedarTokenRope[stream: stream];
WHILE tokenKind=tokenREAL DO
x: REAL ~ Convert.RealFromRope[token];
[tokenKind: tokenKind, token: token] ← IO.GetCedarTokenRope[stream: stream];
SELECT tokenKind FROM
tokenREAL => RedBlackTree.Insert[self: instance.pins, dataToInsert: NEW[PinRep ← [[x: x, y: Convert.RealFromRope[token]]]], insertKey: RealToRef[x]];
ENDCASE => ERROR;
[tokenKind: tokenKind, token: token] ← IO.GetCedarTokenRope[stream: stream];
ENDLOOP;
[tokenKind: tokenKind, token: token] ← IO.GetCedarTokenRope[stream: stream];
token ← ParseManualInstance[instance, stream];
IF ~Rope.Equal[token, "}"] THEN ERROR;
};
ManualControl: Trc.BuildControlViewerProc = {
[trc: TRC, info: ViewerClasses.ViewerRec, paint: BOOL] RETURNS [viewer: ViewerClasses.Viewer]
text, button: ViewerClasses.Viewer;
instance: ManualInstance;
IF trc.instance=NIL THEN { --Need to instantiate viewer
trc.instance ← instance ← NEW[ManualInstanceRep];
}
ELSE instance ← NARROW[trc.instance];
viewer ← Abutters.Create[viewerFlavor: Abutters.vanilla, info: info, paint: paint].QuaViewer;
text ← ViewerTools.MakeNewTextViewer[info: [parent: viewer, wx: 5, wy: 25, wh: 200, ww: 200], paint: FALSE];
{
contents: IO.STREAM ~ IO.ROS[];
PutValuesToStream[instance, contents];
ViewerTools.SetContents[viewer: text, contents: IO.RopeFromROS[self: contents], paint: FALSE];
};
ViewerOps.AddProp[viewer: text, prop: $Trc, val: trc];
button ← Buttons.Create[info: [parent: viewer, wx: 5, wy: 5, name: "Read"], proc: ReadViewer, clientData: text, paint: FALSE];
ViewerOps.MoveViewer[viewer: viewer, x: viewer.wx, y: viewer.wy, w: text.wx+text.ww+5, h: text.wy+text.wh+5, paint: paint];
};
ManualCopy: Trc.CopyProc = {
[trc: TRC] RETURNS [new: TRC]
CopyEachPin: RedBlackTree.EachNode = {
[data: RedBlackTree.UserData] RETURNS [stop: BOOL ← FALSE]
RedBlackTree.Insert[self: newInstance.pins, dataToInsert: data, insertKey: data];
};
instance: ManualInstance ~ NARROW[trc.instance];
newInstance: ManualInstance ~ NEW[ManualInstanceRep];
new ← NEW[Trc.TRCRep ← [class: trc.class, instance: newInstance, listener: NIL]];
RedBlackTree.EnumerateIncreasing[self: instance.pins, procToApply: CopyEachPin];
};
manualClass: Trc.Class ~ NEW[Trc.ClassRep ← [
flavor: $Manual,
fcn: ManualFcn,
blockFcn: Trc.DefaultBlockFcn,
copy: ManualCopy,
pickle: ManualPickle,
depickle: ManualDepickle,
notify: NIL,
background: ManualBackground,
control: ManualControl,
classData: NIL
]];
ReadViewer: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
text: ViewerClasses.Viewer ~ NARROW[clientData];
trc: Trc.TRC ~ NARROW[ViewerOps.FetchProp[viewer: text, prop: $Trc]];
instance: ManualInstance ~ NARROW[trc.instance];
stream: IO.STREAM ~ IO.RIS[rope: ViewerTools.GetContents[viewer: text]];
[] ← ParseManualInstance[instance, stream];
Trc.NotifyListeners[trc: trc, fork: TRUE];
};
ParseManualInstance: PROC [instance: ManualInstance, stream: IO.STREAM] RETURNS [token: ROPENIL] ~ {
tokenKind: IO.TokenKind;
{
ENABLE IO.EndOfStream => {token ← NIL; tokenKind ← tokenEOF; CONTINUE};
instance.pins ← RedBlackTree.Create[getKey: TrcManualGet, compare: TrcManualCompare];
instance.xScale ← instance.yScale ← 1.0;
DO--Get any scale factors
[token: token, tokenKind: tokenKind] ← IO.GetCedarTokenRope[stream: stream];
SELECT tokenKind FROM
tokenID => SELECT TRUE FROM
Rope.Equal[s1: token, s2: "xScale", case: FALSE] => instance.xScale ← Convert.RealFromRope[IO.GetCedarTokenRope[stream: stream].token];
Rope.Equal[s1: token, s2: "yScale", case: FALSE] => instance.yScale ← Convert.RealFromRope[IO.GetCedarTokenRope[stream: stream].token];
ENDCASE => ERROR;
ENDCASE => EXIT;
ENDLOOP;
DO
SELECT tokenKind FROM
tokenDECIMAL, tokenREAL => {
x: REAL ~ Convert.RealFromRope[token]/instance.xScale;
y: REAL ~ Convert.RealFromRope[IO.GetCedarTokenRope[stream: stream].token]/instance.yScale;
[] ← RedBlackTree.Insert[self: instance.pins, dataToInsert: NEW[PinRep ← [[x, y]]], insertKey: NEW[REAL ← x]];
[token: token, tokenKind: tokenKind] ← IO.GetCedarTokenRope[stream: stream];
};
ENDCASE => EXIT;
ENDLOOP;
};
};
PutValuesToStream: PROC [instance: ManualInstance, stream: IO.STREAM, indentation: ROPENIL] ~ {
WriteEachPin: RedBlackTree.EachNode = {
[data: RedBlackTree.UserData] RETURNS [stop: BOOL ← FALSE]
WITH data SELECT FROM
pin: Pin => IO.PutF[stream: stream, format: "\n%g\t%g\t%g", v1: [rope[indentation]], v2: [real[pin.x*instance.xScale]], v3: [real[pin.y*instance.yScale]]];
ENDCASE => ERROR;
};
IF instance.xScale#1.0 THEN IO.PutF[stream: stream, format: "\n%g\txScale %g", v1: [rope[indentation]], v2: [real[instance.xScale]]];
IF instance.yScale#1.0 THEN IO.PutF[stream: stream, format: "\n%g\tyScale %g", v1: [rope[indentation]], v2: [real[instance.yScale]]];
RedBlackTree.EnumerateIncreasing[self: instance.pins, procToApply: WriteEachPin];
};
RealToRef: PROC [real: REAL] RETURNS [ref: REF] ~ INLINE {
RETURN [NEW[REAL ← real]];
};
RefToReal: PROC [ref: REF] RETURNS [real: REAL] ~ INLINE {
WITH ref SELECT FROM
refReal: REF REAL => RETURN [refReal^];
pin: Pin => RETURN [pin.x]
ENDCASE => ERROR;
};
TrcManualGet: RedBlackTree.GetKey = {
[data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]
RETURN [data];
};
TrcManualCompare: RedBlackTree.Compare = {
[k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison]
RETURN [Real.CompareREAL[RefToReal[data], RefToReal[k]]];
};
NoPins: SIGNAL ~ CODE;
FindNearestPin: PROC [pins: RedBlackTree.Table, loc: VEC, trc: Trc.TRC] RETURNS [closest: VEC, joinPin: BOOL] ~ {
PinFromRef: PROC [ref: REF] RETURNS [pin: Pin] ~ {
IF ref=NIL THEN RETURN [NIL];
WITH ref SELECT FROM
p: Pin => RETURN [p];  --This will return NIL as well
real: REF REAL => RETURN [NEW[PinRep ← [[x: real^, y: Trc.ApplyFcn[trc, real^]]]]];
ENDCASE => ERROR;
};
left, equal, right: REF;
[left, equal, right] ← RedBlackTree.Lookup3[self: pins, lookupKey: RealToRef[loc.x]];
IF equal=NIL THEN {
pin1: Pin ~ PinFromRef[left];
pin2: Pin ~ PinFromRef[right];
pickLeft: BOOL ~ SELECT TRUE FROM
pin1=NIL AND pin2=NIL => ERROR NoPins[],
pin1=NIL => FALSE,
pin2=NIL => TRUE,
ENDCASE => pin1^.Sub[loc].Length[] < pin2^.Sub[loc].Length[];
IF pickLeft THEN RETURN [pin1^, ISTYPE[left, REF REAL]] ELSE RETURN [pin2^, ISTYPE[right, REF REAL]];
}
ELSE {
pin1: Pin ~ PinFromRef[equal];
RETURN [pin1^, ISTYPE[equal, REF REAL]];
};
};
Trc.RegisterClass[manualClass];
END.