<> <> <> <> DIRECTORY CD, CDApplications, CDBasics, CDCells, CDDirectory, CDOps, CDCommandOps, CDOrient, CDProperties, CDX, TokenIO; CDXImpl: CEDAR PROGRAM IMPORTS CD, CDApplications, CDBasics, CDCells, CDCommandOps, CDDirectory, CDOps, CDOrient, CDProperties, CDX, TokenIO EXPORTS CDX = BEGIN <<--Public interface between chipndale and outside clients.>> <<>> <<--Maps chipndales complex and mutable (but fast clippable) positioning >> <<--mechanism to an immutable client cordinate system.>> <<--The Origin is a hypothtical point of an object; the client's cordinate >> <<--system origin.>> <<--types>> ClientPosition: TYPE = CD.Position; ClientRect: TYPE = CD.Rect; CoordSystem: TYPE = CDX.CoordSystem; --{outerCoordinates, innerCoordinates, clientCoordinates}; <<>> <<--code>> ClientOrigin: PUBLIC PROC [ob: CD.ObPtr] RETURNS [pos: CD.DesignPosition] = <<--returns the position of the client's object origin in objects internal coords>> BEGIN IF ob.p.origin#NIL THEN pos _ ob.p.origin[ob] ELSE pos _ CDBasics.BaseOfRect[CD.InterestRect[ob]] END; <<--Transfer between chipndale and client coordinates, both relative to the object>> <<-- have all been inlines>> <<--Transfer between client object relative coordinates and chipndale global coordinates>> MapClientPos: PUBLIC PROC [cPos: ClientPosition_[0, 0], app: CD.ApplicationPtr] RETURNS [globPos: CD.DesignPosition] = BEGIN cPos _ CDX.ClientToCDPos[app.ob, cPos]; RETURN [CDOrient.MapPoint[ pointInCell: cPos, cellSize: app.ob.size, cellInstOrient: app.orientation, cellInstPos: app.location ]] END; DeMapClientPos: PUBLIC PROC [globPos: CD.DesignPosition, app: CD.ApplicationPtr] RETURNS [cPos: ClientPosition] = BEGIN pointInCell: CD.DesignPosition = CDOrient.DeMapPoint[ pointInWorld: globPos, cellSize: app.ob.size, cellInstOrient: app.orientation, cellInstPos: app.location ]; RETURN [CDX.CDToClientPos[app.ob, pointInCell]] END; MapClientRect: PUBLIC PROC [cRect: ClientRect, app: CD.ApplicationPtr] RETURNS [globRect: CD.DesignRect] = BEGIN RETURN [CDOrient.MapRect[ itemInCell: CDX.ClientToCDRect[app.ob, cRect], cellSize: app.ob.size, cellInstOrient: app.orientation, cellInstPos: app.location ]] END; DeMapClientRect: PUBLIC PROC [globRect: CD.DesignRect, app: CD.ApplicationPtr] RETURNS [cRect: ClientRect] = BEGIN RETURN [CDX.CDToClientRect[app.ob, CDOrient.DeMapRect[ itemInWorld: globRect, cellSize: app.ob.size, cellInstOrient: app.orientation, cellInstPos: app.location ] ]] END; PositionFromPairO: PUBLIC PROC [ob: CD.ObPtr, cPos: ClientPosition_[0,0], correspondingGlobPos: CD.DesignPosition_[0,0], orientation: CD.Orientation_0 ] RETURNS [appPos: CD.DesignPosition] = <<--Computes a position useable for an application, such that the >> <<--client-origin relative point oPos is at the global position correspondingGlobPos>> BEGIN obCDPos: CD.DesignPosition = CDX.ClientToCDPos[ob, cPos]; fakeAppPos: CD.DesignPosition = CDOrient.MapPoint[ pointInCell: obCDPos, cellSize: ob.size, cellInstOrient: orientation, cellInstPos: [0, 0] ]; RETURN [CDBasics.SubPoints[correspondingGlobPos, fakeAppPos]] END; PositionFromPairI: PUBLIC PROC [ob: CD.ObPtr, cPos: ClientPosition_[0,0], correspondingGlobPos: CD.DesignPosition_[0,0], orientation: CD.Orientation_0 ] RETURNS [iPos: CD.DesignPosition] = <<--Computes the position of the innerrect, such that the client-origin >> <<--relative point oPos is at the global position correspondingGlobPos>> BEGIN appOPos: CD.DesignPosition = PositionFromPairO[ob, cPos, correspondingGlobPos, orientation]; RETURN [CDBasics.BaseOfRect[CDOrient.MapRect[ itemInCell: CD.InterestRect[ob], cellSize: ob.size, cellInstOrient: orientation, cellInstPos: appOPos ]]] END; IncludeOb: PUBLIC PROC [design: CD.Design_NIL, cell: CD.ObPtr_NIL, ob: CD.ObPtr, position: CD.Position_[0, 0], --evaluated before an eventual repositioning orientation: CD.Orientation_0, cellCSystem: CoordSystem_originCoords, obCSystem: CoordSystem_interrestCoords, mode: CDX.IncludeMode_doit] RETURNS [newApp: CD.ApplicationPtr, rep: BOOL_FALSE] = <<--design (NIL: allowed, if cell really is not yet part of a design)>> <<--cell (NIL: include into design; assumes the designs origin at [0, 0])>> <<-- (design&cell NIL: simply create an application)>> <<--ob: object to include in cell >> <<--position: ...>> <<--orientation: of ob inside cell >> <<--cellCSystem: tells reference point in cell (for designs: [0, 0] anyway)>> <<--obCSystem: reference point of object>> <<--mode:>> <<-- doit: normal case everything is done>> <<-- dontReposition: speed up hack>> <<-- Caution: makes temporary a wrong coordinate system! cell is >> <<-- not legal until repositioning is called to clean up.>> <<-- Has no effect if cell is NIL.>> <<-- Does not cause redrawing of the design.>> <<-- dontPropagate: speed up hack.>> <<-- does neither reposition nor propagate the changed event; cell gets>> <<-- an illegal state until repositioning and change-propagation occurs. >> <<-- dontInclude: hack to create applications; cell is not changed at all.>> <<--newApp: the new created application>> <<--rep: Reposition was done or should be done, depending of mode>> BEGIN cp: CD.CellPtr; obInterestRect: CD.DesignRect = 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, 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)>> newApp _ NEW[CD.Application _ [ 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[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[newApp, cp.contents]; --does not yet change insideRect !! IF cell#NIL THEN { rep _ ~CDBasics.Inside[CDApplications.ARectO[newApp], CDBasics.RectAt[[0, 0], cell.size]] OR (cp.useDIr AND ~CDBasics.Inside[ CDOrient.MapRect[ itemInCell: obInterestRect, cellSize: ob.size, cellInstOrient: orientation, cellInstPos: newApp.location], CD.InterestRect[cell] ] ); IF rep AND mode=doit THEN [] _ CDCells.RepositionCell[cell, design]; IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design]; }; --cell#NIL IF design#NIL AND mode=doit THEN { IF cell=NIL THEN CDCommandOps.RedrawApplication[design, newApp, FALSE] ELSE CDOps.DelayedRedraw[design] }; }; END; RemoveApp: PUBLIC PROC [design: CD.Design_NIL, cell: CD.ObPtr_NIL, app: CD.ApplicationPtr, mode: CDX.IncludeMode_doit] RETURNS [removed: BOOL_FALSE, rep: BOOL_FALSE] = BEGIN cp: CD.CellPtr; IF app=NIL THEN ERROR CD.Error[callingError, "Remove NIL app"]; <<--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=app THEN { removed _ TRUE; cp.contents _ cp.contents.rest } ELSE FOR list: CD.ApplicationList _ cp.contents, list.rest WHILE list.rest#NIL DO IF list.rest.first=app THEN { removed _ TRUE; list.rest _ list.rest.rest; EXIT } ENDLOOP; }; IF cell#NIL THEN { r: CD.DesignRect = CDApplications.ARectO[app]; 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 [] _ CDCells.RepositionCell[cell, design]; IF mode#dontPropagate THEN CDDirectory.PropagateChange[cell, design]; }; --cell#NIL IF design#NIL AND mode=doit THEN { IF cell=NIL THEN CDCommandOps.RedrawApplication[design, app] ELSE CDOps.DelayedRedraw[design] }; }; END; SimpleSetOrigin: PUBLIC PROC[ob: CD.ObPtr, new: CD.DesignPosition] = BEGIN <<--we handle the val of the originProperty property as readonly; and may share records>> IF ~ob.p.inDirectory THEN ERROR; CDProperties.PutPropOnObject[ob, originProperty, NEW[CD.DesignPosition_new]] END; <<>> SimpleGetOrigin: PUBLIC PROC[ob: CD.ObPtr] RETURNS [CD.DesignPosition] = BEGIN IF ob.p.inDirectory THEN WITH CDProperties.GetPropFromObject[ob, originProperty] SELECT FROM pp: REF CD.DesignPosition => RETURN [pp^] ENDCASE => NULL; RETURN [ CDBasics.BaseOfRect[CD.InterestRect[ob]] ] END; InternalWriteProperty: PROC [prop: REF, val: REF] = BEGIN p: REF CD.DesignPosition = NARROW[val]; TokenIO.WriteInt[p.x]; TokenIO.WriteInt[p.y]; END; InternalReadProperty: PROC [prop: ATOM] RETURNS [val: REF] = BEGIN x: INT = TokenIO.ReadInt[]; y: INT = TokenIO.ReadInt[]; val _ NEW[CD.DesignPosition _ [x, y]] END; originProperty: ATOM = $simpleOrigin; [] _ CDProperties.RegisterProperty[originProperty]; CDProperties.InstallProcs[prop: originProperty, new: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.CopyVal, --because we treat the coordinates readonly internalWrite: InternalWriteProperty, internalRead: InternalReadProperty, exclusive: TRUE ] ]; END.