CDBasicCommands.mesa (part of ChipNDale)
Copyright © 1983, 1986, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 29, 1983 4:44 pm
Last edited by: Christian Jacobi, April 2, 1987 3:27:41 pm PST
DIRECTORY
BasicTime,
CD,
CDBasics,
CDInstances,
CDLayers,
CDOps,
CDRects,
CDSequencer,
CDValue,
IO,
PopUpSelection,
Rope,
TerminalIO;
CDBasicCommands: CEDAR PROGRAM
IMPORTS BasicTime, CDInstances, CDLayers, CDOps, CDSequencer, CDValue, PopUpSelection, TerminalIO, CDRects, CDBasics =
BEGIN
-- common xxxxxxxxxxxxxxxxxxxxxx
DescribeInst: PROC [inst: CD.Instance, design: CD.Design←NIL] RETURNS [r: Rope.ROPE] = {
r ← CDOps.InstRope[inst, design];
IF inst#NIL AND inst.ob.class.composed THEN {
r ← IO.PutFR["%g [%g]", [rope[r]], [cardinal[LOOPHOLE[inst.ob]]]];
};
};
-- selections xxxxxxxxxxxxxxxxxxxxxx
MatchLayer: PROC [template, found: CD.Layer] RETURNS [BOOL] = INLINE {
IF template#CD.undefLayer THEN
IF CDLayers.AbstractToPaint[template]#CDLayers.AbstractToPaint[found] THEN RETURN [FALSE];
RETURN [TRUE]
};
RectDist: PROC [pos: CD.Position, r: CD.Rect] RETURNS [CD.Number] = {
--Distance between a point and a rectangle
RETURN [MAX[
(IF pos.x<r.x1 THEN (r.x1-pos.x) ELSE IF pos.x>r.x2 THEN (pos.x-r.x2) ELSE 0),
(IF pos.y<r.y1 THEN (r.y1-pos.y) ELSE IF pos.y>r.y2 THEN (pos.y-r.y2) ELSE 0)
]]
};
ComputeBB: PROC [list: CD.InstanceList, selectedOnly: BOOLFALSE] RETURNS [bound: CD.Rect�sics.empty, cnt: INT𡤀] = {
FOR l: LIST OF CD.Instance ← list, l.rest WHILE l#NIL DO
IF selectedOnly AND NOT l.first.selected THEN LOOP;
cnt ← cnt+1;
bound ← CDBasics.Surround[bound, CDInstances.InstRectO[l.first]]
ENDLOOP;
};
--Crazy heuristics to determine which kind of selection is wanted
--these variables are used by PROC ReUseSameSelection only
lastPos: CD.Position;
lastKey: REFNIL;
lastTime: BasicTime.GMT ← BasicTime.earliestGMT;
ReUseSameSelection: PROC [comm: CDSequencer.Command] RETURNS [yes: BOOL] = {
lambda: CD.Number = comm.design.technology.lambda;
ReallyClose: PROC [p1, p2: CD.Position] RETURNS [BOOL] = INLINE {
RETURN [ABS[p1.x-p2.x]<=lambda AND ABS[p1.y-p2.y]<=lambda]
};
now: BasicTime.GMT ← BasicTime.Now[];
yes ← ReallyClose[lastPos, comm.pos] AND lastKey=comm.key AND BasicTime.Period[lastTime, now]<=2;
lastPos ← comm.pos;
lastKey ← comm.key;
lastTime ← now;
};
Select: PROC [design: CD.Design, pos: CD.Position] = {
--Select an instance at position pos
sel: CD.Instance ← NIL;
--check whether a different instances should be selected
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF ~w.first.selected THEN {
IF CDInstances.PointToI[pos, w.first] THEN {sel ← w.first; EXIT}
};
ENDLOOP;
IF sel#NIL THEN {
--a new instance will be selected
sel.selected ← TRUE;
--reorder list, future selection will selects next lower instance
CDOps.ReOrderInstance[design, sel];
CDOps.RedrawInstance[design, sel, FALSE];
TerminalIO.PutRope[DescribeInst[sel, design]];
}
ELSE {
--no new instance found; can we select an already selected one?
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF w.first.selected THEN {
IF CDInstances.PointToI[pos, w.first] THEN {
TerminalIO.PutRopes[DescribeInst[w.first, design], " again"];
RETURN
}
};
ENDLOOP;
TerminalIO.PutRope[" no pointed object"];
}
};
DeSelect: PROC [design: CD.Design, pos: CD.Position] = {
--Deselect an instance at position pos
inst: CD.Instance ← CDInstances.InstanceAt[CDOps.InstList[design], pos, TRUE];
IF inst#NIL THEN {
inst.selected ← FALSE;
CDOps.RedrawInstance[design, inst, TRUE];
--reorder list, future selection will find next instance
CDOps.ReOrderInstance[design, inst];
};
TerminalIO.PutRope[DescribeInst[inst, design]];
};
AreaSelect: PROC [design: CD.Design, area: CD.Rect, includePartial: BOOLFALSE] = {
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF ~w.first.selected THEN {
IF CDBasics.Intersect[area, CDInstances.InstRectI[w.first]] THEN
IF includePartial OR CDBasics.Inside[CDInstances.InstRectI[w.first], area] THEN {
w.first.selected ← TRUE;
CDOps.RedrawInstance[design, w.first, FALSE];
};
};
ENDLOOP;
};
AreaDeSelect: PROC [design: CD.Design, area: CD.Rect, includePartial: BOOLFALSE] = {
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF w.first.selected THEN {
IF CDBasics.Intersect[area, CDInstances.InstRectI[w.first]] THEN
IF includePartial OR CDBasics.Inside[CDInstances.InstRectI[w.first], area] THEN {
w.first.selected ← FALSE;
CDOps.RedrawInstance[design, w.first, TRUE];
};
};
ENDLOOP;
};
SelectExclusiveComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select pointed "];
CDOps.DeselectAll[comm.design, FALSE];
Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
ReSelectExclusive: PROC [design: CD.Design, pos: CD.Position, verbose: BOOLTRUE, layer: CD.Layer←CD.undefLayer] RETURNS [done: BOOLTRUE] = {
Deselect: PROC [i: CD.Instance] = INLINE {
IF i.selected THEN {
i.selected ← FALSE;
CDOps.RedrawInstance[design, i, TRUE]
}
};
DeselectList: PROC [list: CD.InstanceList] = {
FOR w: CD.InstanceList ← list, w.rest WHILE w#NIL DO
Deselect[w.first]
ENDLOOP
};
ValidForSelection: PROC [inst: CD.Instance] RETURNS [BOOL] = INLINE {
RETURN [ CDInstances.PointToI[pos, inst] AND MatchLayer[layer, inst.ob.layer] ];
};
inst: CD.Instance ← NIL; --any instance where pos points to
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF ValidForSelection[w.first] THEN {
--hit
IF w.first.selected THEN {
DeselectList[w.rest];
CDOps.ReOrderInstance[design, w.first];
IF verbose THEN TerminalIO.PutRope[DescribeInst[w.first, design]];
RETURN
}
ELSE IF inst=NIL THEN inst ← w.first
}
ELSE Deselect[w.first]
ENDLOOP;
--if a selected inst is pointed we already did return
IF inst#NIL THEN {
inst.selected ← TRUE;
CDOps.ReOrderInstance[design, inst];
CDOps.RedrawInstance[design, inst, FALSE];
IF verbose THEN TerminalIO.PutRope[DescribeInst[inst, design]]
}
ELSE {
done ← FALSE;
IF verbose THEN TerminalIO.PutRope[" (no object)"];
}
};
CloseReSelectExclusive: PROC [design: CD.Design, pos: CD.Position, verbose: BOOLTRUE, dist: CD.Number�, layer: CD.Layer←CD.undefLayer] = {
IF ~ReSelectExclusive[design, pos, verbose, layer] THEN {
inst: CD.Instance ← NIL;
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
d: CD.Number = RectDist[pos, CDInstances.InstRectI[w.first]];
IF d<dist AND MatchLayer[layer, w.first.ob.layer] THEN {inst ← w.first; dist ← d}
ENDLOOP;
IF inst#NIL THEN {
inst.selected ← TRUE;
CDOps.RedrawInstance[design, inst, FALSE];
IF verbose THEN TerminalIO.PutRopes[" found close object ", DescribeInst[inst, design]];
}
}
};
ReSelectExclusiveComm: PROC [comm: CDSequencer.Command] = {
--select pointed instance exclusive;
--(but dont select an other instance if the pointed one is already the right one)
TerminalIO.PutRope["select "];
[] ← ReSelectExclusive[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
ReSelectExclusiveWithLayerComm: PROC [comm: CDSequencer.Command] = {
--select pointed instance of right layer exclusive
layer: CD.Layer ← CDLayers.AbstractToPaint[CDLayers.PlaceholderToAbstract[comm.design, CDLayers.CurrentLayer[comm.design]]];
TerminalIO.PutF["select with layer %g ", [rope[CDOps.LayerRope[layer]]]];
[] ← ReSelectExclusive[comm.design, comm.pos, TRUE, layer];
TerminalIO.PutRope["\n"];
};
CloseReSelectComm: PROC [comm: CDSequencer.Command] = {
--select pointed instance exclusive;
--(but dont select an other instance if the pointed one is already the right one)
--if there is none, select closest
--cycle through if exactly sme position
TerminalIO.PutRope["select "];
IF ReUseSameSelection[comm] THEN CDOps.DeselectAll[comm.design, FALSE];
[] ← CloseReSelectExclusive[comm.design, comm.pos, TRUE, 50];
TerminalIO.PutRope["\n"];
};
MultiOnlySelectComm: PROC [comm: CDSequencer.Command] = {
ReallyClose: PROC [p1, p2: CD.Position] RETURNS [BOOL] = INLINE {
RETURN [ABS[p1.x-p2.x]<=lambda OR ABS[p1.y-p2.y]<=lambda]
};
lambda: CD.Number = comm.design.technology.lambda;
IF ReallyClose[comm.pos, comm.sPos]
THEN CloseReSelectComm[comm]
ELSE AreaOnlySelectComm[comm];
};
DoubleAddSelectComm: PROC [comm: CDSequencer.Command] = {
IF ReUseSameSelection[comm] THEN {
TerminalIO.PutRope["change selection "];
[] ← DeSelectLast[comm.design, comm.pos, TRUE];
}
ELSE TerminalIO.PutRope["add selection "];
Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeselectPointedComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["remove selection "];
DeSelect[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeSelectLast: PROC [design: CD.Design, pos: CD.Position, usePos: BOOLTRUE] RETURNS [done: BOOLFALSE] = {
sel: CD.Instance ← NIL;
FOR w: CD.InstanceList ← CDOps.InstList[design], w.rest WHILE w#NIL DO
IF w.first.selected THEN {
IF ~usePos OR CDInstances.PointToI[pos, w.first] THEN sel ← w.first;
};
ENDLOOP;
IF sel#NIL THEN {
sel.selected ← FALSE;
done ← TRUE;
CDOps.RedrawInstance[design, sel, TRUE]
}
};
DeselectLastSelectedComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["remove selection "];
[] ← DeSelectLast[comm.design, comm.pos, TRUE];
TerminalIO.PutRope["\n"];
};
AddSelectionComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["add selection "];
Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeselectAllComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select all\n"];
CDOps.DeselectAll[comm.design, FALSE]
};
SelectAllComm: PROC [comm: CDSequencer.Command] = {
cnt: INT ← 0;
TerminalIO.PutRope["select all: "];
CDOps.DeselectAll[comm.design, TRUE];
FOR w: CD.InstanceList ← CDOps.InstList[comm.design], w.rest WHILE w#NIL DO
cnt ← cnt+1;
ENDLOOP;
TerminalIO.PutF1["%g selected objects\n", [integer[cnt]]];
};
AreaAddSelectComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["inclusive select area\n"];
AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
MultiAddSelectComm: PROC [comm: CDSequencer.Command] = {
--Auto select area or pointed or changed
NotRect: PROC [p1, p2: CD.Position] RETURNS [BOOL] = INLINE {
RETURN [ABS[p1.x-p2.x]<=lambda OR ABS[p1.y-p2.y]<=lambda]
};
lambda: CD.Number = comm.design.technology.lambda;
IF NotRect[comm.pos, comm.sPos] THEN DoubleAddSelectComm[comm]
ELSE {
TerminalIO.PutRope["select inclusive area\n"];
AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
}
};
AreaAddSelectTouchingComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select inclusive touching\n"];
AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos], TRUE]
};
AreaOnlySelectComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select area\n"];
CDOps.DeselectAll[comm.design, FALSE];
AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
ADeSelectComm: PROC [comm: CDSequencer.Command] = {
--Auto deselect area or pointed
TerminalIO.PutRope["de-select "];
IF comm.pos=comm.sPos THEN DeSelect[comm.design, comm.pos]
ELSE AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]];
TerminalIO.PutRope["\n"];
};
AreaDeSelectComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select area\n"];
AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
AreaDeSelectTouchingComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select touching\n"];
AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos], TRUE]
};
-- xx delete, abort xxxxxxxxxxxxxxxxxxxxxx
DeleteSelected: PROC [design: CD.Design] = {
toDelete, newContents: CD.InstanceList; count: INT ← 0;
[selected: toDelete, others: newContents] ← CDInstances.SplitSelected[CDOps.InstList[design]];
CDOps.SetInstList[design, newContents];
CDOps.Remember[design, toDelete];
FOR w: CD.InstanceList ← toDelete, w.rest WHILE w#NIL DO
count ← count+1;
CDOps.RedrawInstance[design, w.first, TRUE];
ENDLOOP;
IF count#1 THEN TerminalIO.PutF1["%g objects", [integer[count]]]
ELSE TerminalIO.PutRope[DescribeInst[toDelete.first, design]]
};
DeleteSelectedComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["delete selected "];
DeleteSelected[comm.design];
TerminalIO.PutRope["\n"];
};
UndeleteComm: PROC [comm: CDSequencer.Command] = {
il: CD.InstanceList ← CDOps.GetRemembered[comm.design];
TerminalIO.PutRope["un-delete\n"];
CDOps.IncludeInstanceList[comm.design, il];
};
AbortComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["try to abort current command\n"];
CDSequencer.AbortDesignsCommand[comm.design]
};
-- xx wires xxxxxxxxxxxxxxxxxxxxxx
AddARect: PROC [design: CD.Design, r: CD.Rect, l: CD.Layer] = {
IF ~CDBasics.NonEmpty[r] THEN TerminalIO.PutRope["empty rect not included\n"]
ELSE {
orient: CD.Orientation ← original;
sz: CD.Position ← CDBasics.SizeOfRect[r];
IF sz.y<sz.x THEN {
w: CD.Number ← sz.x; sz.x ← sz.y; sz.y ← w;
orient ← rotate90
};
[] ← CDOps.IncludeObjectI[design: design, ob: CDRects.CreateRect[sz, l], location: CDBasics.BaseOfRect[r], orientation: orient]
}
};
InternalAddWire: PROC [comm: CDSequencer.Command, firstOnly: BOOLFALSE] = {
--this procedure knows EXACTLY the algorithm used for drawing
--temporary wires in the rubber banding part
start: CD.Position ← comm.sPos;
stop: CD.Position ← comm.pos;
wireWidth: CD.Number ← comm.n;
IF wireWidth=0 THEN {AddRectComm[comm]; RETURN};
TerminalIO.PutRope["draw wire\n"];
IF --firstHorizontal-- comm.b THEN {
IF stop.x<=start.x AND stop.x>=start.x-wireWidth
AND (stop.y<start.y OR stop.y>start.y+wireWidth) THEN { --crazy vertical wire
IF ABS[start.y-stop.y]<comm.design.technology.lambda THEN {
TerminalIO.PutRope[" empty wire not added\n"]; RETURN
};
stop.x ← start.x+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
RETURN
};
--not only crazy vertical
IF stop.y>=start.y AND stop.y<=start.y+wireWidth THEN { --horizontal wire
stop.y ← start.y+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l]
}
ELSE { --L shaped (firsthorizontal)
IF start.x<=stop.x THEN {stop.x ← stop.x+wireWidth}
ELSE {t: CD.Number=stop.x; stop.x ← start.x; start.x ← t};
stop.y ← start.y+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
IF firstOnly THEN RETURN;
start.x ← comm.pos.x; stop.y ← comm.pos.y; stop.x ← start.x+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
}
}
ELSE { -- NOT firstHorizontalVC --
IF stop.y<=start.y AND stop.y>=start.y-wireWidth
AND (stop.x<start.x OR stop.x>start.x+wireWidth) THEN { --crazy horizontal wire
IF ABS[stop.x-start.x]<comm.design.technology.lambda THEN {
TerminalIO.PutRope[" empty wire not added\n"]; RETURN
};
stop.y ← start.y+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
RETURN
};
-- not only crazy horizontal
IF stop.x>=start.x AND stop.x<=start.x+wireWidth THEN { --vertical wire
stop.x ← start.x+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l]
}
ELSE { --L shaped (firstVertical)
IF start.y<=stop.y THEN {stop.y ← stop.y+wireWidth}
ELSE {t: CD.Number = stop.y; stop.y ← start.y; start.y ← t};
stop.x ← start.x+wireWidth;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
IF firstOnly THEN RETURN;
start.y ← comm.pos.y; stop.y ← start.y+wireWidth; stop.x ← comm.pos.x;
AddARect[comm.design, CDBasics.ToRect[start, stop], comm.l];
}
}
};
AddRectComm: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["draw rect\n"];
AddARect[comm.design, CDBasics.ToRect[comm.sPos, comm.pos], comm.l];
};
AddWireComm: PROC [comm: CDSequencer.Command] = {
--uses pos, sPos, n (for width), b (for firstHorizontal), l (for layer)
InternalAddWire[comm: comm, firstOnly: FALSE]
};
ContinueWireComm: PROC [comm: CDSequencer.Command] = {
InternalAddWire[comm: comm, firstOnly: TRUE]
};
-- moves and copies xxxxxxxxxxxxxxxxxxxxxx
RedrawMoved: PROC [design: CD.Design, r: CD.Rect, offset: CD.Position] = {
moved: CD.Rect ← CDBasics.MoveRect[r, offset];
IF CDBasics.Intersect[r, moved] THEN
CDOps.Redraw[design, CDBasics.Surround[r, moved], TRUE]
ELSE {
CDOps.Redraw[design, r];
CDOps.Redraw[design, moved, FALSE]; -- use eraseFirst because also used by copy
}
};
OrientSelected: PROC [design: CD.Design, transform: CD.Orientation, base: CD.Rect←[0,0,-1,-1]] = {
--Orientates the selection such that:
--takes the base rectangle, transforms orientation and translates the transformed rectangle
--to fit its lower left point [after transformation] to be at the same point as the lower left
--point of the base rectangle before the transformation.
--If base is empty, use bbox of selection.
ib, is, orientOff: CD.Position; r, oldbb: CD.Rect; oldPseudoCellT, newPseudoCellT: CD.Transformation;
sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]];
IF sel=NIL THEN RETURN;
oldbb ← CDInstances.BoundingRectO[sel];
IF ~CDBasics.NonEmpty[base] THEN base ← CDInstances.BoundingRectI[sel];
ib ← CDBasics.BaseOfRect[base];
is ← CDBasics.SizeOfRect[base];
oldPseudoCellT ← [ib, original];
r ← CDBasics.MapRect[CDBasics.RectAt[[0,0], is], [[0,0], transform]];
orientOff ← CDBasics.BaseOfRect[r];
newPseudoCellT ← [CDBasics.SubPoints[ib, orientOff], transform];
FOR w: CD.InstanceList ← sel, w.rest WHILE w#NIL DO
pseudoCellRel: CD.Transformation ← CDBasics.DecomposeTransform[w.first.trans, oldPseudoCellT];
w.first.trans ← CDBasics.ComposeTransform[pseudoCellRel, newPseudoCellT]
ENDLOOP;
CDOps.Redraw[design, oldbb, TRUE];
CDOps.Redraw[design, CDBasics.MapRect[CDBasics.DeMapRect[oldbb, oldPseudoCellT], newPseudoCellT], FALSE]
};
MoveSelected: PROC [design: CD.Design, offset: CD.Position] = {
sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]];
bounding: CD.Rect ← CDBasics.empty;
FOR w: CD.InstanceList ← sel, w.rest WHILE w#NIL DO
inst: CD.Instance ← w.first;
bounding ← CDBasics.Surround[bounding, CDInstances.InstRectO[inst]];
inst.trans.off ← CDBasics.AddPoints[inst.trans.off, offset];
ENDLOOP;
RedrawMoved[design, bounding, offset]
};
CopySelected: PUBLIC PROC [design: CD.Design, offset: CD.Position] = {
new: CD.InstanceList←NIL;
sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]];
bounding: CD.Rect ← CDInstances.BoundingRectO[sel];
FOR w: CD.InstanceList ← sel, w.rest WHILE w#NIL DO
inst: CD.Instance ← CDInstances.Copy[w.first];
inst.trans.off ← CDBasics.AddPoints[inst.trans.off, offset];
inst.selected ← TRUE;
new ← CONS[inst, new];
w.first.selected ← FALSE;
ENDLOOP;
CDOps.IncludeInstanceList[design, new, FALSE];
RedrawMoved[design, bounding, offset];
};
TransformS: PROC [comm: CDSequencer.Command] = {
n: CARDINAL;
TerminalIO.PutRope["transform: "];
n ← PopUpSelection.Request[
header: "transform",
choice: LIST["mirror x", "mirror y", "rot 90", "rot 180", "rot 270"]];
SELECT n FROM
1 => {TerminalIO.PutRope["mirror x\n"];
OrientSelected[comm.design, mirrorX]};
2 => {TerminalIO.PutRope["mirror y\n"];
OrientSelected[comm.design, rotate180];
OrientSelected[comm.design, mirrorX]};
3 => {TerminalIO.PutRope["rot 90\n"];
OrientSelected[comm.design, rotate90]};
4 => {TerminalIO.PutRope["rot 180\n"];
OrientSelected[comm.design, rotate180]};
5 => {TerminalIO.PutRope["rot 270\n"];
OrientSelected[comm.design, rotate270]};
ENDCASE => TerminalIO.PutRope["Skipped\n"];
};
RotS: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["rotate counterclockwise\n"];
OrientSelected[comm.design, rotate90]
};
MirrorS: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["mirror on x axis\n"];
OrientSelected[comm.design, mirrorX]
};
MirrorYS: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["mirror on y axis\n"];
OrientSelected[comm.design, CD.mirrorY];
};
SimpleMoveSCommand: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["move (no stretch)\n"];
MoveSelected[design: comm.design, offset: CD.Position[comm.pos.x-comm.sPos.x, comm.pos.y-comm.sPos.y]]
};
CopySCommand: PROC [comm: CDSequencer.Command] = {
IF comm.pos.x#comm.sPos.x OR comm.pos.y#comm.sPos.y THEN {
IF comm.data#NIL AND comm.data#comm.design AND ISTYPE[comm.data, CD.Design] THEN {
--we dont want to import fancy imports; copy is logically deeper in hierachy
p: CDSequencer.CommandProc ← CDSequencer.FetchCommand[$UnqueuedCopyInterDesign].proc;
IF p=NIL
THEN TerminalIO.PutRope["failed, command issued in other design\n"]
ELSE CDSequencer.ExecuteProc[p, comm.design, dontQueue, comm];
RETURN
};
TerminalIO.PutRope["copy\n"];
CopySelected[comm.design, CD.Position[comm.pos.x-comm.sPos.x, comm.pos.y-comm.sPos.y]]
}
ELSE TerminalIO.PutRope["no copy in place\n"];
};
StepSize: PROC [comm: CDSequencer.Command] RETURNS [n: CD.Number] = {
design: CD.Design ← comm.design;
n ← CDValue.FetchInt[boundTo: design, key: $CDxStepValue, propagation: design];
IF n<=0 THEN {
n ← CDOps.GetGrid[design, comm];
IF n<=0 THEN n ← design.technology.lambda
}
};
LambdaUpS: PROC [comm: CDSequencer.Command] = {
--TerminalIO.PutRope["step move up\n"];
MoveSelected[comm.design, [0, StepSize[comm]]]
};
LambdaDownS: PROC [comm: CDSequencer.Command] = {
--TerminalIO.PutRope["step move down\n"];
MoveSelected[comm.design, [0, -StepSize[comm]]]
};
LambdaLeftS: PROC [comm: CDSequencer.Command] = {
--TerminalIO.PutRope["step move left\n"];
MoveSelected[comm.design, [-StepSize[comm], 0]]
};
LambdaRightS: PROC [comm: CDSequencer.Command] = {
--TerminalIO.PutRope["step move right\n"];
MoveSelected[comm.design, [StepSize[comm], 0]]
};
RenameDesign: PROC [comm: CDSequencer.Command] = {
name: Rope.ROPE; done: BOOL;
TerminalIO.PutRopes["rename design ", comm.design.name, "\n"];
name ← TerminalIO.RequestRope["enter name: "];
done ← CDOps.RenameDesign[comm.design, name];
IF done THEN TerminalIO.PutRope["done\n"] ELSE TerminalIO.PutRope["not done\n"];
};
CDValue.StoreInt[boundTo: NIL, key: $CDxStepValue, value: 0];
CDSequencer.ImplementCommand[$DrawRect, AddRectComm];
CDSequencer.ImplementCommand[$DrawWire, AddWireComm];
CDSequencer.ImplementCommand[$ContinueWire, ContinueWireComm];
CDSequencer.ImplementCommand[$DeleteS, DeleteSelectedComm];
CDSequencer.ImplementCommand[$Undel, UndeleteComm];
CDSequencer.ImplementCommand[$AbortCommand, AbortComm,, dontQueue];
CDSequencer.ImplementCommand[$OnlySelectP, SelectExclusiveComm,, doQueue];
CDSequencer.ImplementCommand[$ReSelectOnlyP, ReSelectExclusiveComm,, doQueue];
CDSequencer.ImplementCommand[$ReSelectOnlyWithLayerP, ReSelectExclusiveWithLayerComm,, doQueue];
CDSequencer.ImplementCommand[$CloseReSelectOnlyP, CloseReSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AddSelectP, AddSelectionComm,, doQueue];
CDSequencer.ImplementCommand[$DeSelectLP, DeselectLastSelectedComm,, doQueue];
CDSequencer.ImplementCommand[$DeSelectFP, DeselectPointedComm,, doQueue];
CDSequencer.ImplementCommand[$DeSelectS, DeselectAllComm,, doQueue];
CDSequencer.ImplementCommand[$SelectAll, SelectAllComm,, doQueue];
CDSequencer.ImplementCommand[$AreaOnlySelect, AreaOnlySelectComm,, doQueue];
CDSequencer.ImplementCommand[$MultiOnlySelect, MultiOnlySelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaAddSelect, AreaAddSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaAddSelectTouching, AreaAddSelectTouchingComm,, doQueue];
CDSequencer.ImplementCommand[$MultiAddSelect, MultiAddSelectComm,, doQueue];
CDSequencer.ImplementCommand[$DoubleAddSelect, DoubleAddSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaDeSelect, AreaDeSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaDeSelectTouching, AreaDeSelectTouchingComm,, doQueue];
CDSequencer.ImplementCommand[$ADeSelect, ADeSelectComm,, doQueue];
CDSequencer.ImplementCommand[$MoveS, SimpleMoveSCommand];
CDSequencer.ImplementCommand[$CopyS, CopySCommand];
CDSequencer.ImplementCommand[$LambdaUpS, LambdaUpS];
CDSequencer.ImplementCommand[$LambdaDownS, LambdaDownS];
CDSequencer.ImplementCommand[$LambdaLeftS, LambdaLeftS];
CDSequencer.ImplementCommand[$LambdaRightS, LambdaRightS];
CDSequencer.ImplementCommand[$RotS, RotS];
CDSequencer.ImplementCommand[$MirrorYS, MirrorYS];
CDSequencer.ImplementCommand[$MirrorS, MirrorS];
CDSequencer.ImplementCommand[$TransformS, TransformS];
CDSequencer.ImplementCommand[$RenameDesign, RenameDesign];
END.