PipalOverlayMutantImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Barth, January 28, 1988 6:21:44 pm PST
Bertrand Serlet March 10, 1988 1:34:37 pm PST
Louis Monier February 2, 1988 3:37:24 pm PST
DIRECTORY Imager, ImagerTransformation, IO, List, Pipal, PipalInt, PipalMutate, PipalOps, PipalOverlayMutant, PipalPaint, PipalReal, Real, RefTab, TerminalIO;
PipalOverlayMutantImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerTransformation, IO, List, Pipal, PipalMutate, PipalInt, PipalOps, PipalPaint, PipalReal, Real, RefTab, TerminalIO
EXPORTS PipalOverlayMutant =
BEGIN OPEN PipalOverlayMutant;
Class
overlayMutantClass: PUBLIC Pipal.Class ← Pipal.RegisterClass["OverlayMutant", CODE [OverlayMutantRec]];
Do: PROC [old: OverlayMutant, message: Pipal.ROPE, overlay: Pipal.Overlay, selected: Pipal.Objects] RETURNS [new: OverlayMutant] = {
new ← NEW [OverlayMutantRec ← [
overlay: overlay,
selected: selected,
undoRedo: PipalOps.Do[old.undoRedo, message, old]
]];
};
ReplaceOverlayMutant: PipalOps.ReplaceProc = {
om: OverlayMutant ← NARROW [parent];
selected: Pipal.Objects ← NIL;
FOR objects: Pipal.Objects ← om.selected, objects.rest UNTIL objects=NIL DO
selected ← CONS [map[objects.first], selected];
ENDLOOP;
newParent ← Do[om, "Replace", NARROW [map[om.overlay]], selected];
};
EnumerateOverlayMutant: PipalOps.EnumerateProc = {
om: OverlayMutant = NARROW [object];
IF each[om.overlay] THEN RETURN [TRUE];
FOR objects: Pipal.Objects ← om.selected, objects.rest UNTIL objects=NIL DO
IF each[objects.first] THEN RETURN [TRUE];
ENDLOOP;
};
OverlayMutantSize: PipalReal.SizeProc = {
om: OverlayMutant = NARROW [object];
size ← PipalReal.ObjectSize[om.overlay];
};
PaintOverlayMutant: PipalPaint.PaintProc = {
transformation: PipalReal.Transformation ← PipalReal.CreateTransformation[]; -- changed the day PaintProcs have a transformation
om: OverlayMutant = NARROW [object];
PipalPaint.Paint[om.overlay, context];
FOR objects: Pipal.Objects ← om.selected, objects.rest UNTIL objects=NIL DO
draw a box around the abut box of each item
PipalPaint.PaintOutline[context, PipalReal.BBox[objects.first, transformation]];
ENDLOOP;
PipalReal.DestroyTransformation[transformation];
};
Basic Operations
Create: PUBLIC PROC [overlay: Pipal.Overlay] RETURNS [om: OverlayMutant] = {
om ← NEW [OverlayMutantRec ← [overlay: overlay]];
};
Object Manipulation
OverlayFromSelection: PROC [om: OverlayMutant] RETURNS [changedArea: PipalPaint.Area, newOm: OverlayMutant] ~ {
newOv: Pipal.Object;
children, selected, changed: Pipal.Objects ← NIL;
new: Pipal.Objects ← NIL;
translation: PipalInt.Vector;
[children, selected, changed] ← SplitThem[om];
translation ← ChildrenBBox[selected].base;
new ← TransformObjects[[PipalInt.Neg[translation]], selected];
newOv ← PipalInt.TransformObject[[translation], Pipal.CreateOverlay[new]];
changed ← CONS [PipalPaint.ChildArea[newOv, bboxChild], changed];
children ← CONS [newOv, children];
newOm ← Do[om, IO.PutFR["overlay "], Pipal.CreateOverlay[children], LIST [newOv]];
changedArea ← Pipal.CreateOverlay[changed];
};
FlattenSelected: PROC [mutant: OverlayMutant] RETURNS [changedArea: PipalPaint.Area] ~ {
-- for every selected object
check if there is an enumerate proc
enumerate the guts of selection and replace by children, properly transformed
};
InsertInt: PUBLIC PROC [om: OverlayMutant, child: Pipal.Object, position: PipalInt.Position, selectNew: BOOLTRUE] RETURNS [new: OverlayMutant] = {
new ← Insert[om, IO.int[position.x], IO.int[position.y], PipalInt.TransformObject[[translation: position], child], selectNew];
};
InsertReal: PUBLIC PROC [om: OverlayMutant, child: Pipal.Object, position: PipalReal.Position, selectNew: BOOLTRUE] RETURNS [new: OverlayMutant] = {
transformation: PipalReal.Transformation ← ImagerTransformation.Translate[position];
new ← Insert[om, IO.real[position.x], IO.real[position.y], PipalReal.TransformObject[transformation, child], selectNew];
};
Insert: PROC [om: OverlayMutant, x, y: IO.Value, child: Pipal.Object, selectNew: BOOL] RETURNS [new: OverlayMutant] = {
children: Pipal.Objects ← Pipal.ExpandOverlay[om.overlay];
children ← CONS [child, children];
new ← Do[om, IO.PutFR["insert of %g at [%g, %g]", IO.rope[Pipal.DescribeToRope[child, 0, 1]], x, y], Pipal.CreateOverlay[children], IF selectNew THEN LIST [child] ELSE om.selected];
};
Delete: PUBLIC PROC [om: OverlayMutant] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] = {
children: Pipal.Objects ← NIL;
changed: Pipal.Objects ← NIL;
[children, , changed] ← SplitThem[om];
new ← Do[om, IO.PutFR["delete "], Pipal.CreateOverlay[children], NIL];
changedArea ← Pipal.CreateOverlay[changed];
};
Copy
CopyInt: PROC [om: OverlayMutant, vector: PipalInt.Vector, selectNew: BOOLTRUE] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] = {
changed: Pipal.Objects ← NIL;
children: Pipal.Objects ← Pipal.ExpandOverlay[om.overlay];
selected: Pipal.Objects ← NIL;
transformation: PipalInt.Transformation = [translation: vector];
FOR i: NAT IN [0 .. om.overlay.size) DO
child: Pipal.Object ← om.overlay[i];
IF Pipal.Member[om.selected, child] THEN {
new: Pipal.Object ← PipalInt.TransformObject[transformation, child];
children ← CONS [new, children];
selected ← CONS [new, selected];
changed ← CONS [PipalPaint.ChildArea[child, bboxChild], changed];
changed ← CONS [PipalPaint.ChildArea[new, bboxChild], changed];
};
ENDLOOP;
new ← Do[om, IO.PutFR["copy translated by [%g, %g]", IO.int[vector.x], IO.int[vector.y]], Pipal.CreateOverlay[children], IF selectNew THEN selected ELSE om.selected];
changedArea ← Pipal.CreateOverlay[changed];
};
Move
MoveInt: PROC [om: OverlayMutant, transformation: PipalInt.Transformation] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] ~ {
changed: Pipal.Objects ← NIL;
children: Pipal.Objects ← NIL;
selected: Pipal.Objects ← NIL;
FOR i: NAT IN [0 .. om.overlay.size) DO
child: Pipal.Object ← om.overlay[i];
IF Pipal.Member[om.selected, child] THEN {
new: Pipal.Object ← PipalInt.TransformObject[transformation, child];
children ← CONS [new, children];
selected ← CONS [new, selected];
changed ← CONS [PipalPaint.ChildArea[child, bboxChild], changed];
changed ← CONS [PipalPaint.ChildArea[new, bboxChild], changed];
} ELSE children ← CONS [child, children];
ENDLOOP;
new ← Do[om, IO.PutFR["move by %g", IO.rope[PipalInt.TransformationToRope[transformation]]], Pipal.CreateOverlay[children], selected];
changedArea ← Pipal.CreateOverlay[changed];
};
MoveReal: PROC [om: OverlayMutant, transformation: PipalReal.Transformation] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] ~ {
changed: Pipal.Objects ← NIL;
children: Pipal.Objects ← NIL;
selected: Pipal.Objects ← NIL;
FOR i: NAT IN [0 .. om.overlay.size) DO
child: Pipal.Object ← om.overlay[i];
IF Pipal.Member[om.selected, child] THEN {
new: Pipal.Object ← PipalReal.TransformObject[transformation, child];
children ← CONS [new, children];
selected ← CONS [new, selected];
changed ← CONS [PipalPaint.ChildArea[child, bboxChild], changed];
changed ← CONS [PipalPaint.ChildArea[new, bboxChild], changed];
} ELSE children ← CONS [child, children];
ENDLOOP;
new ← Do[om, IO.PutFR["move by %g", IO.rope[PipalReal.TransformationToRope[transformation]]], Pipal.CreateOverlay[children], selected];
changedArea ← Pipal.CreateOverlay[changed];
};
Selection
Select: PUBLIC PROC [om: OverlayMutant, exclusive: BOOLTRUE, remove: BOOLFALSE, style: ATOM, pos1: PipalReal.Position, pos2: PipalReal.Position] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] = {
AddOrRemove: PROC [child: Pipal.Object] = {
(IF remove THEN Remove ELSE Add)[child];
};
Remove: PROC [child: Pipal.Object] = {
selected ← Pipal.Delete[selected, child];
changed ← CONS [PipalPaint.ChildArea[child, edgesChild], changed];
};
Add: PROC [child: Pipal.Object] = {
selected ← Pipal.Add[selected, child];
changed ← CONS [PipalPaint.ChildArea[child, edgesChild], changed];
};
changed: Pipal.Objects ← NIL;
selected: Pipal.Objects ← om.selected;
rect: PipalReal.Rectangle ← PipalReal.BoundingRectangle[pos1, pos2];
transformation: PipalReal.Transformation ← PipalReal.CreateTransformation[];
IF exclusive THEN WHILE selected#NIL DO Remove[selected.first] ENDLOOP;
SELECT style FROM
$Point => FOR i: NAT IN [0 .. om.overlay.size) DO
IF ~PipalReal.IsInsidePoint[PipalReal.BBox[om.overlay[i], transformation], rect.base] THEN LOOP;
AddOrRemove[om.overlay[i]];
TerminalIO.PutF["Selected: %g.\n", IO.rope[Pipal.DescribeToRope[om.overlay[i], 0, 1]]];
EXIT;
ENDLOOP;
$Area => {
count: INT ← 0;
FOR i: NAT IN [0 .. om.overlay.size) DO
IF ~PipalReal.IsInsideRectangle[rect, PipalReal.BBox[om.overlay[i], transformation]] THEN LOOP;
AddOrRemove[om.overlay[i]];
count ← count+1;
ENDLOOP;
TerminalIO.PutF["%g objects (de)selected in area.\n", IO.int[count]];
};
$Touch => {
count: INT ← 0;
FOR i: NAT IN [0 .. om.overlay.size) DO
IF ~PipalReal.DoRectanglesIntersect[PipalReal.BBox[om.overlay[i], transformation], rect] THEN LOOP;
AddOrRemove[om.overlay[i]];
count ← count+1;
ENDLOOP;
TerminalIO.PutF["%g objects touch-(de)selected.\n", IO.int[count]];
};
$Close => ERROR;
ENDCASE => ERROR;
PipalReal.DestroyTransformation[transformation];
new ← Do[om, "Select", om.overlay, selected];
changedArea ← Pipal.CreateOverlay[changed];
};
Transformations
TransformInt: PROC [om: OverlayMutant, transformation: PipalInt.Transformation] RETURNS [changedArea: PipalPaint.Area, new: OverlayMutant] = {
children, selected, changed: Pipal.Objects ← NIL;
translation, fudgeFactor: PipalInt.Vector;
[children, selected, changed] ← SplitThem[om];
translation ← ChildrenBBox[selected].base;
selected ← TransformObjects[[PipalInt.Neg[translation]], selected];
selected ← TransformObjects[transformation, selected];
fudgeFactor ← ChildrenBBox[selected].base;
selected ← TransformObjects[[PipalInt.Neg[fudgeFactor]], selected];
selected ← TransformObjects[[translation], selected];
children ← List.Append[children, selected];
changed ← List.Append[changed, ChildrenAreaAnnotation[selected]];
new ← Do[om, IO.PutFR["transform by %g", IO.rope[PipalInt.TransformationToRope[transformation]]], Pipal.CreateOverlay[children], selected];
changedArea ← Pipal.CreateOverlay[changed];
};
Utilities
SplitThem: PROC [om: OverlayMutant] RETURNS [unselected, selected, changed: Pipal.Objects ← NIL] ~ {
FOR i: NAT IN [0 .. om.overlay.size) DO
child: Pipal.Object ← om.overlay[i];
IF ~Pipal.Member[om.selected, child] THEN unselected ← CONS [child, unselected]
ELSE {
selected ← CONS [child, selected];
changed ← CONS [PipalPaint.ChildArea[child, bboxChild], changed];
};
ENDLOOP;
};
SingleSelection: PROC [om: OverlayMutant] RETURNS [selected: Pipal.Object ← NIL] = {
SELECT TRUE FROM
om.selected=NIL => ERROR Pipal.Error[$noSelection];
om.selected.rest#NIL => ERROR Pipal.Error[$multipleSelections];
ENDCASE => selected ← om.selected.first;
};
TransformObjects: PROC [transformation: PipalInt.Transformation, children: Pipal.Objects] RETURNS [new: Pipal.Objects ← NIL] = {
FOR list: Pipal.Objects ← children, list.rest WHILE list#NIL DO
new ← CONS [PipalInt.TransformObject[transformation, list.first], new];
ENDLOOP;
};
ChildrenBBox: PROC [children: Pipal.Objects] RETURNS [bbox: PipalInt.Rectangle ← PipalInt.emptyRectangle] = {
FOR list: Pipal.Objects ← children, list.rest WHILE list#NIL DO
bbox ← PipalInt.BoundingBox[bbox, PipalInt.BBox[list.first, []]];
ENDLOOP;
};
ChildrenAreaAnnotation: PROC [children: Pipal.Objects] RETURNS [changed: Pipal.Objects ← NIL] = {
FOR list: Pipal.Objects ← children, list.rest WHILE list#NIL DO
changed ← CONS [PipalPaint.ChildArea[list.first, bboxChild], changed];
ENDLOOP;
};
MutateOverlay: PipalMutate.MutationProc = {
overlay: Pipal.Overlay ← NARROW [object];
mutant ← Create[overlay];
};
Commands
CopyIntCommand: PipalMutate.CommandProc = {
om: OverlayMutant = NARROW [mutant];
start: PipalReal.Position ← NARROW [arguments.first, REF PipalReal.Position]^;
end: PipalReal.Position ← NARROW [arguments.rest.first, REF PipalReal.Position]^;
realDelta: PipalReal.Vector = PipalReal.Sub[end, start];
delta: PipalInt.Vector = [Real.Round[realDelta.x], Real.Round[realDelta.y]];
resultType ← changedArea;
[result, new] ← CopyInt[om, [delta.x, delta.y]];
};
MoveIntCommand: PipalMutate.CommandProc = {
om: OverlayMutant = NARROW [mutant];
start: PipalReal.Position ← NARROW [arguments.first, REF PipalReal.Position]^;
end: PipalReal.Position ← NARROW [arguments.rest.first, REF PipalReal.Position]^;
realDelta: PipalReal.Vector = PipalReal.Sub[end, start];
delta: PipalInt.Vector = [Real.Round[realDelta.x], Real.Round[realDelta.y]];
resultType ← changedArea;
[result, new] ← MoveInt[om, [delta]];
};
MoveRealCommand: PipalMutate.CommandProc = {
om: OverlayMutant = NARROW [mutant];
start: PipalReal.Position ← NARROW [arguments.first, REF PipalReal.Position]^;
end: PipalReal.Position ← NARROW [arguments.rest.first, REF PipalReal.Position]^;
delta: PipalReal.Vector = PipalReal.Sub[end, start];
resultType ← changedArea;
[result, new] ← MoveReal[om, ImagerTransformation.Translate[delta]];
};
SelectCommand: PipalMutate.CommandProc = {
om: OverlayMutant = NARROW [mutant];
exclusive, remove: BOOL;
style: ATOM;
pos1, pos2: PipalReal.Position;
first argument tells if we should get rid of existing selection
SELECT arguments.first FROM
$Add => exclusive ← FALSE;
$Exclusive => exclusive ← TRUE;
ENDCASE => ERROR;
arguments ← arguments.rest;
second argument tells if we select/deselect
SELECT arguments.first FROM
$Select => remove ← FALSE;
$Deselect => remove ← TRUE;
ENDCASE => ERROR;
arguments ← arguments.rest;
third argument tells the style
SELECT arguments.first FROM
$Point, $Area, $Touch, $Close => style ← NARROW [arguments.first];
ENDCASE => ERROR;
arguments ← arguments.rest;
fourth argument is pos1
pos1 ← NARROW [arguments.first, REF PipalReal.Position]^;
arguments ← arguments.rest;
fifth argument may be pos2
pos2 ← IF arguments#NIL THEN NARROW [arguments.first, REF PipalReal.Size]^ ELSE pos1;
IF style=$Area AND pos1=pos2 THEN style ← $Point;
resultType ← changedArea;
[result, new] ← Select[om, exclusive, remove, style, pos1, pos2];
};
SelectedOutlinesCommand: PipalMutate.CommandProc = {
om: OverlayMutant = NARROW [mutant];
changed: Pipal.Objects ← NIL;
changed ← ChildrenAreaAnnotation[om.selected];
resultType ← selectionArea;
new ← mutant;
result ← Pipal.CreateOverlay[changed];
};
DeleteSelectCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
resultType ← changedArea;
[result, new] ← Delete[om];
};
MakeOverlayCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
resultType ← changedArea;
[result, new] ← OverlayFromSelection[om];
};
TransformSelectCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
transformation: PipalInt.Transformation ← SELECT arguments.first FROM
$Rot90 => [ , rotate90],
$Rot270 => [ , rotate270],
$FlipX => [ , mirrorX],
$FlipY => [ , rotate180X],
ENDCASE => ERROR;
resultType ← changedArea;
[result, new] ← TransformInt[om, transformation];
};
FlattenCommand: PipalMutate.CommandProc ~ {
resultType ← changedArea;
[result, new] ← FlattenSelected[mutant];
};
Undo/Redo Commands
DoUndoRedo: PROC [old: OverlayMutant, message: Pipal.ROPE, op: PipalOps.UndoRedoOp] RETURNS [new: OverlayMutant] = {
newUndoRedo: PipalOps.UndoRedo;
newState: REF;
newOM: OverlayMutant;
[newUndoRedo, newState] ← op[old.undoRedo, old];
newOM ← NARROW [newState];
new ← NEW [OverlayMutantRec ← [
overlay: newOM.overlay,
selected: newOM.selected,
undoRedo: newUndoRedo
]];
};
ResetCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
new ← DoUndoRedo[om, "Reset", PipalOps.Reset];
};
UndoCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
IF om.undoRedo.undo=NIL
THEN {TerminalIO.PutF["*** Cant Undo!\n"]; RETURN [changedArea, Pipal.void, om]};
new ← DoUndoRedo[om, "Undo", PipalOps.Undo];
};
RedoCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
IF om.undoRedo.redo=NIL
THEN {TerminalIO.PutF["*** Cant Redo!\n"]; RETURN [changedArea, Pipal.void, om]};
new ← DoUndoRedo[om, "Redo", PipalOps.Redo];
};
FlushCommand: PipalMutate.CommandProc ~ {
om: OverlayMutant = NARROW [mutant];
new ← NEW [OverlayMutantRec ← [
overlay: om.overlay,
selected: om.selected,
undoRedo: []
]];
RETURN [changedArea, Pipal.void, new];
};
Push
PopData: TYPE = REF PopDataRec;
PopDataRec: TYPE = RECORD [om: OverlayMutant, editable: Pipal.Object, selected: Pipal.Object, path: PipalMutate.Path, newMutant: Pipal.Object];
OverlayPopWatchDog: PipalOps.WatchDog = {
pd: PopData ← NARROW [registrationData];
newMutant: Pipal.Object ← NARROW [arg1];
new: Pipal.Object ← NARROW [arg2];
table: PipalOps.ReplaceTable ← RefTab.Create[];
IF newMutant#pd.newMutant THEN RETURN; -- irrelevant pop!
IF TerminalIO.Confirm["Global Replace"]
THEN {[] ← RefTab.Store[table, pd.editable, new]; PipalOps.BroadcastReplace[table]}
ELSE {
om: OverlayMutant = pd.om;
newSelected: Pipal.Object;
table ← PipalMutate.ReplaceInPath[pd.selected, pd.path, pd.editable, new];
newSelected ← RefTab.Fetch[table, pd.selected].val;
table ← RefTab.Create[];
[] ← RefTab.Store[table, pd.selected, newSelected];
PipalOps.TransitiveReplace[om.overlay, table];
PipalMutate.Do[om, IO.PutFR["Pop new: %g replaced by %g", IO.rope[Pipal.DescribeToRope[pd.editable, 0, 1]], IO.rope[Pipal.DescribeToRope[new, 0, 1]]], RefTab.Fetch[table, om.overlay].val, CreateOverlayMutant[]];
};
};
RegisterPopWatchDog: PROC [pdr: PopDataRec] = {
PipalOps.RegisterWatchDog[PipalMutate.popEvent, OverlayPopWatchDog, NEW [PopDataRec ← pdr]];
};
Push: PUBLIC PROC [om: OverlayMutant] RETURNS [mutants: Pipal.Objects ← NIL, new: OverlayMutant] = {
count: NAT ← 0;
FOR selected: Pipal.Objects ← om.selected, selected.rest UNTIL selected=NIL DO
EachEditableChild: PipalMutate.EachChildProc = {
newMutant: Pipal.Object ← PipalMutate.Mutation[child];
mutants ← CONS [newMutant, mutants];
count ← count + 1;
RegisterPopWatchDog[[om, child, root, path, newMutant]];
};
root: Pipal.Object = selected.first;
[] ← PipalMutate.EnumerateMutantChildren[root, EachEditableChild];
ENDLOOP;
new ← Do[om, IO.PutFR["Pushing in %g objects", IO.int[count]], om.overlay, om.selected];
};
Initialization
PipalMutate.RegisterCommand[overlayMutantClass, $Select, SelectCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $SelectedOutlines, SelectedOutlinesCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $MoveInt, MoveIntCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $MoveReal, MoveRealCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $CopyInt, CopyIntCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $DeleteSelect, DeleteSelectCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $MakeOverlay, MakeOverlayCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $TransformSelect, TransformSelectCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $Flatten, FlattenCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $Reset, ResetCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $Undo, UndoCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $Redo, RedoCommand];
PipalMutate.RegisterCommand[overlayMutantClass, $Flush, FlushCommand];
Pipal.PutClassMethod[overlayMutantClass, PipalOps.replaceMethod, NEW [PipalOps.ReplaceProc ← ReplaceOverlayMutant]];
Pipal.PutClassMethod[overlayMutantClass, PipalOps.enumerateMethod, NEW [PipalOps.EnumerateProc ← EnumerateOverlayMutant]];
Pipal.PutClassMethod[overlayMutantClass, PipalReal.sizeMethod, NEW [PipalReal.SizeProc ← OverlayMutantSize]];
Pipal.PutClassMethod[overlayMutantClass, PipalPaint.paintMethod, NEW [PipalPaint.PaintProc ← PaintOverlayMutant]];
Pipal.PutClassMethod[Pipal.overlayClass, PipalMutate.mutationMethod, NEW [PipalMutate.MutationProc ← MutateOverlay]];
END.