<<>> <> <> <> DIRECTORY Controls, ControlsPrivate, Draw2d, Imager, ViewerClasses, ViewerOps; ControlsSketchImpl: CEDAR PROGRAM IMPORTS ControlsPrivate, Draw2d, Imager, ViewerOps EXPORTS Controls, ControlsPrivate ~ BEGIN <> Context: TYPE ~ Imager.Context; Control: TYPE ~ Controls.Control; IntegerPair: TYPE ~ Controls.IntegerPair; IntegerPairSequenceRep: TYPE ~ Controls.IntegerPairSequenceRep; IntegerPairSequence: TYPE ~ Controls.IntegerPairSequence; IntegerPairSequences: TYPE ~ Controls.IntegerPairSequences; IntegerPairSequencesRep: TYPE ~ Controls.IntegerPairSequencesRep; Mouse: TYPE ~ Controls.Mouse; <> Chain: TYPE ~ REF ChainRep; ChainRep: TYPE ~ RECORD [ p0, p1: INTEGER ¬ 0, -- current vector to draw firstRun: Run ¬ NIL, lastRun: Run ¬ NIL, pairs: IntegerPairSequence ¬ 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[IntegerPairSequenceRep[10000]]; -- should be large enough chain.firstRun ¬ NEW[RunRep]; chain.lastRun ¬ chain.firstRun; }; LengthenChain: PROC [chain: Chain] ~ { IF chain # NIL AND chain.pairs # NIL THEN { old: IntegerPairSequence ¬ chain.pairs; new: IntegerPairSequence ¬ NEW[IntegerPairSequenceRep[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]; chain.p0 ¬ chain.p1 ¬ 0; chain.firstRun ¬ chain.lastRun ¬ NIL; chain.pairs.length ¬ 0; IF repaint THEN RequestPaint[control, FALSE, NIL]; }; }; DeleteLastSketchStroke: PUBLIC PROC [control: Control, repaint: BOOL ¬ TRUE] ~ { IF control.type = sketch THEN { chain: Chain ¬ NARROW[control.sketchRef]; pairs: IntegerPairSequence ¬ chain.pairs; start: Run ¬ chain.firstRun; IF start = NIL THEN RETURN; IF start.next = NIL THEN { chain.p0 ¬ chain.p1 ¬ 0; chain.firstRun ¬ chain.lastRun ¬ NIL; chain.pairs.length ¬ 0; } ELSE FOR run: Run ¬ start, run.next DO IF run.next.next = NIL THEN { run.next ¬ NIL; chain.lastRun ¬ run; chain.pairs.length ¬ run.stop+1; EXIT; }; ENDLOOP; IF repaint THEN RequestPaint[control, FALSE, NIL]; }; }; <> AddIntegerPair: PROC [chain: Chain, pair: IntegerPair] ~ { pairs: IntegerPairSequence ¬ chain.pairs; IF pairs.length = pairs.maxLength THEN LengthenChain[chain]; pairs[pairs.length] ¬ pair; pairs.length ¬ pairs.length+1; }; NotifySketch: PUBLIC PROC [control: Control, mouse: Mouse] ~ { chain: Chain ¬ NARROW[control.sketchRef]; control.mouse ¬ 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; }; AddIntegerPair[chain, mouse.pos]; }; held => { IF (chain.p1 ¬ chain.pairs.length) # 0 THEN chain.p0 ¬ chain.p1-1; AddIntegerPair[chain, mouse.pos]; }; up => chain.lastRun.stop ¬ chain.p1; ENDCASE => RETURN; RequestPaint[control, FALSE, control]; IF mouse.state = up THEN ControlsPrivate.MaybeForkControlProc[control]; }; <> LineIntegerPair: PROC [context: Context, p0, p1: IntegerPair] ~ { Draw2d.Line[context, [p0.x, p0.y], [p1.x, p1.y]]; }; RequestPaint: PROC [control: Control, clearClient: BOOL, whatChanged: REF ANY] ~ { ViewerOps.PaintViewer[control.viewer, client, clearClient, whatChanged]; }; PaintSketch: PUBLIC ViewerClasses.PaintProc ~ { control: Control ¬ NARROW[self.data]; chain: Chain ¬ NARROW[control.sketchRef]; IF chain = NIL THEN RETURN; IF whatChanged = NIL THEN { Draw2d.Clear[context]; SketchReDraw[context, chain]; } ELSE { pairs: IntegerPairSequence ¬ chain.pairs; LineIntegerPair[context, pairs[chain.p0], pairs[chain.p1]]; }; }; SketchReDraw: PROC [context: Context, chain: Chain] ~ { pairs: IntegerPairSequence ¬ 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 LineIntegerPair[context, pairs[n], pairs[n+1]]; ENDLOOP; ENDLOOP; }; <> GetSketch: PUBLIC PROC [control: Control] RETURNS [sketch: IntegerPairSequences] ~ { nSketch: NAT ¬ 0; chain: Chain ¬ NARROW[control.sketchRef]; chainIntegerPairs: IntegerPairSequence ¬ chain.pairs; start: Run ¬ chain.firstRun; FOR run: Run ¬ start, run.next WHILE run # NIL DO nSketch ¬ nSketch+1; ENDLOOP; sketch ¬ NEW[IntegerPairSequencesRep[nSketch]]; FOR run: Run ¬ start, run.next WHILE run # NIL DO n: INTEGER ¬ 0; sketchIntegerPairs: IntegerPairSequence ¬ NEW[IntegerPairSequenceRep[run.stop-run.start+1]]; sketchIntegerPairs.length ¬ sketchIntegerPairs.maxLength; sketch[sketch.length] ¬ sketchIntegerPairs; sketch.length ¬ sketch.length+1; FOR r: NAT IN [run.start..run.stop] DO sketchIntegerPairs[n] ¬ chainIntegerPairs[r]; n ¬ n+1; ENDLOOP; ENDLOOP; }; SetSketch: PUBLIC PROC [control: Control, sketch: IntegerPairSequences, repaint: BOOL ¬ TRUE] ~ { run: Run ¬ NIL; iIntegerPair, nIntegerPairs: CARDINAL ¬ 0; chain: Chain ¬ NARROW[control.sketchRef]; FOR n: INT IN [0..sketch.length) DO nIntegerPairs ¬ nIntegerPairs+sketch[n].length; ENDLOOP; IF nIntegerPairs > chain.pairs.maxLength THEN chain.pairs ¬ NEW[IntegerPairSequenceRep[nIntegerPairs]]; FOR n: INT IN [0..sketch.length) DO pairs: IntegerPairSequence ¬ sketch[n]; FOR i: INT IN [0..pairs.length) DO chain.pairs[i+iIntegerPair] ¬ pairs[i]; ENDLOOP; IF run # NIL THEN {run.next ¬ NEW[RunRep]; run ¬ run.next} ELSE chain.firstRun ¬ run ¬ NEW[RunRep]; run.start ¬ iIntegerPair; iIntegerPair ¬ iIntegerPair+pairs.length; run.stop ¬ iIntegerPair-1; ENDLOOP; IF repaint THEN RequestPaint[control, 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]; }; }; NPointsInSketch: PUBLIC PROC [control: Control] RETURNS [INTEGER] ~ { IF control.sketchRef = NIL THEN RETURN[0] ELSE { chain: Chain ¬ NARROW[control.sketchRef]; nIntegerPairs: INTEGER ¬ 0; FOR run: Run ¬ chain.firstRun, run.next WHILE run # NIL DO nIntegerPairs ¬ nIntegerPairs+run.stop-run.start+1; ENDLOOP; RETURN[nIntegerPairs]; }; }; END.