<> <> <> DIRECTORY Controls, ControlsPrivate, Draw2d, Imager, ViewerClasses, ViewerOps; ControlsSketchImpl: CEDAR PROGRAM IMPORTS ControlsPrivate, Draw2d, Imager, ViewerOps EXPORTS Controls, ControlsPrivate ~ BEGIN OPEN Controls; <> Chain: TYPE ~ REF ChainRep; ChainRep: TYPE ~ RECORD [ p0, p1: INTEGER _ 0, -- current vector to draw firstRun: Run _ NIL, lastRun: Run _ NIL, pairs: PosSequence _ NIL -- chain points ]; Run: TYPE ~ REF RunRep; RunRep: TYPE ~ RECORD [ start, stop: INTEGER _ 0, -- inclusive indices into pairs next: Run _ NIL ]; <> NewSketch: PUBLIC PROC [control: Control] ~ { chain: Chain _ NEW[ChainRep]; control.sketchRef _ chain; chain.pairs _ NEW[PosSequenceRep[10000]]; -- should be large enough chain.firstRun _ NEW[RunRep]; chain.lastRun _ chain.firstRun; }; EnlargePosSequence: PROC [chain: Chain] ~ { IF chain # NIL AND chain.pairs # NIL THEN { old: PosSequence _ chain.pairs; new: PosSequence _ NEW[PosSequenceRep[2*old.maxLength]]; FOR n: NAT IN [0..old.length) DO new[n] _ old[n]; ENDLOOP; new.length _ old.length; chain.pairs _ new; }; }; ClearSketch: PUBLIC PROC [control: Control, repaint: BOOL _ TRUE] ~ { IF control.type = sketch THEN { chain: Chain _ NARROW[control.sketchRef]; newChain: Chain _ NEW[ChainRep _ [pairs: chain.pairs]]; chain.pairs.length _ 0; control.sketchRef _ newChain; newChain.firstRun _ NEW[RunRep]; newChain.lastRun _ newChain.firstRun; IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, NIL]; }; }; <> AddPos: PROC [chain: Chain, pair: Pos] ~ { pairs: PosSequence _ chain.pairs; IF pairs.length = pairs.maxLength THEN EnlargePosSequence[chain]; pairs[pairs.length] _ pair; pairs.length _ pairs.length+1; }; NotifySketch: PUBLIC PROC [control: Control] ~ { chain: Chain _ NARROW[control.sketchRef]; mouse: Mouse _ control.mouse; SELECT mouse.state FROM down => { chain.p0 _ chain.p1 _ chain.pairs.length; IF chain.firstRun = NIL THEN { chain.firstRun _ NEW[RunRep_ [start: chain.p0]]; chain.lastRun _ chain.firstRun; } ELSE { chain.lastRun.next _ NEW[RunRep]; chain.lastRun _ chain.lastRun.next; chain.lastRun.start _ chain.p0; }; AddPos[chain, [mouse.x, mouse.y]]; }; held => { chain.p1 _ chain.pairs.length; chain.p0 _ chain.p1-1; AddPos[chain, [mouse.x, mouse.y]]; }; up => chain.lastRun.stop _ chain.p1; ENDCASE => RETURN; ViewerOps.PaintViewer[control.viewer, client, FALSE, control]; IF mouse.state = up THEN ControlsPrivate.MaybeForkControlProc[control]; }; <> LinePos: PROC [context: Context, p0, p1: Pos] ~ { Draw2d.Line[context, [p0.x, p0.y], [p1.x, p1.y]]; }; PaintSketch: PUBLIC ViewerClasses.PaintProc ~ { control: Control _ NARROW[self.data]; chain: Chain _ NARROW[control.sketchRef]; IF chain = NIL THEN RETURN; IF whatChanged = NIL THEN { Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, 0, 0, self.ww, self.wh]; Imager.SetColor[context, Imager.black]; SketchReDraw[context, chain]; } ELSE { pairs: PosSequence _ chain.pairs; LinePos[context, pairs[chain.p0], pairs[chain.p1]]; }; }; SketchReDraw: PROC [context: Context, chain: Chain] ~ { pairs: PosSequence _ chain.pairs; start: Run _ chain.firstRun; FOR run: Run _ start, run.next WHILE run # NIL DO FOR n: NAT IN [run.start..run.stop) DO LinePos[context, pairs[n], pairs[n+1]]; ENDLOOP; ENDLOOP; }; <> GetSketch: PUBLIC PROC [control: Control] RETURNS [PosSequences] ~ { chain: Chain _ NARROW[control.sketchRef]; chainPoss: PosSequence _ chain.pairs; start: Run _ chain.firstRun; sketch: PosSequences _ NEW[PosSequencesRep]; FOR run: Run _ start, run.next WHILE run # NIL DO n: INTEGER _ 0; sketchPoss: PosSequence _ NEW[PosSequenceRep[run.stop-run.start+1]]; sketch[sketch.length] _ sketchPoss; sketch.length _ sketch.length+1; FOR r: NAT IN [run.start..run.stop] DO sketchPoss[n] _ chainPoss[r]; n _ n+1; ENDLOOP; ENDLOOP; RETURN[sketch]; }; SetSketch: PUBLIC PROC [control: Control, sketch: PosSequences, repaint: BOOL _ TRUE] ~ { run: Run _ NIL; iPos, nPoss: INT _ 0; chain: Chain _ NARROW[control.sketchRef]; FOR n: INT IN [0..sketch.length) DO nPoss _ nPoss+sketch[n].length; ENDLOOP; IF nPoss > chain.pairs.maxLength THEN chain.pairs _ NEW[PosSequenceRep[nPoss]]; FOR n: INT IN [0..sketch.length) DO pairs: PosSequence _ sketch[n]; FOR i: INT IN [0..pairs.length) DO chain.pairs[i+iPos] _ pairs[i]; ENDLOOP; IF run # NIL THEN {run.next _ NEW[RunRep]; run _ run.next} ELSE chain.firstRun _ run _ NEW[RunRep]; run.start _ iPos; iPos _ iPos+pairs.length; run.stop _ iPos-1; ENDLOOP; IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, NIL]; }; NLinesInSketch: PUBLIC PROC [control: Control] RETURNS [INTEGER] ~ { IF control.sketchRef = NIL THEN RETURN[0] ELSE { chain: Chain _ NARROW[control.sketchRef]; nLines: INTEGER _ 0; FOR r: Run _ chain.firstRun, r.next WHILE r # NIL DO nLines _ nLines+1; ENDLOOP; RETURN[nLines]; }; }; NPossInSketch: PUBLIC PROC [control: Control] RETURNS [INTEGER] ~ { IF control.sketchRef = NIL THEN RETURN[0] ELSE { chain: Chain _ NARROW[control.sketchRef]; nPoss: INTEGER _ 0; FOR run: Run _ chain.firstRun, run.next WHILE run # NIL DO nPoss _ nPoss+run.stop-run.start+1; ENDLOOP; RETURN[nPoss]; }; }; END.