--GriffinToTANodesImpl.mesa
-- Beach, July 3, 1982 3:53 pm
-- Stone November 26, 1982 7:08 pm

DIRECTORY
 GFileFormatDefs,
 GriffinToTA,
 GriffinToTANodes,
 GriffinToTAPrivate,
IO,
 NameSymbolTable USING [Name, RopeFromName],
 PairList,
 PutGet USING [ToFile],
 Rope,
 SplineDefs,
 StyleDefs,
 TAProperties USING [SetArtworkProp, SetArtworkPathProp, SetBoundingBoxProp, SetOriginProp],
 TextEdit USING [AppendRope, ChangeStyle, ChangeType, DocFromNode, FromRope],
 TextNode USING [Ref, RefTextNode],
 UserExec USING [GetNameAndPassword],
 GraphicsBasic USING [Vec],
 CGPath USING [Generate];


GriffinToTANodesImpl: PROGRAM
IMPORTS GriffinToTA, GriffinToTAPrivate, IO, NameSymbolTable, PairList, PutGet, Rope, TAProperties, TextEdit, UserExec, CGPath
EXPORTS GriffinToTANodes = {
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];
 TextEdit.ChangeStyle[figureRoot, figureName];
 TAProperties.SetArtworkProp[figureRoot];
FOR thisCluster IN [firstCluster .. lastCluster] DO
  clusterNode ← NIL;
  clusterX ← clusterY ← LAST[INTEGER];
  PairList.ForAllPairs[clusterMap, objectBBox];
  PairList.ForAllPairs[clusterMap, doObject];
  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];
 TAProperties.SetArtworkProp[node];
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%d %d .translate",
   IO.card[cluster], IO.int[clusterX], IO.int[clusterY]]];
 TAProperties.SetArtworkProp[node];
RETURN[node];
 };

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;
 TAProperties.SetArtworkProp[objectNode];
 };

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;
 pathStyle: PathStyleRef;
 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;
 pathStyle ← FindPathStyle[areaColor, outlineColor, pathType, lineWeight];
 [] ← TextEdit.AppendRope[figureRoot, objectNode,
  IO.PutFToRope["\n%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]];
 TextEdit.ChangeType[pathNode, pathStyle^.name];
 TAProperties.SetArtworkProp[pathNode];
 TAProperties.SetArtworkPathProp[pathNode];
 TAProperties.SetBoundingBoxProp[pathNode, griffinObject^.bright-griffinObject^.bleft, griffinObject^.bbottom-griffinObject^.btop];
 TAProperties.SetOriginProp[pathNode, 0, 0];
 };

PutCaptionNode: PROCEDURE[figureRoot: TextNode.Ref, objectNode: TextNode.RefTextNode, griffinObject: ObjectRef, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = {
 captionNode: TextNode.RefTextNode ← InsertNodeAfterChildrenOf[objectNode];
 captionStyle: CaptionStyleRef;
 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;
 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";
 captionStyle ← FindCaptionStyle[family, size, face, charRotation, lineFormatting];
 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%d %d .translate %d .rotate",
  IO.real[caption^.position.x-clusterX],
  IO.real[caption^.position.y-clusterY], 
  IO.int[textRotation]]];
 [] ← TextEdit.AppendRope[figureRoot, captionNode, caption^.text];
 TextEdit.ChangeType[captionNode, captionStyle^.name];
 };

PutStyles: PUBLIC PROCEDURE[fileName: ROPE] = {
OPEN IO;
 userName, password: ROPE;
 styleRope: ROPE;
 p, pp, pTemp: PathStyleRef;
 c, cc, cTemp: CaptionStyleRef;
 node: TextNode.RefTextNode;
 root: TextNode.Ref;
 [userName, password] ← UserExec.GetNameAndPassword[];
 userName← Rope.Substr[userName, 0, Rope.Find[userName, "."]];
 styleRope ← PutFToRope["%% %s\n%% %s, %g\n\n", rope[fileName], rope[userName], time[]];
 styleRope ← Rope.Cat[styleRope, "BeginStyle\n\n(BasicGraphics) AttachStyle\n\n(Cedar) AttachStyle\n\n"];
 p ← pathStyles;
 pp ← NIL;
WHILE p#NIL DO -- reverse the styles list
  pTemp ← p.next; p.next ← pp; pp ← p; p ← pTemp;
  ENDLOOP;
 p ← pathStyles ← pp;
WHILE p#NIL DO
  styleRope ← Rope.Cat[styleRope, PathStyleToRope[p]];
  p ← p.next;
  ENDLOOP;
 c ← captionStyles;
 cc ← NIL;
WHILE c#NIL DO -- reverse the styles list
  cTemp ← c.next; c.next ← cc; cc ← c; c ← cTemp;
  ENDLOOP;
 c ← captionStyles ← cc;
WHILE c#NIL DO
  styleRope ← Rope.Cat[styleRope, CaptionStyleToRope[c]];
  c ← c.next;
  ENDLOOP;
 styleRope ← Rope.Cat[styleRope, "EndStyle\n"];
 node ← TextEdit.FromRope[styleRope];
 root ← TextEdit.DocFromNode[node];
 [] ← PutGet.ToFile[fileName, root];
 };

PathStyleToRope: PUBLIC PROCEDURE[p: PathStyleRef] RETURNS[styleRope: ROPE] = {
OPEN IO;
 styleRope ← PutFToRope["(%s) \". . .\" {\n", rope[NameSymbolTable.RopeFromName[p.name]]];
IF p.areaColor#NIL THEN
  styleRope ← Rope.Cat[styleRope, PutFToRope["\t%s areaColor\n", rope[p.areaColor.name]]];
IF p.outlineColor#NIL THEN
  styleRope ← Rope.Cat[styleRope, PutFToRope["\t%s outlineColor\n", rope[p.outlineColor.name]]];
 styleRope ← Rope.Cat[styleRope, PutFToRope["\t%s pathType\n", rope[p.pathType]]];
IF p.lineWeight#0 THEN
  styleRope ← Rope.Cat[styleRope, PutFToRope["\t%g pt lineWeight\n", real[p.lineWeight]]];
 styleRope ← Rope.Cat[styleRope, "\t} StyleRule\n\n"];
 };

CaptionStyleToRope: PUBLIC PROCEDURE[p: CaptionStyleRef] RETURNS[styleRope: ROPE] = {
OPEN IO;
 styleRope ← Rope.Cat[
  PutFToRope["(%s) \". . .\" {\n", rope[NameSymbolTable.RopeFromName[p.name]]],
  PutFToRope["\t\"%s\" family\n", rope[p.family]],
  PutFToRope["\t%g bp size\n", real[p.size]],
  PutFToRope["\t%s face\n", rope[p.face]],
  PutFToRope["\t%% %s charRotation\n", rope[p.charRotation]],
  PutFToRope["\t%s captionFormatting\n\tflushTop captionAlignment\n\t0 left.indent\n\t} StyleRule\n\n", rope[p.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];
 };

}.