<> <> <> <> <> <<>> 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; <> 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 <> PipalPaint.PaintOutline[context, PipalReal.BBox[objects.first, transformation]]; ENDLOOP; PipalReal.DestroyTransformation[transformation]; }; <> Create: PUBLIC PROC [overlay: Pipal.Overlay] RETURNS [om: OverlayMutant] = { om _ NEW [OverlayMutantRec _ [overlay: overlay]]; }; <> 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]; }; <> <<-- for every selected object>> <> <> <<};>> <<>> InsertInt: PUBLIC PROC [om: OverlayMutant, child: Pipal.Object, position: PipalInt.Position, selectNew: BOOL _ TRUE] 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: BOOL _ TRUE] 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]; }; <> CopyInt: PROC [om: OverlayMutant, vector: PipalInt.Vector, selectNew: BOOL _ TRUE] 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]; }; <> 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]; }; <> Select: PUBLIC PROC [om: OverlayMutant, exclusive: BOOL _ TRUE, remove: BOOL _ FALSE, 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]; }; <> 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]; }; <> 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]; }; <<>> <> 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; <> SELECT arguments.first FROM $Add => exclusive _ FALSE; $Exclusive => exclusive _ TRUE; ENDCASE => ERROR; arguments _ arguments.rest; <> SELECT arguments.first FROM $Select => remove _ FALSE; $Deselect => remove _ TRUE; ENDCASE => ERROR; arguments _ arguments.rest; <> SELECT arguments.first FROM $Point, $Area, $Touch, $Close => style _ NARROW [arguments.first]; ENDCASE => ERROR; arguments _ arguments.rest; <> pos1 _ NARROW [arguments.first, REF PipalReal.Position]^; arguments _ arguments.rest; <> 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]; }; <> <> <<[result, new] _ FlattenSelected[mutant];>> <<};>> <> 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]; }; <> PopData: TYPE = REF PopDataRec; PopDataRec: TYPE = RECORD [om: OverlayMutant, editable: Pipal.Object, selected: Pipal.Object, path: PipalOps.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 _ PipalOps.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]; <> }; }; 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]; }; <> 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, $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.