CDCreateLabelsImpl.mesa
Copyright (C) 1984, 1985, 1987 by Xerox Corporation. All rights reserved.
Created by: Christian Jacobi, March 1, 1985 4:52:57 pm PST
Last edited by: Christian Jacobi, April 13, 1987 1:37:33 pm PDT
DIRECTORY
CD,
CDBasics,
CDCells,
CDCreateLabels,
CDDirectory,
CDOps,
CDPanelFonts,
CDProperties,
CDRects,
CDSequencer,
CDSymbolicObjects,
CDTexts,
CStitching,
Imager,
ImagerBitmapContext,
ImagerFont,
ImagerSample,
IO,
Real,
Rope,
SF,
TerminalIO;
CDCreateLabelsImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDOps, CDPanelFonts, CDProperties, CDRects, CDSequencer, CDSymbolicObjects, CStitching, Imager, ImagerBitmapContext, ImagerFont, ImagerSample, IO, Real, Rope, SF, TerminalIO
EXPORTS CDCreateLabels =
BEGIN
DoStop: ERROR = CODE;
IntValue:
PROC [ob:
CD.Object, a:
ATOM]
RETURNS [i:
INT𡤀] = {
WITH CDProperties.GetObjectProp[ob, a]
SELECT
FROM
ri: REF INT => i ← ri^;
ENDCASE => NULL;
};
PutIntValue:
PROC [ob:
CD.Object, a:
ATOM, i:
INT𡤀] = {
CDProperties.PutObjectProp[ob, a, (IF i=0 THEN NIL ELSE NEW[INT ← i])];
};
NameForCharCache:
PROC [font: Imager.Font, ch:
CHAR, scale:
INT, layer:
CD.Layer]
RETURNS [n: Rope.
ROPE←
NIL] = {
--A NIL name should not be hashed
HashT:
PROC [t: Imager.Transformation]
RETURNS [Rope.
ROPE] = {
--returns a rope for hashing transformation
r: Rope.ROPE ← IO.PutFR["%g,%g,%g,%g", IO.real[t.a], IO.real[t.b], IO.real[t.c], IO.real[t.d]];
RETURN [IO.PutFR["%g,%g,%g", IO.rope[r], IO.real[t.e], IO.real[t.f]]]
};
h: Rope.ROPE ← HashT[font.charToClient];
n ←
IO.PutFR["#%g[%g|%d|%g|%g]",
IO.char[ch], IO.rope[ImagerFont.Name[font]], IO.int[scale], IO.atom[CD.LayerKey[layer]], IO.rope[h]
];
};
CStitchSampleMap:
PUBLIC PROC [map: ImagerSample.SampleMap, stop:
REF
BOOL←
NIL]
RETURNS [plane: CStitching.Tesselation] = {
box: ImagerSample.Box = ImagerSample.GetBox[map];
height: INTEGER ← box.max.s-box.min.s;
IF stop=NIL THEN stop ← NEW[BOOL←FALSE];
plane ← CStitching.NewTesselation[stopFlag: stop];
FOR y:
INTEGER
IN [box.min.s..box.max.s)
DO
IF stop^ THEN RETURN;
FOR x:
INTEGER
IN [box.min.f..box.max.f)
DO
IF ImagerSample.Get[map, [s: y, f: x]]#0
THEN
CStitching.ChangeRect[
plane: plane,
rect: [x1: x, x2: x+1, y1: y, y2: y+1],
new: $covered
];
ENDLOOP;
ENDLOOP;
};
CreateCellFromCStitching:
PUBLIC PROC [plane: CStitching.Tesselation, layer:
CD.Layer, csOrigin: CStitching.Pos ← [0, 0], scale:
INT ← 1]
RETURNS [cell:
CD.Object] = {
stop: REF BOOL ← plane.stopFlag;
IncludeRect: CStitching.TileProc = {
r: CD.Rect = CStitching.Area[tile];
IF CDBasics.NonEmpty[r]
THEN {
IF stop^ THEN ERROR DoStop;
[] ← CDCells.IncludeOb[cell: cell,
ob: CDRects.CreateRect[size: [x: (r.x2-r.x1)*scale, y: (r.y2-r.y1)*scale], l: layer],
trans: [[(r.x1-csOrigin.x)*scale, (r.y1-csOrigin.y)*scale], original],
mode: dontResize
];
};
};
stop ← plane.stopFlag;
IF stop=NIL THEN stop ← NEW[BOOL←FALSE];
cell ← CDCells.CreateEmptyCell[];
[] ← CStitching.EnumerateArea[plane: plane, rect: CDBasics.universe, eachTile: IncludeRect, data: NIL ! DoStop => CONTINUE];
--prevent empty cell
IF CDCells.IsEmpty[cell]
THEN
[] ← CDCells.IncludeOb[cell: cell, ob: CDSymbolicObjects.CreateMark[]];
[] ← CDCells.ResizeCell[NIL, cell];
};
BuildCharCell:
PROC [font: Imager.Font, char: ImagerFont.XChar, scale:
INT𡤁, layer:
CD.Layer, stop:
REF
BOOL←
NIL]
RETURNS [cell:
CD.Object] = {
bitmap: ImagerSample.SampleMap; context: Imager.Context; plane: CStitching.Tesselation;
ext: ImagerFont.Extents ← ImagerFont.BoundingBox[font, char];
descent: INT ← Real.Ceiling[ext.descent];
ascent: INT ← Real.Ceiling[ext.ascent];
leftExtent: INT ← Real.Ceiling[ext.leftExtent];
rightExtent: INT ← Real.Ceiling[ext.rightExtent];
box: ImagerSample.Box ← [min: [0, 0], max: [ascent+descent, rightExtent+leftExtent]];
--paint character in bitmap
bitmap ← ImagerSample.NewSampleMap[box: box]; ImagerSample.Clear[bitmap];
context ← ImagerBitmapContext.Create[
deviceSpaceSize: SF.Size[box],
scanMode: Imager.ScanMode[slow: up, fast: right],
surfaceUnitsPerInch: [1, 1], --???
pixelUnits: TRUE
];
ImagerBitmapContext.SetBitmap[context, bitmap];
Imager.SetColor[context, Imager.black];
Imager.SetXY[context, [leftExtent, descent]];
Imager.SetFont[context, font];
Imager.ShowXChar[context, char];
--create cell from bitmap
plane ← CStitchSampleMap[bitmap, stop];
cell ← CreateCellFromCStitching[plane: plane, layer: layer, scale: scale, csOrigin: [leftExtent, descent]];
--positioning and spacing
BEGIN
esc: Imager.VEC ← ImagerFont.Escapement[font, char];
PutIntValue[cell, $CDxWidth, scale*Real.Round[esc.x]];
PutIntValue[cell, $CDxHeight, scale*Real.Round[esc.y]];
END;
CDProperties.PutObjectProp[cell, $CreatedBy, $CreateLabel];
MakeCharCell:
PUBLIC
PROC [design:
CD.Design, font: Imager.Font, char:
CHAR, scale:
INT, layer:
CD.Layer, stop:
REF
BOOL←
NIL]
RETURNS [cell:
CD.Object←
NIL] = {
cacheName: Rope.ROPE;
IF stop=NIL THEN stop ← NEW[BOOL←FALSE];
IF scale<=0 THEN scale ← design.technology.lambda;
cacheName ← NameForCharCache[font, char, scale, layer];
IF design#
NIL
AND cacheName#
NIL
THEN {
cell ← CDDirectory.Fetch[design, cacheName].object;
IF cell#
NIL
THEN
IF CDProperties.GetProp[cell, $CreatedBy]#$CreateLabel THEN cell ← NIL
};
IF cell=
NIL
THEN {
cell ← BuildCharCell[font, [0, LOOPHOLE[char]], scale, layer, stop];
IF design#
NIL
THEN {
IF cacheName=NIL THEN cacheName ← Rope.Cat["#", Rope.FromChar[char]];
[] ← CDDirectory.Include[design, cell, IF stop^ THEN "@stopped" ELSE cacheName];
};
}
};
MakeRopeCell:
PUBLIC
PROC [design:
CD.Design, text: Rope.
ROPE, font: Imager.Font, scale:
INT𡤁, layer:
CD.Layer, stop:
REF
BOOL←
NIL]
RETURNS [cell:
CD.Object] = {
--NIL if not done
IncludeChar:
PROC [c:
CHAR]
RETURNS [quit:
BOOL ←
FALSE] = {
IF c='
THEN {
vec: Imager.VEC ← ImagerFont.RopeEscapement[font, Rope.FromChar[' ]];
x ← x + scale*Real.Round[vec.x];
y ← y + scale*Real.Round[vec.y];
}
ELSE {
charCell: CD.Object ← MakeCharCell[design, font, c, scale, layer, stop];
IF charCell#
NIL
THEN {
[] ← CDCells.IncludeOb[cell: cell, ob: charCell, trans: [[x, y]]];
x ← x + IntValue[charCell, $CDxWidth];
y ← y + IntValue[charCell, $CDxHeight];
}
}
};
x, y: CD.Number𡤀
IF scale<=0 THEN scale ← design.technology.lambda;
cell ← CDCells.CreateEmptyCell[];
[] ← Rope.Map[base: text, action: IncludeChar ! DoStop => CONTINUE];
IF CDCells.IsEmpty[cell] THEN RETURN [NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, cell, Rope.Cat["Label[", text, "]"]];
};
CreateTextCellComm:
PROC[comm: CDSequencer.Command] = {
SelectFont:
PROC [design:
CD.Design]
RETURNS [font: Imager.Font←
NIL] = {
cdFont: CDTexts.CDFont ← CDPanelFonts.CurrentFont[design];
IF cdFont#NIL THEN font ← cdFont.font
};
text: Rope.ROPE; font: Imager.Font;
layer: CD.Layer; scale: INT; cell: CD.Object;
stop: REF BOOL ← NEW[BOOL←FALSE];
layer ← comm.l;
TerminalIO.PutRopes["create a label (on layer ", CDOps.LayerRope[layer], ")\n"];
CDSequencer.UseAbortFlag[comm.design, stop];
font ← SelectFont[comm.design];
IF font=
NIL
THEN {
TerminalIO.PutRope["font not found\n"]; RETURN
};
text ← TerminalIO.RequestRope[" text -> "];
scale ← MAX[1, TerminalIO.RequestInt[" post scale factor > "]];
IF Rope.IsEmpty[text]
THEN {
TerminalIO.PutRope["empty text\n"]; RETURN
};
cell ← MakeRopeCell[comm.design, text, font, scale, layer];
IF cell=NIL THEN TerminalIO.PutRope["not done\n"]
ELSE {
[] ← CDOps.IncludeObjectI[comm.design, cell, comm.pos];
TerminalIO.PutRope["done\n"];
}
CDSequencer.ImplementCommand[$CreateTextCell, CreateTextCellComm];