<> <> <> <> DIRECTORY CD, CDInstances, CDCells, CDCellsExtras, CDCellsInteractions, CDDirectory, CDEvents, CDBasics, CDIO, CDOps, CDOrient, CDProperties, CDRects, Process USING [Yield], Real, Rope, TokenIO, TerminalIO; CDCellsImpl: CEDAR PROGRAM IMPORTS CD, CDCellsInteractions, CDInstances, CDIO, CDDirectory, CDEvents, CDBasics, CDOps, CDOrient, CDProperties, CDRects, Process, Real, Rope, TokenIO, TerminalIO EXPORTS CDCells, CDCellsExtras SHARES CD, CDRects, CDDirectory = BEGIN cellClass: PUBLIC CD.ObjectClass = CD.RegisterObjectClass[$Cell, [ drawMe: DrawMeForCells, quickDrawMe: QuickDrawMeForCells, showMeSelected: DrawCellSelection, internalRead: ReadCell, internalWrite: WriteCell, describe: Describe, interestRect: InterestRectCells, origin: OriginForCells ]]; lastOutputDesign: CD.Design _ NIL; Init: PROC [] = { dp: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[cellClass, [ enumerateChildObjects: EnumerateChildObjects, name: Name, setName: SetName, another: Another, replaceDirectChilds: ReplaceDirectChildForCells ]]; [] _ CDProperties.RegisterProperty[$dummyCell]; CDProperties.InstallProcs[prop: $dummyCell, new: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.DontCopy, internalWrite: NIL, exclusive: TRUE ] ]; [] _ CDProperties.RegisterProperty[$InsideRect]; CDProperties.InstallProcs[prop: $InsideRect, new: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.DontCopy, internalWrite: NIL, internalRead: InternalReadProperty, exclusive: TRUE ] ]; CDEvents.RegisterEventProc[$WriteTechnologyPrivate, RememberDesignOnWriting]; }; IsDummyCell: PUBLIC PROC [cell: CD.Object] RETURNS [BOOL] = { RETURN [CDProperties.GetObjectProp[cell, $dummyCell]=$TRUE] }; InternalReadProperty: PROC [prop: ATOM] RETURNS [val: REF] = { <<--old stuff for io format version 4>> val _ NEW[CD.Rect _ CDIO.ReadRect[]] }; InterestRectCells: PROC [ob: CD.Object] RETURNS [CD.Rect] = { RETURN [NARROW[ob.specificRef, CD.CellPtr].ir] }; OriginForCells: PROC [ob: CD.Object] RETURNS [CD.Position] = { RETURN [NARROW[ob.specificRef, CD.CellPtr].origin] }; SetName: PROC [me: CD.Object, r: Rope.ROPE] = { NARROW[me.specificRef, CD.CellPtr].name _ r }; Name: PROC [me: CD.Object] RETURNS [Rope.ROPE] = { RETURN [NARROW[me.specificRef, CD.CellPtr].name] }; EnumerateChildObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] = { FOR list: CD.InstanceList _ NARROW[me.specificRef, CD.CellPtr].contents, list.rest WHILE list#NIL DO p[list.first.ob, x] ENDLOOP }; Another: PROC [me: CD.Object, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL] RETURNS [ new: CD.Object _ CreateEmptyCell[], topMode: CDDirectory.InclOrReady _ ready, childMode: CDDirectory.ImmOrIncl _ immutable] = { oldCp: CD.CellPtr _ NARROW[me.specificRef]; newCp: CD.CellPtr _ NARROW[new.specificRef]; new.size _ me.size; newCp^ _ oldCp^; newCp.contents _ CDInstances.CopyList[oldCp.contents]; CDProperties.AppendProps[winner: new.properties, looser: me.properties, putOnto: new]; IF fromOrNil=into AND into#NIL THEN childMode _ included }; DrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { cp: CD.CellPtr _ NARROW[inst.ob.specificRef, CD.CellPtr]; <<--draw border>> IF pr.borders AND cp.drawBorder THEN pr.drawOutLine[ CDOrient.MapRect[ itemInCell: CD.InterestRect[inst.ob], cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos ], CD.outlineLayer, pr]; <<--draw inside>> FOR w: CD.InstanceList _ cp.contents, w.rest WHILE w#NIL DO r: CD.Rect _ CDOrient.MapRect[ itemInCell: CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation], cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos ]; IF CDBasics.Intersect[r, pr.interestClip] THEN { IF pr.stopFlag^ THEN EXIT; pr.drawChild[ w.first, CDBasics.BaseOfRect[r], CDOrient.ComposeOrient[w.first.orientation, orient], pr]; } ENDLOOP; Yield[]; }; n: INTEGER _ 5; Yield: PROC [] = INLINE { <<--we do want to yield, but not too often>> IF (n_n-1)<0 THEN {n_5; Process.Yield[]} }; IntersectRI: PROC[r: CD.Rect, inst: CD.Instance] RETURNS [BOOL] = TRUSTED INLINE { <<--returns rect intersects or touches inst>> IF inst.location.x>r.x2 OR inst.location.y>r.y2 THEN RETURN [FALSE]; IF PrincOpsUtils.BITAND[inst.orientation, CDOrient.rotate90]=0 THEN --even rot 90 RETURN [ inst.location.x+inst.ob.size.x>=r.x1 AND inst.location.y+inst.ob.size.y>=r.y1 ] ELSE --odd rot 90 RETURN [ inst.location.x+inst.ob.size.y>=r.x1 AND inst.location.y+inst.ob.size.x>=r.y1 ]; }; QuickDrawMeForCells: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { cp: CD.CellPtr = NARROW[inst.ob.specificRef]; IF pr.scaleHint0 THEN { pr.drawOutLine[ CDOrient.MapRect[ itemInCell: cp.ir, cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos ], CD.outlineLayer, pr]; IF pr.scaleHint*inst.ob.size.y>9 THEN pr.drawComment[CDOrient.RectAt[pos, inst.ob.size, orient], cp.name, pr]; } ELSE { mapClip: CD.Rect _ CDOrient.DeMapRect[ --clipping boundary in cell coordinates itemInWorld: pr.interestClip, cellSize: inst.ob.size, cellInstPos: pos, cellInstOrient: orient ].itemInCell; <<--draw border>> IF pr.borders AND cp.drawBorder THEN pr.drawOutLine[ CDOrient.MapRect[ itemInCell: cp.ir, cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos ], CD.outlineLayer, pr]; <<--draw inside>> FOR w: CD.InstanceList _ cp.contents, w.rest WHILE w#NIL DO IF IntersectRI[mapClip, w.first] THEN { r: CD.Rect _ CDOrient.MapRect[ itemInCell: CDOrient.RectAt[w.first.location, w.first.ob.size, w.first.orientation], cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos ]; <<--speed up rects...>> IF w.first.ob.class=CDRects.bareRectClass THEN pr.drawRect[r, w.first.ob.layer, pr] ELSE { IF pr.stopFlag^ THEN EXIT; w.first.ob.class.quickDrawMe[ w.first, CDBasics.BaseOfRect[r], CDOrient.ComposeOrient[w.first.orientation, orient], pr]; } } ENDLOOP; Yield[]; IF pr.checkPriority THEN pr.priorityChecker[pr]; } }; DrawCellSelection: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { IF pr.scaleHint0 THEN pr.drawRect[CDOrient.RectAt[pos, inst.ob.size, orient], CD.shadeLayer, pr] ELSE pr.drawOutLine[ CDOrient.MapRect[itemInCell: CD.InterestRect[inst.ob], cellSize: inst.ob.size, cellInstOrient: orient, cellInstPos: pos], CD.selectionLayer, pr ] }; CreateEmptyCell: PUBLIC PROC [] RETURNS [ob: CD.Object] = { ob _ NEW[CD.ObjectRep_[ class: cellClass, size: [0, 0], specificRef: NEW[CD.CellRep_[simplifyOn: 1]] ]]; }; CreateCellSelected: PUBLIC PROC [design: CD.Design, name: Rope.ROPE_NIL] RETURNS [done: BOOL_FALSE, cellOb: CD.Object_NIL] = { [done, cellOb] _ CDCellsInteractions.CreateCellSelected[design, name] }; PushInCellInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance] RETURNS [done: BOOL _ FALSE] = { done _ CDCellsInteractions.PushInCellInstance[design, inst]; }; PopFromCell: PUBLIC PROC [design: CD.Design, m: CDCells.Method_interactive, name: Rope.ROPE_NIL] RETURNS [done: BOOL] = { done _ CDCellsInteractions.PopFromCell[design, LOOPHOLE[m], name]; }; ReadCell: CD.InternalReadProc --PROC [] RETURNS [Object]-- = { i: INT; ob: CD.Object = CreateEmptyCell[]; specific: CD.CellPtr = NARROW[ob.specificRef]; ob.size _ CDIO.ReadPos[]; IF CDIO.VersionKey[]>=8 THEN { --now specific.simplifyOn _ TokenIO.ReadInt[]; i _ TokenIO.ReadInt[]; specific.useDIr _ (i MOD 2)=0; specific.drawBorder _ (i/2)#0; IF ~specific.useDIr THEN specific.ir _ CDIO.ReadRect[]; specific.origin _ CDIO.ReadPos[]; } ELSE { -- old versions IF CDIO.VersionKey[]<1 THEN { specific.name _ TokenIO.ReadRope[]; } ELSE { specific.simplifyOn _ TokenIO.ReadInt[]; }; }; IF ob.size.y>0 THEN specific.simplifyOn _ specific.simplifyOn/ob.size.y; specific.contents _ CDIO.ReadInstanceList[]; specific.dIr _ CDInstances.BoundingRectI[specific.contents]; IF specific.useDIr THEN specific.ir _ specific.dIr; RETURN [ob]; }; RememberDesignOnWriting: CDEvents.EventProc = { <<-- PROC [event: REF, design: CD.Design, x: REF] >> lastOutputDesign _ design }; WriteCell: CD.InternalWriteProc -- PROC [me: Object] -- = { specific: CD.CellPtr = NARROW[me.specificRef]; i: INT _ IF specific.drawBorder THEN 2 ELSE 0; CDIO.WritePos[me.size]; TokenIO.WriteInt[Real.Round[ MAX[MIN[specific.simplifyOn, 500.0], 0.0] * MAX[MIN[me.size.y, 100000], 0] ]]; IF specific.useDIr AND specific.ir=specific.dIr THEN TokenIO.WriteInt[i] ELSE { TokenIO.WriteInt[i+1]; CDIO.WriteRect[specific.ir]; }; CDIO.WritePos[specific.origin]; CDIO.WriteInstanceList[specific.contents]; }; Describe: PROC[me: CD.Object] RETURNS [Rope.ROPE] = { RETURN [Rope.Concat["cell ", NARROW[me.specificRef, CD.CellPtr].name]] }; ReplaceDirectChildForCells: CDDirectory.ReplaceDChildsProc = { <<-- PROC[me: CD.Object, design: CD.Design, replace: LIST OF REF ReplaceRec] -->> cp: CD.CellPtr = NARROW[me.specificRef]; needReposition: BOOL = ReplaceDirectChildForDummyCells[me, replace]; newIr: CD.Rect = CDInstances.BoundingRectI[cp.contents]; IF needReposition OR cp.dIr#newIr THEN changed _ RepositionCell[me, design]; }; ReplaceDirectChildForDummyCells: PUBLIC PROC [cellOb: CD.Object, replace: CDDirectory.ReplaceList] RETURNS [needReposition: BOOL _ FALSE] = { cp: CD.CellPtr = NARROW[cellOb.specificRef]; FOR replaceList: CDDirectory.ReplaceList _ replace, replaceList.rest WHILE replaceList#NIL DO rep: REF CDDirectory.ReplaceRec = replaceList.first; IF rep.old=cellOb THEN LOOP; FOR instL: CD.InstanceList _ cp.contents, instL.rest WHILE instL#NIL DO IF instL.first.ob=rep.old THEN { IF rep.newSize#rep.oldSize OR rep.off#[0, 0] THEN { realPos: CD.Position = CDOrient.MapPoint[ pointInCell: rep.off, cellSize: rep.oldSize, cellInstOrient: instL.first.orientation, cellInstPos: instL.first.location ]; fakePos: CD.Position = CDOrient.MapPoint[ pointInCell: [0, 0], cellSize: rep.newSize, cellInstOrient: instL.first.orientation, cellInstPos: [0, 0] ]; instL.first.location _ CDBasics.SubPoints[realPos, fakePos]; needReposition _ TRUE; }; instL.first.ob _ rep.new }; ENDLOOP; ENDLOOP; }; RepositionCell: PUBLIC PROC [cellOb: CD.Object, design: CD.Design] RETURNS [didReposition: BOOL] = { IsDummy: PROC [cellOb: CD.Object, design: CD.Design] RETURNS [isDummy: BOOL_FALSE] = INLINE { IF design#NIL THEN FOR list: LIST OF CD.PushRec _ design.actual, list.rest WHILE list#NIL DO IF list.first.dummyCell.ob=cellOb THEN RETURN [isDummy_TRUE] ENDLOOP; }; IF IsDummy[cellOb, design] THEN RETURN [didReposition_FALSE] ELSE { cp: CD.CellPtr = NARROW[cellOb.specificRef]; oldSize: CD.Position _ cellOb.size; oldR: CD.Rect _ CDBasics.RectAt[[0,0], oldSize]; oldDIr: CD.Rect _ cp.dIr; newR: CD.Rect = CDInstances.BoundingRectO[cp.contents]; newSize: CD.Position _ CDBasics.SizeOfRect[newR]; newBase: CD.Position = CDBasics.BaseOfRect[newR]; newDIr: CD.Rect _ CDInstances.BoundingRectI[cp.contents]; didReposition _ oldR#newR OR oldSize#newSize OR (cp.useDIr AND oldDIr#newDIr); IF didReposition THEN { IF cp.contents=NIL THEN { <<--actually this is an error; but it could be produced by some silly client program, >> <<--so we do not abort>> TerminalIO.WriteRopes["** tried to reposition an empty cell ", CDOps.ObjectInfo[cellOb], "\n"]; RETURN }; IF newBase#[0, 0] THEN { CDInstances.TranslateList[cp.contents, CDBasics.NegOffset[newBase]]; newDIr _ CDBasics.MoveRect[newDIr, CDBasics.NegOffset[newBase]]; cp.origin _ CDBasics.SubPoints[cp.origin, newBase]; }; cellOb.size _ newSize; cp.dIr _ newDIr; cp.ir _ IF cp.useDIr THEN newDIr ELSE CDBasics.MoveRect[cp.ir, CDBasics.NegOffset[newBase]]; CDDirectory.RepositionObject[ design: design, ob: cellOb, oldSize: oldSize, baseOff: newBase ] } } }; IsPushedIn: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL] = { RETURN [ design^.actual.rest#NIL ] }; <<>> PushedCellName: PUBLIC PROC [design: CD.Design] RETURNS [Rope.ROPE] = { RETURN [SELECT TRUE FROM design=NIL => "no design", design.actual.rest=NIL => "top level", ENDCASE => design.actual.first.specific.name ] }; SetInterestRect: PUBLIC PROC [cellOb: CD.Object, r: CD.Rect _ [0, 0, -1, -1]] = { WITH cellOb.specificRef SELECT FROM cp: CD.CellPtr => { cp.useDIr _ ~CDBasics.NonEmpty[r]; IF cp.useDIr THEN cp.ir _ cp.dIr ELSE cp.ir _ r }; ENDCASE => NULL; }; SetBorder: PUBLIC PROC [cell: CD.Object, border: BOOL] = { WITH cell.specificRef SELECT FROM cp: CD.CellPtr => cp.drawBorder _ border ENDCASE => NULL; }; SetSimplificationTreshhold: PUBLIC PROC [cell: CD.Object, val: REAL, inPixels: BOOL_TRUE] = { WITH cell.specificRef SELECT FROM cp: CD.CellPtr => cp.simplifyOn _ IF val<0 THEN 50.0/MAX[cell.size.y, 1] ELSE IF inPixels THEN val/MAX[cell.size.y, 1] ELSE val; ENDCASE => NULL; }; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- IncludeOb: PUBLIC PROC [design: CD.Design_NIL, cell: CD.Object _ NIL, ob: CD.Object, position: CD.Position _ [0, 0], --evaluated before an eventual repositioning orientation: CD.Orientation _ 0, cellCSystem: CDCells.CoordSystem _ originCoords, obCSystem: CDCells.CoordSystem _ interrestCoords, mode: CDCells.IncludeMode _ doit] RETURNS [newInst: CD.Instance, rep: BOOL_FALSE] = { cp: CD.CellPtr; obInterestRect: CD.Rect = CD.InterestRect[ob]; IF ob=NIL THEN ERROR CD.Error[callingError, "Include NIL ob"]; <<--prepare cell and position relative to cell>> IF cell=NIL THEN { IF design=NIL THEN cp _ NIL ELSE cp _ design^.actual.first.specific; } ELSE { cp _ NARROW[cell.specificRef]; SELECT cellCSystem FROM originCoords => position _ CDBasics.AddPoints[position, CD.ClientOrigin[cell]]; interrestCoords => position _ CDBasics.AddPoints[position, CDBasics.BaseOfRect[CD.InterestRect[cell]]]; ENDCASE --cdCoords-- => NULL; }; <<--handle position: >> <<-- realPos _ (clientPos+cellOrigin) - (position of object origin at fake [0,0] pos)>> newInst _ NEW[CD.InstanceRep _ [ ob: ob, location: CDBasics.SubPoints[ position, --in cell coordinate system CDBasics.BaseOfRect[ --correction for object coordinate system CDOrient.MapRect[ itemInCell: (SELECT obCSystem FROM interrestCoords => obInterestRect, originCoords => CDBasics.RectAt[CD.ClientOrigin[ob], [0, 0]], cdCoords => CDBasics.RectAt[[0, 0], ob.size], ENDCASE => ERROR ), cellSize: ob.size, cellInstOrient: orientation, cellInstPos: [0, 0] ] ] ], orientation: orientation, selected: FALSE ]]; <<--include, handle propagation and reposition >> IF cp#NIL AND mode#dontInclude THEN { cp.contents _ CONS[newInst, cp.contents]; --does not yet change insideRect !! IF cell#NIL THEN { rep _ ~CDBasics.Inside[CDInstances.InstRectO[newInst], CDBasics.RectAt[[0, 0], cell.size]] OR (cp.useDIr AND ~CDBasics.Inside[ CDOrient.MapRect[ itemInCell: obInterestRect, cellSize: ob.size, cellInstOrient: orientation, cellInstPos: newInst.location], CD.InterestRect[cell] ] ); IF rep AND mode=doit THEN [] _ RepositionCell[cell, design]; IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design]; }; --cell#NIL IF design#NIL AND mode=doit THEN { IF cell=NIL THEN CDOps.RedrawInstance[design, newInst, FALSE] ELSE CDOps.DelayedRedraw[design] }; }; }; RemoveInstance: PUBLIC PROC [design: CD.Design_NIL, cell: CD.Object _ NIL, inst: CD.Instance, mode: CDCells.IncludeMode _ doit] RETURNS [removed: BOOL _ FALSE, rep: BOOL _ FALSE] = { cp: CD.CellPtr; IF inst=NIL THEN ERROR CD.Error[callingError, "Remove NIL inst"]; <<--prepare cell >> IF cell=NIL THEN { IF design=NIL THEN ERROR CD.Error[callingError, "Remove from NIL cell"]; cp _ design^.actual.first.specific; } ELSE cp _ NARROW[cell.specificRef]; <<--remove, handle propagation and reposition >> IF cp#NIL AND mode#dontInclude THEN { IF cp.contents#NIL THEN { IF cp.contents.first=inst THEN { removed _ TRUE; cp.contents _ cp.contents.rest } ELSE FOR list: CD.InstanceList _ cp.contents, list.rest WHILE list.rest#NIL DO IF list.rest.first=inst THEN { removed _ TRUE; list.rest _ list.rest.rest; EXIT } ENDLOOP; }; IF cell#NIL THEN { r: CD.Rect = CDInstances.InstRectO[inst]; rep _ r.x1<=0 OR r.y1<=0 OR r.x2>=cell.size.x OR r.y2>=cell.size.y; IF ~rep AND cp.useDIr THEN { rep _ r.x1<=cp.ir.x1 OR r.y1<=cp.ir.y1 OR r.x2>=cp.ir.x2 OR r.y2>=cp.ir.y2; }; IF rep AND mode=doit THEN [] _ RepositionCell[cell, design]; IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design]; }; --cell#NIL IF design#NIL AND mode=doit THEN { IF cell=NIL THEN CDOps.RedrawInstance[design, inst] ELSE CDOps.DelayedRedraw[design] }; }; }; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Init[]; END.