CDSimpleOpsImpl.mesa (part of ChipNDale)
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, July 12, 1983 10:56 am
last edited by Christian Jacobi, April 11, 1985 9:29:15 am PST
DIRECTORY
CD,
CDApplications,
CDSimpleOps,
CDCommandOps,
CDEvents,
CDBasics,
CDOps,
CDOrient,
CDProperties,
CDRects,
CDStretchyExtras,
CDValue,
Rope USING [IsEmpty, ROPE],
TerminalIO;
CDSimpleOpsImpl:
CEDAR
PROGRAM
IMPORTS CD, CDApplications, CDBasics, CDCommandOps,
CDEvents, CDOps, CDOrient, CDProperties, CDRects, CDStretchyExtras, CDValue, Rope, TerminalIO
EXPORTS CDSimpleOps =
BEGIN
renameEvent: CDEvents.EventRegistrationvents.RegisterEventType[$RenameDesign];
RenameDesign:
PUBLIC
PROC [design:
CD.Design, name: Rope.
ROPE] =
--is only local name
BEGIN
dont: BOOL;
oldName: Rope.ROPE ← design.name;
IF Rope.IsEmpty[name]
THEN {
TerminalIO.WriteRope[" not renamed\n"];
RETURN
};
design.name ← name;
dont ← CDEvents.ProcessEvent[renameEvent, design, oldName, TRUE];
IF dont
THEN {
design.name ← oldName;
[] ← CDEvents.ProcessEvent[renameEvent, design, oldName, FALSE];
}
END;
Select:
PUBLIC
PROC [design:
CD.Design, pos:
CD.DesignPosition, verbose:
BOOL] =
BEGIN
sel: CD.ApplicationPtr ← NIL;
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF ~w.first.selected
THEN {
IF CDApplications.PointToI[pos, w.first] THEN {sel ← w.first; EXIT}
};
ENDLOOP;
IF sel#
NIL
THEN {
sel.selected ← TRUE;
--reorder list, future select selects next lower application
CDOps.ReOrderApplication[design, sel];
CDCommandOps.RedrawApplication[design, sel];
IF verbose THEN CDCommandOps.WriteInfo[sel]
}
ELSE
IF verbose
THEN {
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
THEN {
IF CDApplications.PointToI[pos, w.first]
THEN {
CDCommandOps.WriteInfo[w.first];
TerminalIO.WriteRope[" again"];
RETURN
}
};
ENDLOOP;
TerminalIO.WriteRope[" no pointed object"];
}
END;
DeSelect:
PUBLIC
PROC [design:
CD.Design, pos:
CD.DesignPosition, verbose:
BOOL] =
BEGIN
aptr: CD.ApplicationPtr ← CDApplications.AplicationAt[CDOps.AppList[design], pos, TRUE];
IF aptr#
NIL
THEN
BEGIN
IF ~aptr.selected THEN ERROR;
aptr.selected ← FALSE;
CDCommandOps.RedrawApplication[design, aptr];
--reorder list, future select op finds next lower application
CDOps.ReOrderApplication[design, aptr];
END;
IF verbose THEN CDCommandOps.WriteInfo[aptr];
END;
BoundingRectAndCount:
PROC[list:
CD.ApplicationList, selectedOnly:
BOOLEAN←
FALSE]
RETURNS [bound: CD.DesignRectsics.empty, cnt: INT𡤀] =
BEGIN
FOR tem:
LIST
OF
CD.ApplicationPtr ← list, tem.rest
WHILE tem#
NIL
DO
IF selectedOnly AND NOT tem.first.selected THEN LOOP;
cnt ← cnt+1;
bound ← CDBasics.Surround[bound, CDApplications.ARectO[tem.first]]
ENDLOOP;
END;
DeselectAll:
PUBLIC
PROC [design:
CD.Design] =
BEGIN
doItSingleWise: NAT = 4;
sel: CD.ApplicationList = CDApplications.OnlySelected[CDOps.AppList[design]];
b: CD.DesignRect;
cnt: INT;
[b, cnt] ← BoundingRectAndCount[list: sel];
CDApplications.DeSelectList[sel];
IF cnt<=doItSingleWise
THEN
FOR l:
CD.ApplicationList ← sel, l.rest
WHILE l#
NIL
DO
CDCommandOps.RedrawApplication[design, l.first]
ENDLOOP
ELSE CDOps.DelayedRedraw[design, b];
END;
SelectAll:
PUBLIC
PROC [design:
CD.Design] =
BEGIN
--dont care about redrawing too much
b: CD.Rect ← CDApplications.BoundingRectO[list: CDOps.AppList[design], selectedOnly: FALSE];
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
w.first.selected ← TRUE
ENDLOOP;
CDOps.DelayedRedraw[design, b, FALSE];
END;
AreaSelectTouched:
PROC [design:
CD.Design, area:
CD.DesignRect] =
BEGIN
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF
NOT w.first.selected
AND CDBasics.Intersect[area, CDApplications.ARectI[w.first]] THEN {
w.first.selected ← TRUE;
CDCommandOps.RedrawApplication[design, w.first, FALSE];
};
ENDLOOP;
END;
AreaDeSelectTouched:
PROC [design:
CD.Design, area:
CD.DesignRect] =
BEGIN
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
AND CDBasics.Intersect[area, CDApplications.ARectI[w.first]] THEN {
w.first.selected ← FALSE;
CDCommandOps.RedrawApplication[design, w.first];
};
ENDLOOP;
END;
AreaSelectContained:
PROC [design:
CD.Design, area:
CD.DesignRect] =
BEGIN
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF CDBasics.Inside[CDApplications.ARectI[w.first], area] THEN w.first.selected ← TRUE
ENDLOOP;
CDOps.DelayedRedraw[design, area, FALSE];
END;
AreaDeSelectContained:
PROC [design:
CD.Design, area:
CD.DesignRect] =
BEGIN
FOR w:
CD.ApplicationList ← CDOps.AppList[design], w.rest
WHILE w#
NIL
DO
IF CDBasics.Inside[CDApplications.ARectI[w.first], area] THEN w.first.selected ← FALSE
ENDLOOP;
CDOps.DelayedRedraw[design, area];
END;
AreaSelect:
PUBLIC
PROC [design:
CD.Design, area:
CD.DesignRect, includePartial:
BOOL] =
BEGIN
IF includePartial THEN AreaSelectTouched[design, area]
ELSE AreaSelectContained[design, area];
END;
AreaDeSelect:
PUBLIC
PROC [design:
CD.Design, area:
CD.DesignRect, includePartial:
BOOL] =
BEGIN
IF includePartial THEN AreaDeSelectTouched[design, area]
ELSE AreaDeSelectContained[design, area];
END;
DeleteSelected:
PUBLIC
PROC [design:
CD.Design, verbose:
BOOL] =
BEGIN
count: INT ← 0;
toDelete, newContents: CD.ApplicationList;
[selected: toDelete, others: newContents] ← CDApplications.SplitSelected[CDOps.AppList[design]];
CDOps.SetAppList[design, newContents];
FOR w:
CD.ApplicationList ← toDelete, w.rest
WHILE w#
NIL
DO
count ← count+1;
CDCommandOps.RedrawApplication[design, w.first, TRUE];
ENDLOOP;
IF verbose
THEN {
IF count#1
THEN {
TerminalIO.WriteInt[count];
TerminalIO.WriteRope[" objects"]
}
ELSE CDCommandOps.WriteInfo[toDelete.first]
};
RememberShortTime[design, toDelete];
END;
RedrawMoved:
PROC [design:
CD.Design, r:
CD.DesignRect, offset:
CD.DesignPosition] =
BEGIN
moved: CD.DesignRect ← CDBasics.MoveRect[r, offset];
IF CDBasics.Intersect[r, moved]
THEN
CDOps.DelayedRedraw[design, CDBasics.Surround[r, moved], TRUE]
ELSE {
CDOps.DelayedRedraw[design, r];
CDOps.DelayedRedraw[design, moved]; -- use eraseFirst because also used by copy
}
END;
StretchyMoveMode:
PROC[design:
CD.Design]
RETURNS [
BOOL] =
BEGIN
mode: INT = CDValue.FetchInt[boundTo: design, key: $CDxStretchyMove, propagation: global, ifNotFound: 0];
RETURN [mode=1]
END;
MoveSelected:
PUBLIC
PROC [design:
CD.Design, offset:
CD.DesignPosition, stretchy: CDSimpleOps.StretchyMode] =
BEGIN
IF stretchy=yes OR ((stretchy=option) AND StretchyMoveMode[design]) THEN StretchyMoveSelected[design, offset]
ELSE SimpleMoveSelected[design, offset]
END;
SimpleMoveSelected:
PUBLIC
PROC [design:
CD.Design, offset:
CD.DesignPosition] =
BEGIN
sel: CD.ApplicationList = CDApplications.OnlySelected[CDOps.AppList[design]];
bounding: CD.DesignRect = CDApplications.BoundingRectO[sel];
FOR w:
CD.ApplicationList ← sel, w.rest
WHILE w#
NIL
DO
w.first.location ← CDBasics.AddPoints[w.first.location, offset];
ENDLOOP;
RedrawMoved[design, bounding, offset]
END;
CopySelected:
PUBLIC
PROC [design:
CD.Design, offset:
CD.DesignPosition] =
BEGIN
new: CD.ApplicationList←NIL;
sel: CD.ApplicationList = CDApplications.OnlySelected[CDOps.AppList[design]];
bounding: CD.DesignRect ← CDApplications.BoundingRectO[sel];
FOR w:
CD.ApplicationList ← sel, w.rest
WHILE w#
NIL
DO
aptr: CD.ApplicationPtr ← NEW[CD.Application];
aptr.ob ← w.first.ob;
aptr.location ← CDBasics.AddPoints[w.first.location, offset];
aptr.orientation ← w.first.orientation;
aptr.properties ← CDProperties.CopyProps[w.first.properties];
aptr.selected ← TRUE;
new ← CONS[aptr, new];
w.first.selected ← FALSE;
ENDLOOP;
CDOps.IncludeApplicationList[design, new, FALSE];
RedrawMoved[design, bounding, offset];
END;
TransformSelected:
PUBLIC
PROC [design:
CD.Design, transform:
CD.Orientation] =
BEGIN
sel: CD.ApplicationList = CDApplications.OnlySelected[CDOps.AppList[design]];
b: CD.DesignRect ← CDApplications.BoundingRectO[sel];
ib: CD.DesignRect = CDApplications.BoundingRectI[sel];
FOR w:
CD.ApplicationList ← sel, w.rest
WHILE w#
NIL
DO
CDApplications.Transform[w.first, ib, transform]
ENDLOOP;
CDOps.DelayedRedraw[design, b];
b ← CDOrient.MapRect[
itemInCell: CDBasics.MoveRect[b, CDBasics.NegOffset[CDBasics.BaseOfRect[ib]]],
cellSize: CDBasics.SizeOfRect[ib],
cellInstOrient: transform,
cellInstPos: CDBasics.BaseOfRect[ib]
];
CDOps.DelayedRedraw[design, b, FALSE];
END;
BaseTransformSelected:
PUBLIC
PROC [design:
CD.Design, transform:
CD.Orientation, base:
CD.DesignRect] =
BEGIN
sel: CD.ApplicationList = CDApplications.OnlySelected[CDOps.AppList[design]];
b: CD.DesignRect ← CDApplications.BoundingRectO[sel];
newB:
CD.DesignRect ← CDOrient.MapRect[
itemInCell: b,
cellSize: CDBasics.SizeOfRect[base],
cellInstOrient: transform,
cellInstPos: CDBasics.BaseOfRect[base]
];
FOR w:
CD.ApplicationList ← sel, w.rest
WHILE w#
NIL
DO
CDApplications.Transform[w.first, base, transform]
ENDLOOP;
CDOps.DelayedRedraw[design, b];
CDOps.DelayedRedraw[design, newB]
END;
-- -- -- -- -- -- -- -- -- -- -- --
remSize: CARDINAL = 20;
RememberBuffer:
TYPE =
RECORD[
a: ARRAY [0..remSize) OF REF ← ALL[NIL],
next: CARDINAL𡤀];
Forgett:
PROC[p:
REF] =
--helps the garbage collector,
--special may prevent circularities through properties
BEGIN
WITH p
SELECT
FROM
al:
CD.ApplicationList =>
FOR l:
CD.ApplicationList ← al, l.rest
WHILE l#
NIL
DO
Forgett[l.first]
ENDLOOP;
app: CD.ApplicationPtr => {app.properties ← NIL; app.ob ← NIL};
ENDCASE => NULL;
END;
RememberShortTime:
PROC [d:
CD.Design, what:
REF] =
BEGIN
dl: REF RememberBuffer;
IF d^.actual.first.deletedList=NIL THEN d^.actual.first.deletedList ← NEW[RememberBuffer];
dl ← NARROW[d^.actual.first.deletedList];
Forgett[dl.a[dl.next]];
dl.a[dl.next] ← what;
dl.next ← (dl.next+1) MOD remSize;
END;
GiveRemembered:
PROC [d:
CD.Design]
RETURNS [
REF] =
BEGIN
x: REF;
dl: REF RememberBuffer;
IF d^.actual.first.deletedList=NIL THEN RETURN [NIL];
dl ← NARROW[d^.actual.first.deletedList];
dl.next ← (dl.next+remSize-1) MOD remSize;
x ← dl.a[dl.next];
dl.a[dl.next] ← NIL;
RETURN [x];
END;
Undelete:
PUBLIC
PROC [design:
CD.Design, n:
INT𡤀] =
BEGIN
del: REF ← GiveRemembered[design];
IF del=NIL THEN RETURN;
WITH del
SELECT
FROM
al: CD.ApplicationList => CDOps.IncludeApplicationList[design, al];
app: CD.ApplicationPtr => CDOps.IncludeApplication[design, app]
ENDCASE => NULL;
END;
FlushDeletedCache:
PUBLIC
PROC [design:
CD.Design] =
BEGIN
dl: REF RememberBuffer;
IF design^.actual.first.deletedList=NIL THEN RETURN;
dl ← NARROW[design^.actual.first.deletedList];
dl.next ← (dl.next+remSize-1) MOD remSize;
DO
dl.next ← (dl.next+remSize-1) MOD remSize;
IF dl.a[dl.next]=NIL THEN EXIT;
Forgett[dl.a[dl.next]];
dl.a[dl.next] ← NIL;
ENDLOOP
END;
-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Primality: TYPE = {primary, secondary};
ChangeWireLength:
PROC [design:
CD.Design, aptr:
CD.ApplicationPtr, amount:
CD.DesignNumber] =
BEGIN
--??? for now CDRects.CreateRect is ONLY method to create wires
sz: CD.DesignPosition = CDBasics.SizeOfRect[CD.InterestRect[aptr.ob]];
r: CD.DesignRect ← CDApplications.ARectO[aptr];
newOb: CD.ObPtr←NIL;
IF NOT WireTyped[aptr.ob] THEN ERROR;
newOb ← CDRects.CreateRect[CD.DesignPosition[x: sz.x, y: sz.y+amount], aptr.ob.layer];
IF newOb=NIL THEN RETURN;
IF aptr.ob.p#newOb.p
THEN
ERROR;
--this checks if old object was created with CDRects.CreateRect
aptr.ob ← newOb;
r ← CDBasics.Surround[r, CDApplications.ARectO[aptr]];
CDOps.DelayedRedraw[design, r];
END;
StretchyMoveSP:
PROC[design:
CD.Design, offset:
CD.DesignPosition, selectedApps, nonSelectedApps:
CD.ApplicationList] =
BEGIN
primApps: CD.ApplicationList ← NIL;
primList, secondList, nonPrimList: StretchList ← NIL;
rect: CD.DesignRect;
rect ← CDApplications.BoundingRectO[selectedApps];
FOR l:
CD.ApplicationList ← nonSelectedApps, l.rest
WHILE l#
NIL
DO
IF WireTyped[l.first.ob]
THEN {
me:
REF StretchRec←
NEW[StretchRec←StretchRec[
ap: l.first,
conductRect: CDApplications.ARectI[l.first],
horizontal: CDOrient.IncludesOddRot90[l.first.orientation] -- (length in y direction)
]];
IF CDBasics.Intersect[rect, me.conductRect] AND HasMatch[me, selectedApps, primary] THEN {primList ← CONS[me, primList]; primApps ← CONS[me.ap, primApps]}
ELSE nonPrimList ← CONS[me, nonPrimList]
};
ENDLOOP;
FOR l: StretchList ← nonPrimList, l.rest
WHILE l#
NIL
DO
IF HasMatch[l.first, primApps, secondary] THEN secondList ← CONS[l.first, secondList]
ENDLOOP;
FOR l: StretchList ← secondList, l.rest
WHILE l#
NIL
DO
FiddleWire[design, l.first, offset, secondary]
ENDLOOP;
FOR l: StretchList ← primList, l.rest
WHILE l#
NIL
DO
FiddleWire[design, l.first, offset, primary]
ENDLOOP;
FOR l:
CD.ApplicationList ← selectedApps, l.rest
WHILE l#
NIL
DO
MoveApplication[design, l.first, offset]
ENDLOOP;
END;
StretchyMoveSelected:
PROC[design:
CD.Design, offset:
CD.DesignPosition] =
BEGIN
selectedApps, nonSelectedApps: CD.ApplicationList ← NIL;
[selectedApps, nonSelectedApps] ← CDApplications.SplitSelected[CDOps.AppList[design]];
StretchyMoveSP[design, offset, selectedApps, nonSelectedApps]
END;
StretchList: TYPE = LIST OF REF StretchRec;
StretchRec:
TYPE =
RECORD [
ap: CD.ApplicationPtr,
conductRect: CD.DesignRect, -- hint only
near: BOOL ← FALSE, -- match at near edge (relative to the origin)
far: BOOL ← FALSE, -- match at far edge (relative to the origin)
horizontal: BOOL ← FALSE
];
FiddleWire:
PROC [design:
CD.Design, wire:
REF StretchRec, offset:
CD.DesignPosition, p: Primality] =
BEGIN
--??? change slow case distinction, but now better is easy to understand
move: CD.DesignPosition←offset;
IF ~wire.near AND ~wire.far THEN RETURN;
IF p#primary THEN {IF wire.horizontal THEN move.y𡤀 ELSE move.x𡤀};
IF wire.near
AND ~wire.far
THEN {
IF p#primary THEN {IF wire.horizontal THEN move.y𡤀 ELSE move.x𡤀};
ChangeWireLength[design, wire.ap, -(IF wire.horizontal THEN offset.x ELSE offset.y)];
};
IF ~wire.near
AND wire.far
THEN {
IF wire.horizontal THEN {move.x𡤀} ELSE {move.y𡤀};
ChangeWireLength[design, wire.ap, (IF wire.horizontal THEN offset.x ELSE offset.y)];
};
IF wire.near AND wire.far THEN NULL;
MoveApplication[design, wire.ap, move]
END;
HasMatch:
PROC [me:
REF StretchRec, list:
CD.ApplicationList, p: Primality]
RETURNS [
BOOL] =
-- checks weather me has some match with any of list
BEGIN
near, far: BOOL;
nearEdge, farEdge: CD.DesignRect;
nearEdge ← farEdge ← me.conductRect; -- edges at near or far end of wire, parallel to width
IF ~CDOrient.IncludesOddRot90[me.ap.orientation]
THEN {
farEdge.y1 ← me.conductRect.y2;
nearEdge.y2 ← me.conductRect.y1;
}
ELSE {
farEdge.x1 ← me.conductRect.x2;
nearEdge.x2 ← me.conductRect.x1;
me.horizontal ← TRUE;
};
FOR l:
CD.ApplicationList ← list, l.rest
WHILE l#
NIL
DO
r: CD.DesignRect = CDApplications.ARectI[l.first];
near ← CDBasics.Intersect[nearEdge, r];
far ← CDBasics.Intersect[farEdge, r];
IF near
OR far
THEN {
IF WireTyped[l.first.ob]
THEN {
--??? Only CDRects.CreateRect for now
IF l.first.ob.layer#me.ap.ob.layer THEN near ← far ← FALSE
ELSE IF p#primary AND me.horizontal=CDOrient.IncludesOddRot90[l.first.orientation] THEN near ← far ← FALSE
}
ELSE IF ISTYPE[l.first.ob.specificRef, CD.CellPtr] THEN NULL
ELSE
IF CDStretchyExtras.HasMatchProc[l.first.ob]
THEN {
rect: CD.DesignRect = CDApplications.ARectI[me.ap];
IF ~CDStretchyExtras.Match[l.first.ob, rect, me.ap.ob.layer, p=primary, me.horizontal] THEN near ← far ← FALSE
}
ELSE near ← far ← FALSE;
me.near ← me.near OR near;
me.far ← me.far OR far;
};
ENDLOOP;
RETURN [me.near OR me.far]
END;
MoveApplication:
PROC [design:
CD.Design, ap:
CD.ApplicationPtr, offset:
CD.DesignPosition] =
BEGIN
r: CD.DesignRect ← CDApplications.ARectO[ap];
ap.location ← CDBasics.AddPoints[ap.location, offset];
RedrawMoved[design, r, offset]
END;
WireTyped: PROC [ob: CD.ObPtr] RETURNS [BOOL] = INLINE {RETURN [ob.p.wireTyped]};
END.