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: BOOLLSE] =
--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: 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.