GriffinToJaMImpl.Mesa
Last Edited by: Beach, May 1, 1984 5:12:29 pm PDT
DIRECTORY
Commander,
GFileFormatDefs,
Graphics,
GriffinToJaM,
IO,
NameSymbolTable,
PairList,
PutGet,
ReadGriffin,
Real,
Rope,
SplineDefs,
StyleDefs,
TextEdit,
TextNode,
GraphicsBasic USING [Vec],
CGPath USING [Generate];
GriffinToJaMImpl:
CEDAR PROGRAM
IMPORTS Commander, IO, PairList, PutGet, ReadGriffin, Rope, TextEdit, TextNode, Real, CGPath
EXPORTS GriffinToJaM = {
ROPE: TYPE = Rope.ROPE;
topScreenCoord: INTEGER = 808;
Griffin Font definitions taken from GriffinFontDefs
Regular: CARDINAL = 0;
Italic: CARDINAL = 1;
Bold: CARDINAL = 2;
BoldItalic: CARDINAL = Bold + Italic;
Rot0Degrees: CARDINAL = 0;
Rot90Degrees: CARDINAL = 5400;
Rot180Degrees: CARDINAL = 10800;
Rot270Degrees: CARDINAL = 16200;
ViewType: TYPE = {main, alternate, both};
GriffinToJaM: Commander.CommandProc ~ {
fileName: ROPE;
jamFileName: ROPE;
stream: IO.STREAM ← IO.RIS[cmd.commandLine];
FileNameBreakProc:
PROC [char:
CHAR]
RETURNS [
IO.CharClass] = {
IF char = ' OR char = ' OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
WHILE
NOT
IO.EndOf[stream]
DO
fileName ← NIL;
fileName ← IO.GetTokenRope[stream, FileNameBreakProc ! IO.EndOfStream => CONTINUE].token;
IF fileName #
NIL
THEN {
cmd.out.PutRope[IO.PutFR["Converting %g to JaM . . . ", IO.rope[fileName]]];
ReadGriffin.ConvertFile[fileName ! ReadGriffin.GriffinFileError => {msg ← why; GOTO FileProblem}];
jamFileName ← ReadGriffin.FixFileName[fileName, ".JaM"];
PutClusters[jamFileName];
cmd.out.PutRope[IO.PutFR["into %g\n", IO.rope[jamFileName]]];
};
ENDLOOP;
EXITS
FileProblem => RETURN[$Failure, msg];
};
PutClusters:
PUBLIC
PROCEDURE[fileName:
ROPE] = {
thisCluster: CARDINAL;
clusterNumber: CARDINAL ← 0;
figureName: ROPE ← Rope.Substr[fileName, 0, Rope.Find[fileName, "."]];
figureRoot: TextNode.Ref;
figureNode, clusterNode: TextNode.RefTextNode;
clusterX, clusterY: INTEGER ← LAST[INTEGER];
objectBBox:
PROC[leftPart, rightPart:
REF
ANY] = {
IF
NARROW[leftPart,
REF
CARDINAL]^=thisCluster
THEN {
refObjectId: REF CARDINAL ← NARROW[rightPart];
griffinObject: ReadGriffin.ObjectRef ← NARROW[PairList.Right[ReadGriffin.objectMap, EqualCardinals, refObjectId]];
clusterX ← MIN[clusterX, griffinObject^.bleft];
clusterY ← MIN[clusterY, topScreenCoord-griffinObject^.bbottom];
};
};
doObject:
PROC[leftPart, rightPart:
REF
ANY] = {
IF
NARROW[leftPart,
REF
CARDINAL]^=thisCluster
THEN {
IF clusterNode=
NIL
THEN {
clusterNumber ← clusterNumber+1;
clusterNode ← PutClusterNode[figureRoot, figureNode, clusterNumber, clusterX, clusterY]};
PutObjectNode[figureRoot, clusterNode, NARROW[rightPart, REF CARDINAL], clusterX, clusterY]};
};
figureNode ← PutFigureNode[figureName];
figureRoot ← TextEdit.DocFromNode[figureNode];
FOR thisCluster
IN [ReadGriffin.firstCluster .. ReadGriffin.lastCluster]
DO
clusterNode ← NIL;
clusterX ← clusterY ← LAST[INTEGER];
PairList.ForAllPairs[ReadGriffin.clusterMap, objectBBox];
PairList.ForAllPairs[ReadGriffin.clusterMap, doObject];
IF clusterNode#NIL THEN PutPopNode[figureRoot, clusterNode];
ENDLOOP;
[] ← PutGet.ToFile[fileName, figureRoot];
};
PutFigureNode:
PROCEDURE[figureName:
ROPE]
RETURNS[node: TextNode.RefTextNode] = {
rope: ROPE ← Rope.Cat["% Tioga Artwork figure for ", figureName];
node ← TextEdit.FromRope[rope];
RETURN[node];
};
PutClusterNode:
PROCEDURE[figureRoot: TextNode.Ref, figureNode: TextNode.RefTextNode, cluster:
CARDINAL, clusterX, clusterY:
INTEGER]
RETURNS[node: TextNode.RefTextNode] = {
node ← InsertNodeAfterChildrenOf[figureNode];
[] ← TextEdit.AppendRope[figureRoot, node,
IO.PutFR["%% Cluster %d\n.pushdc %d %d .translate",
IO.card[cluster], IO.int[clusterX], IO.int[clusterY]]];
RETURN[node];
};
PutPopNode:
PROCEDURE[figureRoot: TextNode.Ref, clusterNode: TextNode.RefTextNode] = {
popNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[clusterNode];
[] ← TextEdit.AppendRope[figureRoot, popNode, ".popdc"];
};
PutObjectNode:
PROCEDURE[figureRoot: TextNode.Ref, clusterNode: TextNode.RefTextNode, refObjectId:
REF
CARDINAL, clusterX, clusterY:
INTEGER] = {
griffinObject: ReadGriffin.ObjectRef ← NARROW[PairList.Right[ReadGriffin.objectMap, EqualCardinals, refObjectId]];
objectNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[clusterNode];
[] ← TextEdit.AppendRope[figureRoot, objectNode,
IO.PutFR["%% Object %d", IO.card[refObjectId^]]];
SELECT griffinObject^.objtype
FROM
GFileFormatDefs.typeCurveObject,
GFileFormatDefs.typeAreaObject =>
PutPathNode[figureRoot, objectNode, griffinObject, refObjectId, clusterX, clusterY];
GFileFormatDefs.typeCaptionObject =>
PutCaptionNode[figureRoot, objectNode, griffinObject, refObjectId, clusterX, clusterY];
ENDCASE;
};
PutPathNode:
PROCEDURE[figureRoot: TextNode.Ref, objectNode: TextNode.RefTextNode, griffinObject: ReadGriffin.ObjectRef, refObjectId:
REF
CARDINAL, clusterX, clusterY:
INTEGER] = {
pathNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[objectNode];
refStyleId: REF CARDINAL ← NEW[CARDINAL ← griffinObject^.style];
griffinStyle: ReadGriffin.StyleRef ← NARROW[PairList.Right[ReadGriffin.styleMap, EqualCardinals, refStyleId]];
areaColor, outlineColor: ReadGriffin.ColorRef ← NIL;
pathType: ROPE ← NIL;
lineWeight: REAL ← 0;
pathRef: ReadGriffin.PathRef;
SELECT griffinObject^.objtype
FROM
GFileFormatDefs.typeAreaObject => {
IF griffinStyle^.afilled
THEN {
areaColor ← FindColor[griffinStyle^.ahue, griffinStyle^.asaturation, griffinStyle^.abrightness];
pathType ← "filled"};
IF griffinStyle^.aoutlined
THEN {
outlineColor ← FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness];
pathType ← IF griffinStyle^.afilled THEN "filled+outlined" ELSE "outlined";
lineWeight ← ScalePressToScreenCoord[griffinStyle^.thickness]}};
GFileFormatDefs.typeCurveObject => {
outlineColor ← FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness];
pathType ← "outlined";
lineWeight ← ScalePressToScreenCoord[griffinStyle^.thickness]};
ENDCASE;
[] ← TextEdit.AppendRope[figureRoot, objectNode,
IO.PutFR["\n.pushdc %d %d .translate",
IO.int[griffinObject^.bleft-clusterX],
IO.int[topScreenCoord-griffinObject^.bbottom-clusterY]]];
can't use a NARROW as pathRef is opaque, and that construct is not implemented
this should be pretty safe
TRUSTED { pathRef ← LOOPHOLE[PairList.Right[ReadGriffin.pathMap, EqualCardinals, refObjectId]] };
[] ← TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]];
SELECT pathType
FROM
"filled" => [] ← TextEdit.AppendRope[figureRoot, pathNode,
IO.PutFR["%g .drawarea", IO.rope[areaColor.name]]];
"outlined" => [] ← TextEdit.AppendRope[figureRoot, pathNode,
IO.PutFR["%g %g 2 .drawstroke", --2=round ends
IO.rope[outlineColor.name], IO.real[lineWeight]]];
"filled+outlined" => {
[] ← TextEdit.AppendRope[figureRoot, pathNode,
IO.PutFR["%g .drawarea\n", IO.rope[areaColor.name]]];
[] ← TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]];
[] ← TextEdit.AppendRope[figureRoot, pathNode,
IO.PutFR["%g %g 2 .drawstroke", --2=round ends
IO.rope[outlineColor.name], IO.real[lineWeight]]];
};
ENDCASE => ERROR;
[] ← TextEdit.AppendRope[figureRoot, pathNode, " .popdc"];
};
PutCaptionNode:
PROCEDURE[figureRoot: TextNode.Ref, objectNode: TextNode.RefTextNode, griffinObject: ReadGriffin.ObjectRef, refObjectId:
REF
CARDINAL, clusterX, clusterY:
INTEGER] = {
captionNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[objectNode];
caption: ReadGriffin.CaptionRef ← NARROW[PairList.Right[ReadGriffin.captionMap, EqualCardinals, refObjectId]];
refStyleId: REF CARDINAL ← NEW[CARDINAL ← griffinObject^.style];
griffinStyle: ReadGriffin.StyleRef ← NARROW[PairList.Right[ReadGriffin.styleMap, EqualCardinals, refStyleId]];
refFontId: REF CARDINAL ← NEW[CARDINAL ← griffinStyle^.fontid];
griffinFont: ReadGriffin.FontRef ← NARROW[PairList.Right[ReadGriffin.fontMap, EqualCardinals, refFontId]];
family, face, charRotation, lineFormatting: ROPE;
fontName: ROPE;
size: REAL;
textRotation: INTEGER;
textColor: ReadGriffin.ColorRef;
i: CARDINAL;
bold, italic: BOOLEAN ← FALSE;
FOR i
IN [1 ..
LOOPHOLE[griffinFont^.char[0],
CARDINAL]]
DO
family ← Rope.Cat[family, Rope.FromChar[griffinFont^.char[i]]];
ENDLOOP;
size ← griffinFont^.points;
SELECT griffinFont^.face
FROM
Regular => face ← "regular";
Italic => {face ← "italic"; italic ← TRUE};
Bold => {face ← "bold"; bold ← TRUE};
BoldItalic => {face ← "bold+italic"; bold ← TRUE; italic ← TRUE};
ENDCASE=> face ← "regular";
charRotation ←
SELECT griffinFont^.rotation
FROM
Rot0Degrees => "0",
Rot90Degrees => "90",
Rot180Degrees => "180",
Rot270Degrees => "270",
ENDCASE => "0";
lineFormatting ←
SELECT griffinStyle^.anchor
FROM
GFileFormatDefs.typeLeftAnchor => "flushLeft",
GFileFormatDefs.typeCenterAnchor => "centered",
GFileFormatDefs.typeRightAnchor => "flushRight",
ENDCASE => "flushLeft";
textRotation ←
SELECT griffinStyle^.torient
FROM
GFileFormatDefs.typeRot0 => 0,
GFileFormatDefs.typeRot90 => 90,
GFileFormatDefs.typeRot180 => 180,
GFileFormatDefs.typeRot270 => 270,
ENDCASE => 0;
textColor ← FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness];
[] ← TextEdit.AppendRope[figureRoot, objectNode,
IO.PutFR["\n.pushdc %d %d .translate %d .rotate",
IO.real[caption^.position.x-clusterX],
IO.real[caption^.position.y-clusterY],
IO.int[textRotation]]];
fontName ← IO.PutFR["(%g%g",IO.rope[family],IO.real[size]];
fontName ← Rope.Cat[fontName,
(SELECT face FROM "italic" => "I", "bold" => "B", "bold+italic" => "BI", ENDCASE=> NIL),
".ks)"];
[] ← TextEdit.AppendRope[figureRoot, captionNode,
IO.PutFR["%g .setfont topEdge %g (%g) %g 0 0 .setcp .drawtext .popdc",
IO.rope[fontName],IO.rope[textColor.name], IO.rope[caption^.text],IO.rope[lineFormatting]]];
};
PathToRope:
PROC [path: ReadGriffin.PathRef]
RETURNS [
ROPE] = {
rope: ROPE;
move:
SAFE
PROC[p: GraphicsBasic.Vec] =
CHECKED {
rope ← Rope.Cat[rope,
IO.PutFR["%f %f %s ",
IO.real[p.x], IO.real[p.y], IO.rope[" .moveto "]]];
};
line:
SAFE
PROC[p: GraphicsBasic.Vec] =
CHECKED {
rope ← Rope.Cat[rope,
IO.PutFR["%f %f %s ",
IO.real[p.x], IO.real[p.y], IO.rope[" .lineto "]]];
};
curve:
SAFE
PROC[b1,b2,b3: GraphicsBasic.Vec] =
CHECKED {
rope ← Rope.Cat[rope,
IO.PutFR["%f %f %f %f ",
IO.real[b1.x], IO.real[b1.y], IO.real[b2.x], IO.real[b2.y]]];
rope ← Rope.Cat[rope,
IO.PutFR["%f %f %s",
IO.real[b3.x], IO.real[b3.y], IO.rope[" .curveto "]]];
};
CGPath.Generate[path,move,line,curve];
RETURN[rope];
};
EqualCardinals: PairList.EqualProc = {
l,r: CARDINAL;
return ← FALSE;
if not a cardinal, will signal out
l ← NARROW[left,REF CARDINAL]^; r ← NARROW[right,REF CARDINAL]^;
IF l=r THEN return ← TRUE;
};
InsertNodeAfterChildrenOf:
PROCEDURE[node: TextNode.RefTextNode, newnode: TextNode.RefTextNode ←
NIL]
RETURNS[TextNode.RefTextNode] = {
p: TextNode.Ref;
IF newnode =
NIL
THEN
-- create a new node
newnode ← TextNode.NewTextNode[]
ELSE {
-- unhook newnode from the tree
p ← TextNode.Parent[newnode];
IF TextNode.FirstChild[p] = newnode
THEN {
-- newnode is a first sibling
IF newnode.last
THEN
-- it was an only child
p.child ← NIL
ELSE
-- its sibling is now the parents first child
p.child ← newnode.next}
ELSE {
-- unhook newnode from the middle of a chain
p ← TextNode.Previous[newnode, p];
p.next ← newnode.next;
p.last ← newnode.last}};
newnode is unattached
IF TextNode.FirstChild[node]=
NIL
THEN {
-- add newnode as a first child
node.child ← newnode;
newnode.next ← node;
newnode.last ← TRUE}
ELSE {
-- finally, add newnode as sibling of last sibling
p ← TextNode.LastChild[node];
newnode.next ← p.next;
newnode.last ← p.last;
p.next ← newnode;
p.last ← FALSE};
RETURN[newnode];
};
FindColor:
PROCEDURE[h, s, b:
REAL]
RETURNS[ReadGriffin.ColorRef] = {
c: ReadGriffin.ColorRef ← ReadGriffin.colors;
MatchColor:
PROCEDURE[c: ReadGriffin.ColorRef, h, s, b:
REAL]
RETURNS[
BOOLEAN] =
INLINE {
RETURN[c#NIL AND c.h=h AND c.s=s AND c.b=b]};
MakeColorName:
PROCEDURE[n:
CARDINAL]
RETURNS[
ROPE] =
INLINE {
RETURN[IO.PutFR["Color%d", IO.card[n]]]};
WHILE c#
NIL
DO
IF MatchColor[c, h, s, b] THEN RETURN[c];
c ← c.next;
ENDLOOP;
ERROR;
};
ScalePressToScreenCoord:
PROCEDURE[a:
REAL]
RETURNS[
INTEGER] =
INLINE {
RETURN[Real.RoundI[a*0.03125]]};
Commander.Register[key: "GriffinToJaM", proc: GriffinToJaM, doc: "convert a given Griffin file into equivalent JaM commands"];
}.