<> <> <> <> DIRECTORY CD, CDInstances, CDSimpleOps, CDCommandOps, CDEvents, CDBasics, CDOps, CDOrient, CDProperties, CDRects, CDStretchyExtras, CDValue, Rope USING [IsEmpty, ROPE], TerminalIO; CDSimpleOpsImpl: CEDAR PROGRAM IMPORTS CD, CDInstances, CDBasics, CDCommandOps, CDEvents, CDOps, CDOrient, CDProperties, CDRects, CDStretchyExtras, CDValue, Rope, TerminalIO EXPORTS CDSimpleOps = BEGIN renameEvent: CDEvents.EventRegistration_CDEvents.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.Position, verbose: BOOL] = BEGIN sel: CD.Instance _ NIL; 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 { sel.selected _ TRUE; <<--reorder list, future select selects next lower application>> CDOps.ReOrderInstance[design, sel]; CDOps.RedrawInstance[design, sel]; IF verbose THEN TerminalIO.WriteRope[CDCommandOps.InstRope[sel]]; } ELSE IF verbose THEN { 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.WriteRopes[CDCommandOps.InstRope[w.first], " again"]; RETURN } }; ENDLOOP; TerminalIO.WriteRope[" no pointed object"]; } END; DeSelect: PUBLIC PROC [design: CD.Design, pos: CD.Position, verbose: BOOL] = BEGIN inst: CD.Instance _ CDInstances.InstanceAt[CDOps.InstList[design], pos, TRUE]; IF inst#NIL THEN BEGIN IF ~inst.selected THEN ERROR; inst.selected _ FALSE; CDOps.RedrawInstance[design, inst]; <<--reorder list, future select op finds next lower application>> CDOps.ReOrderInstance[design, inst]; END; IF verbose THEN TerminalIO.WriteRope[CDCommandOps.InstRope[inst]]; END; BoundingRectAndCount: PROC[list: CD.InstanceList, selectedOnly: BOOLEAN_FALSE] RETURNS [bound: CD.Rect_CDBasics.empty, cnt: INT_0] = BEGIN FOR tem: LIST OF CD.Instance _ list, tem.rest WHILE tem#NIL DO IF selectedOnly AND NOT tem.first.selected THEN LOOP; cnt _ cnt+1; bound _ CDBasics.Surround[bound, CDInstances.InstRectO[tem.first]] ENDLOOP; END; DeselectAll: PUBLIC PROC [design: CD.Design] = BEGIN doItSingleWise: NAT = 4; sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]]; b: CD.Rect; cnt: INT; [b, cnt] _ BoundingRectAndCount[list: sel]; CDInstances.DeSelectList[sel]; IF cnt<=doItSingleWise THEN FOR l: CD.InstanceList _ sel, l.rest WHILE l#NIL DO CDOps.RedrawInstance[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 _ CDInstances.BoundingRectO[list: CDOps.InstList[design], selectedOnly: FALSE]; FOR w: CD.InstanceList _ CDOps.InstList[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.Rect] = BEGIN FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF NOT w.first.selected AND CDBasics.Intersect[area, CDInstances.InstRectI[w.first]] THEN { w.first.selected _ TRUE; CDOps.RedrawInstance[design, w.first, FALSE]; }; ENDLOOP; END; AreaDeSelectTouched: PROC [design: CD.Design, area: CD.Rect] = BEGIN FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF w.first.selected AND CDBasics.Intersect[area, CDInstances.InstRectI[w.first]] THEN { w.first.selected _ FALSE; CDOps.RedrawInstance[design, w.first]; }; ENDLOOP; END; AreaSelectContained: PROC [design: CD.Design, area: CD.Rect] = BEGIN FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF CDBasics.Inside[CDInstances.InstRectI[w.first], area] THEN w.first.selected _ TRUE ENDLOOP; CDOps.DelayedRedraw[design, area, FALSE]; END; AreaDeSelectContained: PROC [design: CD.Design, area: CD.Rect] = BEGIN FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF CDBasics.Inside[CDInstances.InstRectI[w.first], area] THEN w.first.selected _ FALSE ENDLOOP; CDOps.DelayedRedraw[design, area]; END; AreaSelect: PUBLIC PROC [design: CD.Design, area: CD.Rect, includePartial: BOOL] = BEGIN IF includePartial THEN AreaSelectTouched[design, area] ELSE AreaSelectContained[design, area]; END; AreaDeSelect: PUBLIC PROC [design: CD.Design, area: CD.Rect, 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.InstanceList; [selected: toDelete, others: newContents] _ CDInstances.SplitSelected[CDOps.InstList[design]]; CDOps.SetInstList[design, newContents]; FOR w: CD.InstanceList _ toDelete, w.rest WHILE w#NIL DO count _ count+1; CDOps.RedrawInstance[design, w.first, TRUE]; ENDLOOP; IF verbose THEN { IF count#1 THEN { TerminalIO.WriteInt[count]; TerminalIO.WriteRope[" objects"] } ELSE TerminalIO.WriteRope[CDCommandOps.InstRope[toDelete.first]] }; RememberShortTime[design, toDelete]; END; RedrawMoved: PROC [design: CD.Design, r: CD.Rect, offset: CD.Position] = BEGIN moved: CD.Rect _ 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; MoveSelected: PUBLIC PROC [design: CD.Design, offset: CD.Position, stretchy: CDSimpleOps.StretchyMode] = BEGIN IF stretchy=option THEN IF CDValue.FetchInt[design, $CDxStretchyMove, global]=1 THEN stretchy_yes; IF stretchy=yes THEN StretchyMoveSelected[design, offset] ELSE SimpleMoveSelected[design, offset] END; SimpleMoveSelected: PUBLIC PROC [design: CD.Design, offset: CD.Position] = BEGIN 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 w.first.location _ CDBasics.AddPoints[w.first.location, offset]; ENDLOOP; RedrawMoved[design, bounding, offset] END; CopySelected: PUBLIC PROC [design: CD.Design, offset: CD.Position] = BEGIN 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 _ NEW[CD.InstanceRep]; inst.ob _ w.first.ob; inst.location _ CDBasics.AddPoints[w.first.location, offset]; inst.orientation _ w.first.orientation; inst.properties _ CDProperties.DCopyProps[w.first.properties]; inst.selected _ TRUE; new _ CONS[inst, new]; w.first.selected _ FALSE; ENDLOOP; CDOps.IncludeInstanceList[design, new, FALSE]; RedrawMoved[design, bounding, offset]; END; Transform: PROC [inst: CD.Instance, cellRect: CD.Rect, transformation: CD.Orientation] = BEGIN r: CD.Rect _ CDOrient.MapRect[ itemInCell: CDOrient.RectAt[ CDBasics.SubPoints[inst.location, CDBasics.BaseOfRect[cellRect]], inst.ob.size, inst.orientation], cellSize: CDBasics.SizeOfRect[cellRect], cellInstOrient: transformation, cellInstPos: CDBasics.BaseOfRect[cellRect] ]; inst.location _ CDBasics.BaseOfRect[r]; inst.orientation _ CDOrient.ComposeOrient[itemOrientInCell: inst.orientation, cellOrientInWorld: transformation]; END; TransformSelected: PUBLIC PROC [design: CD.Design, transform: CD.Orientation] = BEGIN sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]]; b: CD.Rect _ CDInstances.BoundingRectO[sel]; ib: CD.Rect = CDInstances.BoundingRectI[sel]; FOR w: CD.InstanceList _ sel, w.rest WHILE w#NIL DO 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.Rect] = BEGIN sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]]; b: CD.Rect _ CDInstances.BoundingRectO[sel]; newB: CD.Rect _ CDOrient.MapRect[ itemInCell: b, cellSize: CDBasics.SizeOfRect[base], cellInstOrient: transform, cellInstPos: CDBasics.BaseOfRect[base] ]; FOR w: CD.InstanceList _ sel, w.rest WHILE w#NIL DO 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_0]; Forgett: PROC[class: REF] = <<--helps the garbage collector, >> <<--special may prevent circularities through properties>> BEGIN WITH class SELECT FROM il: CD.InstanceList => FOR l: CD.InstanceList _ il, l.rest WHILE l#NIL DO Forgett[l.first] ENDLOOP; inst: CD.Instance => {inst.properties _ NIL; inst.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_0] = BEGIN del: REF _ GiveRemembered[design]; IF del=NIL THEN RETURN; WITH del SELECT FROM il: CD.InstanceList => CDOps.IncludeInstanceList[design, il]; inst: CD.Instance => CDOps.IncludeInstance[design, inst] 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, inst: CD.Instance, amount: CD.Number] = BEGIN <<--??? for now CDRects.CreateRect is ONLY method to create wires >> sz: CD.Position = CD.InterestSize[inst.ob]; r: CD.Rect _ CDInstances.InstRectO[inst]; newOb: CD.Object_NIL; IF NOT WireTyped[inst.ob] THEN ERROR; newOb _ CDRects.CreateRect[CD.Position[x: sz.x, y: sz.y+amount], inst.ob.layer]; IF newOb=NIL THEN RETURN; IF inst.ob.class#newOb.class THEN ERROR; <<--this checks if old object was created with CDRects.CreateRect>> inst.ob _ newOb; r _ CDBasics.Surround[r, CDInstances.InstRectO[inst]]; CDOps.DelayedRedraw[design, r]; END; StretchyMoveSP: PROC[design: CD.Design, offset: CD.Position, selectedApps, nonSelectedApps: CD.InstanceList] = BEGIN primApps: CD.InstanceList _ NIL; primList, secondList, nonPrimList: StretchList _ NIL; rect: CD.Rect; rect _ CDInstances.BoundingRectO[selectedApps]; FOR l: CD.InstanceList _ nonSelectedApps, l.rest WHILE l#NIL DO IF WireTyped[l.first.ob] THEN { me: REF StretchRec_NEW[StretchRec_StretchRec[ ap: l.first, conductRect: CDInstances.InstRectI[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.InstanceList _ selectedApps, l.rest WHILE l#NIL DO MoveInst[design, l.first, offset] ENDLOOP; END; StretchyMoveSelected: PROC[design: CD.Design, offset: CD.Position] = BEGIN selectedApps, nonSelectedApps: CD.InstanceList _ NIL; [selectedApps, nonSelectedApps] _ CDInstances.SplitSelected[CDOps.InstList[design]]; StretchyMoveSP[design, offset, selectedApps, nonSelectedApps] END; StretchList: TYPE = LIST OF REF StretchRec; StretchRec: TYPE = RECORD [ ap: CD.Instance, conductRect: CD.Rect, -- 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.Position, class: Primality] = BEGIN <<--??? change slow case distinction, but now better is easy to understand>> move: CD.Position_offset; IF ~wire.near AND ~wire.far THEN RETURN; IF class#primary THEN {IF wire.horizontal THEN move.y_0 ELSE move.x_0}; IF wire.near AND ~wire.far THEN { IF class#primary THEN {IF wire.horizontal THEN move.y_0 ELSE move.x_0}; 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_0} ELSE {move.y_0}; ChangeWireLength[design, wire.ap, (IF wire.horizontal THEN offset.x ELSE offset.y)]; }; IF wire.near AND wire.far THEN NULL; MoveInst[design, wire.ap, move] END; HasMatch: PROC [me: REF StretchRec, list: CD.InstanceList, class: Primality] RETURNS [BOOL] = <<-- checks weather me has some match with any of list>> BEGIN near, far: BOOL; nearEdge, farEdge: CD.Rect; 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.InstanceList _ list, l.rest WHILE l#NIL DO r: CD.Rect = CDInstances.InstRectI[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 class#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.Rect = CDInstances.InstRectI[me.ap]; IF ~CDStretchyExtras.Match[l.first.ob, rect, me.ap.ob.layer, class=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; MoveInst: PROC [design: CD.Design, inst: CD.Instance, offset: CD.Position] = BEGIN r: CD.Rect _ CDInstances.InstRectO[inst]; inst.location _ CDBasics.AddPoints[inst.location, offset]; RedrawMoved[design, r, offset]; END; WireTyped: PROC [ob: CD.Object] RETURNS [BOOL] = INLINE { RETURN [ob.class.wireTyped] }; END.