CDBasicCommands.mesa (part of ChipNDale)
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, June 29, 1983 4:44 pm
Last edited by: Christian Jacobi, January 15, 1987 11:58:10 am PST
DIRECTORY
BasicTime,
CD,
CDBasics,
CDInstances,
CDLayers,
CDSimpleOps,
CDOps,
CDRects,
CDSequencer,
TerminalIO;
CDBasicCommands:
CEDAR
PROGRAM
IMPORTS BasicTime, CDInstances, CDLayers, CDSimpleOps, CDOps, CDSequencer, TerminalIO, CDRects, CDBasics =
BEGIN
AddARect:
PROC [design:
CD.Design, r:
CD.Rect, l:
CD.Layer] = {
IF CDBasics.NonEmpty[r]
THEN {
ob: CD.Object;
sz: CD.Position ← CDBasics.SizeOfRect[r];
orient: CD.Orientation ← original;
IF sz.y<sz.x
THEN {
w: CD.Number ← sz.x; sz.x ← sz.y; sz.y ← w;
orient ← rotate90
};
ob ← CDRects.CreateRect[sz, l];
CDOps.IncludeObjectI[design: design, ob: ob, location: CDBasics.BaseOfRect[r], orientation: orient]
}
ELSE TerminalIO.PutRope["empty rect not included\n"];
};
AddRect:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["draw rect\n"];
AddARect[comm.design, CDBasics.ToRect[comm.sPos, comm.pos], comm.l];
};
AddWire:
PROC [comm: CDSequencer.Command] = {
--uses pos, sPos, n (for width), b (for firstHorizontal), l (for layer)
InternalAddWire[comm: comm, firstOnly: FALSE]
};
ContinueWire:
PROC [comm: CDSequencer.Command] = {
InternalAddWire[comm: comm, firstOnly: TRUE]
};
InternalAddWire:
PROC [comm: CDSequencer.Command, firstOnly:
BOOL←
FALSE] = {
--this procedure knows EXACTLY the algorithm used for showing
--temporary wires in the cursor part
start: CD.Position ← comm.sPos;
stop: CD.Position ← comm.pos;
wireWidth: CD.Number ← comm.n;
IF wireWidth=0 THEN {AddRect[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];
}
}
};
DeleteSelected:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["delete selected "];
CDSimpleOps.DeleteSelected[comm.design];
TerminalIO.PutRope["\n"];
};
Undelete:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["un-delete\n"];
CDSimpleOps.Undelete[comm.design]
};
AbortCommand:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["try to abort current command\n"];
CDSequencer.AbortDesignsCommand[comm.design]
};
SelectExclusive:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select pointed "];
CDSimpleOps.DeselectAll[comm.design];
CDSimpleOps.Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
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]
};
ReSelectExclusive:
PROC [design:
CD.Design, pos:
CD.Position, verbose:
BOOL←
TRUE, layer:
CD.Layer←
CD.undefLayer]
RETURNS [done:
BOOL←
TRUE] = {
Deselect:
PROC [i:
CD.Instance] =
INLINE {
IF i.selected
THEN {
i.selected ← FALSE;
CDOps.RedrawInstance[design, i]
}
};
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[CDOps.InstRope[w.first]];
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[CDOps.InstRope[inst]]
}
ELSE {
done ← FALSE;
IF verbose THEN TerminalIO.PutRope[" (no object)"];
}
};
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)
]]
};
CloseReSelectExclusive:
PROC [design:
CD.Design, pos:
CD.Position, verbose:
BOOL←
TRUE, 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 ", CDOps.InstRope[inst]];
}
}
};
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"];
};
crazy heuristics to determine which kind of selection is wanted
lastPos: CD.Position;
lastKey: REF ← NIL;
lastTime: BasicTime.GMT ← BasicTime.earliestGMT;
SameAsLast:
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;
};
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 SameAsLast[comm] THEN CDSimpleOps.DeselectAll[comm.design];
[] ← CloseReSelectExclusive[comm.design, comm.pos, TRUE, 50];
TerminalIO.PutRope["\n"];
};
MultiOnlySelectComm:
PROC [comm: CDSequencer.Command] = {
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 CloseReSelectComm[comm]
ELSE AreaOnlySelect[comm];
};
DoubleAddSelectComm:
PROC [comm: CDSequencer.Command] = {
IF SameAsLast[comm]
THEN {
TerminalIO.PutRope["change selection "];
[] ← DeSelectLast[comm.design, comm.pos, TRUE];
}
ELSE TerminalIO.PutRope["add selection "];
CDSimpleOps.Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeselectPointed:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["remove selection "];
CDSimpleOps.DeSelect[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeSelectLast:
PROC [design:
CD.Design, pos:
CD.Position, usePos:
BOOL←
TRUE]
RETURNS [done:
BOOL←
FALSE] = {
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]
}
};
DeselectLastSelected:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["remove selection "];
[] ← DeSelectLast[comm.design, comm.pos, TRUE];
TerminalIO.PutRope["\n"];
};
AddSelection:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["add selection "];
CDSimpleOps.Select[comm.design, comm.pos];
TerminalIO.PutRope["\n"];
};
DeselectAll:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select all\n"];
CDSimpleOps.DeselectAll[comm.design]
};
SelectAll:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select all\n"];
CDSimpleOps.SelectAll[comm.design]
};
AreaAddSelect:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["inclusive select area\n"];
CDSimpleOps.AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
MultiAddSelect:
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"];
CDSimpleOps.AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
}
};
AreaAddSelectTouching:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select inclusive touching\n"];
CDSimpleOps.AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos], TRUE]
};
AreaOnlySelect:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["select area\n"];
CDSimpleOps.DeselectAll[comm.design];
CDSimpleOps.AreaSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
ADeSelect:
PROC [comm: CDSequencer.Command] = {
--Auto deselect area or pointed
TerminalIO.PutRope["de-select "];
IF comm.pos=comm.sPos THEN CDSimpleOps.DeSelect[comm.design, comm.pos]
ELSE CDSimpleOps.AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]];
TerminalIO.PutRope["\n"];
};
AreaDeSelect:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select area\n"];
CDSimpleOps.AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos]]
};
AreaDeSelectTouching:
PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["de-select touching\n"];
CDSimpleOps.AreaDeSelect[comm.design, CDBasics.ToRect[comm.pos, comm.sPos], TRUE]
};
CDSequencer.ImplementCommand[$AbortCommand, AbortCommand,, dontQueue];
CDSequencer.ImplementCommand[$DrawRect, AddRect];
CDSequencer.ImplementCommand[$DrawWire, AddWire];
CDSequencer.ImplementCommand[$ContinueWire, ContinueWire];
CDSequencer.ImplementCommand[$DeleteS, DeleteSelected];
CDSequencer.ImplementCommand[$Undel, Undelete];
CDSequencer.ImplementCommand[$OnlySelectP, SelectExclusive,, doQueue];
CDSequencer.ImplementCommand[$ReSelectOnlyP, ReSelectExclusiveComm,, doQueue];
CDSequencer.ImplementCommand[$ReSelectOnlyWithLayerP, ReSelectExclusiveWithLayerComm,, doQueue];
CDSequencer.ImplementCommand[$CloseReSelectOnlyP, CloseReSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AddSelectP, AddSelection,, doQueue];
CDSequencer.ImplementCommand[$DeSelectLP, DeselectLastSelected,, doQueue];
CDSequencer.ImplementCommand[$DeSelectFP, DeselectPointed,, doQueue];
CDSequencer.ImplementCommand[$DeSelectS, DeselectAll,, doQueue];
CDSequencer.ImplementCommand[$SelectAll, SelectAll,, doQueue];
CDSequencer.ImplementCommand[$AreaOnlySelect, AreaOnlySelect,, doQueue];
CDSequencer.ImplementCommand[$MultiOnlySelect, MultiOnlySelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaAddSelect, AreaAddSelect,, doQueue];
CDSequencer.ImplementCommand[$AreaAddSelectTouching, AreaAddSelectTouching,, doQueue];
CDSequencer.ImplementCommand[$MultiAddSelect, MultiAddSelect,, doQueue];
CDSequencer.ImplementCommand[$DoubleAddSelect, DoubleAddSelectComm,, doQueue];
CDSequencer.ImplementCommand[$AreaDeSelect, AreaDeSelect,, doQueue];
CDSequencer.ImplementCommand[$AreaDeSelectTouching, AreaDeSelectTouching,, doQueue];
CDSequencer.ImplementCommand[$ADeSelect, ADeSelect,, doQueue];
END.