--GriffinToJaMImpl.mesa
--- Stone December 10, 1982 1:29 pm

DIRECTORY
 GFileFormatDefs,
 GriffinToTA,
 GriffinToTANodes,
 GriffinToTAPrivate,
 GriffinToJaM,
IO,
 PairList,
 PutGet USING [WriteFilePlain],
 Rope,
 SplineDefs,
 StyleDefs,
 TextEdit USING [AppendRope, DocFromNode, FromRope],
 TextNode USING [Ref, RefTextNode],
 GraphicsBasic USING [Vec],
 CGPath USING [Generate];


GriffinToJaMImpl: PROGRAM
IMPORTS GriffinToTA, GriffinToTAPrivate, IO, PairList, PutGet, Rope, TextEdit, CGPath
EXPORTS GriffinToJaM = {
OPEN GriffinToTA, GriffinToTAPrivate;

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;

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: INTEGERLAST[INTEGER];
 objectBBox: PROC[leftPart, rightPart: REF ANY] = {
  IF NARROW[leftPart, REF CARDINAL]^=thisCluster THEN {
   refObjectId: REF CARDINALNARROW[rightPart];
   griffinObject: ObjectRef ← NARROW[PairList.Right[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 [firstCluster .. lastCluster] DO
  clusterNode ← NIL;
  clusterX ← clusterY ← LAST[INTEGER];
  PairList.ForAllPairs[clusterMap, objectBBox];
  PairList.ForAllPairs[clusterMap, doObject];
  IF clusterNode#NIL THEN PutPopNode[figureRoot, clusterNode];
  ENDLOOP;
 [] ← PutGet.WriteFilePlain[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.PutFToRope["%% 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: ObjectRef ← NARROW[PairList.Right[objectMap, EqualCardinals, refObjectId]];
 objectNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[clusterNode];
 [] ← TextEdit.AppendRope[figureRoot, objectNode,
  IO.PutFToRope["%% 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: ObjectRef, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = {
 pathNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[objectNode];
 refStyleId: REF CARDINALNEW[CARDINAL ← griffinObject^.style];
 griffinStyle: StyleRef ← NARROW[PairList.Right[styleMap, EqualCardinals, refStyleId]];
 areaColor, outlineColor: ColorRef ← NIL;
 pathType: ROPENIL;
 lineWeight: REAL ← 0;
 pathRef: 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 ← GriffinToTAPrivate.ScalePressToScreenCoord[griffinStyle^.thickness]}};
  GFileFormatDefs.typeCurveObject => {
   outlineColor ← FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness];
   pathType ← "outlined";
   lineWeight ← GriffinToTAPrivate.ScalePressToScreenCoord[griffinStyle^.thickness]};
  ENDCASE;
 [] ← TextEdit.AppendRope[figureRoot, objectNode,
  IO.PutFToRope["\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
 pathRef ← LOOPHOLE[PairList.Right[pathMap, EqualCardinals, refObjectId]];
 [] ← TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]];
 SELECT pathType FROM
  "filled" => [] ← TextEdit.AppendRope[figureRoot, pathNode,
   IO.PutFToRope["%g .drawarea", IO.rope[areaColor.name]]];
  "outlined" => [] ← TextEdit.AppendRope[figureRoot, pathNode,
   IO.PutFToRope["%g %g 2 .drawstroke", --2=round ends
   IO.rope[outlineColor.name], IO.real[lineWeight]]];
  "filled+outlined" => {
   [] ← TextEdit.AppendRope[figureRoot, pathNode,
   IO.PutFToRope["%g .drawarea\n", IO.rope[areaColor.name]]];
   [] ← TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]];
   [] ← TextEdit.AppendRope[figureRoot, pathNode,
    IO.PutFToRope["%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: ObjectRef, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = {
 captionNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[objectNode];
 caption: CaptionRef ← NARROW[PairList.Right[captionMap, EqualCardinals, refObjectId]];
 refStyleId: REF CARDINALNEW[CARDINAL ← griffinObject^.style];
 griffinStyle: StyleRef ← NARROW[PairList.Right[styleMap, EqualCardinals, refStyleId]];
 refFontId: REF CARDINALNEW[CARDINAL ← griffinStyle^.fontid];
 griffinFont: FontRef ← NARROW[PairList.Right[fontMap, EqualCardinals, refFontId]];
 family, face, charRotation, lineFormatting: ROPE;
 fontName: ROPE;
 size: REAL;
 textRotation: INTEGER;
 textColor: 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.PutFToRope["\n.pushdc %d %d .translate %d .rotate",
  IO.real[caption^.position.x-clusterX],
  IO.real[caption^.position.y-clusterY], 
  IO.int[textRotation]]];
 fontName ← IO.PutFToRope["(%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.PutFToRope["%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: PathRef] RETURNS [ROPE] = {
 rope: ROPE;
 move: SAFE PROC[p: GraphicsBasic.Vec] = CHECKED {
  rope ← Rope.Cat[rope,IO.PutFToRope["%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.PutFToRope["%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.PutFToRope["%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.PutFToRope["%f %f %s",
   IO.real[b3.x], IO.real[b3.y], IO.rope[" .curveto "]]];
  };
 CGPath.Generate[path,move,line,curve];
RETURN[rope];
 };

}.