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.quickDrawMe ← QuickDrawMeForCells;
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: 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;
pr.drawChild[w.first, CDInline.BaseOfRect[r], o, pr];
}
ENDLOOP;
IF pr.nesting.first=aptr THEN pr.nesting ← pr.nesting.rest
END;
QuickDrawMeForCells: 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.quickDrawMe[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.Orientation�Orient.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: BOOLFALSE;
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 OR Rope.IsEmpty[name]] 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.ROPENIL]
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: BOOLFALSE] =
BEGIN
done ← DoPushInCell[design, CDOps.PointedApplication[design, pos]]
END;
DoPushInCell: PROC [design: CD.Design, originalApp: CD.ApplicationPtr]
RETURNS [done: BOOLFALSE] =
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.NewApplicationI[
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.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
c: CARDINAL;
currentRect, pushedRect: CD.DesignRect;
currentAptr, pushedAptr: CD.ApplicationPtr;
currentCellOb: CD.ObPtr;
currentCellPtr, pushedCellPtr: CD.CellPtr;
recursive: BOOLFALSE;
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.IncludeApplication[design, pushedAptr, FALSE];
END;
DoReplace: PROC [] =
BEGIN
p: CD.Properties;
[] ← CDEvents.ProcessEvent[beforeReplacement, design, pushedAptr.ob];
TerminalIO.WriteRope["replace\n"];
p ← currentCellOb.properties;
--HACK for CDDirectory XXX
CDProperties.PutPropOnObject[onto: currentCellOb, prop: $Owner, val: design];
p ← currentCellOb.properties;
currentAptr.ob ← pushedAptr.ob;
currentAptr.ob.properties ← p;
design^.actual ← design^.actual.rest;
design^.actual.first.indirectlyChanged ← TRUE;
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];
};
design^.actual.first.indirectlyChanged ← TRUE;
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;
design^.actual.first.indirectlyChanged ← TRUE;
design^.actual.first.changed ← TRUE;
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;
design^.actual.first.indirectlyChanged ← TRUE;
[] ← 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.NewApplicationI[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 OR (m=interactive AND ~design^.actual.first.changed) THEN {
DoFlush[];
RETURN [TRUE]
};
IF CDInline.NonEmpty[currentRect] THEN {
mark: CDMarks.MarkRange = CDMarks.GetNewMark[design! CD.Error => GOTO markProblem];
CDMarks.MarkUnMarkedInclusiveChildren[design, currentCellOb, mark];
recursive ← (pushedAptr.ob.marked=mark);
CDMarks.ReturnMark[design];
IF recursive 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];
EXITS
markProblem => TerminalIO.WriteRope["internal problem; not done\n"];
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: BOOLTRUE] RETURNS [removed: CD.ApplicationPtr←NIL, repositioned: BOOLFALSE] =
--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.ARectO[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: BOOLTRUE, relativeTo: CD.ApplicationPtr←NIL] RETURNS [repositioned: BOOLFALSE] =
--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.ARectO[aptr], CDInline.RectAt[[0, 0], cell.size]] THEN {
repositioned ← TRUE;
CDDirectory.RepositionAnObject[design, cell];
};
END;
-- -- -- -- -- -- -- -- -- -- -- --
Init[];
END.