GriffinShowObjectImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by: Maureen Stone, April 24, 1981 3:10 PM
Edited by: Maureen Stone, May 15, 1986 10:29:48 am PDT
Last Edited by: Ken Pier, November 21, 1985 2:47:51 pm PST
Russ Atkinson (RRA) April 3, 1986 0:50:49 am PST
DIRECTORY
FS USING [Error],
GriffinData USING [DataRec],
GriffinDisplay USING [ClearScreen, DrawArea, DrawCaption, DrawFastStroke, DrawFrame, DrawHGrid, DrawSelection, DrawStroke, DrawToken, DrawVGrid, ResetClipEdges, SetClipEdges],
GriffinEncoding USING [EdgeEncoding, EncodeArea, EncodeCubicLink, EncodeEdge, EncodeLinearLink, Link, PointInArea, PointOnEdge],
GriffinGrid USING [GetFrame],
GriffinKernel USING [Box, DataRec],
GriffinMenu USING [PlotMenu],
GriffinObject USING [ForAllObjects, ForAllObjectsReversed, ForAllPictureObjects, GetTopPictureObj, Link, Object, ObjectHandle, ObjectProc, openCluster, ReturnSelectToken, tokenSize, Visible],
GriffinPoint USING [ObjToScr, ObjToScrReal, ObjValToScrVal, ScrPt, ScrRealPt, ScrRealToScr, X, Y],
GriffinRefresh USING [EraseAndSaveBox],
GriffinStyle USING [StyleHandle],
GriffinText USING [GetBoundingBox],
GriffinUserMessage USING [UserMessage],
GriffinViewer USING [DoPaint, PaintProc],
Imager USING [ClipRectangleI, Context, metersPerPoint, ScaleT, SetPriorityImportant, SetStrokeEnd, SetStrokeJoint, TranslateT],
ImagerBackdoor USING [DoIfVisible],
ImagerInterpress USING [Close, Create, DoPage, Ref],
Real USING [Fix],
Rope USING [ROPE];
GriffinShowObjectImpl: CEDAR PROGRAM
IMPORTS FS, GriffinDisplay, GriffinEncoding, GriffinGrid, GriffinMenu, GriffinObject, GriffinPoint, GriffinRefresh, GriffinText, GriffinUserMessage, GriffinViewer, Imager, ImagerBackdoor, ImagerInterpress, Real
EXPORTS GriffinKernel, GriffinObject = BEGIN
Data: TYPE = REF DataRec;
DataRec: PUBLIC TYPE = GriffinData.DataRec; --exported to GriffinKernel
Context: TYPE = Imager.Context;
X: NAT = GriffinPoint.X;
Y: NAT = GriffinPoint.Y;
ReplotAllObjects: PUBLIC PROC [data: Data, dc: Context] = {
Proc: GriffinObject.ObjectProc = { PlotObject[object, dc]; };
GriffinObject.ForAllObjects[data, Proc];
};
ObjectsToInterpress: PUBLIC PROC [data: Data, fileName: Rope.ROPE] = {
Action: PROC [dc: Imager.Context] = {
Proc: GriffinObject.ObjectProc = { PlotObject[object, dc]; };
frame: REF GriffinObject.Object[token] ← GriffinGrid.GetFrame[data: data];
Imager.ScaleT[dc, Imager.metersPerPoint];
Imager.SetPriorityImportant[dc, TRUE];
IF frame.visible THEN {
Imager.TranslateT[context: dc, t: [x: -frame.tl[X], y: -frame.br[Y]] ];
GriffinDisplay.SetClipEdges[data, frame.tl, frame.br];
Imager.ClipRectangleI[dc, data.clipBox.x, data.clipBox.y, data.clipBox.w, data.clipBox.h];
};
Imager.SetStrokeEnd[dc, round];
Imager.SetStrokeJoint[dc, round];
GriffinObject.ForAllPictureObjects[data, Proc];
GriffinDisplay.ResetClipEdges[data: data];
};
Get an interpress context from the rope, "display" only the visible objects
ip: ImagerInterpress.Ref ← ImagerInterpress.Create[fileName ! FS.Error => {
IF error.group=user AND error.code=$unknownFile
THEN SIGNAL GriffinUserMessage.UserMessage["Unknown file"]
ELSE IF error.group=user AND error.code=$globalCreation
THEN SIGNAL GriffinUserMessage.UserMessage["Can't write on remote file"]
ELSE SIGNAL GriffinUserMessage.UserMessage["FS file error"]
};];
GriffinDisplay.ResetClipEdges[data];
ImagerInterpress.DoPage[ip, Action];
ImagerInterpress.Close[ip];
};
ReplotFromObject: PUBLIC PROC [startObject: GriffinObject.ObjectHandle, dc: Context] = {
object: REF GriffinObject.Object ← startObject;
UNTIL object=NIL DO
PlotObject[object, dc];
object ← object.link;
ENDLOOP;
};
calls the correct type of plotting routine, be it splines, encoding, whatever
PlotObject: PUBLIC PROC [object: GriffinObject.ObjectHandle, dc: Context] = {
IsCull: PROC RETURNS [BOOL] = {
Action: PROC = {cull ← FALSE};
cull: BOOLEANTRUE;
clip: GriffinKernel.Box ← data.clipBox^;
tl: GriffinPoint.ScrPt ← object.tl;
br: GriffinPoint.ScrPt ← object.br;
IF clip.enable AND (clip.x+clip.w < tl[X] OR clip.x > br[X] OR clip.y+clip.h < br[Y] OR clip.y > tl[Y]) THEN RETURN[TRUE]; --test for inside local clipper, if enabled
ImagerBackdoor.DoIfVisible[dc, [x: tl[X], y: br[Y], w: br[X]-tl[X], h: tl[Y]-br[Y]], Action];
RETURN [cull];
rect: Imager.Rectangle;
rect ← ImagerBackdoor.GetBounds[context: dc];
clip ← [x: Real.Fix[rect.x], y: Real.Fix[rect.y], w: Real.Fix[rect.w]+1, h: Real.Fix[rect.h]+1];
clip now contains approximately the Imager clipper bounding box !!
RETURN[clip.x+clip.w < tl[X] OR clip.x > br[X] OR clip.y+clip.h < br[Y] OR clip.y > tl[Y]];
};
data: Data;
IF object=NIL OR ~GriffinObject.Visible[object] THEN RETURN;
data ← object.data;
IF IsCull[] THEN RETURN;
IF data.clipBox.enable THEN IF GriffinDisplay.IsCull[object.tl, object.br, data.clipBox, dc] THEN RETURN;
IF NOT object.validEncoding THEN ERROR;
WITH object SELECT FROM
in: REF GriffinObject.Object[shape] => {
IF NOT in.closed THEN { --Strokes
IF in.cluster=GriffinObject.openCluster AND in.style.outlined=FALSE
THEN GriffinDisplay.DrawFastStroke[in.edgeEncoding, data.clipBox, dc]
ELSE GriffinDisplay.DrawStroke[in.edgeEncoding, in.style, data.clipBox, dc];
}
ELSE GriffinDisplay.DrawArea[in.edgeEncoding, in.style, data.clipBox, dc];
};
in: REF GriffinObject.Object[caption] => GriffinDisplay.DrawCaption[GriffinPoint.ObjToScrReal[in.p0], in.text, in.style, data.clipBox, dc];
in: REF GriffinObject.Object[menu] => GriffinMenu.PlotMenu[in, dc];
in: REF GriffinObject.Object[selectToken] => DrawSelectToken[in, dc];
in: REF GriffinObject.Object[token] => SELECT in.tokenType FROM
CP => GriffinDisplay.DrawToken[GriffinPoint.ObjToScr[in.p0], cp, data.clipBox, dc];
open => GriffinDisplay.DrawToken[GriffinPoint.ObjToScr[in.p0], open, data.clipBox, dc];
vgrid => GriffinDisplay.DrawVGrid[data, in, dc];
hgrid => GriffinDisplay.DrawHGrid[data, in, dc];
frame => GriffinDisplay.DrawFrame[data, in, dc];
ENDCASE;
ENDCASE;
};
DrawSelectToken: PROC [token: REF GriffinObject.Object[selectToken], dc: Context] = {
covered, clustered: BOOLEANFALSE;
coverObj: GriffinObject.ObjectHandle ← NIL;
selectedObject: GriffinObject.ObjectHandle;
pt: GriffinPoint.ScrPt;
data: Data;
IF token=NIL OR NOT token.located THEN ERROR; --added check (KAP)
data ← token.data;
selectedObject ← token.selectedObj;
pt ← GriffinPoint.ObjToScr[token.p0];
is token covered?
coverObj ← GetObjectHandleBetweenObjects[pt, GriffinObject.GetTopPictureObj[data], selectedObject];
covered ← coverObj#NIL;
clustered ← selectedObject.cluster#0;
GriffinDisplay.DrawSelection[pt, covered, clustered, data.clipBox, dc];
};
ReplotBoxFromObject: PUBLIC PROC [tl, br: GriffinPoint.ScrPt, object: GriffinObject.ObjectHandle, dc: Context] = {
data: Data ← object.data;
GriffinDisplay.SetClipEdges[data, tl, br];
Imager.ClipRectangleI[dc, data.clipBox.x, data.clipBox.y, data.clipBox.w, data.clipBox.h];
ReplotFromObject[object, dc];
GriffinDisplay.ResetClipEdges[data];
};
ReplotBox: PUBLIC PROC [data: Data, tl, br: GriffinPoint.ScrPt, dc: Context] = {
GriffinDisplay.SetClipEdges[data, tl, br];
Imager.ClipRectangleI[dc, data.clipBox.x, data.clipBox.y, data.clipBox.w, data.clipBox.h];
ReplotAllObjects[data, dc];
GriffinDisplay.ResetClipEdges[data];
};
PlotOneObject: PUBLIC PROC [object: GriffinObject.ObjectHandle] = {
PaintOne: GriffinViewer.PaintProc = {
PlotObject[object, dc];
};
data: Data ← object.data;
GriffinViewer.DoPaint[data.viewer, PaintOne];
};
EraseObject: PUBLIC PROC [erase: GriffinObject.ObjectHandle] = {
select: REF GriffinObject.Object[selectToken] ← NIL;
eraseData: Data;
selectData: Data;
Painter: GriffinViewer.PaintProc = {
EraseSelectToken: GriffinViewer.PaintProc = {
GriffinDisplay.SetClipEdges[selectData, select.tl, select.br];
Imager.ClipRectangleI[dc, selectData.clipBox.x, selectData.clipBox.y, selectData.clipBox.w, selectData.clipBox.h];
GriffinDisplay.ClearScreen[selectData.clipBox, selectData.bkgndColor, dc];
GriffinDisplay.ResetClipEdges[selectData];
};
Erase: GriffinViewer.PaintProc = {
GriffinDisplay.SetClipEdges[eraseData, erase.tl, erase.br];
Imager.ClipRectangleI[dc, eraseData.clipBox.x, eraseData.clipBox.y, eraseData.clipBox.w, eraseData.clipBox.h];
GriffinDisplay.ClearScreen[eraseData.clipBox, eraseData.bkgndColor, dc];
GriffinObject.ForAllObjects[eraseData, Replot];
GriffinDisplay.ResetClipEdges[eraseData];
};
Replot: GriffinObject.ObjectProc = {
IF object#erase AND object#select THEN PlotObject[object, dc];
};
IF erase.selected THEN {
select ← GriffinObject.ReturnSelectToken[erase];
IF select = NIL THEN RETURN;
selectData ← select.data;
GriffinViewer.DoPaint[eraseData.viewer, EraseSelectToken];
};
GriffinViewer.DoPaint[eraseData.viewer, Erase];
};
IF erase=NIL THEN RETURN;
IF NOT erase.validEncoding THEN ERROR;
eraseData ← erase.data;
GriffinViewer.DoPaint[eraseData.viewer, Painter];
};
PlotLink: PUBLIC PROC [data: Data, link: GriffinEncoding.Link, style: GriffinStyle.StyleHandle]= {
PaintLink: GriffinViewer.PaintProc = {
IF doFastStroke THEN GriffinDisplay.DrawFastStroke[encoding, data.clipBox, dc]
ELSE GriffinDisplay.DrawStroke[encoding, style, data.clipBox, dc];
};
doFastStroke: BOOLEAN ← style=NIL OR style.outlined=FALSE;
encoding: GriffinEncoding.EdgeEncoding ← GriffinEncoding.EncodeEdge[LIST[link]];
GriffinViewer.DoPaint[data.viewer, PaintLink]; --direct way to paint viewer client
};
EraseLink: PUBLIC PROC [data: Data, link: GriffinEncoding.Link, style: GriffinStyle.StyleHandle] = {
[newtl: link.tl, newbr: link.br] ← AdjustLinkForStyle[link: link, style: style];
GriffinRefresh.EraseAndSaveBox[data, GriffinPoint.ScrRealToScr[link.tl], GriffinPoint.ScrRealToScr[link.br]];
};
AdjustLinkForStyle: PROC [link: GriffinEncoding.Link, style: GriffinStyle.StyleHandle] RETURNS [newtl, newbr: GriffinPoint.ScrRealPt] = {
w: INTEGER← GriffinPoint.ObjValToScrVal[style.width/2]+GriffinObject.tokenSize;
RETURN[ [link.tl[X]-w, link.tl[Y]+w], [link.br[X]+w, link.br[Y]-w] ];
};
EncodeObject: PUBLIC PROC [shape: REF GriffinObject.Object[shape]] = TRUSTED {
WITH traj: shape.trajectory SELECT FROM
cyclic => {
link: GriffinEncoding.Link;
traj.splineType ← SELECT traj.splineType FROM
naturalUM => cyclicUM, naturalAL => cyclicAL, ENDCASE => traj.splineType;
link ← GriffinEncoding.EncodeCubicLink[traj.knots, traj.splineType];
shape.edgeEncoding ← GriffinEncoding.EncodeEdge[LIST[link]];
};
linked => {
list, rList: LIST OF GriffinEncoding.Link;
FOR l: REF GriffinObject.Link ← traj.links, l.link UNTIL l=NIL DO
new: GriffinEncoding.Link ←
IF l.degree=D1 THEN GriffinEncoding.EncodeLinearLink[l.knots]
ELSE GriffinEncoding.EncodeCubicLink[l.knots, traj.splineType];
list ← CONS[new, list];
ENDLOOP;
FOR l: LIST OF GriffinEncoding.Link ← list, l.rest UNTIL l=NIL DO
rList ← CONS[l.first, rList];
ENDLOOP;
shape.edgeEncoding ← GriffinEncoding.EncodeEdge[rList];
};
ENDCASE;
IF shape.closed THEN shape.areaEncoding ← GriffinEncoding.EncodeArea[shape.edgeEncoding];
shape.tl ← GriffinPoint.ScrRealToScr[shape.edgeEncoding.tl];
shape.br ← GriffinPoint.ScrRealToScr[shape.edgeEncoding.br];
shape.validEncoding ← TRUE;
};
AdjustBoxForStyle: PUBLIC PROC [object: GriffinObject.ObjectHandle] = TRUSTED {
WITH obj: object SELECT FROM
shape => { -- notice that tokens are big enough to encompass style.widths
obj.tl ← GriffinPoint.ScrRealToScr[[obj.edgeEncoding.tl[X]-GriffinObject.tokenSize, obj.edgeEncoding.tl[Y]+GriffinObject.tokenSize]];
obj.br ←GriffinPoint.ScrRealToScr[[obj.edgeEncoding.br[X]+GriffinObject.tokenSize, obj.edgeEncoding.br[Y]-GriffinObject.tokenSize]];
};
caption => [obj.tl, obj.br] ← GriffinText.GetBoundingBox[obj.text, obj.style, obj.p0];
ENDCASE;
};
Hit Test..
GetObjectHandle: PUBLIC PROC [data: Data, pt: GriffinPoint.ScrPt] RETURNS [GriffinObject.ObjectHandle] = {
Do: GriffinObject.ObjectProc = {
IF HitTest[pt, object] THEN {found ← object; RETURN[TRUE]};
};
found: GriffinObject.ObjectHandle ← NIL;
GriffinObject.ForAllObjectsReversed[data, Do];
IF found#NIL THEN WITH found SELECT FROM
type: REF GriffinObject.Object[selectToken] => RETURN[type.selectedObj];
ENDCASE;
RETURN[found];
};
GetObjectHandleBetweenObjects: PUBLIC PROC [pt: GriffinPoint.ScrPt, topObject, bottomObject: GriffinObject.ObjectHandle] RETURNS [GriffinObject.ObjectHandle] = {
FOR object: GriffinObject.ObjectHandle ← topObject, object.backLink UNTIL object = bottomObject DO
IF HitTest[pt, object] THEN RETURN[object];
ENDLOOP;
RETURN[NIL];
};
HitTest: PROC [pt: GriffinPoint.ScrPt, object: GriffinObject.ObjectHandle] RETURNS [BOOLEAN] ~ TRUSTED {
tol: REAL;
IF ~GriffinObject.Visible[object] THEN RETURN[FALSE];
IF pt[X]<object.tl[X] OR pt[X]>object.br[X] OR pt[Y]>object.tl[Y] OR pt[Y]<object.br[Y] THEN RETURN[FALSE];
object may be touched
WITH obj: object SELECT FROM
caption, menu, selectToken => RETURN[TRUE];
shape => {
tol ← MAX[1, GriffinPoint.ObjValToScrVal[obj.style.width/2.0]];
IF GriffinEncoding.PointOnEdge[pt, obj.edgeEncoding, tol] THEN RETURN[TRUE]
ELSE IF obj.closed AND object.style.filled
AND GriffinEncoding.PointInArea[pt, obj.areaEncoding, tol] THEN RETURN[TRUE];
};
token => {
micasPerPoint: REAL = 32.0;
Box: TYPE = RECORD[tl, br: GriffinPoint.ScrPt];
leftBox, rightBox, topBox, bottomBox: Box;
width: INT;
Inside: PROC [pt: GriffinPoint.ScrPt, box: Box] RETURNS [BOOL] = TRUSTED {
RETURN[ ~ (pt[X]<box.tl[X] OR pt[X]>box.br[X] OR pt[Y]<box.br[Y] OR pt[Y]>box.tl[Y]) ];
};
IF obj.tokenType#frame THEN RETURN[TRUE];
special hit test for frame
width ← Real.Fix[ object.style.width/micasPerPoint ]; -- line width in points
leftBox ← [tl: obj.tl, br: [ obj.tl[X]+width, obj.br[Y] ]];
IF Inside[pt, leftBox] THEN RETURN[TRUE];
rightBox ← [tl: [ obj.br[X]-width, obj.tl[Y] ], br: obj.br ];
IF Inside[pt, rightBox] THEN RETURN[TRUE];
topBox ← [tl: obj.tl, br: [ obj.br[X]-width, obj.tl[Y]-width ] ];
IF Inside[pt, topBox] THEN RETURN[TRUE];
bottomBox ← [tl: [ obj.tl[X], obj.br[Y]+width ], br: obj.br ];
IF Inside[pt, bottomBox] THEN RETURN[TRUE];
};
ENDCASE;
RETURN[FALSE];
};
END.