CDCreateLabelsImpl.mesa
Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved.
Created by: Jacobi, March 1, 1985 4:52:57 pm PST
Last Edited by: Jacobi, January 8, 1986 3:45:23 pm PST
DIRECTORY
Basics,
CD,
CDCells,
CDCreateLabels,
CDDirectory,
CDBasics,
CDMenus,
CDSymbolicObjects,
CDOps,
CDPanelFonts,
CDProperties,
CDRects,
CDSequencer,
CDTexts,
CornerStitching,
Imager,
ImagerBackdoor,
ImagerFont,
IO,
Real,
Rope,
TerminalIO;
CDCreateLabelsImpl: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDSymbolicObjects, CDCells, CDDirectory, CDMenus, CDOps, CDPanelFonts, CDProperties, CDSequencer, CDRects, CornerStitching, Imager, ImagerBackdoor, ImagerFont, IO, Real, Rope, TerminalIO
EXPORTS CDCreateLabels =
BEGIN
IntValue: PROC [ob: CD.Object, a: ATOM] RETURNS [i: INT𡤀] =
BEGIN
WITH CDProperties.GetPropFromObject[ob, a] SELECT FROM
ri: REF INT => i ← ri^;
ENDCASE => NULL;
END;
PutIntValue: PROC [ob: CD.Object, a: ATOM, i: INT𡤀] =
BEGIN
CDProperties.PutPropOnObject[ob, a, (IF i=0 THEN NIL ELSE NEW[INT ← i])];
END;
HashT: PROC [t: Imager.Transformation] RETURNS [Rope.ROPE] =
BEGIN
r: Rope.ROPEIO.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]]]
END;
MakeName: PROC [font: Imager.Font, ch: CHAR, scale: INT, lev: CD.Layer] RETURNS [n: Rope.ROPENIL] =
--A NIL name should not be hashed
BEGIN
h: Rope.ROPE ← HashT[font.charToClient];
n ← IO.PutFR["#%g[%g|%d|%g|%g]",
IO.char[ch], IO.rope[font.name], IO.int[scale], IO.atom[CD.LayerKey[lev]], IO.rope[h]
];
END;
BitmapToCornerstitching: PROC [bitmap: ImagerBackdoor.Bitmap] RETURNS [plane: REF CornerStitching.Tesselation] =
BEGIN
plane ← CornerStitching.NewTesselation[];
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
CornerStitching.ChangeRect[
plane: plane,
rect: [x1: x, x2: x+1, y1: bitmap.height-y-1, y2: bitmap.height-y],
newValue: $covered
];
}
ENDLOOP;
ENDLOOP;
END;
CornerstitchingToCell: PROC [plane: REF CornerStitching.Tesselation, layer: CD.Layer, csOrigin: CornerStitching.Pos ← [0, 0], scale: INT ← 1] RETURNS [cell: CD.Object] =
--does not yet include cell into a design
--csOrigin: in CornerStitching coords; will be origin of cell
--scale: applied after offset for csOrigin
BEGIN
offset: CD.Position ← [-csOrigin.x*scale, -csOrigin.y*scale];
IncludeRectangle: CornerStitching.PerTileProc =
BEGIN
r: CD.Rect ~ CornerStitching.Area[tile];
IF CDBasics.NonEmpty[r] THEN
[] ← CDCells.IncludeOb[cell: cell,
ob: CDRects.CreateRect[size: [x: (r.x2-r.x1)*scale, y: (r.y2-r.y1)*scale], l: layer],
position: CDBasics.AddPoints[[x: r.x1*scale, y: r.y1*scale], offset],
cellCSystem: cdCoords,
obCSystem: cdCoords,
mode: dontPropagate
];
END;
cell ← CDCells.CreateEmptyCell[];
[] ← CornerStitching.EnumerateArea[plane: plane, rect: CDBasics.universe, perTile: IncludeRectangle, data: NIL];
--prevent empty cell
IF NARROW[cell.specificRef, CD.CellPtr].contents=NIL THEN
[] ← CDCells.IncludeOb[cell: cell, ob: CDSymbolicObjects.CreateMark[], mode: dontPropagate];
[] ← CDCells.RepositionCell[cell, NIL];
END;
Up: PROC [r: REAL] RETURNS [i: INT] = {
-- returns integer i: i >= r; there exists no integer j such that j < i and j >= r
i ← Real.Fix[r];
IF Real.Float[i]#r THEN i ← i+1;
};
MakeChar: PROC [font: Imager.Font, char: CHAR, scale: INT𡤁, lev: CD.Layer] RETURNS [cell: CD.Object] =
BEGIN
vec: Imager.VEC;
bitmap: ImagerBackdoor.Bitmap;
context: Imager.Context;
plane: REF CornerStitching.Tesselation;
ext: ImagerFont.Extents ← ImagerFont.FontBoundingBox[font];
p1: CD.Position ← [Up[ext.leftExtent], Up[ext.descent]];
p2: CD.Position ← [Up[ext.rightExtent], Up[ext.ascent]];
--paint character in bitmap
bitmap ← ImagerBackdoor.NewBitmap[width: p1.x+p2.x, height: p1.y+p2.y];
context ← ImagerBackdoor.BitmapContext[bitmap];
Imager.SetColor[context, Imager.white];
Imager.MaskRectangleI[context, 0, 0, bitmap.width, bitmap.height];
Imager.SetColor[context, Imager.black];
Imager.SetXY[context, [x: p1.x, y: p1.y]];
Imager.SetFont[context, font];
Imager.ShowChar[context, char];
--create cell from bitmap
plane ← BitmapToCornerstitching[bitmap];
cell ← CornerstitchingToCell[plane, lev, p1, scale];
--positioning and spacing
vec ← ImagerFont.RopeWidth[font, Rope.FromChar[char]];
PutIntValue[cell, $CDxWidth, scale*Real.RoundI[vec.x]];
PutIntValue[cell, $CDxHeight, scale*Real.RoundI[vec.y]];
END;
FindOrCreateCharCell: PUBLIC PROC [design: CD.Design, font: Imager.Font, char: CHAR, scale: INT, lev: CD.Layer] RETURNS [cell: CD.Object←NIL] =
BEGIN
hashName: Rope.ROPE;
IF scale<=0 THEN scale ← design.technology.lambda;
hashName ← MakeName[font, char, scale, lev];
IF design#NIL AND hashName#NIL THEN
cell ← CDDirectory.Fetch[design, hashName].object;
IF cell=NIL THEN {
cell ← MakeChar[font, char, scale, lev];
IF design#NIL THEN {
IF hashName=NIL THEN hashName ← Rope.Cat["#", Rope.FromChar[char]];
[] ← CDDirectory.Include[design, cell, hashName];
};
}
END;
CreateTextCell: PUBLIC PROC [design: CD.Design, text: Rope.ROPE, font: Imager.Font, scale: INT𡤁, lev: CD.Layer] RETURNS [cell: CD.Object] =
--NIL if not done
BEGIN
IncludeChar: PROC [c: CHAR] RETURNS [quit: BOOLFALSE] =
BEGIN
IF c=' THEN {
vec: Imager.VEC ← ImagerFont.RopeWidth[font, Rope.FromChar[' ]];
x ← x + scale*Real.RoundI[vec.x];
y ← y + scale*Real.RoundI[vec.y];
}
ELSE {
charCell: CD.Object ← FindOrCreateCharCell[design, font, c, scale, lev];
IF charCell#NIL THEN {
[] ← CDCells.IncludeOb[cell: cell, ob: charCell,
position: [x, y],
cellCSystem: originCoords,
obCSystem: originCoords
];
x ← x + IntValue[charCell, $CDxWidth];
y ← y + IntValue[charCell, $CDxHeight];
}
}
END;
x: CD.Number𡤀
y: CD.Number𡤀
IF scale<=0 THEN scale ← design.technology.lambda;
cell ← CDCells.CreateEmptyCell[];
[] ← Rope.Map[base: text, action: IncludeChar];
IF NARROW[cell.specificRef, CD.CellPtr].contents=NIL THEN RETURN [NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, cell, Rope.Cat["Label[", text, "]"]];
END;
GetFont: PROC [design: CD.Design] RETURNS [font: Imager.Font←NIL] =
BEGIN
IF TerminalIO.Confirm["use font from panel"] THEN {
cdFont: CDTexts.CDFont ← CDPanelFonts.CurrentFont[design];
IF cdFont#NIL THEN font ← cdFont.font
}
ELSE {
fontName: Rope.ROPE ← TerminalIO.RequestRope["font name -> "];
font ← ImagerFont.Find[fontName !
Imager.Error => {
TerminalIO.WriteRope[Rope.Cat["font not loaded: ", error.explanation]];
GOTO oops
};
];
}
EXITS oops => NULL
END;
PostScaling: PROC [lambda: INT] RETURNS [scale: INT𡤁] =
BEGIN
IF TerminalIO.Confirm["use a post scale factor on cell?"] THEN {
text: Rope.ROPEIO.PutFR1["post scale [lambda/%g] >", IO.int[lambda]];
scale ← MAX[1, TerminalIO.RequestInt[text]];
}
END;
PreScaling: PROC [font: Imager.Font] RETURNS [Imager.Font] =
BEGIN
IF TerminalIO.Confirm["use a pre scale factor on font (but prevents caching)"] THEN {
scale: INTMAX[1, TerminalIO.RequestInt["pre scale -> "]];
font ← ImagerFont.Scale[font, scale];
};
RETURN [font]
END;
CreateTextCellComm: PROC[comm: CDSequencer.Command] =
BEGIN
text: Rope.ROPE;
font: Imager.Font;
layer: CD.Layer;
scale: INT;
cell: CD.Object;
layer ← comm.l;
TerminalIO.WriteRope[Rope.Cat["create a label (using ", CDOps.LayerName[layer], ")\n"]];
font ← GetFont[comm.design];
IF font=NIL THEN {
TerminalIO.WriteRope["font not found\n"];
RETURN
};
scale ← PostScaling[comm.design.technology.lambda];
font ← PreScaling[font];
text ← TerminalIO.RequestRope["text -> "];
IF Rope.IsEmpty[text] THEN {
TerminalIO.WriteRope["empty text\n"];
RETURN
};
cell ← CreateTextCell[comm.design, text, font, scale, layer];
IF cell=NIL THEN TerminalIO.WriteRope["not done\n"]
ELSE {
CDOps.AddAnObject[comm.design, cell, comm.pos];
TerminalIO.WriteRope["done\n"];
}
END;
CDSequencer.ImplementCommand[$CreateTextCell, CreateTextCellComm];
CDMenus.CreateEntry[menu: $RectProgramMenu, entry: "Enter text", key: $CreateTextCell];
END.