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, March 27, 1986 5:13:17 pm PST
DIRECTORY
CD,
CDInstances,
CDCells,
CDDirectory,
CDMenus,
CDEvents,
CDBasics,
CDIO,
CDMarks,
CDOps,
CDOrient,
CDProperties,
CDRects,
Process USING [Yield],
Real,
Rope,
TokenIO,
TerminalIO;
CDCellsImpl: CEDAR PROGRAM
IMPORTS CD, CDInstances, CDIO, CDDirectory, CDEvents, CDBasics, CDMarks, CDMenus, CDOps, CDOrient, CDProperties, CDRects, Process, Real, Rope, TokenIO, TerminalIO
EXPORTS CDCells
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
]];
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, [
enumerateChildObjects: EnumerateChildObjects,
name: Name,
setName: SetName,
another: Another,
replaceDirectChilds: ReplaceDirectChildForCells
]];
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 ← CDIO.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;
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, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL]
RETURNS [
new: CD.Object ← CreateEmptyCell[],
topMode: CDDirectory.InclOrReady ← ready,
childMode: CDDirectory.ImmOrIncl ← immutable] =
BEGIN
oldCp, newCp: CD.CellPtr ;
new ← CreateEmptyCell[];
oldCp ← NARROW[me.specificRef];
newCp ← 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
END;
DrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation,
pr: CD.DrawRef] =
BEGIN
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;
Process.Yield[];
END;
QuickDrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] =
BEGIN
cp: CD.CellPtr = NARROW[inst.ob.specificRef];
IF pr.scaleHint<cp.simplifyOn AND pr.scaleHint>0 THEN {
pr.drawOutLine[CDOrient.RectAt[pos, inst.ob.size, orient], CD.selectionLayer, 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: 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
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<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
]
}
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: 1]]
]];
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.DeComposedList[use, CDBasics.BaseOfRect[gOutR], ob.size, orient];
cp.ir ← cp.dIr ← CDInstances.BoundingRectI[cp.contents];
cp.simplifyOn ← 50.0/MAX[ob.size.y, 1];
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];
cp: CD.CellPtr;
inst.ob ← cellOb ← CreateCellObject[use: sel];
cp ← NARROW[cellOb.specificRef];
cp.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.ObjectInfo[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 {
cp: CD.CellPtr = NARROW[inst.ob.specificRef];
dummy: CD.Object = CreateEmptyCell[];
newCp: CD.CellPtr = NARROW[dummy.specificRef];
dummyCellInst: CD.Instance;
dummy.size ← CDBasics.highposition;
IF CheckRecursionForPush[design, inst.ob] THEN {
TerminalIO.WriteRopes[" recursive push into ", CDOps.ObjectInfo[inst.ob], " not possible\n"];
RETURN [done ← FALSE];
};
newCp^ ← cp^; --copies interest rect ....
newCp.ir ← CDOrient.MapRect[
itemInCell: cp.ir,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location
];
newCp.dIr ← CDOrient.MapRect[
itemInCell: cp.dIr,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location
];
newCp.contents ← CDInstances.ComposedList[
il: newCp.contents,
cellPos: inst.location,
cellSize: inst.ob.size,
cellOrient: inst.orientation
];
dummyCellInst ← NEW[CD.InstanceRep←[
ob: dummy,
selected: TRUE,
properties: CDProperties.DCopyProps[inst.properties]
]];
CDProperties.CopyProps[inst.ob.properties, dummy];
CDOps.RemoveInstance[design, inst];
design^.actual ← CONS[
CD.PushRec[dummyCell: dummyCellInst, specific: newCp, 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 {
CDProperties.PutObjectProp[ob, $OwnerDesign, design.reserved];
};
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.DCopyProps[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
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];
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];
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];
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: BOOL] =
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.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
]
}
}
END;
IsPushedIn: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL] = {
RETURN [ design^.actual.rest#NIL ]
};
PushedCellName: PUBLIC PROC [design: CD.Design] RETURNS [Rope.ROPE] =
BEGIN
RETURN [SELECT TRUE FROM
design=NIL => "no design",
design.actual.rest=NIL => "top level",
ENDCASE => design.actual.first.specific.name
]
END;
SetInterestRect: PUBLIC PROC [cellOb: CD.Object, r: CD.Rect ← [0, 0, -1, -1]] =
BEGIN
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;
END;
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 inPixels THEN val/MAX[cell.size.y, 1] ELSE val
ENDCASE => NULL;
};
Init[];
END.