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 Christian Jacobi, February 19, 1986 3:28:27 pm PST
DIRECTORY
CD,
CDInstances,
CDCells,
CDDirectory,
CDMenus,
CDEvents,
CDBasics,
CDInterestRects,
CDIO,
CDIOExtras,
CDMarks,
CDOps,
CDOrient,
CDProperties,
CDRects,
Process USING [Yield],
Rope,
TokenIO,
TerminalIO;
CDCellsImpl: CEDAR PROGRAM
IMPORTS CD, CDInstances, CDIO, CDIOExtras, CDDirectory, CDEvents, CDBasics, CDMarks, CDMenus, CDOps, CDOrient, CDProperties, CDRects, Process, Rope, TokenIO, TerminalIO, CDInterestRects
EXPORTS CDCells
SHARES CD, CDRects, CDDirectory =
BEGIN
-- -- -- -- -- -- -- -- -- -- -- --
cellClass: PUBLIC REF CD.ObjectClass = CD.RegisterObjectClass[$Cell];
beforeReplace: CDEvents.EventRegistration =
CDEvents.RegisterEventType[$BeforeCellReplacement];
afterReplace: CDEvents.EventRegistration
= CDEvents.RegisterEventType[$AfterCellReplacement];
pushEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterPush];
popEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterPop];
createEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$InteractiveCreatedCell];
fullPopMenu: REF = CDMenus.CreateMenu["Pop from cell"];
partialPopMenu: REF = CDMenus.CreateMenu["Pop from cell"];
emptyPopMenu: REF = CDMenus.CreateMenu["Pop from cell: empty cell"];
lastOutputDesign: CD.Design ← NIL;
Init: PROC [] =
BEGIN
dp: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[cellClass];
dp.enumerateChildObjects ← EnumerateChildObjects;
dp.name ← Name;
dp.setName ← SetName;
dp.another ← Another;
dp.replaceDirectChilds ← ReplaceDirectChildForCells;
cellClass.drawMe ← DrawMeForCells;
cellClass.quickDrawMe ← QuickDrawMeForCells;
cellClass.showMeSelected ← DrawCellSelection;
cellClass.internalRead ← ReadCell;
cellClass.internalWrite ← WriteCell;
cellClass.describe ← Describe;
cellClass.interestRect ← InterestRectCells;
cellClass.oldInsideRect ← OldInsideRect;
cellClass.origin ← OriginForCells;
CDInterestRects.InstallOldSetInterest[cellClass, OldSetInterest];
CDMenus.CreateEntry[fullPopMenu, "flush", $flush];
CDMenus.CreateEntry[partialPopMenu, "flush", $flush];
CDMenus.CreateEntry[emptyPopMenu, "flush", $flush];
CDMenus.CreateEntry[fullPopMenu, "new cell", $new];
CDMenus.CreateEntry[partialPopMenu, "new cell", $new];
CDMenus.CreateEntry[fullPopMenu, "replace", $replace];
[] ← CDProperties.RegisterProperty[$InsideRect];
CDProperties.InstallProcs[prop: $InsideRect,
new: CDProperties.PropertyProcsRec[
makeCopy: CDProperties.DontCopy,
internalWrite: NIL,
internalRead: InternalReadProperty,
exclusive: TRUE
]
];
CDEvents.RegisterEventProc[$WriteTechnologyPrivate, RememberDesignOnWriting];
END;
InternalReadProperty: PROC [prop: ATOM] RETURNS [val: REF] =
--old stuff for io format version 4
BEGIN
val ← NEW[CD.Rect ← CDIOExtras.ReadRect[]]
END;
InterestRectCells: PROC [ob: CD.Object] RETURNS [CD.Rect] =
BEGIN
RETURN [NARROW[ob.specificRef, CD.CellPtr].ir]
END;
OriginForCells: PROC [ob: CD.Object] RETURNS [CD.Position] =
BEGIN
RETURN [NARROW[ob.specificRef, CD.CellPtr].origin]
END;
OldInsideRect: PROC [ob: CD.Object] RETURNS [CD.Rect] =
BEGIN
RETURN [NARROW[ob.specificRef, CD.CellPtr].dIr]
END;
OldSetInterest: PROC [ob: CD.Object, r: CD.Rect] =
BEGIN
cptr: CD.CellPtr = NARROW[ob.specificRef];
cptr.ir ← r;
cptr.useDIr ← FALSE;
END;
SetName: PROC [me: CD.Object, r: Rope.ROPE] =
BEGIN
NARROW[me.specificRef, CD.CellPtr].name ← r
END;
Name: PROC [me: CD.Object] RETURNS [Rope.ROPE] =
BEGIN
RETURN [NARROW[me.specificRef, CD.CellPtr].name]
END;
EnumerateChildObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] =
BEGIN
cptr: CD.CellPtr = NARROW[me.specificRef];
FOR list: CD.InstanceList ← cptr.contents, list.rest WHILE list#NIL DO
p[list.first.ob, x]
ENDLOOP
END;
Another: PROC [me: CD.Object, from, to: CD.Design] RETURNS [CD.Object] =
BEGIN
oldCp: CD.CellPtr = NARROW[me.specificRef];
newOb: CD.Object = CreateEmptyCell[];
newCp: CD.CellPtr = NARROW[newOb.specificRef];
newOb.size ← me.size;
newCp^ ← oldCp^;
newCp.contents ← CDInstances.CopyList[oldCp.contents];
CDProperties.AppendProps[winner: newOb.properties, looser: me.properties, putOnto: newOb];
IF to#NIL THEN [] ← CDDirectory.Include[to, newOb];
RETURN [newOb]
END;
DrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation,
pr: CD.DrawRef] =
BEGIN
--draw border
IF ~pr.b4 THEN WITH CDProperties.GetPropFromList[pr.properties^, $border] SELECT FROM
ro: REF CD.DrawOutLineProc =>
IF CDProperties.GetPropFromObject[inst.ob, $border]#NIL THEN
ro[
CDOrient.MapRect[
itemInCell: CD.InterestRect[inst.ob],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
pr];
ENDCASE => NULL;
--draw inside
FOR w: CD.InstanceList ← NARROW[inst.ob.specificRef, CD.CellPtr].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;
Process.Yield[];
END;
QuickDrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation,
pr: CD.DrawRef] =
BEGIN
cptr: CD.CellPtr = NARROW[inst.ob.specificRef];
r: REAL;
IF (r ← pr.scaleHint*inst.ob.size.y)<cptr.simplifyOn AND pr.scaleHint>0 THEN {
pr.drawOutLine[CDOrient.RectAt[pos, inst.ob.size, orient], pr];
IF r>9 THEN pr.drawComment[CDOrient.RectAt[pos, inst.ob.size, orient], cptr.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.b4 THEN WITH CDProperties.GetPropFromList[pr.properties^, $border] SELECT FROM
ro: REF CD.DrawOutLineProc =>
IF CDProperties.GetPropFromObject[inst.ob, $border]#NIL THEN
ro[
CDOrient.MapRect[
itemInCell: CD.InterestRect[inst.ob],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
pr];
ENDCASE => NULL;
--draw inside
FOR w: CD.InstanceList ← cptr.contents, w.rest WHILE w#NIL DO
IF CDBasics.Intersect[mapClip, CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation]] 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;
Process.Yield[];
IF pr.checkPriority THEN pr.priorityChecker[pr];
}
END;
DrawCellSelection: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation,
pr: CD.DrawRef] =
BEGIN
IF (pr.scaleHint*inst.ob.size.y)<NARROW[inst.ob.specificRef, CD.CellPtr].simplifyOn
AND pr.scaleHint>0 THEN pr.drawRect[CDOrient.RectAt[pos, inst.ob.size, orient], CD.highLightShade, pr]
ELSE {
pr.drawOutLine[
CDOrient.MapRect[
itemInCell: CD.InterestRect[inst.ob],
cellSize: inst.ob.size,
cellInstOrient: orient,
cellInstPos: pos
],
pr
]
}
END;
RemoveSelectedFromWorld: PROC [design: CD.Design] RETURNS [CD.InstanceList] =
-- removes the selected instances from design and returns them
BEGIN
remove, keep: CD.InstanceList;
[others: keep, selected: remove] ← CDInstances.SplitSelected[CDOps.InstList[design]];
CDOps.SetInstList[design, keep];
RETURN [remove]
END;
CreateEmptyCell: PUBLIC PROC [] RETURNS [ob: CD.Object] =
-- does not includes the cell into any design or celldirectory
-- does not name the cell
BEGIN
ob ← NEW[CD.ObjectRep←[
class: cellClass,
size: [0, 0],
specificRef: NEW[CD.CellRep←[simplifyOn: 50]]
]];
END;
CreateCellObject: PROC [use: CD.InstanceList, orient: CD.Orientation�Orient.original] RETURNS [CD.Object] =
-- not yet included in design
BEGIN
ob: CD.Object = CreateEmptyCell[];
cp: CD.CellPtr = NARROW[ob.specificRef];
gOutR: CD.Rect = CDInstances.BoundingRectO[use]; -- coordsys of use, non oriented
ob.size ← CDOrient.OrientedSize[CDBasics.SizeOfRect[gOutR], orient];
cp.contents ← CDInstances.DeComposedCopy[use, CDBasics.BaseOfRect[gOutR], ob.size, orient];
cp.ir ← cp.dIr ← CDInstances.BoundingRectI[cp.contents];
RETURN [ob]
END;
IncludeAndNameCell: PROC [design: CD.Design, cell: CD.Object, interactive: BOOLTRUE, allowAbort: BOOLFALSE] RETURNS [done: BOOL] =
BEGIN
IF ~interactive THEN {
[] ← CDDirectory.Include[design, cell];
RETURN [done←TRUE];
};
--interactive
DO
fiddle: BOOLFALSE;
aborted: BOOLFALSE;
name: Rope.ROPE;
name ← TerminalIO.RequestRope["enter object name: "
! TerminalIO.UserAbort => {aborted ← TRUE; fiddle ← TRUE; CONTINUE}
];
IF aborted THEN {
TerminalIO.WriteRope[" **name input aborted\n"];
IF allowAbort THEN RETURN [done←FALSE];
};
IF Rope.IsEmpty[name] THEN {
fiddle ← TRUE;
name ← "-no name";
};
IF Rope.Fetch[name, name.Length[]-1]='@ THEN {
fiddle ← TRUE;
name ← Rope.Substr[name, 0, name.Length[]-1];
};
IF CDDirectory.Include[design, cell, name, fiddle] THEN {
TerminalIO.WriteRopes[CDDirectory.Name[cell], " included\n"];
RETURN [done←TRUE];
};
TerminalIO.WriteRopes[name, " does already exist\nnot accepted, please repeat\n"];
ENDLOOP;
END;
CreateCellSelected: PUBLIC PROC [design: CD.Design, name: Rope.ROPENIL]
RETURNS [done: BOOLFALSE, cellOb: CD.Object←NIL] =
-- if name is NIL: interactive read for name
-- cell is included in directory
BEGIN
sel: CD.InstanceList = RemoveSelectedFromWorld[design];
inst: CD.Instance = NEW[CD.InstanceRep];
b: CD.Rect = CDInstances.BoundingRectO[sel];
cptr: CD.CellPtr;
inst.ob ← cellOb ← CreateCellObject[use: sel];
cptr ← NARROW[cellOb.specificRef];
cptr.name ← name;
inst.location ← CDBasics.BaseOfRect[b];
inst.selected ← TRUE;
IF NOT CDBasics.NonEmpty[b] THEN {
TerminalIO.WriteRope["no empty cell\n"];
RETURN [done: FALSE, cellOb: NIL]
};
IF name=NIL THEN {
IF ~IncludeAndNameCell[design: design, cell: cellOb, allowAbort: TRUE, interactive: TRUE].done THEN {
--undo the command
CDOps.IncludeInstanceList[design, sel, FALSE];
RETURN [done: FALSE, cellOb: NIL]
};
}
ELSE [] ← CDDirectory.Include[design, cellOb];
CDOps.IncludeInstance[design, inst, TRUE]; -- redraw removes seletion
[] ← CDEvents.ProcessEvent[createEvent, design, cellOb];
RETURN [done: TRUE, cellOb: cellOb]
END;
IsCellInstance: PROC [inst: CD.Instance] RETURNS [yes: BOOL FALSE] =
--verbose if inst is not a cell
BEGIN
SELECT TRUE FROM
inst=NIL => TerminalIO.WriteRope[" no object\n"];
inst.ob=NIL OR inst.ob.specificRef=NIL => TerminalIO.WriteRope[" bad object\n"];
ISTYPE[inst.ob.specificRef, CD.CellPtr] => yes ← TRUE;
ENDCASE => TerminalIO.WriteRopes[" object is not cell but ", CDOps.Info[inst.ob], "\n"];
END;
CheckRecursionForPush: PROC [design: CD.Design, ob: CD.Object] RETURNS [yes: BOOLFALSE] =
--Returns "pushing into ob would cause recursion"
BEGIN
FOR l: LIST OF CD.PushRec ← design.actual, l.rest WHILE l#NIL DO
IF l.first.mightReplace#NIL AND l.first.mightReplace.ob=ob THEN RETURN [yes ← TRUE]
ENDLOOP;
END;
PushInCellInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance] RETURNS [done: BOOL FALSE] =
BEGIN
IF IsCellInstance[inst] THEN {
cptr: CD.CellPtr = NARROW[inst.ob.specificRef];
dummy: CD.Object = CreateEmptyCell[];
newCptr: CD.CellPtr = NARROW[dummy.specificRef];
dummyCellInst: CD.Instance;
dummy.size ← CDBasics.highposition;
IF CheckRecursionForPush[design, inst.ob] THEN {
TerminalIO.WriteRopes[" recursive push into ", CDOps.Info[inst.ob], " not possible\n"];
RETURN [done ← FALSE];
};
newCptr^ ← cptr^; --copies interest rect ....
newCptr.ir ← CDOrient.MapRect[
itemInCell: cptr.ir,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location
];
newCptr.dIr ← CDOrient.MapRect[
itemInCell: cptr.dIr,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location
];
newCptr.contents ← CDInstances.ComposedCopy[
il: newCptr.contents,
cellPos: inst.location,
cellSize: inst.ob.size,
cellOrient: inst.orientation
];
dummyCellInst ← NEW[CD.InstanceRep←[
ob: dummy,
selected: TRUE,
properties: CDProperties.DangerousCopyProps[inst.properties]
]];
CDProperties.CopyProps[inst.ob.properties, dummy];
CDOps.RemoveInstance[design, inst];
design^.actual ← CONS[
CD.PushRec[dummyCell: dummyCellInst, specific: newCptr, mightReplace: inst],
design^.actual
];
[] ← CDEvents.ProcessEvent[pushEvent, design];
RETURN [done ← TRUE];
}
END;
PopFromCell: PUBLIC PROC [design: CD.Design,
m: CDCells.Method←interactive, name: Rope.ROPENIL]
RETURNS [done: BOOL] =
BEGIN
done ← IPopFromCell[design, m, name];
IF done THEN [] ← CDEvents.ProcessEvent[popEvent, design];
END;
IPopFromCell: PROC [design: CD.Design, m: CDCells.Method, name: Rope.ROPE]
RETURNS [done: BOOL�LSE] =
BEGIN
currentRect, originalRect: CD.Rect; --cd coords
currentInst, originalInst: CD.Instance;
currentCellOb, originalCellOb: CD.Object;
currentCellPtr, originalCellPtr: CD.CellPtr;
recursive: BOOLFALSE;
CheckRecursionForPop: PROC [mark: CDMarks.MarkRange] =
BEGIN
CDMarks.MarkUnMarkedInclusiveChildren[design, currentCellOb, mark];
recursive ← (originalInst.ob.marked=mark);
END;
DoFlush: PROC [] =
BEGIN
b: BOOL ← design^.actual.first.indirectlyChanged;
TerminalIO.WriteRope["flush\n"];
design^.actual ← design^.actual.rest;
design^.actual.first.indirectlyChanged ← TRUE;
IF b THEN design^.actual.first.indirectlyChanged ← TRUE;
CDOps.IncludeInstance[design, originalInst, FALSE];
END;
HackSetOwner: PROC [ob: CD.Object, design: CD.Design] = TRUSTED {
DesignPtr: TYPE = LONG POINTER TO CD.DesignRec;
x: REF DesignPtr ← NEW[DesignPtr←LOOPHOLE[design]];
CDProperties.PutPropOnObject[ob, $OwnerDesign, x];
};
DoReplace: PROC [] =
BEGIN
needsRep: BOOLFALSE;
[] ← CDEvents.ProcessEvent[beforeReplace, design, originalInst.ob];
TerminalIO.WriteRope["replace\n"];
--HACK for CDDirectory XXX
HackSetOwner[currentCellOb, design];
design^.actual ← design^.actual.rest;
design^.actual.first.indirectlyChanged ← TRUE;
--originalInst.ob.properties ← currentCellOb.properties; is a second copy anyway
needsRep ← originalRect#currentRect OR originalCellPtr.ir#currentCellPtr.ir OR currentCellPtr.dIr#originalCellPtr.dIr OR originalCellPtr.useDIr#currentCellPtr.useDIr;
originalCellPtr.contents ← currentCellPtr.contents;
originalCellPtr.useDIr ← currentCellPtr.useDIr;
originalCellPtr.ir ← currentCellPtr.ir;
IF needsRep THEN {
oldSize: CD.Position ← originalInst.ob.size;
newFakeOrigin: CD.Position; --absolute coordinates
newInOldCoordinates: CD.Position; --coordinates of old cell
originalInst.ob.size ←
CDOrient.OrientedSize[CDBasics.SizeOfRect[currentRect], originalInst.orientation];
newFakeOrigin ← CDOrient.MapPoint[
pointInCell: [0, 0],
cellSize: originalInst.ob.size,
cellInstOrient: originalInst.orientation,
cellInstPos: currentInst.location
].pointInWorld;
newInOldCoordinates ← CDOrient.DeMapPoint[
pointInWorld: newFakeOrigin,
cellSize: oldSize,
cellInstOrient: originalInst.orientation,
cellInstPos: originalInst.location
].pointInCell;
originalCellPtr.origin ← CDBasics.SubPoints[originalCellPtr.origin, newInOldCoordinates];
IF ~originalCellPtr.useDIr THEN
originalCellPtr.ir ← CDBasics.MoveRect[originalCellPtr.ir, CDBasics.NegOffset[newInOldCoordinates]];
CDDirectory.RepositionObject[design: design,
ob: originalInst.ob,
oldSize: oldSize,
baseOff: newInOldCoordinates
];
};
originalInst.location ← currentInst.location;
CDOps.IncludeInstance[design, originalInst, FALSE];
[] ← CDEvents.ProcessEvent[afterReplace, design, originalInst.ob];
CDDirectory.PropagateChange[originalInst.ob, design];
END;
DoNewCell: PROC [interactive: BOOLFALSE] =
BEGIN
TerminalIO.WriteRope["new cell\n"];
currentInst.ob ← currentCellOb;
design^.actual ← design^.actual.rest;
design^.actual.first.indirectlyChanged ← TRUE;
design^.actual.first.changed ← TRUE;
IF ~IncludeAndNameCell[design, currentCellOb, interactive, FALSE].done THEN ERROR;
CDOps.IncludeInstance[design, currentInst, FALSE];
CDDirectory.PropagateChange[currentInst.ob, design];
END;
menu: REF ← fullPopMenu;
IF design^.actual.rest=NIL THEN {
TerminalIO.WriteRope["not in cell\n"];
RETURN [FALSE]
};
originalInst ← design^.actual.first.mightReplace;
originalCellOb ← originalInst.ob;
originalCellPtr ← NARROW[originalCellOb.specificRef];
originalRect ← CDOrient.RectAt[originalInst.location, originalCellOb.size, originalInst.orientation];
TerminalIO.WriteRopes["Pop from cell ", originalCellPtr.name, "\n"];
CDInstances.DeSelectList[CDOps.InstList[design]];
currentRect ← CDInstances.BoundingRectO[CDOps.InstList[design]]; -- design coordinates
currentCellOb ← CreateCellObject[CDOps.InstList[design], originalInst.orientation];
currentCellPtr ← NARROW[currentCellOb.specificRef];
currentCellPtr.useDIr ← design^.actual.first.specific.useDIr;
IF ~currentCellPtr.useDIr THEN
currentCellPtr.ir ← CDOrient.DeMapRect[
itemInWorld: design^.actual.first.specific.ir,
cellSize: originalInst.ob.size,
cellInstOrient: originalInst.orientation,
cellInstPos: originalInst.location
].itemInCell;
currentInst ← NEW[CD.InstanceRep ← [
ob: currentCellOb,
location: CDBasics.BaseOfRect[currentRect],
orientation: originalInst.orientation,
selected: TRUE,
properties: CDProperties.DangerousCopyProps[originalInst.properties]
]];
CDProperties.CopyProps[originalInst.ob.properties, currentCellOb];
IF m=flush OR (m=interactive AND ~design^.actual.first.changed) THEN {
DoFlush[];
RETURN [TRUE]
};
IF CDBasics.NonEmpty[currentRect] THEN {
IF m=newcell THEN {
DoNewCell[interactive: FALSE];
RETURN [TRUE]
};
CDMarks.DoWithMark[design, CheckRecursionForPop];
IF recursive THEN {
TerminalIO.WriteRope[" Original cell used inside, replace not possible\n"];
IF m=replace THEN RETURN[FALSE];
menu ← partialPopMenu;
}
ELSE { --ok, normal case
IF m=replace THEN {
DoReplace[];
RETURN [TRUE]
};
}
}
ELSE { -- empty
TerminalIO.WriteRope[" create empty cell not possible\n"];
IF m#interactive THEN {DoFlush[]; RETURN [TRUE]};
menu ← emptyPopMenu;
};
SELECT CDMenus.CallMenu[menu] FROM
$flush => DoFlush[];
$replace => DoReplace[];
$new => DoNewCell[interactive: TRUE];
ENDCASE => {
TerminalIO.WriteRope["skipped\n"];
RETURN [FALSE]
};
RETURN [TRUE];
END;
-- -- -- -- -- -- -- -- -- -- -- --
ReadCell: CD.InternalReadProc --PROC [] RETURNS [Object]-- =
BEGIN
ob: CD.Object = CreateEmptyCell[];
specific: CD.CellPtr = NARROW[ob.specificRef];
ob.size ← CDIOExtras.ReadPos[];
IF CDIO.VersionKey[]>=8 THEN { --now
specific.simplifyOn ← TokenIO.ReadInt[];
specific.useDIr ← (TokenIO.ReadInt[]=0);
IF ~specific.useDIr THEN specific.ir ← CDIOExtras.ReadRect[];
specific.origin ← CDIOExtras.ReadPos[];
}
ELSE { -- old versions
IF CDIO.VersionKey[]<1 THEN {
specific.name ← TokenIO.ReadRope[];
}
ELSE {
specific.simplifyOn ← TokenIO.ReadInt[];
};
};
specific.contents ← CDIO.ReadInstanceList[];
specific.dIr ← CDInstances.BoundingRectI[specific.contents];
IF specific.useDIr THEN specific.ir ← specific.dIr;
RETURN [ob];
END;
RememberDesignOnWriting: CDEvents.EventProc =
-- PROC [event: REF, design: CD.Design, x: REF]
BEGIN
lastOutputDesign ← design
END;
WriteCell: CD.InternalWriteProc -- PROC [me: Object] -- =
BEGIN
specific: CD.CellPtr = NARROW[me.specificRef];
CDIOExtras.WritePos[me.size];
TokenIO.WriteInt[specific.simplifyOn];
IF specific.useDIr AND specific.ir=specific.dIr THEN TokenIO.WriteInt[0]
ELSE {
TokenIO.WriteInt[1];
CDIOExtras.WriteRect[specific.ir];
};
CDIOExtras.WritePos[specific.origin];
CDIO.WriteInstanceList[specific.contents];
END;
Describe: PROC[me: CD.Object] RETURNS [Rope.ROPE] =
BEGIN
RETURN [Rope.Concat["cell ", NARROW[me.specificRef, CD.CellPtr].name]]
END;
ReplaceDirectChildForCells: CDDirectory.ReplaceDChildsProc =
-- PROC[me: CD.Object, design: CD.Design, replace: LIST OF REF ReplaceRec] --
BEGIN
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];
}
END;
ReplaceDirectChildForDummyCells: PUBLIC PROC [cellOb: CD.Object, replace: CDDirectory.ReplaceList] RETURNS [needReposition: BOOL] =
BEGIN
PointRect: PROC [class: CD.Position] RETURNS [CD.Rect] = INLINE {
RETURN [[x1: class.x, y1: class.y, x2: class.x, y2: class.y]]
};
cp: CD.CellPtr = NARROW[cellOb.specificRef];
needReposition ← FALSE;
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;
END;
IsDummyCell: PROC [cellOb: CD.Object, design: CD.Design] RETURNS [isDummy: BOOLFALSE] =
INLINE BEGIN
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;
};
END;
RepositionCell: PUBLIC PROC [cellOb: CD.Object, design: CD.Design] RETURNS [didReposition: BOOLEAN] =
BEGIN
IF IsDummyCell[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.Info[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
]
}
}
END;
SetInterestRect: PUBLIC PROC [cellOb: CD.Object, r: CD.Rect ← [0, 0, -1, -1]] =
--defaulting r means to use a reasonable default for the interest rect
BEGIN
cp: CD.CellPtr = NARROW[cellOb.specificRef];
cp.useDIr ← ~CDBasics.NonEmpty[r];
IF cp.useDIr THEN cp.ir ← cp.dIr ELSE cp.ir ← r
END;
Init[];
END.