CDCellsImpl.mesa (part of ChipNDale)
Copyright © 1983, 1986 by Xerox Corporation. All rights reserved.
by Christian Jacobi, June 24, 1983 5:00 pm
Last Edited by: Christian Jacobi, September 1, 1986 4:13:25 pm PDT
DIRECTORY
CD,
CDInstances,
CDCells,
CDCellsExtras,
CDCellsInteractions,
CDDirectory,
CDEvents,
CDBasics,
CDIO,
CDOps,
CDOrient,
CDProperties,
CDRects,
Process USING [Yield],
Real,
Rope,
TokenIO,
TerminalIO;
CDCellsImpl: CEDAR PROGRAM
IMPORTS CD, CDCellsInteractions, CDInstances, CDIO, CDDirectory, CDEvents, CDBasics, CDOps, CDOrient, CDProperties, CDRects, Process, Real, Rope, TokenIO, TerminalIO
EXPORTS CDCells, CDCellsExtras
SHARES CD, CDRects, CDDirectory =
BEGIN
cellClass: PUBLIC CD.ObjectClass = CD.RegisterObjectClass[$Cell, [
drawMe: DrawMeForCells,
quickDrawMe: QuickDrawMeForCells,
showMeSelected: DrawCellSelection,
internalRead: ReadCell,
internalWrite: WriteCell,
describe: Describe,
interestRect: InterestRectCells,
origin: OriginForCells
]];
lastOutputDesign: CD.Design ← NIL;
Init: PROC [] = {
dp: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[cellClass, [
enumerateChildObjects: EnumerateChildObjects,
name: Name,
setName: SetName,
another: Another,
replaceDirectChilds: ReplaceDirectChildForCells
]];
[] ← CDProperties.RegisterProperty[$dummyCell];
CDProperties.InstallProcs[prop: $dummyCell,
new: CDProperties.PropertyProcsRec[
makeCopy: CDProperties.DontCopy,
internalWrite: NIL,
exclusive: TRUE
]
];
[] ← CDProperties.RegisterProperty[$InsideRect];
CDProperties.InstallProcs[prop: $InsideRect,
new: CDProperties.PropertyProcsRec[
makeCopy: CDProperties.DontCopy,
internalWrite: NIL,
internalRead: InternalReadProperty,
exclusive: TRUE
]
];
CDEvents.RegisterEventProc[$WriteTechnologyPrivate, RememberDesignOnWriting];
};
IsDummyCell: PUBLIC PROC [cell: CD.Object] RETURNS [BOOL] = {
RETURN [CDProperties.GetObjectProp[cell, $dummyCell]=$TRUE]
};
InternalReadProperty: PROC [prop: ATOM] RETURNS [val: REF] = {
--old stuff for io format version 4
val ← NEW[CD.Rect ← CDIO.ReadRect[]]
};
InterestRectCells: PROC [ob: CD.Object] RETURNS [CD.Rect] = {
RETURN [NARROW[ob.specificRef, CD.CellPtr].ir]
};
OriginForCells: PROC [ob: CD.Object] RETURNS [CD.Position] = {
RETURN [NARROW[ob.specificRef, CD.CellPtr].origin]
};
SetName: PROC [me: CD.Object, r: Rope.ROPE] = {
NARROW[me.specificRef, CD.CellPtr].name ← r
};
Name: PROC [me: CD.Object] RETURNS [Rope.ROPE] = {
RETURN [NARROW[me.specificRef, CD.CellPtr].name]
};
EnumerateChildObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] = {
FOR list: CD.InstanceList ← NARROW[me.specificRef, CD.CellPtr].contents, list.rest WHILE list#NIL DO
p[list.first.ob, x]
ENDLOOP
};
Another: PROC [me: CD.Object, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL] RETURNS [
new: CD.Object ← CreateEmptyCell[],
topMode: CDDirectory.InclOrReady ← ready,
childMode: CDDirectory.ImmOrIncl ← immutable] = {
oldCp: CD.CellPtr ← NARROW[me.specificRef];
newCp: CD.CellPtr ← NARROW[new.specificRef];
new.size ← me.size;
newCp^ ← oldCp^;
newCp.contents ← CDInstances.CopyList[oldCp.contents];
CDProperties.AppendProps[winner: new.properties, looser: me.properties, putOnto: new];
IF fromOrNil=into AND into#NIL THEN childMode ← included
};
DrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = {
cp: CD.CellPtr ← NARROW[inst.ob.specificRef, CD.CellPtr];
--draw border
IF pr.borders AND cp.drawBorder THEN
pr.drawOutLine[
CDOrient.MapRect[
itemInCell: CD.InterestRect[inst.ob],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
CD.outlineLayer,
pr];
--draw inside
FOR w: CD.InstanceList ← cp.contents, w.rest WHILE w#NIL DO
r: CD.Rect ← CDOrient.MapRect[
itemInCell: CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
];
IF CDBasics.Intersect[r, pr.interestClip] THEN {
IF pr.stopFlag^ THEN EXIT;
pr.drawChild[
w.first,
CDBasics.BaseOfRect[r],
CDOrient.ComposeOrient[w.first.orientation, orient],
pr];
}
ENDLOOP;
Yield[];
};
n: INTEGER ← 5;
Yield: PROC [] = INLINE {
--we do want to yield, but not too often
IF (n←n-1)<0 THEN {n𡤅 Process.Yield[]}
};
IntersectRI: PROC[r: CD.Rect, inst: CD.Instance] RETURNS [BOOL] = TRUSTED INLINE {
--returns rect intersects or touches inst
IF inst.location.x>r.x2 OR inst.location.y>r.y2 THEN RETURN [FALSE];
IF PrincOpsUtils.BITAND[inst.orientation, CDOrient.rotate90]=0 THEN --even rot 90
RETURN [ inst.location.x+inst.ob.size.x>=r.x1 AND inst.location.y+inst.ob.size.y>=r.y1 ]
ELSE --odd rot 90
RETURN [ inst.location.x+inst.ob.size.y>=r.x1 AND inst.location.y+inst.ob.size.x>=r.y1 ];
};
QuickDrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = {
cp: CD.CellPtr = NARROW[inst.ob.specificRef];
IF pr.scaleHint<cp.simplifyOn AND pr.scaleHint>0 THEN {
pr.drawOutLine[
CDOrient.MapRect[
itemInCell: cp.ir,
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
CD.outlineLayer,
pr];
IF pr.scaleHint*inst.ob.size.y>9 THEN
pr.drawComment[CDOrient.RectAt[pos, inst.ob.size, orient], cp.name, pr];
}
ELSE {
mapClip: CD.Rect ← CDOrient.DeMapRect[ --clipping boundary in cell coordinates
itemInWorld: pr.interestClip,
cellSize: inst.ob.size,
cellInstPos: pos,
cellInstOrient: orient
].itemInCell;
--draw border
IF pr.borders AND cp.drawBorder THEN
pr.drawOutLine[
CDOrient.MapRect[
itemInCell: cp.ir,
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
CD.outlineLayer,
pr];
--draw inside
FOR w: CD.InstanceList ← cp.contents, w.rest WHILE w#NIL DO
IF IntersectRI[mapClip, w.first] THEN {
r: CD.Rect ← CDOrient.MapRect[
itemInCell: CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
];
--speed up rects...
IF w.first.ob.class=CDRects.bareRectClass THEN pr.drawRect[r, w.first.ob.layer, pr]
ELSE {
IF pr.stopFlag^ THEN EXIT;
w.first.ob.class.quickDrawMe[
w.first,
CDBasics.BaseOfRect[r],
CDOrient.ComposeOrient[w.first.orientation, orient],
pr];
}
}
ENDLOOP;
Yield[];
IF pr.checkPriority THEN pr.priorityChecker[pr];
}
};
DrawCellSelection: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = {
IF pr.scaleHint<NARROW[inst.ob.specificRef, CD.CellPtr].simplifyOn AND pr.scaleHint>0 THEN
pr.drawRect[CDOrient.RectAt[pos, inst.ob.size, orient], CD.shadeLayer, pr]
ELSE
pr.drawOutLine[
CDOrient.MapRect[itemInCell: CD.InterestRect[inst.ob], cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos],
CD.selectionLayer,
pr
]
};
CreateEmptyCell: PUBLIC PROC [] RETURNS [ob: CD.Object] = {
ob ← NEW[CD.ObjectRep←[
class: cellClass,
size: [0, 0],
specificRef: NEW[CD.CellRep←[simplifyOn: 1]]
]];
};
CreateCellSelected: PUBLIC PROC [design: CD.Design, name: Rope.ROPENIL] RETURNS [done: BOOLFALSE, cellOb: CD.Object←NIL] = {
[done, cellOb] ← CDCellsInteractions.CreateCellSelected[design, name]
};
PushInCellInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance] RETURNS [done: BOOLFALSE] = {
done ← CDCellsInteractions.PushInCellInstance[design, inst];
};
PopFromCell: PUBLIC PROC [design: CD.Design, m: CDCells.Method←interactive, name: Rope.ROPENIL] RETURNS [done: BOOL] = {
done ← CDCellsInteractions.PopFromCell[design, LOOPHOLE[m], name];
};
ReadCell: CD.InternalReadProc --PROC [] RETURNS [Object]-- = {
i: INT;
ob: CD.Object = CreateEmptyCell[];
specific: CD.CellPtr = NARROW[ob.specificRef];
ob.size ← CDIO.ReadPos[];
IF CDIO.VersionKey[]>=8 THEN { --now
specific.simplifyOn ← TokenIO.ReadInt[];
i ← TokenIO.ReadInt[];
specific.useDIr ← (i MOD 2)=0;
specific.drawBorder ← (i/2)#0;
IF ~specific.useDIr THEN specific.ir ← CDIO.ReadRect[];
specific.origin ← CDIO.ReadPos[];
}
ELSE { -- old versions
IF CDIO.VersionKey[]<1 THEN {
specific.name ← TokenIO.ReadRope[];
}
ELSE {
specific.simplifyOn ← TokenIO.ReadInt[];
};
};
IF ob.size.y>0 THEN specific.simplifyOn ← specific.simplifyOn/ob.size.y;
specific.contents ← CDIO.ReadInstanceList[];
specific.dIr ← CDInstances.BoundingRectI[specific.contents];
IF specific.useDIr THEN specific.ir ← specific.dIr;
RETURN [ob];
};
RememberDesignOnWriting: CDEvents.EventProc = {
-- PROC [event: REF, design: CD.Design, x: REF]
lastOutputDesign ← design
};
WriteCell: CD.InternalWriteProc -- PROC [me: Object] -- = {
specific: CD.CellPtr = NARROW[me.specificRef];
i: INTIF specific.drawBorder THEN 2 ELSE 0;
CDIO.WritePos[me.size];
TokenIO.WriteInt[Real.Round[
MAX[MIN[specific.simplifyOn, 500.0], 0.0] * MAX[MIN[me.size.y, 100000], 0]
]];
IF specific.useDIr AND specific.ir=specific.dIr THEN TokenIO.WriteInt[i]
ELSE {
TokenIO.WriteInt[i+1];
CDIO.WriteRect[specific.ir];
};
CDIO.WritePos[specific.origin];
CDIO.WriteInstanceList[specific.contents];
};
Describe: PROC[me: CD.Object] RETURNS [Rope.ROPE] = {
RETURN [Rope.Concat["cell ", NARROW[me.specificRef, CD.CellPtr].name]]
};
ReplaceDirectChildForCells: CDDirectory.ReplaceDChildsProc = {
-- PROC[me: CD.Object, design: CD.Design, replace: LIST OF REF ReplaceRec] --
cp: CD.CellPtr = NARROW[me.specificRef];
needReposition: BOOL = ReplaceDirectChildForDummyCells[me, replace];
newIr: CD.Rect = CDInstances.BoundingRectI[cp.contents];
IF needReposition OR cp.dIr#newIr THEN
changed ← RepositionCell[me, design];
};
ReplaceDirectChildForDummyCells: PUBLIC PROC [cellOb: CD.Object, replace: CDDirectory.ReplaceList] RETURNS [needReposition: BOOLFALSE] = {
cp: CD.CellPtr = NARROW[cellOb.specificRef];
FOR replaceList: CDDirectory.ReplaceList ← replace, replaceList.rest WHILE replaceList#NIL DO
rep: REF CDDirectory.ReplaceRec = replaceList.first;
IF rep.old=cellOb THEN LOOP;
FOR instL: CD.InstanceList ← cp.contents, instL.rest WHILE instL#NIL DO
IF instL.first.ob=rep.old THEN {
IF rep.newSize#rep.oldSize OR rep.off#[0, 0] THEN {
realPos: CD.Position = CDOrient.MapPoint[
pointInCell: rep.off,
cellSize: rep.oldSize,
cellInstOrient: instL.first.orientation,
cellInstPos: instL.first.location
];
fakePos: CD.Position = CDOrient.MapPoint[
pointInCell: [0, 0],
cellSize: rep.newSize,
cellInstOrient: instL.first.orientation,
cellInstPos: [0, 0]
];
instL.first.location ← CDBasics.SubPoints[realPos, fakePos];
needReposition ← TRUE;
};
instL.first.ob ← rep.new
};
ENDLOOP;
ENDLOOP;
};
RepositionCell: PUBLIC PROC [cellOb: CD.Object, design: CD.Design] RETURNS [didReposition: BOOL] = {
IsDummy: PROC [cellOb: CD.Object, design: CD.Design] RETURNS [isDummy: BOOLFALSE] = INLINE {
IF design#NIL THEN
FOR list: LIST OF CD.PushRec ← design.actual, list.rest WHILE list#NIL DO
IF list.first.dummyCell.ob=cellOb THEN RETURN [isDummy←TRUE]
ENDLOOP;
};
IF IsDummy[cellOb, design] THEN RETURN [didReposition←FALSE]
ELSE {
cp: CD.CellPtr = NARROW[cellOb.specificRef];
oldSize: CD.Position ← cellOb.size;
oldR: CD.Rect ← CDBasics.RectAt[[0,0], oldSize];
oldDIr: CD.Rect ← cp.dIr;
newR: CD.Rect = CDInstances.BoundingRectO[cp.contents];
newSize: CD.Position ← CDBasics.SizeOfRect[newR];
newBase: CD.Position = CDBasics.BaseOfRect[newR];
newDIr: CD.Rect ← CDInstances.BoundingRectI[cp.contents];
didReposition ← oldR#newR OR oldSize#newSize OR (cp.useDIr AND oldDIr#newDIr);
IF didReposition THEN {
IF cp.contents=NIL THEN {
--actually this is an error; but it could be produced by some silly client program,
--so we do not abort
TerminalIO.WriteRopes["** tried to reposition an empty cell ",
CDOps.ObjectInfo[cellOb], "\n"];
RETURN
};
IF newBase#[0, 0] THEN {
CDInstances.TranslateList[cp.contents, CDBasics.NegOffset[newBase]];
newDIr ← CDBasics.MoveRect[newDIr, CDBasics.NegOffset[newBase]];
cp.origin ← CDBasics.SubPoints[cp.origin, newBase];
};
cellOb.size ← newSize;
cp.dIr ← newDIr;
cp.ir ←
IF cp.useDIr THEN newDIr
ELSE CDBasics.MoveRect[cp.ir, CDBasics.NegOffset[newBase]];
CDDirectory.RepositionObject[
design: design,
ob: cellOb,
oldSize: oldSize,
baseOff: newBase
]
}
}
};
IsPushedIn: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL] = {
RETURN [ design^.actual.rest#NIL ]
};
PushedCellName: PUBLIC PROC [design: CD.Design] RETURNS [Rope.ROPE] = {
RETURN [SELECT TRUE FROM
design=NIL => "no design",
design.actual.rest=NIL => "top level",
ENDCASE => design.actual.first.specific.name
]
};
SetInterestRect: PUBLIC PROC [cellOb: CD.Object, r: CD.Rect ← [0, 0, -1, -1]] = {
WITH cellOb.specificRef SELECT FROM
cp: CD.CellPtr => {
cp.useDIr ← ~CDBasics.NonEmpty[r];
IF cp.useDIr THEN cp.ir ← cp.dIr ELSE cp.ir ← r
};
ENDCASE => NULL;
};
SetBorder: PUBLIC PROC [cell: CD.Object, border: BOOL] = {
WITH cell.specificRef SELECT FROM
cp: CD.CellPtr => cp.drawBorder ← border
ENDCASE => NULL;
};
SetSimplificationTreshhold: PUBLIC PROC [cell: CD.Object, val: REAL, inPixels: BOOLTRUE] = {
WITH cell.specificRef SELECT FROM
cp: CD.CellPtr => cp.simplifyOn ←
IF val<0 THEN 50.0/MAX[cell.size.y, 1]
ELSE IF inPixels THEN val/MAX[cell.size.y, 1]
ELSE val;
ENDCASE => NULL;
};
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
IncludeOb: PUBLIC PROC [design: CD.Design←NIL, cell: CD.Object ← NIL, ob: CD.Object,
position: CD.Position ← [0, 0], --evaluated before an eventual repositioning
orientation: CD.Orientation ← 0,
cellCSystem: CDCells.CoordSystem ← originCoords,
obCSystem: CDCells.CoordSystem ← interrestCoords,
mode: CDCells.IncludeMode ← doit]
RETURNS
[newInst: CD.Instance, rep: BOOLFALSE] = {
cp: CD.CellPtr;
obInterestRect: CD.Rect = CD.InterestRect[ob];
IF ob=NIL THEN ERROR CD.Error[callingError, "Include NIL ob"];
--prepare cell and position relative to cell
IF cell=NIL THEN {
IF design=NIL THEN cp ← NIL
ELSE cp ← design^.actual.first.specific;
}
ELSE {
cp ← NARROW[cell.specificRef];
SELECT cellCSystem FROM
originCoords => position ← CDBasics.AddPoints[position, CD.ClientOrigin[cell]];
interrestCoords => position ← CDBasics.AddPoints[position,
CDBasics.BaseOfRect[CD.InterestRect[cell]]];
ENDCASE --cdCoords-- => NULL;
};
--handle position:
-- realPos ← (clientPos+cellOrigin) - (position of object origin at fake [0,0] pos)
newInst ← NEW[CD.InstanceRep ← [
ob: ob,
location: CDBasics.SubPoints[
position, --in cell coordinate system
CDBasics.BaseOfRect[ --correction for object coordinate system
CDOrient.MapRect[
itemInCell: (SELECT obCSystem FROM
interrestCoords => obInterestRect,
originCoords => CDBasics.RectAt[CD.ClientOrigin[ob], [0, 0]],
cdCoords => CDBasics.RectAt[[0, 0], ob.size],
ENDCASE => ERROR
),
cellSize: ob.size,
cellInstOrient: orientation,
cellInstPos: [0, 0]
]
]
],
orientation: orientation,
selected: FALSE
]];
--include, handle propagation and reposition
IF cp#NIL AND mode#dontInclude THEN {
cp.contents ← CONS[newInst, cp.contents]; --does not yet change insideRect !!
IF cell#NIL THEN {
rep ←
~CDBasics.Inside[CDInstances.InstRectO[newInst], CDBasics.RectAt[[0, 0], cell.size]]
OR
(cp.useDIr AND
~CDBasics.Inside[
 CDOrient.MapRect[
 itemInCell: obInterestRect,
 cellSize: ob.size,
 cellInstOrient: orientation,
 cellInstPos: newInst.location],
CD.InterestRect[cell]
]
);
IF rep AND mode=doit THEN [] ← RepositionCell[cell, design];
IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design];
}; --cell#NIL
IF design#NIL AND mode=doit THEN {
IF cell=NIL THEN CDOps.RedrawInstance[design, newInst, FALSE]
ELSE CDOps.DelayedRedraw[design]
};
};
};
RemoveInstance: PUBLIC PROC [design: CD.Design←NIL, cell: CD.Object ← NIL, inst: CD.Instance, mode: CDCells.IncludeMode ← doit] RETURNS [removed: BOOL FALSE, rep: BOOL FALSE] = {
cp: CD.CellPtr;
IF inst=NIL THEN ERROR CD.Error[callingError, "Remove NIL inst"];
--prepare cell
IF cell=NIL THEN {
IF design=NIL THEN ERROR CD.Error[callingError, "Remove from NIL cell"];
cp ← design^.actual.first.specific;
}
ELSE cp ← NARROW[cell.specificRef];
--remove, handle propagation and reposition
IF cp#NIL AND mode#dontInclude THEN {
IF cp.contents#NIL THEN {
IF cp.contents.first=inst THEN {
removed ← TRUE;
cp.contents ← cp.contents.rest
}
ELSE
FOR list: CD.InstanceList ← cp.contents, list.rest WHILE list.rest#NIL DO
IF list.rest.first=inst THEN {
removed ← TRUE;
list.rest ← list.rest.rest;
EXIT
}
ENDLOOP;
};
IF cell#NIL THEN {
r: CD.Rect = CDInstances.InstRectO[inst];
rep ← r.x1<=0 OR r.y1<=0 OR r.x2>=cell.size.x OR r.y2>=cell.size.y;
IF ~rep AND cp.useDIr THEN {
rep ← r.x1<=cp.ir.x1 OR r.y1<=cp.ir.y1 OR r.x2>=cp.ir.x2 OR r.y2>=cp.ir.y2;
};
IF rep AND mode=doit THEN [] ← RepositionCell[cell, design];
IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design];
}; --cell#NIL
IF design#NIL AND mode=doit THEN {
IF cell=NIL THEN CDOps.RedrawInstance[design, inst]
ELSE CDOps.DelayedRedraw[design]
};
};
};
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Init[];
END.