CDDefaultProcsImpl.mesa (part of ChipNDale)
Copyright © 1985, 1987 by Xerox Corporation. All rights reserved.
Created by Ch. Jacobi, May 22, 1985 3:35:49 pm PDT
Last edited by: Christian Jacobi, February 23, 1987 1:17:36 pm PST
DIRECTORY
Atom,
CD,
CDBasics,
CDBasicsInline,
CDDefaultProcs,
CDDirectory,
CDProperties,
D2Orient,
Imager,
ImagerManhattan,
ImagerMaskCapture,
ImagerTransformation,
Real,
Rope,
TokenIO;
CDDefaultProcsImpl: CEDAR PROGRAM
IMPORTS Atom, CD, CDBasics, CDBasicsInline, CDDirectory, CDProperties, Imager, ImagerManhattan, ImagerMaskCapture, ImagerTransformation, Real
EXPORTS CDDefaultProcs
SHARES CD =
BEGIN
OPEN CD;
--ObjectClass
QuickDrawMe: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
IF ob.class.drawMe#DrawMe THEN ob.class.drawMe[pr, ob, trans, readOnlyInstProps]
ELSE {
ob1: CD.Object = CDDirectory.Expand1[ob].new;
IF ob1#NIL THEN ob1.class.quickDrawMe[pr, ob1, trans, readOnlyInstProps]
ELSE pr.drawRect[pr, CDBasics.MapRect[ob.bbox, trans], CD.shadeLayer]
}
};
DrawMe: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
IF ob.class.quickDrawMe#QuickDrawMe THEN
ob.class.quickDrawMe[pr, ob, trans, readOnlyInstProps]
ELSE {
ob1: CD.Object = CDDirectory.Expand1[ob].new;
IF ob1#NIL THEN ob1.class.drawMe[pr, ob1, trans, readOnlyInstProps]
ELSE pr.drawRect[pr, CDBasics.MapRect[ob.bbox, trans], CD.shadeLayer]
}
};
ShowMeSelected: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
pr.drawOutLine[pr, CDBasics.MapRect[CD.InterestRect[ob], trans], CD.selectionLayer]
};
ShowMeSelectedWithExpand: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
ob1: CD.Object = CDDirectory.Expand1[ob].new;
IF ob1=NIL THEN
pr.drawOutLine[pr, CDBasics.MapRect[CD.InterestRect[ob], trans], CD.selectionLayer]
ELSE
ob1.class.showMeSelected[pr, ob1, trans, readOnlyInstProps];
};
HitInside: PUBLIC PROC [ob: Object, hitRect: Rect] RETURNS [BOOL] = {
RETURN [CDBasics.Intersect[CD.InterestRect[ob], hitRect] ]
};
InterestRect: PUBLIC PROC [ob: Object] RETURNS [Rect] = {
RETURN [ob.bbox]
};
InterestRectWithExpand: PUBLIC PROC [ob: Object] RETURNS [Rect] = {
ob1: CD.Object = CDDirectory.Expand1[ob].new;
RETURN [(IF ob1#NIL THEN CD.InterestRect[ob1] ELSE ob.bbox)]
};
InternalRead: PUBLIC PROC [h: TokenIO.Handle, key: ATOM] RETURNS [Object] = {
ERROR
};
Describe: PUBLIC PROC [ob: Object, readOnlyInstProps: PropList, verbosity: NAT] RETURNS [Rope.ROPE] = {
RETURN [
IF ob.class.description=NIL THEN Atom.GetPName[ob.class.objectType]
ELSE ob.class.description
];
};
--DrawProcs
DrawChild: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
ob.class.drawMe[pr, ob, trans, readOnlyInstProps]
};
IgnoreChild: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
};
DrawChildSel: PUBLIC PROC [pr: REF DrawInformation, ob: CD.Object, trans: Transformation, readOnlyInstProps: PropList] = {
ob.class.showMeSelected[pr, ob, trans, readOnlyInstProps]
};
DrawRect: PUBLIC PROC [pr: DrawRef, r: Rect, l: Layer] = {
DrawRectInContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = {
Imager.MaskBox[context, [xmin: r.x1, xmax: r.x2, ymin: r.y1, ymax: r.y2]];
};
pr.drawContext[pr, DrawRectInContext, NIL, [[0, 0], original], l]
};
IgnoreRect: PUBLIC PROC [pr: DrawRef, r: Rect, l: Layer] = {
};
more general draw outline procedure
DrawOutLine: PUBLIC PROC [pr: DrawRef, r: Rect, l: Layer] = {
OutlineInContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = {
Imager.SetColor[pr.deviceContext, pr.contextColors[l]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y1], [r.x2, r.y1]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y1], [r.x2, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y2], [r.x1, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y2], [r.x1, r.y1]];
};
pr.drawContext[pr, OutlineInContext, NIL, [[0, 0], original], l]
};
ContextOutLine: PUBLIC PROC [pr: DrawRef, r: Rect, l: Layer] = {
ActionWithContext: PROC [] = {
Imager.SetColor[pr.deviceContext, pr.contextColors[l]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y1], [r.x2, r.y1]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y1], [r.x2, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y2], [r.x1, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y2], [r.x1, r.y1]];
};
IF pr.deviceContext#NIL THEN {
IF pr.contextColors[l]#NIL THEN Imager.DoSave[pr.deviceContext, ActionWithContext]
}
};
DrawComment: PUBLIC PROC [pr: DrawRef, r: Rect, comment: Rope.ROPE] = {
};
--version with bitmaps
--uncomment carefully; is some releases old
DrawContext: PUBLIC PROC [pr: DrawRef, proc: DrawContextLayerProc, ob: Object, trans: Transformation, layer: Layer] = {
--calls proc which may use context; mode and color are set to layer's need
--call is suppressed if layer does not need drawing; this is default.
--on recursive calls, the context may or may not include previous transformations
ActionWithContext: PROC [] = {
TransContext[pr.deviceContext, trans];
Imager.SetColor[pr.deviceContext, pr.contextFilter[layer]];
proc[pr.deviceContext, ob, layer];
};
IF pr.deviceContext#NIL THEN {
IF pr.contextColors[layer]#NIL THEN Imager.DoSave[pr.deviceContext, ActionWithContext];
RETURN
};
IF pr.contextFilter#NIL AND pr.contextFilter[layer]#NIL THEN {
clip: CD.Rect ← CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; --in object coordinates
IF ob#NIL THEN clip ← CDBasics.Intersection[ob.bbox, clip];
--but not clipping to an object size would kill us!!
IF CDBasics.NonEmpty[clip] THEN {
DrawToBitmapContext: PROC [] = {
proc[context, ob, layer];
};
CapturePixel: PROC [x, y: INT] = INLINE {
r: CD.Rect ← CDBasics.MapRect[[x1: x, y1: y, x2: x+1, y2: y+1], trans];
r ← CDBasics.Intersection[r, pr.interestClip];
IF CDBasics.NonEmpty[r] THEN pr.drawRect[r, layer, pr];
};
CaptureBitmap: PROC [bitmap: ImagerBackdoor.Bitmap, off: CD.Position] = {
FOR y: CARDINAL IN [0..bitmap.height) DO
FOR x: CARDINAL IN [0..bitmap.width) DO
TRUSTED {
bitsRef: LONG POINTER TO CARDINAL
LOOPHOLE[bitmap.base, LONG POINTER TO CARDINAL]
+ LONG[y]*bitmap.wordsPerLine
+ LONG[x/Basics.bitsPerWord];
IF Basics.BITAND[8000h, Basics.BITSHIFT[bitsRef^, x MOD Basics.bitsPerWord]]#0 THEN
CapturePixel[off.x+x, off.y+bitmap.height-y-1]
}
ENDLOOP;
ENDLOOP;
};
bitmap: ImagerBackdoor.Bitmap ← ImagerBackdoor.NewBitmap[width: clip.x2-clip.x1, height: clip.y2-clip.y1];
context: Imager.Context ← ImagerBackdoor.BitmapContext[bitmap];
Imager.SetColor[context, Imager.white];
Imager.MaskRectangleI[context, 0, 0, bitmap.width, bitmap.height];
Imager.TranslateT[context, [-clip.x1, -clip.y1]];
Imager.SetColor[context, Imager.black];
Imager.DoSave[context, DrawToBitmapContext];
CaptureBitmap[bitmap, CDBasics.BaseOfRect[clip]];
};
};
};
TransContext: PROC [cont: Imager.Context, trans: Transformation] = INLINE {
Imager.TranslateT[cont, [trans.off.x, trans.off.y]];
IF CDBasics.IncludesMirrorX[trans.orient] THEN Imager.Scale2T[cont, [-1, 1]];
SELECT CDBasics.ConcentrateOnRotate90[trans.orient] FROM
original => NULL;
rotate90 => Imager.RotateT[cont, 90];
rotate180 => Imager.RotateT[cont, 180];
rotate270 => Imager.RotateT[cont, 270];
ENDCASE => ERROR;
--or Imager.ConcatT[cont, CDBasicsInline.ImagerTransform[trans]]
};
DrawContext: PUBLIC PROC [pr: DrawRef, proc: DrawContextLayerProc, ob: Object, trans: Transformation, layer: Layer] = {
--calls proc which may use context; mode and color are set to layer's need
--call is suppressed if layer does not need drawing; this is default.
--on recursive calls, the context may or may not include previous transformations
ActionWithContext: PROC [] = {
TransContext[pr.deviceContext, trans];
Imager.SetColor[pr.deviceContext, pr.contextColors[layer]];
proc[pr.deviceContext, ob, layer];
};
IF pr.deviceContext#NIL THEN {
IF pr.contextColors[layer]#NIL THEN Imager.DoSave[pr.deviceContext, ActionWithContext];
RETURN
};
IF pr.contextFilter#NIL AND pr.contextFilter[layer] THEN {
clip: CD.Rect ← CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; --in object coordinates
IF ob#NIL THEN clip ← CDBasics.Intersection[ob.bbox, clip];
IF CDBasics.NonEmpty[clip] THEN {
Operator: PROC [context: Imager.Context] = {
Imager.SetAmplifySpace[context, 1];
Imager.SetStrokeWidth[context, 1];
Imager.SetStrokeEnd[context, round];
Imager.SetStrokeJoint[context, round];
Imager.ClipRectangle[context, [x: clip.x1, y: clip.y1, w: clip.x2-clip.x1, h: clip.y2-clip.y1]];
proc[context, ob, layer ! ImagerMaskCapture.Cant => REJECT];
};
man: ImagerManhattan.Polygon;
man ← ImagerMaskCapture.CaptureManhattan[Operator, CDBasics.ImagerTransform[[orient: rotate90]]];
--rotated so that mask capture will returned horizontal patches bottom up
--instead of vertical patches. Using horizontal bands for corner stitching, and,
--using corner stitchings maximal east west property, this gave an improvement
--factor (in the one experimenmt I made) of about 50 (fifty!)
FOR m: ImagerManhattan.Polygon ← man, m.rest UNTIL m=NIL DO
r: CD.Rect ← CDBasics.MapRect[[x1: m.first.min.f, y1: -m.first.max.s, x2: m.first.max.f, y2: -m.first.min.s], trans];
--undo rotation! don't use
--[x1: m.first.min.s, y1: m.first.min.f, x2: m.first.max.s, y2: m.first.max.f]
r ← CDBasics.Intersection[r, pr.interestClip];
IF CDBasics.NonEmpty[r] THEN pr.drawRect[pr, r, layer];
ENDLOOP;
ImagerManhattan.Destroy[man];
};
};
};
IgnoreGround: PUBLIC PROC [pr: DrawRef, pushedOut: BOOL] = {
};
IgnorePriority: PUBLIC PROC [pr: DrawRef] = {
};
DrawExtension: TYPE = RECORD [
dDrawRect: CD.DrawRectProc,
dOrigin: CD.Position,
scale: REAL
];
ExtendedDrawContext: PROC [pr: DrawRef, proc: DrawContextLayerProc, ob: Object, trans: Transformation, layer: Layer] = {
--procedure not usefull in case pr.deviceContext#NIL
IF pr.contextFilter#NIL AND pr.contextFilter[layer] THEN
WITH CDProperties.GetPRefProp[pr.properties, $ExtendedDrawContext] SELECT FROM
de: REF DrawExtension => {
clip: CD.Rect ← CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; --in ob coords
IF ob#NIL THEN clip ← CDBasics.Intersection[ob.bbox, clip];
IF CDBasics.NonEmpty[clip] THEN {
Operator: PROC [context: Imager.Context] = {
Imager.SetAmplifySpace[context, 1];
Imager.SetStrokeWidth[context, 1];
Imager.SetStrokeEnd[context, round];
Imager.SetStrokeJoint[context, round];
Imager.ClipRectangle[context, [x: clip.x1, y: clip.y1, w: clip.x2-clip.x1, h: clip.y2-clip.y1]];
proc[context, ob, layer ! ImagerMaskCapture.Cant => REJECT];
};
t: CD.Transformation = [
off: [
Real.Round[de.scale*(trans.off.x-de.dOrigin.x)],
Real.Round[de.scale*(trans.off.y-de.dOrigin.y)]],
orient: trans.orient];
man: ImagerManhattan.Polygon;
man ← ImagerMaskCapture.CaptureManhattan[Operator, ImagerTransformation.PreScale[CDBasics.ImagerTransform[[orient: rotate90]], de.scale]]; --rotation: see simple case why
FOR m: ImagerManhattan.Polygon ← man, m.rest UNTIL m=NIL DO
r: CD.Rect ← [x1: m.first.min.f, y1: -m.first.max.s, x2: m.first.max.f, y2: -m.first.min.s];
--undo rotation! don't use
--[x1: m.first.min.s, y1: m.first.min.f, x2: m.first.max.s, y2: m.first.max.f]
IF CDBasics.NonEmpty[r] THEN {
--we do the translation on the rectangles instead in the Operator because
--that would exceed the range where ImagerMaskCapture works correctly.
de.dDrawRect[pr, CDBasicsInline.MapRect[r, t], layer];
}
ENDLOOP;
ImagerManhattan.Destroy[man];
};
};
ENDCASE => ERROR
};
ConvertContextsToDeviceRects: PUBLIC PROC [pr: CD.DrawRef, dDrawRect: CD.DrawRectProc, dOrigin: CD.Position←[0, 0], scale: REAL𡤁] = {
de: REF DrawExtension ← NEW[DrawExtension ← [
dDrawRect: dDrawRect, dOrigin: dOrigin, scale: scale
]];
IF pr.deviceContext#NIL THEN ERROR;
CDProperties.PutPRefProp[pr.properties, $ExtendedDrawContext, de];
pr.drawContext ← ExtendedDrawContext
};
END.