CDXImpl.mesa (part of ChipNDale)
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
by Ch. Jacobi, September 10, 1984 9:20:09 am PDT
last edited by Ch. Jacobi, April 16, 1985 12:53:28 pm PST
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𡤀
] 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𡤀
] 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𡤀,
cellCSystem: CoordSystem←originCoords,
obCSystem: CoordSystem←interrestCoords,
mode: CDX.IncludeMode𡤍oit]
RETURNS [newApp: CD.ApplicationPtr, rep: BOOL�LSE] =
--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𡤍oit] RETURNS [removed: BOOLFALSE, rep: BOOLFALSE] =
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.