DIRECTORY
GriffinColor USING [ColorToConstantColor],
GriffinData USING [DataRec],
GriffinDisplay USING [BkgndColor, TokenType],
GriffinEncoding USING [EdgeEncoding, WalkEdge],
GriffinGrid USING [Grid],
GriffinKernel USING [ClipBox, DataRec],
GriffinObject USING [Object, TokenType],
GriffinPoint USING [ObjToScr, ObjValToScrVal, ScrPt, ScrRealPt, X, Y],
GriffinStyle USING [StyleHandle],
Imager USING [Context, DoSave, MaskBits, MaskFill, MaskRectangleI, MaskStroke, PathProc, RotateT, SetColor, SetFont, SetSampledColor, SetStrokeWidth, SetXY, ShowRope, TranslateT],
ImagerBackdoor USING [DrawBits, invert],
ImagerFont USING [FontBoundingBox, RopeWidth],
Rope USING [Length, ROPE],
Vector2 USING [VEC];
GriffinDisplayImpl:
CEDAR
PROGRAM
IMPORTS GriffinColor, GriffinEncoding, GriffinGrid, GriffinPoint, Imager, ImagerBackdoor, ImagerFont, Rope
EXPORTS GriffinDisplay, GriffinKernel = BEGIN
Data: TYPE = REF DataRec;
DataRec: PUBLIC TYPE = GriffinData.DataRec; -- exported to GriffinKernel
Context: TYPE = Imager.Context;
ClipBox: TYPE = GriffinKernel.ClipBox;
ROPE: TYPE = Rope.ROPE;
ScrPt: TYPE = GriffinPoint.ScrPt;
ScrRealPt: TYPE = GriffinPoint.ScrRealPt;
StyleHandle: TYPE = GriffinStyle.StyleHandle;
EdgeEncoding: TYPE = GriffinEncoding.EdgeEncoding;
TokenType: TYPE = GriffinDisplay.TokenType; --{cp, open};
X: NAT = GriffinPoint.X;
Y: NAT = GriffinPoint.Y;
screenLimit: INT = 10000; -- used by ClearScreen as "big enough"
DrawFastStroke:
PUBLIC
PROC [edge: EdgeEncoding, clip: ClipBox, dc: Context] = {
PathProc: Imager.PathProc = {GriffinEncoding.WalkEdge[edge, moveTo, lineTo, curveTo]};
Proc:
PROC =
TRUSTED {
Imager.SetStrokeWidth[dc, 0];
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
Imager.MaskStroke[dc, PathProc, FALSE];
};
Imager.DoSave[dc, Proc];
};
DrawStroke:
PUBLIC
PROC [edge: EdgeEncoding, style: StyleHandle, clip: ClipBox, dc: Context] = {
PathProc: Imager.PathProc = {GriffinEncoding.WalkEdge[edge, moveTo, lineTo, curveTo]};
Proc:
PROC = {
Imager.SetStrokeWidth[dc, GriffinPoint.ObjValToScrVal[style.width]];
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
Imager.SetColor[dc, GriffinColor.ColorToConstantColor[style.color]];
Imager.MaskStroke[dc, PathProc, FALSE];
};
Imager.DoSave[dc, Proc];
};
DrawArea:
PUBLIC
PROC [edge: EdgeEncoding, style: StyleHandle, clip: ClipBox, dc: Context] = {
PathProc: Imager.PathProc = {GriffinEncoding.WalkEdge[edge, moveTo, lineTo, curveTo]};
Proc:
PROC = {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
IF style.filled
THEN {
Imager.SetColor[dc, GriffinColor.ColorToConstantColor[style.fillcolor]];
Imager.MaskFill[dc, PathProc];
};
IF style.outlined
THEN {
Imager.SetStrokeWidth[dc, GriffinPoint.ObjValToScrVal[style.width]];
Imager.SetColor[dc, GriffinColor.ColorToConstantColor[style.color]];
Imager.MaskStroke[dc, PathProc, TRUE];
};
};
Imager.DoSave[dc, Proc];
};
DrawCaption:
PUBLIC
PROC [anchor: ScrRealPt, rope:
ROPE, style: StyleHandle, clip: ClipBox, dc: Context] = {
width: Vector2.VEC ← ImagerFont.RopeWidth[style.font, rope];
ascent: REAL ← ImagerFont.FontBoundingBox[style.font].ascent;
point: Vector2.
VEC ←
SELECT style.anchor
FROM
--assumes anchor at origin when used
left => [0, 0-ascent],
center => [0-width.x/2.0, 0-ascent],
right => [0-width.x, 0-ascent],
ENDCASE => ERROR;
Proc:
PROC = {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
dc.SetColor[GriffinColor.ColorToConstantColor[style.color]];
dc.SetFont[style.font];
dc.TranslateT[[anchor[X], anchor[Y]]];
SELECT style.stringRotation
FROM
or90 => dc.RotateT[90.0];
or180 => dc.RotateT[180.0];
or270 => dc.RotateT[270.0];
ENDCASE;
dc.SetXY[point];
dc.ShowRope[rope: rope, len: Rope.Length[rope]];
};
Imager.DoSave[dc, Proc];
};
ClearScreen:
PUBLIC
PROC [clip: ClipBox, bkgnd: GriffinDisplay.BkgndColor, dc: Context] = {
Proc:
PROC = {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
IF bkgnd.constant#NIL THEN Imager.SetColor[dc, bkgnd.constant]
ELSE Imager.SetSampledColor[context: dc, m: bkgnd.scale, pa: bkgnd.pa, colorOperator: bkgnd.op];
Imager.MaskRectangleI[dc, -screenLimit, -screenLimit, 2*screenLimit, 2*screenLimit];
};
Imager.DoSave[dc, Proc];
};
IsCull: PUBLIC PROC [tl, br: ScrPt, clip: ClipBox, dc: Context] RETURNS [cull: BOOLEAN] = {
Action: PROC = {cull ← FALSE};
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
cull ← TRUE;
ImagerBackdoor.DoIfVisible[dc, [x: tl[X], y: br[Y], w: br[X]-tl[X], h: tl[Y]-br[Y]], Action];
};
DrawToken:
PUBLIC
PROC [pt: ScrPt, type: TokenType, clip: ClipBox, dc: Context] = {
Proc:
PROC =
TRUSTED {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
ImagerBackdoor.DrawBits[context: dc,
base: IF type=cp THEN @RuntimeBitmaps[0] ELSE @RuntimeBitmaps[1],
wordsPerLine: 1,
sMin: 0, fMin: 0,
sSize: 9, fSize: 9,
tx: pt[X]-4, ty: pt[Y]+4];
};
Imager.DoSave[dc, Proc];
};
DrawHGrid:
PUBLIC
PROC [data: Data, hg:
REF GriffinObject.Object[token], dc: Context] = {
lx: INTEGER ← hg.tl[X];
p0: GriffinPoint.ScrPt ← GriffinPoint.ObjToScr[hg.p0];
ty: INTEGER ← GriffinGrid.Grid[data, p0][Y]+1;
ngridpieces: INTEGER ← (hg.br[X]-hg.tl[X])/16 - 1;
Proc:
PROC =
TRUSTED {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
THROUGH [0..ngridpieces]
DO
Imager.MaskBits[context: dc,
base: BASE[hgridbits],
wordsPerLine: 1,
sMin: 0, fMin: 0,
sSize: 3, fSize: 16,
tx: lx, ty: ty];
lx ← lx+16;
ENDLOOP;
};
IF hg.tokenType#hgrid THEN ERROR;
Imager.DoSave[dc, Proc];
};
DrawVGrid:
PUBLIC
PROC [data: Data, vg:
REF GriffinObject.Object[token], dc: Context] = {
by: INTEGER ← vg.br[Y]+17; -- +17 makes it look right on the screen
p0: GriffinPoint.ScrPt ← GriffinPoint.ObjToScr[vg.p0];
lx: INTEGER ← GriffinGrid.Grid[data, p0][X]-1;
ngridpieces: INTEGER ← (vg.tl[Y]-vg.br[Y])/16 - 1;
Proc:
PROC =
TRUSTED {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
THROUGH [0..ngridpieces]
DO
Imager.MaskBits[context: dc,
base: BASE[vgridbits],
wordsPerLine: 1,
sMin: 0, fMin: 0,
sSize: 16, fSize: 3,
tx: lx, ty: by];
by ← by+16;
ENDLOOP;
};
IF vg.tokenType#vgrid THEN ERROR;
Imager.DoSave[dc, Proc];
};
DrawFrame:
PUBLIC
PROC [data: Data, frame:
REF GriffinObject.Object[token], dc: Context] = {
PathProc: Imager.PathProc = {
halfwidth is needed becaus the frames BBox doesn't allow for style width (4 pts)
halfwidth: INTEGER ← GriffinPoint.ObjValToScrVal[frame.style.width]/2;
moveTo[p: [x: frame.tl[X]+halfwidth, y: frame.tl[Y]-halfwidth] ];
lineTo[p1: [x: frame.br[X]-halfwidth, y: frame.tl[Y]-halfwidth] ];
lineTo[p1: [x: frame.br[X]-halfwidth, y: frame.br[Y]+halfwidth] ];
lineTo[p1: [x: frame.tl[X]+halfwidth, y: frame.br[Y]+halfwidth] ];
};
Proc:
PROC =
TRUSTED {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
Imager.SetStrokeWidth[dc, GriffinPoint.ObjValToScrVal[frame.style.width]];
Imager.SetColor[dc, GriffinColor.ColorToConstantColor[frame.style.color]];
Imager.MaskStroke[dc, PathProc, TRUE];
};
IF frame.tokenType#frame THEN ERROR;
Imager.DoSave[dc, Proc];
};
DrawSelection:
PUBLIC
PROC [pt: ScrPt, covered, clustered:
BOOLEAN, clip: ClipBox, dc: Context] = {
base: LONG POINTER;
Proc:
PROC =
TRUSTED {
SELECT
TRUE
FROM
NOT covered AND NOT clustered => base ← @SelectBitmaps[0];
covered AND NOT clustered => base ← @SelectBitmaps[1];
NOT covered AND clustered => base ← @SelectBitmaps[2];
covered AND clustered => base ← @SelectBitmaps[3];
ENDCASE => ERROR;
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
ImagerBackdoor.DrawBits[context: dc,
base: base,
wordsPerLine: 1,
sMin: 0, fMin: 3,
sSize: 10, fSize: 10,
tx: pt[X]-5, ty: pt[Y]+5];
};
Imager.DoSave[dc, Proc];
};
BoxFill:
PUBLIC
PROC [tl,br: ScrPt, bkgnd: GriffinDisplay.BkgndColor, clip: ClipBox, dc: Context] = {
Proc:
PROC = {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
IF bkgnd.constant#NIL THEN Imager.SetColor[dc, bkgnd.constant]
ELSE Imager.SetSampledColor[context: dc, m: bkgnd.scale, pa: bkgnd.pa, colorOperator: bkgnd.op];
Imager.MaskRectangleI[dc, tl[X], br[Y], br[X]-tl[X], tl[Y]-br[Y]];
};
Imager.DoSave[dc, Proc];
};
InvertBox:
PUBLIC
PROC [tl,br: ScrPt, clip: ClipBox, dc: Context] = {
Proc:
PROC = {
IF clip.enable THEN Imager.ClipRectangleI[dc, clip.x, clip.y, clip.w, clip.h];
Imager.SetColor[dc, ImagerBackdoor.invert];
Imager.MaskRectangleI[dc, tl[X], br[Y], br[X]-tl[X], tl[Y]-br[Y]];
};
Imager.DoSave[dc, Proc];
};
The following work in Screen Points. Partial pixels would only be a nuisance for us.
SetClipEdges:
PUBLIC
PROC [data: Data, tl, br: ScrPt] = {
data.clipBox^ ← [enable: TRUE, x: tl[X], y: br[Y], w: br[X]-tl[X], h: tl[Y]-br[Y]];
};
ResetClipEdges:
PUBLIC
PROC [data: Data] = {
data.clipBox.enable ← FALSE;
};
RuntimeBitmaps: ARRAY [0..3] OF ARRAY [0..8] OF CARDINAL;
SelectBitmaps: ARRAY [0..3] OF ARRAY [0..15] OF CARDINAL;
vgridbits: PACKED ARRAY [0..16) OF CARDINAL ← ALL[040000B];
hgridbits: PACKED ARRAY [0..8) OF CARDINAL ← ALL[100200B];
vgridbits[0] ← vgridbits[8] ← 120000B; --rest are "040000B"
hgridbits[1] ← hgridbits[4] ← 77577B; --rest are "100200B"
RuntimeBitmaps[0] ←
[16000B,12000B,12000B,173600B,104200B,173600B,12000B,12000B,16000B]; --CP
RuntimeBitmaps[1] ← [37000B,61400B,140600B,100200B,104200B,100200B,140600B,61400B,37000B]; --open
SelectBitmaps[0] ← [17770B,17770B,14030B,14030B,14630B,14630B,14030B,
14030B,17770B,17770B,0,0,0,0,0,0]; --selected not hidden.
SelectBitmaps[1] ← [17770B,17770B,17030B,17430B,15630B,14730B,14370B,
14170B,17770B,17770B,0,0,0,0,0,0]; --selected and hidden.
SelectBitmaps[2] ← [17770B,17770B,14030B,15730B,15030B,15030B,15730B,
14030B,17770B,17770B,0,0,0,0,0,0]; --selected not hidden cluster.
SelectBitmaps[3] ← [17770B,17770B,14070B,15730B,15230B,15430B,15730B,
16030B,17770B,17770B,0,0,0,0,0,0]; --selected and hidden cluster.