ControlsSketchmpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 2, 1992 6:20 pm PDT
DIRECTORY Controls, ControlsPrivate, Draw2d, Imager, ViewerClasses, ViewerOps;
ControlsSketchImpl: CEDAR PROGRAM
IMPORTS ControlsPrivate, Draw2d, Imager, ViewerOps
EXPORTS Controls, ControlsPrivate
~ BEGIN
Types
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;
Sketch Type Definitions
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
];
Sketch Initialization/Clearing
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];
};
};
Sketch Notification
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];
};
Sketch Painting
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;
};
Sketch Processing
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.