CDOpsImpl.mesa (part of Chipndale)
Copyright © 1983 by Xerox Corporation. All rights reserved.
by Christian Jacobi July 12, 1983 10:56 am
last edited by Christian Jacobi November 5, 1984 10:19:27 am PST
DIRECTORY
Atom,
CD,
CDApplications,
CDCommands,
CDCells,
CDDraw,
CDEvents,
CDBasics,
CDInterestRects,
CDOps,
CDOrient,
CDValue,
Rope USING [ROPE],
SymTab;
CDOpsImpl:
CEDAR
MONITOR
IMPORTS Atom, CD, CDApplications, CDCells, CDCommands, CDDraw, CDEvents, CDBasics, CDInterestRects, CDOps, CDOrient, CDValue, SymTab
EXPORTS CDOps
SHARES CD =
BEGIN
createEvent: CDEvents.EventRegistration=CDEvents.RegisterEventType[$CreateNewDesign];
resetDesignEvent: CDEvents.EventRegistration=CDEvents.RegisterEventType[$ResetDesign];
DelRec:
TYPE =
RECORD [
delayedList: LIST OF Remember←NIL
];
GetDelRec:
PROC [design:
CD.Design]
RETURNS [
REF DelRec] =
BEGIN
x: REF ← CDValue.Fetch[boundTo: design, key: $CDxDeleted, propagation: design];
IF x#NIL AND ISTYPE[x, REF DelRec] THEN RETURN [NARROW[x]]
ELSE {
dr: REF DelRec = NEW[DelRec←[NIL]];
CDValue.Store[design, $CDxDeleted, dr];
RETURN [dr]
}
END;
Remember: TYPE = RECORD [area: CD.DesignRect, clear: BOOL];
InternalResetDesign:
PROC[design:
CD.Design] =
--is local since it does not cause a redraw
BEGIN
dummy: CD.ObPtr ← CDCells.CreateEmptyCell[];
dummy.size ← CDBasics.highposition;
design.cellDirectory ← SymTab.Create[];
design^.actual ←
LIST[
CD.PushRec[
dummyCell: CDApplications.NewApplicationI[ob: dummy],
mightReplace: NIL,
specific: NARROW[dummy.specificRef]
]];
END;
CreateDesign:
PUBLIC
PROC [technology:
CD.Technology]
RETURNS [design:
CD.Design] =
BEGIN
IF technology=NIL THEN ERROR CD.Error[callingError, "NIL technology"];
design ← NEW[CD.DesignRec];
design.technology ← technology;
InternalResetDesign[design]; -- must not cause redraw since event not yet processed
[] ← CDEvents.ProcessEvent[createEvent, design];
END;
ResetDesign:
PUBLIC
PROC [design:
CD.Design] =
BEGIN
InternalResetDesign[design];
[] ← CDEvents.ProcessEvent[resetDesignEvent, design];
CDValue.Store[design, $CDxDeleted, NIL];
Redraw[design];
END;
RemoveApplication:
PUBLIC
PROC [design:
CD.Design, aptr:
CD.ApplicationPtr, draw:
BOOL←
TRUE] =
BEGIN
al: CD.ApplicationList ← CDOps.AppList[design];
IF al#
NIL
THEN
IF al.first=aptr THEN CDOps.SetAppList[design, al.rest]
ELSE
FOR l:
CD.ApplicationList ← al, l.rest
WHILE l.rest#
NIL
DO
IF l.rest.first=aptr THEN {l.rest←l.rest.rest; EXIT}
ENDLOOP;
IF draw THEN DelayedRedraw[design, CDApplications.ARectO[aptr]];
END;
SelectNewMode:
PROC[design:
CD.Design]
RETURNS [
BOOL] =
BEGIN
mode: INT = CDValue.FetchInt[boundTo: design, key: $CDxSelectNewMode, propagation: technology, ifNotFound: 0];
RETURN [mode=1]
END;
NewApplicationX:
PUBLIC
PROC [ob:
CD.ObPtr←
NIL, location:
CD.DesignPosition←[0,0], orientation:
CD.Orientation𡤀,
selected: BOOLEAN ← FALSE, properties: CD.Properties←NIL] RETURNS [CD.ApplicationPtr] =
--creates a new application, does neither draw nor include it into any world
--modifies location such that ob...insideRect is at original location
BEGIN
inr: CD.DesignRect ← CDInterestRects.GetInterestRect[ob].r;
off:
CD.DesignPosition ← CDOrient.MapPosition[
itemInCell: inr,
cellSize: ob.size,
cellInstOrient: orientation,
cellInstPos: [0, 0]
];
a:
CD.ApplicationPtr ←
NEW[
CD.Application ←
CD.Application[
ob: ob,
location: CDBasics.SubPoints[location, off],
orientation: orientation,
selected: selected,
properties: properties
]];
RETURN [a]
END;
AddAnObject:
PUBLIC
PROC[design:
CD.Design, ob:
CD.ObPtr, location:
CD.DesignPosition, orientation:
CD.Orientation] =
BEGIN
aptr: CD.ApplicationPtr;
IF ob#
NIL
THEN {
aptr ← NewApplicationX[
ob: ob,
location: location,
orientation: orientation
];
IF SelectNewMode[design]
THEN {
CDCommands.DeselectAll[design];
aptr.selected ← TRUE;
};
IncludeApplication[design, aptr];
}
END;
IncludeApplication:
PUBLIC PROC [design:
CD.Design, aptr:
CD.ApplicationPtr, draw:
BOOL←
TRUE] =
BEGIN
IF aptr=NIL THEN ERROR CD.Error[callingError, "Include of NIL application"];
IF aptr.ob=NIL THEN ERROR CD.Error[callingError, "Include application with NIL object"];
CDOps.SetAppList[design, CONS[aptr, CDOps.AppList[design]]];
IF draw THEN DelayedRedraw[design, CDApplications.ARectO[aptr], TRUE];
END;
IncludeApplicationList:
PUBLIC
PROC [design:
CD.Design, al:
CD.ApplicationList, draw:
BOOL←
TRUE] =
BEGIN
FOR list:
CD.ApplicationList ← al, list.rest
WHILE list#
NIL
DO
IncludeApplication[design, list.first, draw];
ENDLOOP;
END;
Redraw:
PUBLIC
PROC [design:
CD.Design, r:
CD.DesignRectOps.all, eraseFirst:
BOOL←
TRUE] =
BEGIN
CDDraw.InsertCommandAll[design,
CDDraw.Comm[cmd: rect, erase: eraseFirst, rect: r, ref: NIL]];
END;
DelayedRedraw:
PUBLIC
ENTRY
PROC [design:
CD.Design, r:
CD.DesignRect, eraseFirst:
BOOL←
TRUE] =
BEGIN
ENABLE UNWIND => NULL;
IF design#
NIL
THEN {
dl: REF DelRec = GetDelRec[design];
IF dl.delayedList=
NIL
THEN
dl.delayedList←LIST[Remember[area: r, clear: eraseFirst]]
ELSE {
list: LIST OF Remember𡤍l.delayedList;
DO
--ASSERTION1: {list#NIL}
--ASSERTION2: {no list rectangle is completely covered by an other one}
IF CDBasics.Intersect[list.first.area, r]
THEN {
IF CDBasics.Inside[r, list.first.area]
THEN {
--r is contained somewhere; we dont include it
--it is unlikely that a small area is cleared and a big one not
list.first.clear ← list.first.clear OR eraseFirst;
--assertion2 => no other elements could be removed
RETURN
}
ELSE
IF CDBasics.Inside[list.first.area, r]
THEN {
--r contains an element; we remove this element and all others
-- which are contained in r
--it is unlikely that a small area is cleared and a big one not
remember: LIST OF Remember←list;
eraseFirst ← list.first.clear OR eraseFirst;
list.first.area ← r;
--remove all other element contained in r; to maintain assertion2
WHILE list.rest#
NIL
DO
assert3: list#NIL
IF CDBasics.Inside[list.rest.first.area, r]
THEN {
eraseFirst ← list.rest.first.clear OR eraseFirst;
list.rest ← list.rest.rest --does not change list -> keeps assertion3
}
ELSE list ← list.rest --since list.rest#NIL -> keeps assertion3
ENDLOOP;
remember.first.clear ← eraseFirst;
RETURN
}
};
IF list.rest#NIL THEN list←list.rest
ELSE {
list.rest←LIST[Remember[area: r, clear: eraseFirst]];
RETURN
}
ENDLOOP;
} --of dl.delayedList#NIL
} --of design#NIL
END;
DoTheDelayedRedraws:
PUBLIC ENTRY PROC [design:
CD.Design] =
BEGIN
ENABLE UNWIND => NULL;
sq: REF DelRec = GetDelRec[design];
UNTIL sq.delayedList=
NIL
DO
CDDraw.InsertCommandAll[design, CDDraw.Comm[
cmd: rect,
erase: sq.delayedList.first.clear,
rect: sq.delayedList.first.area,
ref: NIL
]];
sq.delayedList ← sq.delayedList.rest
ENDLOOP;
END;
DrawDesign:
PUBLIC
PROC[design:
CD.Design, pr:
CD.DrawRef] =
BEGIN
FOR w:
LIST
OF
CD.PushRec ← design^.actual, w.rest
WHILE w#
NIL
DO
IF pr.stopFlag^ THEN EXIT;
pr.drawChild[w.first.dummyCell, [0, 0], CDOrient.original, pr];
pr.pushLevel ← pr.pushLevel+1;
ENDLOOP;
END;
QuickDrawDesign:
PUBLIC
PROC[design:
CD.Design, pr:
CD.DrawRef] =
BEGIN
SomeCommon:
PROC[ob:
CD.ObPtr, pos:
CD.DesignPosition, orient:
CD.Orientation,
pr: CD.DrawRef] RETURNS [BOOLEAN] =
INLINE
BEGIN
RETURN CDBasics.Intersect[CDOrient.RectAt[pos, ob.size, orient], pr.worldClip]
END;
DrawAndShowSelectionList:
PROC [list:
CD.ApplicationList, pr:
CD.DrawRef] =
BEGIN
FOR w:
CD.ApplicationList ← list, w.rest
WHILE w#
NIL
DO
IF SomeCommon[w.first.ob, w.first.location, w.first.orientation, pr]
THEN
BEGIN
IF pr.stopFlag^ THEN EXIT;
w.first.ob.p.quickDrawMe[w.first, w.first.location, w.first.orientation, pr];
IF w.first.selected
THEN
w.first.ob.p.showMeSelected[w.first, w.first.location, w.first.orientation, pr];
END;
ENDLOOP;
END;
-- drawDesign
pr.setGround[pr: pr, pushedOut: FALSE];
DrawAndShowSelectionList[CDOps.AppList[design], pr];
IF pr.suppressOutsidePushedCell THEN RETURN;
pr.setGround[pr: pr, pushedOut: TRUE];
FOR w:
LIST
OF
CD.PushRec ← design^.actual.rest, w.rest
WHILE w#
NIL
DO
IF pr.stopFlag^ THEN EXIT;
pr.pushLevel ← pr.pushLevel+1;
w.first.dummyCell.ob.p.quickDrawMe[w.first.dummyCell, [0, 0], CDOrient.original, pr];
ENDLOOP;
END;
PointedApplication:
PUBLIC
PROC [design:
CD.Design, pos:
CD.DesignPosition]
RETURNS [CD.ApplicationPtr] =
BEGIN
RETURN [ CDApplications.AplicationAt[CDOps.AppList[design], pos] ];
END;
SelectedApplication:
PUBLIC PROC [design:
CD.Design]
RETURNS [first:
CD.ApplicationPtr←NIL, multiple:
BOOLLSE] =
--first: returns ref to any selected application if there is one or more, otherwise nil.
--multiple: more than one application is selected
BEGIN
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
THEN
IF first=NIL THEN first←w.first
ELSE {multiple←TRUE; RETURN}
ENDLOOP;
END;
Info:
PUBLIC
PROC[ob:
CD.ObPtr]
RETURNS [Rope.
ROPE] =
BEGIN
IF ob=NIL THEN RETURN ["nil object"]
ELSE IF ob.p.describe#NIL THEN RETURN [ob.p.describe[ob]]
ELSE RETURN [Atom.GetPName[ob.p.objectType]]
END;
ReOrderApplication:
PUBLIC
PROC [design:
CD.Design, aptr:
CD.ApplicationPtr] =
--on return: design has exactly one occurrence of aptr, and it is at the end.
--(includes aptr if necessary and removes double occurences)
BEGIN
al: CD.ApplicationList ← CDOps.AppList[design];
found: BOOL ← FALSE;
IF aptr=NIL THEN ERROR CD.Error[callingError, "Reorder of NIL application"];
WHILE al#NIL AND al.first=aptr DO {found←TRUE; al ← al.rest} ENDLOOP;
IF al=
NIL
THEN {
IF found THEN al←LIST[aptr]
ELSE ERROR CD.Error[callingError, "Reorder of application not in design"];
}
ELSE
FOR l:
CD.ApplicationList ← al, l.rest
DO
-- l#NIL AND l.first#aptr holds at this point
WHILE l.rest#NIL AND l.rest.first=aptr DO {found←TRUE; l.rest ← l.rest.rest} ENDLOOP;
IF l.rest=
NIL
THEN {
IF found THEN l.rest ← LIST[aptr]
ELSE ERROR CD.Error[callingError, "Reorder of application not contained in design"];
EXIT
}
ENDLOOP;
CDOps.SetAppList[design, al];
END;
END.