<> <> <> <> DIRECTORY Imager USING [Context, DoSaveAll, Error, MakeGray, MaskRectangle, SetXY, Trans], ImagerBackdoor USING [Clipper, IntKey, RealKey], ImagerColor USING [Color, MakeSampledColor], ImagerColorOperator USING [BlackColorModel, ColorOperator], ImagerFont USING [Font, MapText, XChar, XStringProc], ImagerPath USING [Outline, OutlineFromPath, PathProc], ImagerPixelArray USING [PixelArray], ImagerPrivate USING [StrokeDashes], ImagerState USING [AndChangeFlags, ChangeFlags, NonPersistentVariables, notChanged, OrChangeFlags, PersistentVariables, State, StateRep], ImagerTransformation USING [ApplyPreConcat, ApplyPreRotate, ApplyPreScale2, ApplyPreTranslate, ApplyTranslateTo, Concat, DRound, InverseTransform, Rectangle, Transform, Transformation, TransformationRep, TransformVec], Rope USING [ROPE], Vector2 USING [Add, Div, InlineAdd, InlineMulC, Length, Mul, Sub, VEC]; ImagerStateImpl: CEDAR PROGRAM IMPORTS Imager, ImagerColor, ImagerColorOperator, ImagerFont, ImagerPath, ImagerState, ImagerTransformation, Vector2 EXPORTS Imager, ImagerState ~ BEGIN OPEN ImagerState; Context: TYPE ~ Imager.Context; State: TYPE ~ ImagerState.State; StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; TransformationRep: TYPE ~ ImagerTransformation.TransformationRep; Rectangle: TYPE ~ ImagerTransformation.Rectangle; Font: TYPE ~ ImagerFont.Font; XChar: TYPE ~ ImagerFont.XChar; XStringProc: TYPE ~ ImagerFont.XStringProc; Color: TYPE ~ ImagerColor.Color; ColorOperator: TYPE ~ ImagerColorOperator.ColorOperator; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; PathProc: TYPE ~ ImagerPath.PathProc; Outline: TYPE ~ ImagerPath.Outline; Clipper: TYPE ~ ImagerBackdoor.Clipper; StrokeDashes: TYPE ~ ImagerPrivate.StrokeDashes; <<>> Changed: PROC[state: State, changed: ChangeFlags] ~ INLINE { state.changed _ OrChangeFlags[state.changed, changed]; state.np.changed _ OrChangeFlags[state.np.changed, changed]; }; refChanges: ChangeFlags ~ [T: TRUE, font: TRUE, color: TRUE, clipper: TRUE]; StateDoSave: PUBLIC PROC[context: Context, action: PROC, all: BOOL _ FALSE] ~ { state: State ~ context.state; p: PersistentVariables ~ state.p; np: NonPersistentVariables ~ state.np; T: TransformationRep ~ state.T^; font: Font ~ state.font; color: Color ~ state.color; clipper: Clipper ~ state.clipper; strokeDashes: StrokeDashes ~ state.strokeDashes; Restore: PROC ~ { state.changed _ OrChangeFlags[state.changed, state.np.changed]; IF all THEN state.p _ p; state.np _ np; state.T^ _ T; state.font _ font; state.color _ color; state.clipper _ clipper; state.strokeDashes _ strokeDashes; }; state.np.changed _ notChanged; action[! UNWIND => Restore[]]; IF AndChangeFlags[state.np.changed, refChanges]=notChanged THEN { state.changed _ OrChangeFlags[state.changed, state.np.changed]; IF all THEN state.p _ p; state.np _ np; } ELSE Restore[]; }; StateSetInt: PUBLIC PROC[context: Context, key: ImagerBackdoor.IntKey, val: INT] ~ { state: State ~ context.state; SELECT key FROM priorityImportant => { state.np.priorityImportant _ val; Changed[state, [priority: TRUE]] }; noImage => state.np.noImage _ val; strokeEnd => state.np.strokeEnd _ val; strokeJoint => state.np.strokeJoint _ val; correctPass => state.np.correctPass _ val; ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown IntKey"]]; }; StateSetReal: PUBLIC PROC[context: Context, key: ImagerBackdoor.RealKey, val: REAL] ~ { state: State ~ context.state; SELECT key FROM DCScpx => state.p.cp.x _ val; DCScpy => state.p.cp.y _ val; correctMX => state.p.correctMeasure.x _ val; correctMY => state.p.correctMeasure.y _ val; mediumXSize => state.np.mediumSize.x _ val; mediumYSize => state.np.mediumSize.y _ val; fieldXMin => state.np.fieldMin.x _ val; fieldYMin => state.np.fieldMin.y _ val; fieldXMax => state.np.fieldMax.x _ val; fieldYMax => state.np.fieldMax.y _ val; strokeWidth => state.np.strokeWidth _ val; underlineStart => state.np.underlineStart _ val; amplifySpace => state.np.amplifySpace _ val; correctShrink => state.np.correctShrink _ val; correctTX => state.np.correctTolerance.x _ val; correctTY => state.np.correctTolerance.y _ val; ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown RealKey"]]; }; StateSetT: PUBLIC PROC[context: Context, m: Transformation] ~ { state: State ~ context.state; state.T^ _ m^; Changed[state, [T: TRUE]]; }; StateSetClipper: PUBLIC PROC[context: Context, clipper: Clipper] ~ { state: State ~ context.state; state.clipper _ clipper; Changed[state, [clipper: TRUE]]; }; StateSetFont: PUBLIC PROC[context: Context, font: Font] ~ { state: State ~ context.state; state.font _ font; Changed[state, [font: TRUE]]; }; StateSetColor: PUBLIC PROC[context: Context, color: Color] ~ { state: State ~ context.state; state.color _ color; Changed[state, [color: TRUE]]; }; StateSetStrokeDashes: PUBLIC PROC[context: Context, strokeDashes: StrokeDashes] ~ { state: State ~ context.state; state.strokeDashes _ strokeDashes; }; StateGetInt: PUBLIC PROC[context: Context, key: ImagerBackdoor.IntKey] RETURNS[INT] ~ { state: State ~ context.state; SELECT key FROM priorityImportant => RETURN[state.np.priorityImportant]; noImage => RETURN[state.np.noImage]; strokeEnd => RETURN[state.np.strokeEnd]; strokeJoint => RETURN[state.np.strokeJoint]; correctPass => RETURN[state.np.correctPass]; ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown IntKey"]]; }; StateGetReal: PUBLIC PROC[context: Context, key: ImagerBackdoor.RealKey] RETURNS[REAL] ~ { state: State ~ context.state; SELECT key FROM DCScpx => RETURN[state.p.cp.x]; DCScpy => RETURN[state.p.cp.y]; correctMX => RETURN[state.p.correctMeasure.x]; correctMY => RETURN[state.p.correctMeasure.y]; mediumXSize => RETURN[state.np.mediumSize.x]; mediumYSize => RETURN[state.np.mediumSize.y]; fieldXMin => RETURN[state.np.fieldMin.x]; fieldYMin => RETURN[state.np.fieldMin.y]; fieldXMax => RETURN[state.np.fieldMax.x]; fieldYMax => RETURN[state.np.fieldMax.y]; strokeWidth => RETURN[state.np.strokeWidth]; underlineStart => RETURN[state.np.underlineStart]; amplifySpace => RETURN[state.np.amplifySpace]; correctShrink => RETURN[state.np.correctShrink]; correctTX => RETURN[state.np.correctTolerance.x]; correctTY => RETURN[state.np.correctTolerance.y]; ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown RealKey"]]; }; StateGetT: PUBLIC PROC[context: Context] RETURNS[Transformation] ~ { state: State ~ context.state; RETURN[NEW[TransformationRep _ state.T^]]; }; StateGetClipper: PUBLIC PROC[context: Context] RETURNS[Clipper] ~ { state: State ~ context.state; RETURN[state.clipper]; }; StateGetFont: PUBLIC PROC[context: Context] RETURNS[Font] ~ { state: State ~ context.state; RETURN[state.font]; }; StateGetColor: PUBLIC PROC[context: Context] RETURNS[Color] ~ { state: State ~ context.state; RETURN[state.color]; }; StateGetStrokeDashes: PUBLIC PROC[context: Context] RETURNS[StrokeDashes] ~ { state: State ~ context.state; RETURN[state.strokeDashes]; }; StateGetCP: PUBLIC PROC[context: Context, rounded: BOOL] RETURNS[VEC] ~ { state: State ~ context.state; p: VEC _ state.p.cp; IF rounded THEN p _ ImagerTransformation.DRound[p]; RETURN[state.T.InverseTransform[p]]; }; StateConcatT: PUBLIC PROC[context: Context, m: Transformation] ~ { state: State ~ context.state; state.T.ApplyPreConcat[m]; Changed[state, [T: TRUE]]; }; StateScale2T: PUBLIC PROC[context: Context, s: VEC] ~ { state: State ~ context.state; state.T.ApplyPreScale2[s]; Changed[state, [T: TRUE]]; }; StateRotateT: PUBLIC PROC[context: Context, a: REAL] ~ { state: State ~ context.state; state.T.ApplyPreRotate[a]; Changed[state, [T: TRUE]]; }; StateTranslateT: PUBLIC PROC[context: Context, t: VEC] ~ { state: State ~ context.state; state.T.ApplyPreTranslate[t]; Changed[state, [T: TRUE]]; }; StateMove: PUBLIC PROC[context: Context, rounded: BOOL _ TRUE] ~ { state: State ~ context.state; p: VEC _ state.p.cp; IF rounded THEN p _ ImagerTransformation.DRound[p]; state.T.ApplyTranslateTo[p]; Changed[state, [T: TRUE]]; }; StateSetXY: PUBLIC PROC[context: Context, p: VEC] ~ { state: State ~ context.state; state.p.cp _ state.T.Transform[p]; }; StateSetXYRel: PUBLIC PROC[context: Context, v: VEC] ~ { state: State ~ context.state; state.p.cp _ state.p.cp.InlineAdd[state.T.TransformVec[v]]; }; StateSetGray: PUBLIC PROC[context: Context, f: REAL] ~ { state: State ~ context.state; state.color _ Imager.MakeGray[f]; Changed[state, [color: TRUE]]; }; StateSetSampledColor: PUBLIC PROC[context: Context, pa: PixelArray, m: Transformation, colorOperator: ColorOperator] ~ { state: State ~ context.state; um: Transformation ~ m.Concat[state.T]; -- color to view state.color _ ImagerColor.MakeSampledColor[pa: pa, um: um, colorOperator: colorOperator]; Changed[state, [color: TRUE]]; }; StateSetSampledBlack: PUBLIC PROC[context: Context, pa: PixelArray, m: Transformation, clear: BOOL] ~ { state: State ~ context.state; um: Transformation ~ m.Concat[state.T]; -- color to view colorOperator: ColorOperator ~ ImagerColorOperator.BlackColorModel[clear]; state.color _ ImagerColor.MakeSampledColor[pa: pa, um: um, colorOperator: colorOperator]; Changed[state, [color: TRUE]]; }; StateStartUnderline: PUBLIC PROC[context: Context] ~ { state: State ~ context.state; p: VEC ~ state.T.InverseTransform[state.p.cp]; state.np.underlineStart _ p.x; }; StateMaskUnderline: PUBLIC PROC[context: Context, dy, h: REAL] ~ { state: State ~ context.state; p2: VEC ~ state.T.InverseTransform[state.p.cp]; -- current position (client coords) p1: VEC ~ [state.np.underlineStart, p2.y-dy-h]; -- starting corner (client coords) underline: PROC ~ { Imager.SetXY[context, p1]; Imager.Trans[context]; Imager.MaskRectangle[context, [0, 0, p2.x-p1.x, h]]; }; Imager.DoSaveAll[context, underline]; }; StateClip: PUBLIC PROC[context: Context, path: PathProc, parity: BOOL, exclude: BOOL] ~ { state: State ~ context.state; outline: Outline ~ ImagerPath.OutlineFromPath[path: path, m: state.T]; state.clipper _ CONS[[outline: outline, parity: parity, exclude: exclude], state.clipper]; Changed[state, [clipper: TRUE]]; }; StateClipRectangle: PUBLIC PROC[context: Context, r: Rectangle, exclude: BOOL] ~ { path: PathProc ~ { moveTo[[r.x, r.y]]; lineTo[[r.x+r.w, r.y]]; lineTo[[r.x+r.w, r.y+r.h]]; lineTo[[r.x, r.y+r.h]]; }; StateClip[context: context, path: path, parity: FALSE, exclude: exclude]; }; StateClipRectangleI: PUBLIC PROC[context: Context, x, y, w, h: INTEGER, exclude: BOOL] ~ { path: PathProc ~ { moveTo[[x, y]]; lineTo[[x+w, y]]; lineTo[[x+w, y+h]]; lineTo[[x, y+h]]; }; StateClip[context: context, path: path, parity: FALSE, exclude: exclude]; }; StateCorrectMask: PUBLIC PROC[context: Context] ~ { state: State ~ context.state; IF state.np.correctPass#0 THEN { SELECT state.np.correctPass FROM 1 => state.p.correctMaskCount _ state.p.correctMaskCount+1; 2 => IF state.p.correctMaskCount#0 THEN { state.p.cp _ state.p.cp.InlineAdd[state.p.correctMask]; state.p.correctMaskCount _ state.p.correctMaskCount-1; }; ENDCASE; }; }; StateCorrectSpace: PUBLIC PROC[context: Context, v: VEC] ~ { state: State ~ context.state; IF state.np.correctPass#0 THEN { s: VEC ~ state.T.TransformVec[v]; SELECT state.np.correctPass FROM 1 => state.p.correctSum _ state.p.correctSum.InlineAdd[s]; 2 => state.p.cp _ state.p.cp.InlineAdd[state.p.correctSpace.InlineMulC[s]]; ENDCASE; }; }; StateSpace: PUBLIC PROC[context: Context, x: REAL] ~ { state: State ~ context.state; s: VEC ~ state.T.TransformVec[[x, 0]]; state.p.cp _ state.p.cp.InlineAdd[s]; SELECT state.np.correctPass FROM 0 => NULL; 1 => state.p.correctSum _ state.p.correctSum.InlineAdd[s]; 2 => state.p.cp _ state.p.cp.InlineAdd[state.p.correctSpace.InlineMulC[s]]; ENDCASE; }; StateSetCorrectMeasure: PUBLIC PROC[context: Context, v: VEC] ~ { state: State ~ context.state; state.p.correctMeasure _ state.T.TransformVec[v]; }; StateSetCorrectTolerance: PUBLIC PROC[context: Context, v: VEC] ~ { state: State ~ context.state; state.np.correctTolerance _ state.T.TransformVec[v]; }; StateCorrect: PUBLIC PROC[context: Context, action: PROC] ~ { state: State ~ context.state; shrink: REAL ~ state.np.correctShrink; tolerance: VEC ~ state.np.correctTolerance; start, end, measure, target, correction: VEC; mask, space: VEC _ [0, 0]; state.p.correctMaskCount _ 0; state.p.correctSum _ [0, 0]; state.np.noImage _ 1; state.np.correctPass _ 1; start _ state.p.cp; -- starting position StateDoSave[context, action]; -- pass 1 end _ state.p.cp; -- ending position measure _ state.p.correctMeasure; -- desired measure (note: may be set during pass 1) target _ start.Add[measure]; -- target position correction _ target.Sub[end]; -- amount of correction needed (end + correction = target) IF correction.Length<=tolerance.Length THEN NULL -- close enough ELSE IF end.Sub[start].Length(shrink*state.p.correctSum.Length) THEN { mask _ correction.Add[state.p.correctSum.Mul[shrink]]; space _ correction.Sub[mask]; }; }; IF state.p.correctSum.x#0 THEN space.x _ space.x/state.p.correctSum.x ELSE IF space.x#0 THEN { mask.x _ mask.x+space.x; space.x _ 0 }; IF state.p.correctSum.y#0 THEN space.y _ space.y/state.p.correctSum.y ELSE IF space.y#0 THEN { mask.y _ mask.y+space.y; space.y _ 0 }; IF state.p.correctMaskCount#0 THEN { IF mask.x=0 AND mask.y=0 THEN state.p.correctMaskCount _ 0 ELSE IF state.p.correctMaskCount>1 THEN { state.p.correctMaskCount _ state.p.correctMaskCount-1; mask _ mask.Div[state.p.correctMaskCount]; }; }; state.p.correctMask _ mask; state.p.correctSpace _ space; state.np.noImage _ 0; state.np.correctPass _ 2; state.p.cp _ start; StateDoSave[context, action]; -- pass 2 state.np.correctPass _ 0; end _ state.p.cp; -- ending position state.p.cp _ target; <tolerance.Length THEN>> <> }; StateDontCorrect: PUBLIC PROC[context: Context, action: PROC, saveCP: BOOL] ~ { state: State ~ context.state; correctPass: INT ~ state.np.correctPass; cp: VEC ~ state.p.cp; Restore: PROC ~ INLINE { state.np.correctPass _ correctPass; IF saveCP THEN state.p.cp _ cp }; action[! UNWIND => Restore[]]; Restore[]; }; StateShow: PUBLIC PROC[context: Context, string: XStringProc, xrel: BOOL] ~ { state: State ~ context.state; <> <> <> <> <> <> <> <> <