<<>> <> <> <> <> <> <<>> DIRECTORY Basics USING [IsBound], Commander USING [CommandProc, Register], Convert USING [RealFromLiteral], FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup], Imager USING [Box, ConcatT, Context, DoSave, ScaleT, Trans, Transformation, Warning], ImagerMemory USING [GetContextSize, NewMemoryContext, Replay], ImagerTransformation USING [ApplyPreTranslate, Scale], InterpressInterpreter USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, DoPage, FromRope, LogProc, Master], IO USING [PutFR1, PutRope, STREAM], NodeProps USING [DeclarePropertyAttribute, GetProp], NodeStyle USING [GetLineFormatting, GetReal, Ref], ProcessProps USING [GetProp], Real USING [Round], Rope USING [Equal, Fetch, Match, ROPE, Run, Size], RuntimeError USING [UNCAUGHT], Scaled USING [Float, Floor, FromReal], SimpleFeedback USING [Append, Blink], TEditFormat, TextEdit USING [Size], TextNode USING [Ref], ViewerOps USING [PaintEverything]; ArtworkInterpressImpl: CEDAR PROGRAM IMPORTS Basics, Commander, Convert, FunctionCache, Imager, ImagerMemory, ImagerTransformation, InterpressInterpreter, IO, NodeProps, NodeStyle, ProcessProps, Real, Rope, RuntimeError, Scaled, SimpleFeedback, TEditFormat, TextEdit, ViewerOps ~ BEGIN ROPE: TYPE ~ Rope.ROPE; GetBounds: PROC [prop: REF, nodeStyle: NodeStyle.Ref] RETURNS [box: Imager.Box ¬ [0,0,0,0]] ~ { rope: ROPE ~ WITH prop SELECT FROM r: ROPE => r, ENDCASE => NIL; size: INT ~ Rope.Size[rope]; IF size # 0 THEN { i: INT ¬ -1; Getc: PROC RETURNS [CHAR] ~ {i¬i+1; RETURN [IF i> startTok: INT ¬ 0; sizeTok: INT ¬ 0; GetTok: PROC ~ { startTok ¬ i; UNTIL c = ' DO c ¬ Getc[] ENDLOOP; sizeTok ¬ i-startTok; WHILE c = ' AND i r ¬ r*0.001; Match["cm"] => r ¬ r*0.01; Match["in"] => r ¬ r*0.0254; Match["pt"] => r ¬ r*0.0254/72.27; Match["bp"] => r ¬ r*0.0254/72; ENDCASE => ERROR; r ¬ r*pointsPerMeter; GetTok[]; SELECT TRUE FROM Match["xmin"] => box.xmin ¬ r; Match["xmax"] => box.xmax ¬ r; Match["ymin"] => box.ymin ¬ r; Match["ymax"] => box.ymax ¬ r; ENDCASE => ERROR; ENDLOOP; } ELSE { box.ymax ¬ NodeStyle.GetReal[nodeStyle, $topLeading]; box.ymin ¬ -NodeStyle.GetReal[nodeStyle, $bottomLeading]; box.xmax ¬ NodeStyle.GetReal[nodeStyle, $lineLength]; }; }; Floor: PROC [r: REAL] RETURNS [i: INT] ~ { i ¬ Real.Round[r]; IF i > r THEN i ¬ i-1; }; Ceiling: PROC [r: REAL] RETURNS [i: INT] ~ { i ¬ Real.Round[r]; IF i < r THEN i ¬ i+1; }; PositiveMin: PROC [a, b: REAL] RETURNS [REAL] ~ { IF a < 0 THEN RETURN [MAX[b, 0.01]]; IF b < 0 THEN RETURN [a]; RETURN [MIN[a, b]] }; HasFit: PROC [node: TextNode.Ref] RETURNS [BOOL] ~ { WITH NodeProps.GetProp[n: node, name: $Fit] SELECT FROM b: REF BOOL => RETURN [b­]; rope: ROPE => RETURN [Rope.Equal[rope, "TRUE"]]; ENDCASE => RETURN [FALSE]; }; DetermineScaleFactor: PROC [box: Imager.Box, lineWidth: REAL] RETURNS [REAL] ~ { size: REAL ~ MAX[box.xmax-box.xmin, 1]; scaleFactor: REAL ~ lineWidth/size; RETURN [scaleFactor] }; ReportUncaught: PROC [who: Rope.ROPE] ~ { SimpleFeedback.Append[$Artwork, begin, $Error, "Artwork Interpress UNCAUGHT ERROR during "]; SimpleFeedback.Append[$Artwork, end, $Error, who]; SimpleFeedback.Blink[$Artwork, $Error]; }; Format: TEditFormat.FormatProc ~ { inner: PROC ~ { extraIndent: REAL ~ nodeStyle.GetReal[$firstIndent]; leftIndent: REAL ~ nodeStyle.GetReal[$leftIndent] + extraIndent; rightIndent: REAL ~ nodeStyle.GetReal[$rightIndent]; clippedLineWidth: REAL ~ PositiveMin[nodeStyle.GetReal[$lineLength], Scaled.Float[lineWidth]]; trimmedLineWidth: REAL ~ MAX[clippedLineWidth-leftIndent-rightIndent, 0]; box: Imager.Box ¬ GetBounds[NodeProps.GetProp[n: node, name: $Bounds], nodeStyle]; lineInfo.artworkData ¬ NIL; IF HasFit[node] THEN { scaleFactor: REAL ~ DetermineScaleFactor[box, trimmedLineWidth]; m: Imager.Transformation ¬ ImagerTransformation.Scale[scaleFactor]; ImagerTransformation.ApplyPreTranslate[m, [-box.xmin, -box.ymin]]; box.xmax ¬ (box.xmax-box.xmin)*scaleFactor; box.ymax ¬ (box.ymax-box.ymin)*scaleFactor; box.xmin ¬ 0; box.ymin ¬ 0; lineInfo.artworkData ¬ m; }; lineInfo.xmin ¬ Floor[box.xmin]; lineInfo.ymin ¬ Floor[box.ymin]; lineInfo.xmax ¬ Ceiling[box.xmax]; lineInfo.ymax ¬ Ceiling[box.ymax]; SELECT nodeStyle.GetLineFormatting[] FROM FlushLeft => {lineInfo.xOffset ¬ Scaled.FromReal[leftIndent]}; FlushRight => {lineInfo.xOffset ¬ Scaled.FromReal[MAX[Scaled.Float[lineWidth]-leftIndent-box.xmax, 0]]}; Centered, Justified => {lineInfo.xOffset ¬ Scaled.FromReal[leftIndent+(trimmedLineWidth-box.xmax)/2]}; ENDCASE => ERROR; }; lineInfo.startPos ¬ [node, 0]; lineInfo.nextPos ¬ [node, TextEdit.Size[node]]; lineInfo.nChars ¬ TextEdit.Size[node]; inner[ ! RuntimeError.UNCAUGHT => IF NOT debug THEN { ReportUncaught["Format"]; CONTINUE }; ]; }; Resolve: TEditFormat.ResolveProc ~ { loc ¬ lineInfo.startPos; xmin ¬ lineInfo.xmin+Scaled.Floor[lineInfo.xOffset]; width ¬ lineInfo.xmax; rightOfLine ¬ FALSE; }; CharPosition: TEditFormat.CharPositionProc ~ { x ¬ lineInfo.xmin+Scaled.Floor[lineInfo.xOffset]; width ¬ lineInfo.xmax; }; BoundingBox: TEditFormat.BoundingBoxProc ~ { RETURN [[lineInfo.xmin, lineInfo.ymin, lineInfo.xmax, lineInfo.ymax]] }; debug: BOOL ¬ FALSE; useFSRope: BOOL ¬ TRUE; pointsPerMeter: REAL ¬ 72/0.0254; memoryCache: FunctionCache.Cache ¬ FunctionCache.GlobalCache[]; cacheID: ROPE ~ "Art"; GetCachedMemoryContext: PROC [ipRope: ROPE] RETURNS [memory: Imager.Context] ~ { Log: InterpressInterpreter.LogProc = { <<[class: INT, code: ATOM, explanation: ROPE]>> tag: ROPE ~ SELECT class FROM InterpressInterpreter.classMasterError => "Artwork Interpress Master Error: ", InterpressInterpreter.classMasterWarning => "Artwork Interpress Master Warning: ", InterpressInterpreter.classAppearanceError => "Artwork Interpress Appearance Error: ", InterpressInterpreter.classAppearanceWarning => "Artwork Interpress Appearance Warning: ", InterpressInterpreter.classComment => "Artwork Interpress Comment: ", ENDCASE => IO.PutFR1["Artwork Interpress Error class %g: ", [integer[class]]]; WITH ProcessProps.GetProp[$StdOut] SELECT FROM errout: IO.STREAM => { IO.PutRope[errout, tag]; IO.PutRope[errout, explanation]; IO.PutRope[errout, "\n"]; }; ENDCASE => { msgClass: ATOM ~ SELECT class FROM InterpressInterpreter.classMasterError => $Error, InterpressInterpreter.classMasterWarning => $Warning, InterpressInterpreter.classAppearanceError => $Error, InterpressInterpreter.classAppearanceWarning => $Warning, InterpressInterpreter.classComment => $Comment, ENDCASE => $Error; SimpleFeedback.Append[$Artwork, begin, msgClass, tag]; SimpleFeedback.Append[$Artwork, end, msgClass, explanation]; }; }; compare: FunctionCache.CompareProc ~ {good ¬ argument = ipRope}; memory ¬ NARROW[FunctionCache.Lookup[memoryCache, compare, cacheID].value]; IF memory = NIL THEN { proc: PROC ~ { ipMaster: InterpressInterpreter.Master ~ InterpressInterpreter.FromRope[rope: ipRope, log: Log]; InterpressInterpreter.DoPage[master: ipMaster, page: 1, context: memory, log: Log]; }; memory ¬ ImagerMemory.NewMemoryContext[]; proc[ ! RuntimeError.UNCAUGHT => IF NOT debug THEN { ReportUncaught["GetCachedMemoryContext"]; CONTINUE }; ]; FunctionCache.Insert[memoryCache, ipRope, memory, ImagerMemory.GetContextSize[memory], cacheID]; }; }; Paint: TEditFormat.PaintProc ~ { prevMsg: ROPE ¬ NIL; ipRope: ROPE ¬ NARROW[NodeProps.GetProp[lineInfo.startPos.node, $Interpress]]; compare: FunctionCache.CompareProc ~ {good ¬ argument = ipRope}; memory: Imager.Context ~ GetCachedMemoryContext[ipRope]; proc: PROC ~ { Imager.Trans[context]; WITH lineInfo.artworkData SELECT FROM m: Imager.Transformation => Imager.ConcatT[context, m]; ENDCASE => NULL; Imager.ScaleT[context, pointsPerMeter]; ImagerMemory.Replay[c: memory, into: context ! Imager.Warning => { IF error.explanation # prevMsg THEN { SimpleFeedback.Append[$Artwork, begin, $Warning, "Artwork Interpress Warning: "]; SimpleFeedback.Append[$Artwork, end, $Warning, error.explanation]; prevMsg ¬ error.explanation; }; RESUME; }; ]; }; Imager.DoSave[context, proc ! RuntimeError.UNCAUGHT => IF NOT debug THEN { ReportUncaught["Paint"]; CONTINUE }; ]; }; class: TEditFormat.ArtworkClass ~ NEW[TEditFormat.ArtworkClassRep ¬ [ name: $Interpress, format: Format, paint: Paint, resolve: Resolve, charPosition: CharPosition, boundingBox: BoundingBox ]]; Command: Commander.CommandProc ~ { oldState: BOOL ¬ TEditFormat.ArtworkEnabled[]; newState: BOOL ¬ oldState; SELECT TRUE FROM Rope.Match["*on*", cmd.commandLine, FALSE] => { newState ¬ TRUE; }; Rope.Match["*off*", cmd.commandLine, FALSE] => { newState ¬ FALSE; }; ENDCASE => { cmd.out.PutRope["Please say on or off.\n"]; }; oldState ¬ TEditFormat.SetArtworkEnabled[newState]; IF newState#oldState AND Basics.IsBound[ViewerOps.PaintEverything] THEN ViewerOps.PaintEverything[]; }; NodeProps.DeclarePropertyAttribute[$Interpress, $ClientOnly]; NodeProps.DeclarePropertyAttribute[$Fit, $Visible]; TEditFormat.RegisterArtwork[class]; Commander.Register["Artwork", Command, "Turn Artwork on or off"]; Commander.Register["ArtworkInterpress", Command, "Turn Artwork on or off"]; END.