CDCellsImpl.mesa (part of Chipndale)
by Christian Jacobi June 24, 1983 5:00 pm
last edited Christian Jacobi February 16, 1984 12:44 pm
DIRECTORY
CD,
CDApplications,
CDCallSpecific,
CDCells,
CDDirectory,
CDEvents,
CDInline,
CDIO,
CDMarks,
CDOps,
CDOrient,
CDProperties,
Rope,
TokenIO,
TerminalIO;
CDCellsImpl:
CEDAR
MONITOR
IMPORTS CD, CDApplications, CDCallSpecific, CDIO, CDDirectory, CDEvents, CDInline, CDMarks, CDOps, CDOrient, CDProperties, Rope, TokenIO, TerminalIO
EXPORTS CDCells
SHARES CDDirectory =
BEGIN
-- -- -- -- -- -- -- -- -- -- -- --
pForCells: REF CD.ObjectProcs ~ CD.RegisterObjectType[$Cell];
beforeReplacement: CDEvents.EventRegistration
~ CDEvents.RegisterEventType[$BeforeCellReplacement];
afterReplacement: CDEvents.EventRegistration
~ CDEvents.RegisterEventType[$AfterCellReplacement];
pushEvent: CDEvents.EventRegistration ~ CDEvents.RegisterEventType[$AfterPush];
popEvent: CDEvents.EventRegistration ~ CDEvents.RegisterEventType[$AfterPop];
Init:
PROC [] =
BEGIN
dp: REF CDDirectory.DirectoryProcs ~ CDDirectory.InstallDirectoryProcs[pForCells];
dp.enumerateChildObjects ← EnumerateChildObjects;
dp.adjustItself ← AdjustItself;
dp.repositionElements ← RepositionElements;
dp.computeBounds ← ComputeBounds;
dp.key ← Key;
dp.name ← Name;
dp.setName ← SetName;
pForCells.drawMe ← DrawMeForCells;
pForCells.showMeSelected ← DrawCellSelection;
pForCells.internalRead ← ReadCell;
pForCells.internalWrite ← WriteCell;
pForCells.describe ← Describe;
CDCallSpecific.Register[$Expand, pForCells, Expand];
END;
SetName:
PROC [me:
CD.ObPtr, r: Rope.
ROPE] =
BEGIN
cptr: CD.CellPtr = NARROW[me.specificRef];
cptr.name ← r
END;
Name:
PROC [me:
CD.ObPtr]
RETURNS [Rope.
ROPE] =
BEGIN
cptr: CD.CellPtr = NARROW[me.specificRef];
RETURN [cptr.name]
END;
Key:
PROC [me:
CD.ObPtr]
RETURNS [Rope.
ROPE] =
BEGIN
cptr: CD.CellPtr = NARROW[me.specificRef];
RETURN [cptr.key]
END;
EnumerateChildObjects:
PROC [me:
CD.ObPtr, p: CDDirectory.EnumerateObjectsProc, x:
REF] =
BEGIN
cptr: CD.CellPtr = NARROW[me.specificRef];
FOR w:
CD.ApplicationList ← cptr.contents, w.rest
WHILE w#
NIL
DO
p[w.first.ob, x]
ENDLOOP
END;
DrawMeForCells:
PROC [aptr:
CD.ApplicationPtr, pos:
CD.DesignPosition, orient:
CD.Orientation,
pr: CD.DrawRef] =
BEGIN
ENABLE UNWIND => IF pr.nesting.first=aptr THEN pr.nesting ← pr.nesting.rest;
cptr: CD.CellPtr ~ NARROW[aptr.ob.specificRef];
r: REAL;
IF (r ← pr.scaleHint*aptr.ob.size.y)<cptr.simplifyOn
AND pr.scaleHint>0
THEN {
pr.outLineProc[CDOrient.RectAt[pos, aptr.ob.size, orient], pr];
IF r>9 THEN pr.drawComment[CDOrient.RectAt[pos, aptr.ob.size, orient], cptr.name, pr];
}
ELSE {
r: CD.DesignRect;
pr.nesting ← CONS[aptr, pr.nesting];
FOR w:
CD.ApplicationList ← cptr.contents, w.rest
WHILE w#
NIL
DO
r ← CDOrient.MapRect[
itemInCell: CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation],
cellSize: aptr.ob.size,
cellInstOrient: orient,
cellInstPos: pos];
IF CDInline.Intersect[r, pr.worldClip]
THEN {
o: CD.Orientation ~ CDOrient.ComposeOrient[w.first.orientation, orient];
IF pr.stopFlag^ THEN EXIT;
w.first.ob.p.drawMe[w.first, CDInline.BaseOfRect[r], o, pr];
}
ENDLOOP;
IF pr.nesting.first=aptr THEN pr.nesting ← pr.nesting.rest
}
END;
DrawCellSelection:
PROC [aptr:
CD.ApplicationPtr, pos:
CD.DesignPosition, orient:
CD.Orientation,
pr: CD.DrawRef] =
BEGIN
IF (pr.scaleHint*aptr.ob.size.y)<
NARROW[aptr.ob.specificRef,
CD.CellPtr].simplifyOn
AND pr.scaleHint>0 THEN pr.drawRect[CDOrient.RectAt[pos, aptr.ob.size, orient], CD.highLightShade, pr]
ELSE pr.outLineProc[CDOrient.RectAt[pos, aptr.ob.size, orient], pr]
END;
RemoveSelectedFromWorld:
PROC [design:
CD.Design]
RETURNS [
CD.ApplicationList] =
-- removes the selected applications from design and returns them
BEGIN
remove, keep: CD.ApplicationList ← NIL;
[others: keep, selected: remove] ← CDApplications.SplitSelected[CDOps.AppList[design]];
CDOps.SetAppList[design, keep];
RETURN [remove]
END;
CreateEmptyCell:
PUBLIC
PROC []
RETURNS [
CD.ObPtr] =
-- does not includes the cell into any design or celldirectory
-- does not name the cell
BEGIN
ob: CD.ObPtr ~ NEW[CD.ObjectDefinition];
cp: CD.CellPtr ~ NEW[CD.CellRecord];
ob.p ← pForCells;
ob.size ← CDInline.highposition;
ob.specificRef ← cp;
cp.simplifyOn ← 50;
RETURN [ob]
END;
CreateCellObject:
PROC [use:
CD.ApplicationList, orient:
CD.OrientationOrient.original]
RETURNS [
CD.ObPtr] =
-- not yet included in design
BEGIN
ob: CD.ObPtr ~ CreateEmptyCell[];
cp: CD.CellPtr ~ NARROW[ob.specificRef];
b: CD.DesignRect ~ CDApplications.BoundingRect[use]; -- coordsys of use, non oriented
ob.size ← CDOrient.OrientedSize[CDInline.SizeOfRect[b], orient];
cp.name ← NIL;
cp.contents ← CDApplications.DeComposedCopy[use, CDInline.BaseOfRect[b], ob.size, orient];
RETURN [ob]
END;
IncludeAndNameCell:
PROC [design:
CD.Design, cp:
CD.ObPtr] =
BEGIN
aborted: BOOL ← FALSE;
name: Rope.ROPE;
cptr: CD.CellPtr ~ NARROW[cp.specificRef];
DO
ENABLE TerminalIO.UserAbort => {aborted ← TRUE; CONTINUE};
IF aborted
THEN {
name ← "-no name";
TerminalIO.WriteRope[" **name input aborted\n"];
}
ELSE name ← TerminalIO.RequestRope["enter name for cell: "];
IF CDDirectory.Include[design: design, object: cp, alternateName: name, fiddleName
: aborted]
THEN {
TerminalIO.WriteRope["Cell "]; TerminalIO.WriteRope[cptr.name];
TerminalIO.WriteRope[" included\n"];
RETURN;
};
TerminalIO.WriteRope["Cell "]; TerminalIO.WriteRope[cptr.name];
TerminalIO.WriteRope[" does already exist\n"];
TerminalIO.WriteRope["name not accepted, please repeat\n"];
aborted ← FALSE;
ENDLOOP;
END;
CreateCellSelected:
PUBLIC
PROC [design:
CD.Design, name: Rope.
ROPE←
NIL]
RETURNS [done: BOOL, cellOb: CD.ObPtr] =
-- if name is NIL: interactive read for name
-- cell is included in directory
BEGIN
sel: CD.ApplicationList ~ RemoveSelectedFromWorld[design];
app: CD.ApplicationPtr ~ NEW[CD.Application];
b: CD.DesignRect ~ CDApplications.BoundingRect[sel];
cptr: CD.CellPtr;
app.ob ← cellOb ← CreateCellObject[use: sel];
cptr ← NARROW[cellOb.specificRef];
cptr.name ← name;
app.location ← CDInline.BaseOfRect[b];
app.selected ← TRUE;
IF
NOT CDInline.NonEmpty[b]
THEN {
TerminalIO.WriteRope["no empty cell\n"];
RETURN [done: FALSE, cellOb: NIL]
};
IF name=NIL THEN IncludeAndNameCell[design, cellOb]
ELSE [] ← CDDirectory.Include[design, cellOb];
CDOps.IncludeApplication[design, app, TRUE]; -- redraw removes seletion
RETURN [done: TRUE, cellOb: cellOb]
END;
IsCell:
PROC [aptr:
CD.ApplicationPtr]
RETURNS [yes:
BOOL ←
FALSE] =
--verbose if aptr is not a cell
BEGIN
IF aptr=NIL THEN TerminalIO.WriteRope[" no object\n"]
ELSE IF aptr.ob=NIL OR aptr.ob.specificRef=NIL THEN TerminalIO.WriteRope[" bad object\n"]
ELSE
IF NOT
ISTYPE[aptr.ob.specificRef,
CD.CellPtr]
THEN {
TerminalIO.WriteRope[" object is not cell but "];
TerminalIO.WriteRope[CDOps.Info[aptr.ob]];
TerminalIO.WriteLn[];
}
ELSE yes←TRUE
END;
PushInCellSelected:
PUBLIC
PROC [design:
CD.Design]
RETURNS [done:
BOOL ←
FALSE] =
BEGIN
first: CD.ApplicationPtr;
multiple: BOOL;
[first, multiple] ← CDOps.SelectedApplication[design];
IF multiple THEN TerminalIO.WriteRope[" multiple selected object\n"]
ELSE done ← DoPushInCell[design, first];
END;
PushInCellPointed:
PUBLIC
PROC [design:
CD.Design, pos:
CD.DesignPosition]
RETURNS [done:
BOOL ←
FALSE] =
BEGIN
done ← DoPushInCell[design, CDOps.PointedApplication[design, pos]]
END;
DoPushInCell:
PROC [design:
CD.Design, originalApp:
CD.ApplicationPtr]
RETURNS [done: BOOL←FALSE] =
BEGIN
IF IsCell[originalApp]
THEN {
cptr: CD.CellPtr ~ NARROW[originalApp.ob.specificRef];
dummy: CD.ObPtr ~ CreateEmptyCell[];
newCptr: CD.CellPtr ~ NARROW[dummy.specificRef];
dummyCellAp: CD.ApplicationPtr;
FOR l:
LIST
OF
CD.PushRec ← design.actual, l.rest
WHILE l#
NIL
DO
IF l.first.mightReplace#
NIL
AND l.first.mightReplace.ob=originalApp.ob
THEN {
TerminalIO.WriteRope[" push not possible; [already pushed in "];
TerminalIO.WriteRope[CDOps.Info[l.first.mightReplace.ob]];
TerminalIO.WriteRope["]\n"];
RETURN [FALSE]
}
ENDLOOP;
newCptr.name ← cptr.name;
newCptr.contents ← CDApplications.ComposedCopy[
al: cptr.contents,
cellPos: originalApp.location,
cellSize: originalApp.ob.size,
cellOrient: originalApp.orientation
];
dummyCellAp ← CDApplications.NewApplication[
ob: dummy
,properties: CDProperties.CopyProps[originalApp.properties]
];
dummy.properties ← CDProperties.CopyProps[originalApp.ob.properties];
CDOps.RemoveApplication[design, originalApp];
design^.actual ←
CONS[
CD.PushRec[dummyCell: dummyCellAp, specific: newCptr, mightReplace: originalApp],
design^.actual];
[] ← CDEvents.ProcessEvent[pushEvent, design];
RETURN [TRUE];
}
END;
PopFromCell:
PUBLIC
PROC [design:
CD.Design,
m: CDCells.Method←interactive, name: Rope.ROPE←NIL]
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] =
BEGIN
c: CARDINAL;
currentRect, pushedRect: CD.DesignRect;
currentAptr, pushedAptr: CD.ApplicationPtr;
currentCellOb: CD.ObPtr;
currentCellPtr, pushedCellPtr: CD.CellPtr;
DoFlush:
PROC [] =
BEGIN
TerminalIO.WriteRope["flush\n"];
design^.actual ← design^.actual.rest;
CDOps.IncludeApplication[design, pushedAptr, FALSE];
END;
DoReplace:
PROC [] =
BEGIN
p: CD.Properties;
[] ← CDEvents.ProcessEvent[beforeReplacement, design, pushedAptr.ob];
TerminalIO.WriteRope["replace\n"];
p ← currentCellOb.properties;
currentAptr.ob ← pushedAptr.ob;
currentAptr.ob.properties ← p;
design^.actual ← design^.actual.rest;
pushedCellPtr.contents ← currentCellPtr.contents;
IF pushedRect#currentRect
THEN {
-- both in design coordinates
newRectInPushedCellCoords:
CD.DesignRect ~ CDOrient.DeMapRect[
itemInWorld: currentRect,
cellSize: CDOrient.OrientedSize[CDInline.SizeOfRect[pushedRect],
pushedAptr.orientation],
cellInstOrient: pushedAptr.orientation,
cellInstPos: pushedAptr.location];
-- Move the new cell such that repositioning its call
-- will put it back to its proper location
CDApplications.TranslateList[currentCellPtr.contents,
CDInline.BaseOfRect[newRectInPushedCellCoords]];
-- Do not here adjust size! this is made by repositioning if necessary
CDDirectory.RepositionAnObject[design, currentAptr.ob];
};
CDOps.IncludeApplication[design, currentAptr, FALSE];
[] ← CDEvents.ProcessEvent[afterReplacement, design, currentAptr.ob];
END;
DoNewCellInteractive:
PROC [] =
BEGIN
TerminalIO.WriteRope["new cell\n"];
currentAptr.ob ← currentCellOb;
design^.actual ← design^.actual.rest;
IncludeAndNameCell[design, currentCellOb];
CDOps.IncludeApplication[design, currentAptr, FALSE];
END;
DoNewCell:
PROC [] =
BEGIN
TerminalIO.WriteRope["new cell\n"];
currentAptr.ob ← currentCellOb;
currentCellPtr.name ← name;
design^.actual ← design^.actual.rest;
[] ← CDDirectory.Include[design, currentCellOb];
CDOps.IncludeApplication[design, currentAptr, FALSE];
END;
IF design^.actual.rest=NIL THEN {TerminalIO.WriteRope["not in cell\n"]; RETURN [FALSE]};
pushedAptr ← design^.actual.first.mightReplace;
pushedCellPtr ← NARROW[pushedAptr.ob.specificRef];
pushedRect ← CDOrient.RectAt[pushedAptr.location,
pushedAptr.ob.size, pushedAptr.orientation]; -- design cordinates
TerminalIO.WriteRope["Pop from cell "];
TerminalIO.WriteRope[pushedCellPtr.name];
TerminalIO.WriteLn[];
CDApplications.DeSelectList[CDOps.AppList[design]];
currentRect ← CDApplications.BoundingRect[CDOps.AppList[design]]; -- design coordinates
currentCellOb ← CreateCellObject[use: CDOps.AppList[design], orient: pushedAptr.orientation];
currentCellPtr ← NARROW[currentCellOb.specificRef];
currentAptr ← CDApplications.NewApplication[ob: currentCellOb,
location: CDInline.BaseOfRect[currentRect], -- might need reposition
orientation: pushedAptr.orientation
,properties: CDProperties.CopyProps[pushedAptr.properties]
];
currentCellOb.properties ← CDProperties.CopyProps[pushedAptr.ob.properties];
IF m=flush THEN {DoFlush[]; RETURN [TRUE]};
IF CDInline.NonEmpty[currentRect]
THEN {
mark: CDMarks.MarkRange = CDMarks.GetNewMark[design];
CDMarks.MarkUnMarkedInclusiveChildren[design, currentCellOb, mark];
IF pushedAptr.ob.marked=mark
THEN {
IF m=newcell THEN DoNewCell[]
ELSE {
TerminalIO.WriteRope[" Original cell used inside, replace not possible\n"];
IF m=replace THEN RETURN[FALSE];
c ← TerminalIO.RequestSelection[
label: "Pop from cell",
choice: LIST["flush", "new cell"],
text: Rope.Cat[" flush: undo modifications\n",
" new cell: Create a new cell\n"] ! TerminalIO.UserAbort => {c𡤀 CONTINUE}];
}
}
ELSE {
IF m=newcell THEN {DoNewCell[]; RETURN [TRUE]};
IF m=replace THEN {DoReplace[]; RETURN [TRUE]};
c ← TerminalIO.RequestSelection[
label: "Pop from cell",
choice: LIST["flush", "new cell", "replace"],
text: Rope.Cat[" flush: undo modifications\n",
" new cell: Create a new cell\n",
" replace: Replace the original cell\n"] !
TerminalIO.UserAbort => {c𡤀 CONTINUE}];
}
}
ELSE {
-- empty
TerminalIO.WriteRope[" create empty cell not possible\n"];
IF m#interactive THEN c ← 0
ELSE c ← TerminalIO.RequestSelection[
label: "Pop from empty cell",
choice: LIST["flush"],
text: " flush: undo modifications\n"
! TerminalIO.UserAbort => {c𡤀 CONTINUE}]
};
SELECT c
FROM
1 => DoFlush[];
3 => DoReplace[];
2 => DoNewCellInteractive[];
ENDCASE => {TerminalIO.WriteRope["skipped\n"]; RETURN [FALSE]};
RETURN [TRUE]
END;
-- -- -- -- -- -- -- -- -- -- -- --
Expand: CDCallSpecific.CallProc =
BEGIN
cptr: CD.CellPtr ~ NARROW[aptr.ob.specificRef];
removeMe ← TRUE;
repaintMe ← TRUE;
include ← CDApplications.ComposedCopy[
cptr.contents, aptr.location, aptr.ob.size, aptr.orientation];
repaintInclude ← TRUE;
END;
-- -- -- -- -- -- -- -- -- -- -- --
ComputeBounds:
PROC [ob:
CD.ObPtr]
RETURNS [
CD.DesignRect] =
--returns bounds in coordinate system of ob itself
BEGIN
WITH ob.specificRef
SELECT
FROM
cptr: CD.CellPtr => RETURN [CDApplications.BoundingRect[cptr.contents]];
ENDCASE => ERROR;
END;
AdjustItself:
PROC [objToReposition:
CD.ObPtr, newBound:
CD.DesignRect] =
--newBound is expected to be in coordinate system of objToReposition itself
BEGIN
objToReposition.size ← CDInline.SizeOfRect[newBound];
WITH objToReposition.specificRef
SELECT
FROM
cptr:
CD.CellPtr =>
CDApplications.TranslateList[cptr.contents,
CDInline.NegOffset[CDInline.BaseOfRect[newBound]]];
ENDCASE => ERROR;
END;
RepositionElements:
PROC [me:
CD.ObPtr,
objToReposition: CD.ObPtr,
oldSize: CD.DesignPosition, -- of objToReposition
newBound: CD.DesignRect, -- of objToReposition
design: CD.Design] =
BEGIN
RepositionApplicationList:
PROC [list:
CD.ApplicationList] =
INLINE
-- repositions all applications which call objToReposition
-- oldSize: size of the original rePositionList.first
-- objToReposition object needing reposition
-- newBound: bound of new objToReposition in coords of old rePositionList.first
-- (oldSize, newBound used by dynamic inner proc)
-- objToReposition.size is NOT used
BEGIN
FOR w:
CD.ApplicationList ← list, w.rest
WHILE w#
NIL
DO
--IF w.first.ob=objToReposition THEN-- RepositionApplication[w.first];
ENDLOOP;
END;
RepositionApplication:
PROC [aptr:
CD.ApplicationPtr] =
INLINE
-- repositions an application if it calls objToReposition
-- oldSize: size of the original objToReposition
-- objToReposition object needing reposition
-- newBound: bound of new objToReposition in coords of old objToReposition
BEGIN
IF aptr#
NIL
AND aptr.ob=objToReposition
THEN {
aptr.location ← CDOrient.MapPosition[
itemInCell: newBound,
cellSize: oldSize,
cellInstOrient: aptr.orientation,
cellInstPos: aptr.location];
}
END;
WITH me.specificRef
SELECT
FROM
cptr:
CD.CellPtr => {
RepositionApplicationList[cptr.contents];
--XXX This could be determined faster.
IF CDInline.RectAt[[0, 0], me.size]#CDApplications.BoundingRect[cptr.contents]
THEN
CDDirectory.RepositionAnObject[design, me];
};
ENDCASE => ERROR;
END;
-- -- -- -- -- -- -- -- -- -- -- --
ReadCell:
CD.InternalReadProc
--PROC [] RETURNS [ObPtr]-- =
BEGIN
ob: CD.ObPtr ~ CreateEmptyCell[];
specific: CD.CellPtr ~ NARROW[ob.specificRef];
ob.size.x ← TokenIO.ReadInt[];
ob.size.y ← TokenIO.ReadInt[];
IF
CDIO.VersionKey[]<1
THEN {
specific.name ← TokenIO.ReadRope[];
}
ELSE {
specific.simplifyOn ← TokenIO.ReadInt[];
};
specific.contents ← CDIO.ReadApplicationList[];
RETURN [ob];
END;
WriteCell:
CD.InternalWriteProc
-- PROC [me: ObPtr] -- =
BEGIN
specific: CD.CellPtr ~ NARROW[me.specificRef];
TokenIO.WriteInt[me.size.x];
TokenIO.WriteInt[me.size.y];
TokenIO.WriteInt[specific.simplifyOn];
CDIO.WriteApplicationList[specific.contents];
END;
Describe:
PROC[me:
CD.ObPtr]
RETURNS [Rope.
ROPE] =
BEGIN
specific: CD.CellPtr = NARROW[me.specificRef];
RETURN [Rope.Concat["cell ", specific.name]]
END;
-- -- -- -- -- -- -- -- -- -- -- --
RemoveApplication:
PUBLIC PROC [design:
CD.Design, cell:
CD.ObPtr, aptr:
CD.ApplicationPtr, draw:
BOOL←
TRUE]
RETURNS [removed:
CD.ApplicationPtr←
NIL, repositioned:
BOOL←
FALSE] =
--If necessary, modifies the boundary and translates all applications of the cell,
-- and further, translates all the instances of the cell. This changes the
-- parent cells, which therefore may be repositioned recursively too.
--noop if cell does not contain aptr (directly).
--Do not assume aptr^ to be freed for other use but use removed;
-- removed=NIL: aptr has not successfully been removed
-- removed#NIL: aptr is removed, removed is a copy of aptr for arbitrary re-use.
BEGIN
cp: CD.CellPtr = NARROW[cell.specificRef];
IF aptr=NIL THEN RETURN;
IF cp.contents#
NIL
THEN {
IF cp.contents.first=aptr
THEN {
removed ← cp.contents.first;
cp.contents ← cp.contents.rest
}
ELSE
FOR list:
CD.ApplicationList ← cp.contents, list.rest
WHILE list.rest#
NIL
DO
IF list.rest.first=aptr
THEN {
removed ← list.rest.first;
list.rest ← list.rest.rest;
EXIT
}
ENDLOOP;
};
IF aptr.ob=NIL THEN RETURN [NIL];
IF draw AND design#NIL THEN CDOps.DelayedRedraw[design: design, eraseFirst: TRUE];
IF ~CDInline.Inside[CDApplications.ApplicationRect[aptr], CDApplications.BoundingRect[cp.contents]]
THEN {
repositioned ← TRUE;
CDDirectory.RepositionAnObject[design, cell];
};
RETURN [removed]
END;
IncludeApplication:
PUBLIC PROC [design:
CD.Design, cell:
CD.ObPtr, aptr:
CD.ApplicationPtr, draw:
BOOL←
TRUE, relativeTo:
CD.ApplicationPtr←
NIL]
RETURNS [repositioned:
BOOL←
FALSE] =
--aptr^ is supposed to be referenced by aptr exclusively, and aptr^ may be changed by
-- IncludeApplication.
--If necessary, modifies the boundary and translates all applications of the cell,
-- and further, translates all the instances of the cell. This changes the
-- parent cells, which therefore may be repositioned recursively too.
--relativeTo#NIL: handy but trivial hook for clients which fear that repositioning
-- fools their origin: aptr is first translated by relativeTo.location: if relativeTo
-- points to an application of the cell itself, repositioning changes relativeTo^
-- exactly the right amount to compensate for the repositioning. It is the clients
-- responsibility that relativeTo is actual contained by cell.
BEGIN
cp: CD.CellPtr = NARROW[cell.specificRef];
IF aptr=NIL OR aptr.ob=NIL OR aptr=relativeTo THEN ERROR;
--check first if application is already contained by cell
FOR list:
CD.ApplicationList ← cp.contents, list.rest
WHILE list#
NIL
DO
IF list.first=aptr THEN RETURN
ENDLOOP;
IF relativeTo#
NIL
THEN
aptr.location ← CDInline.AddPoints[relativeTo.location, aptr.location];
cp.contents ← CONS[aptr, cp.contents];
IF draw AND design#NIL THEN CDOps.DelayedRedraw[design: design, eraseFirst: FALSE];
IF ~CDInline.Inside[CDApplications.ApplicationRect[aptr], CDInline.RectAt[[0, 0], cell.size]]
THEN {
repositioned ← TRUE;
CDDirectory.RepositionAnObject[design, cell];
};
END;
-- -- -- -- -- -- -- -- -- -- -- --
Init[];
END.