<> <> <> <> <> <<>> DIRECTORY Commander USING [CommandProc, Register], Convert USING [RealFromLiteral], FSRope USING [StreamFromRope], FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup], Imager USING [Box, ConcatT, Context, DoSave, ScaleT, Trans, Transformation], ImagerMemory USING [GetContextSize, NewMemoryContext, Replay], ImagerTransformation USING [ApplyPreTranslate, Scale], Interpress USING [DoPage, FromStream, Master], IO USING [PutRope, RIS, STREAM], NodeProps USING [GetProp], NodePropsExtras USING [DeclarePropertyAttribute], NodeStyle USING [GetBottomLeading, GetFirstIndent, GetLeftIndent, GetLineFormatting, GetLineLength, GetRightIndent, GetTopLeading, Ref], Real USING [Round], Rope USING [Equal, Fetch, Match, ROPE, Run, Size], RuntimeError USING [UNCAUGHT], Scaled USING [Float, FromReal], TEditFormat USING [ArtworkClass, ArtworkClassRep, BoundingBoxProc, CharPositionProc, FormatProc, GetArtworkClass, PaintProc, RegisterArtwork, ResolveProc, UnRegisterArtwork], TextEdit USING [Size], TextNode USING [Ref], ViewerOps USING [BlinkDisplay, PaintEverything]; ArtworkInterpressImpl: CEDAR PROGRAM IMPORTS Commander, Convert, FSRope, FunctionCache, Imager, ImagerMemory, ImagerTransformation, Interpress, IO, NodeProps, NodePropsExtras, NodeStyle, Real, Rope, RuntimeError, Scaled, 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.GetTopLeading[nodeStyle]; box.ymin _ -NodeStyle.GetBottomLeading[nodeStyle]; box.xmax _ NodeStyle.GetLineLength[nodeStyle]; }; }; 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] }; Format: TEditFormat.FormatProc ~ { inner: PROC ~ { extraIndent: REAL ~ nodeStyle.GetFirstIndent; leftIndent: REAL ~ nodeStyle.GetLeftIndent + extraIndent; rightIndent: REAL ~ nodeStyle.GetRightIndent; clippedLineWidth: REAL ~ PositiveMin[nodeStyle.GetLineLength, lineWidth.Float]; 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[lineWidth.Float-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 {ViewerOps.BlinkDisplay[]; CONTINUE}}]; }; Resolve: TEditFormat.ResolveProc ~ { loc _ lineInfo.startPos; xmin _ lineInfo.xmin+lineInfo.xOffset.integerPart; width _ lineInfo.xmax; rightOfLine _ FALSE; }; CharPosition: TEditFormat.CharPositionProc ~ { x _ lineInfo.xmin+lineInfo.xOffset.integerPart; 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] ~ { compare: FunctionCache.CompareProc ~ {good _ argument = ipRope}; memory _ NARROW[FunctionCache.Lookup[memoryCache, compare, cacheID].value]; IF memory = NIL THEN { ipStream: IO.STREAM _ IF useFSRope THEN FSRope.StreamFromRope[ipRope] ELSE IO.RIS[ipRope]; proc: PROC ~ { ipMaster: Interpress.Master ~ Interpress.FromStream[stream: ipStream, log: NIL]; Interpress.DoPage[master: ipMaster, page: 1, context: memory, log: NIL]; }; memory _ ImagerMemory.NewMemoryContext[]; proc[ ! RuntimeError.UNCAUGHT => {IF NOT debug THEN {ViewerOps.BlinkDisplay[]; CONTINUE}}]; FunctionCache.Insert[memoryCache, ipRope, memory, ImagerMemory.GetContextSize[memory], cacheID]; }; }; Paint: TEditFormat.PaintProc ~ { 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.DoSave[context, proc]; }; class: TEditFormat.ArtworkClass ~ NEW[TEditFormat.ArtworkClassRep _ [ name: $Interpress, format: Format, paint: Paint, resolve: Resolve, charPosition: CharPosition, boundingBox: BoundingBox ]]; Command: Commander.CommandProc ~ { old, new: TEditFormat.ArtworkClass _ NIL; old _ TEditFormat.GetArtworkClass[class.name]; SELECT TRUE FROM Rope.Match["*on*", cmd.commandLine, FALSE] => { TEditFormat.RegisterArtwork[class]; new _ class; }; Rope.Match["*off*", cmd.commandLine, FALSE] => { TEditFormat.UnRegisterArtwork[class.name]; new _ NIL; }; ENDCASE => { cmd.out.PutRope["Please say on or off.\n"]; new _ old; }; IF new#old THEN ViewerOps.PaintEverything[]; }; NodePropsExtras.DeclarePropertyAttribute[$Fit, $Visible]; Commander.Register["ArtworkInterpress", Command, "Turn ArtworkInterpress on or off"]; END.