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;
~
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.TRC ← NIL,
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:
ROPE ←
NIL] ~ {
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:
ROPE ←
NIL] ~ {
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];