ControlsSketchmpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, October 8, 1986 9:55:22 pm PDT
DIRECTORY Controls, ControlsPrivate, Draw2d, Imager, ViewerClasses, ViewerOps;
ControlsSketchImpl: CEDAR PROGRAM
IMPORTS ControlsPrivate, Draw2d, Imager, ViewerOps
EXPORTS Controls, ControlsPrivate
~ BEGIN
OPEN Controls;
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:       PosSequence ← 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[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: BOOLTRUE] ~ {
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];
};
};
Sketch Notification
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];
};
Sketch Painting
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;
};
Sketch Processing
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: BOOLTRUE] ~ {
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.