CDRepetitionsImpl.mesa        (part of ChipNDale)
Copyright © 1983, 1986 by Xerox Corporation.  All rights reserved.
by Christian Jacobi, October 27, 1983 3:36 pm 
last edited Christian Jacobi, March 25, 1986 1:37:32 pm PST
Last Edited by: Christian Jacobi, August 18, 1986 3:40:44 pm PDT
 
DIRECTORY
CD,
CDBasics,
CDCallSpecific,
CDDirectory,
CDIO,
CDOrient,
CDProperties,
CDRepetitions,
IO,
Rope,
TokenIO;
 
CDRepetitionsImpl: 
CEDAR 
PROGRAM 
IMPORTS CD, CDRepetitions, CDBasics, CDCallSpecific, CDDirectory, CDIO, CDOrient, CDProperties, IO, TokenIO, Rope
EXPORTS CDRepetitions
SHARES CDDirectory =
 
BEGIN
RepPtr: TYPE = CDRepetitions.RepPtr;
RepRec: TYPE = CDRepetitions.RepRec;
pForRepetitions: 
CD.ObjectClass = 
CD.RegisterObjectClass[$Repetitions, [
drawMe: DrawMeForRepetitions,
quickDrawMe: QuickDrawMeForRepetitions,
internalRead: ReadRepetition,
internalWrite: WriteRepetition,
describe: Describe
]];
Describe: 
PROC [me: 
CD.Object] 
RETURNS [Rope.
ROPE] = {
rp: RepPtr = NARROW[me.specificRef];
RETURN [
IO.PutFR[
"repetition [%g] ""%g""", 
[integer[rp.count]], 
[rope[CDDirectory.Name[me]]]
]]
 
};
 
ComputeBoundsR: 
PROC [ob: 
CD.Object] 
RETURNS [
CD.Rect] = {
rp: RepPtr = NARROW[ob.specificRef];
sz: CD.Position = CDOrient.OrientedSize[rp.ob.size, rp.orientation];
toffset: CD.Position = [(rp.count-1)*rp.offset.x, (rp.count-1)*rp.offset.y];
r1: CD.Rect = CDBasics.RectAt[rp.offsetOfFirst, sz];
r2: CD.Rect = CDBasics.RectAt[CDBasics.AddPoints[rp.offsetOfFirst, toffset], sz];
RETURN CDBasics.Surround[r1, r2];
};
 
InternalCreateRepetition: 
PROC [ob: 
CD.Object, count: 
NAT, offset: 
CD.Position, orientation: 
CD.Orientation] 
RETURNS [
CD.Object] =
BEGIN
repOb: CD.Object = NEW[CD.ObjectRep];
rp: RepPtr = NEW[RepRec];
sz: CD.Position = CDOrient.OrientedSize[ob.size, orientation];
repOb.class ← pForRepetitions;
count ← MAX[1, MIN[count, 512]];
repOb.size.x ← sz.x+(count-1)*ABS[offset.x];
repOb.size.y ← sz.y+(count-1)*ABS[offset.y];
repOb.layer ← ob.layer;
rp.ob ← ob;
rp.offsetOfFirst ← [0, 0];
IF offset.x<0 THEN rp.offsetOfFirst.x← -(count-1)*offset.x;
IF offset.y<0 THEN rp.offsetOfFirst.y← -(count-1)*offset.y;
rp.orientation ← orientation;
rp.offset ← offset;
rp.count ← count;
repOb.specificRef ← rp;
BEGIN
iR: 
CD.Rect ← CDOrient.DeMapRect[
itemInWorld: iR,
cellSize: ob.size,
cellInstOrient: orientation
];
iR.x2 ← iR.x2+(count-1)*ABS[offset.x];
iR.y2 ← iR.y2+(count-1)*ABS[offset.y];
rp.ir ← iR
END;
 
RETURN [repOb];
END;
 
CreateRepetition: 
PUBLIC 
PROC [design: 
CD.Design, ob: 
CD.Object, count: 
NAT, offset: 
CD.Position, orientation: 
CD.Orientation𡤀] 
RETURNS [
CD.Object] =
BEGIN
repOb: CD.Object = InternalCreateRepetition[ob, count, offset, orientation];
[] ← CDDirectory.Include[design, repOb, Rope.Cat["=rep-", CDDirectory.Name[ob]]];
RETURN [repOb];
END;
 
DrawMeForRepetitions: 
PROC [inst: 
CD.Instance, pos: 
CD.Position, orient: 
CD.Orientation,
pr: CD.DrawRef] =
BEGIN
rptr: RepPtr ← NARROW[inst.ob.specificRef];
rel, sz: CD.Position;
o: CD.Orientation ← CDOrient.ComposeOrient[rptr.orientation, orient];
dummyInstance: CD.Instance ← NEW[CD.InstanceRep];
xi: REF INT;
dummyInstance.ob ← rptr.ob;
rel ← rptr.offsetOfFirst;
sz ← CDOrient.OrientedSize[rptr.ob.size, rptr.orientation];
--hang two properties on the application; both pointing to the same int containing the 
--repetition number;
--the first property has the name $CDxIndex
--the second property name is the value of the property $CDxIndexProperty 
WITH CDProperties.GetInstanceProp[inst, $CDxIndex] 
SELECT 
FROM
intP: REF INT => xi ← intP;
ENDCASE => {
xi ← NEW[INT];
CDProperties.PutInstanceProp[inst, $CDxIndex, xi];
WITH CDProperties.GetInstanceProp[inst, $CDxIndexProperty] 
SELECT 
FROM
ixP: 
ATOM =>  {
CDProperties.PutInstanceProp[inst, ixP, xi];
};
ENDCASE => NULL
 
};
 
 
--do drawing
FOR i: 
INT 
IN [0..rptr.count) 
DO
r: 
CD.Rect ← CDOrient.MapRect[
itemInCell: CDBasics.RectAt[rel, sz],  
cellSize: inst.ob.size, 
cellInstOrient: orient,
cellInstPos: pos
];
IF pr.stopFlag^ THEN EXIT;
xi^ ← i;
pr.drawChild[dummyInstance, CDBasics.BaseOfRect[r], o, pr];
rel ← CDBasics.AddPoints[rel, rptr.offset];
ENDLOOP;
 
END; 
 
QuickDrawMeForRepetitions: 
PROC [inst: 
CD.Instance, pos: 
CD.Position, orient: 
CD.Orientation,
pr: CD.DrawRef] =
BEGIN
rptr: RepPtr ← NARROW[inst.ob.specificRef];
rel, sz: CD.Position;
o: CD.Orientation ← CDOrient.ComposeOrient[rptr.orientation, orient];
dummyInstance: CD.Instance ← NEW[CD.InstanceRep];
xi: REF INT;
dummyInstance.ob ← rptr.ob;
rel ← rptr.offsetOfFirst;
sz ← CDOrient.OrientedSize[rptr.ob.size, rptr.orientation];
--hang two properties on the application; both pointing to the same int containing the 
--repetition number;
--the first property has the name $CDxIndex
--the second property name is the value of the property $CDxIndexProperty 
WITH CDProperties.GetInstanceProp[inst, $CDxIndex] 
SELECT 
FROM
intP: REF INT => xi ← intP;
ENDCASE => {
xi ← NEW[INT];
CDProperties.PutInstanceProp[inst, $CDxIndex, xi];
WITH CDProperties.GetInstanceProp[inst, $CDxIndexProperty] 
SELECT 
FROM
ixP: 
ATOM =>  {
CDProperties.PutInstanceProp[inst, ixP, xi];
};
ENDCASE => NULL
 
};
 
 
--do drawing
FOR i: 
INT 
IN [0..rptr.count) 
DO
r: 
CD.Rect ← CDOrient.MapRect[
itemInCell: CDBasics.RectAt[rel, sz],  
cellSize: inst.ob.size, 
cellInstOrient: orient,
cellInstPos: pos
];
IF pr.stopFlag^ THEN EXIT;
xi^ ← i;
rptr.ob.class.quickDrawMe[dummyInstance, CDBasics.BaseOfRect[r], o, pr];
rel ← CDBasics.AddPoints[rel, rptr.offset];
ENDLOOP;
 
END; 
 
Another: 
PROC [me: 
CD.Object, fromOrNil: 
CD.Design, into: 
CD.Design
, friendly: 
BOOL] 
RETURNS [new: 
CD.Object, topMode: CDDirectory.InclOrReady←ready, childMode: CDDirectory.ImmOrIncl←immutable] =
BEGIN
rp: RepPtr = NARROW[me.specificRef];
new ← InternalCreateRepetition[rp.ob, rp.count, rp.offset, rp.orientation];
CDProperties.AppendProps[winner: new.properties, looser: me.properties, putOnto: new];
IF ~rp.ob.class.inDirectory OR (fromOrNil#NIL AND fromOrNil=into) THEN childMode ← included
END;
 
IncCount: CDCallSpecific.CallProc
-- PROC [design: CD.Design, inst: CD.Instance, x: REF] RETURNS [done: BOOL←TRUE, removeMe: BOOLLSE, include: CD.InstanceList←NIL, repaintMe: BOOLLSE, repaintInclude: BOOLLSE] --  =
BEGIN
sz: CD.Position ← inst.ob.size;
ap: CD.Instance ← NEW[CD.InstanceRep←inst^];
rptr: RepPtr ← NARROW[inst.ob.specificRef];
newOb: CD.Object = CreateRepetition[design, rptr.ob, rptr.count+1, rptr.offset, rptr.orientation];
IF ap.ob.size#newOb.size 
THEN {
relativeNewBound: CD.Rect ← [x1: 0, y1: 0, x2: inst.ob.size.x, y2: inst.ob.size.y];
IF rptr.offset.x>=0 THEN relativeNewBound.x2 ← inst.ob.size.x+rptr.offset.x 
ELSE relativeNewBound.x1 ← rptr.offset.x;
IF rptr.offset.y>=0 THEN relativeNewBound.y2 ← inst.ob.size.y+rptr.offset.y 
ELSE relativeNewBound.y1 ← rptr.offset.y;
ap.location ← CDBasics.BaseOfRect[
CDOrient.MapRect[
itemInCell: relativeNewBound,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location]];
};
 
ap.ob ← newOb;
include ← LIST[ap];
repaintMe ← TRUE;
removeMe ← TRUE;
repaintInclude ← TRUE;
END;   
 
DecCount: CDCallSpecific.CallProc
-- PROC [design: CD.Design, inst: CD.Instance, x: REF] RETURNS [done: BOOL←TRUE, removeMe: BOOLLSE, include: CD.InstanceList←NIL, repaintMe: BOOLLSE, repaintInclude: BOOLLSE] --  =
BEGIN
sz: CD.Position ← inst.ob.size;
ap: CD.Instance ← NEW[CD.InstanceRep←inst^];
rptr: RepPtr ← NARROW[inst.ob.specificRef];
newOb: CD.Object = CreateRepetition[design, rptr.ob, rptr.count-1, rptr.offset, rptr.orientation];
IF ap.ob.size#newOb.size 
THEN {
relativeNewBound: CD.Rect ← [x1: 0, y1: 0, x2: inst.ob.size.x, y2: inst.ob.size.y];
IF rptr.offset.x>=0 THEN relativeNewBound.x2 ← inst.ob.size.x-rptr.offset.x 
ELSE relativeNewBound.x1 ← -rptr.offset.x;
IF rptr.offset.y>=0 THEN relativeNewBound.y2 ← inst.ob.size.y-rptr.offset.y 
ELSE relativeNewBound.y1 ← -rptr.offset.y; 
ap.location ← CDBasics.BaseOfRect[
CDOrient.MapRect[
itemInCell: relativeNewBound,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location]];
};
 
ap.ob ← newOb;
include ← LIST[ap];
repaintMe ← TRUE;
removeMe ← TRUE;
repaintInclude ← TRUE;
END;
 
TransformToCell: CDCallSpecific.CallProc 
-- PROC [design: CD.Design, inst: CD.Instance, x: REF] RETURNS [done: BOOL←TRUE, removeMe: BOOLLSE, include: CD.InstanceList←NIL, repaintMe: BOOLLSE, repaintInclude: BOOLLSE] -- =
BEGIN
cob: CD.Object ← NIL; 
IF CDRepetitions.IsRepetition[inst.ob] THEN cob ← CDDirectory.ExpandByDraw[inst.ob].new;
IF done ← 
(cob#
NIL) 
THEN {
[] ← CDDirectory.Include[design, cob];
removeMe ← TRUE;
repaintMe ← TRUE;
include ← 
LIST[
NEW[
CD.InstanceRep ← [ 
ob: cob, 
location: inst.location, 
orientation: inst.orientation, 
selected: inst.selected, 
properties: CDProperties.DCopyProps[inst.properties]
]]];
repaintInclude ← TRUE;
}
 
END;
 
EnumerateRepeatedObjects: 
PROC [me: 
CD.Object, p: CDDirectory.EnumerateObjectsProc, x: 
REF] = 
BEGIN
rptr: RepPtr = NARROW[me.specificRef];
p[rptr.ob, x];
END;
 
ReadRepetition: 
CD.InternalReadProc 
--PROC [] RETURNS [Object]-- =
BEGIN
ob: CD.Object = CDIO.ReadObject[];
count: NAT = TokenIO.ReadInt[];
offset: CD.Position = CDIO.ReadPos[];
orientation: CD.Orientation = CDIO.ReadOrientation[];
RETURN [InternalCreateRepetition[ob: ob, count: count, offset: offset, orientation: orientation]];
END;
 
WriteRepetition: 
CD.InternalWriteProc 
-- PROC [me: Object] -- =
BEGIN
specific: RepPtr = NARROW[me.specificRef];
CDIO.WriteObject[specific.ob];
TokenIO.WriteInt[specific.count];
CDIO.WritePos[specific.offset];
CDIO.WriteOrientation[specific.orientation];
END;
 
ReplaceDirectChildForReps: CDDirectory.ReplaceDChildsProc =
BEGIN
AdjustItself: 
PROC [me: 
CD.Object] = 
BEGIN
rp: RepPtr = NARROW[me.specificRef];
rp.offsetOfFirst ← [0, 0];
IF rp.offset.x<0 THEN rp.offsetOfFirst.x← -(rp.count-1)*rp.offset.x;
IF rp.offset.y<0 THEN rp.offsetOfFirst.y← -(rp.count-1)*rp.offset.y;
END;
 
found: BOOL ← FALSE;
rp: CDRepetitions.RepPtr = NARROW[me.specificRef];
FOR replaceList: CDDirectory.ReplaceList ← replace, replaceList.rest 
WHILE replaceList#
NIL 
DO
rep: REF CDDirectory.ReplaceRec = replaceList.first;
IF rep.old=rp.ob 
THEN {
IF rep.newSize#rep.oldSize 
OR rep.off#[0, 0] 
THEN {
rp.offsetOfFirst ← CDBasics.BaseOfRect[
CDOrient.MapRect[
itemInCell: CDBasics.MoveRect[
[x1: 0, y1: 0, x2: rep.newSize.x, y2: rep.newSize.y], rep.off],
cellSize: rep.oldSize,
cellInstOrient: rp.orientation,
cellInstPos: rp.offsetOfFirst]];
rp.ob ← rep.new;
found ← TRUE;
EXIT
}
 
};
 
ENDLOOP;
 
IF found 
THEN {
newR: CD.Rect ← ComputeBoundsR[me];
IF newR#CDBasics.RectAt[[0, 0], me.size] 
THEN {
newSize: CD.Position ← CDBasics.SizeOfRect[newR];
oldSize: CD.Position ← me.size;
newBase: CD.Position = CDBasics.BaseOfRect[newR];
AdjustItself[me];
me.size ← newSize;
IF design#
NIL 
THEN
CDDirectory.RepositionObject[
design: design, 
ob: me, 
oldSize: oldSize,
baseOff: newBase
]
 
}
 
}
 
END;
 
InitRepetitions: 
PROC [] =
BEGIN
rp: 
REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[pForRepetitions, [
enumerateChildObjects: EnumerateRepeatedObjects,
replaceDirectChilds: ReplaceDirectChildForReps,
another: Another
]];
CDCallSpecific.Register[$TransformToCell, pForRepetitions, TransformToCell];
CDCallSpecific.Register[$IncCount, pForRepetitions, IncCount];
CDCallSpecific.Register[$DecCount, pForRepetitions, DecCount];
END; 
 
InitRepetitions[];
END.