<> <> <> <> <<>> DIRECTORY Cursors, Imager, ImagerTransformation, InputFocus, List, Pipal, PipalEdit, PipalMutate, PipalOps, PipalOverlayMutant, PipalPaint, PipalReal, Rope; PipalOverlayEditorImpl: CEDAR PROGRAM IMPORTS ImagerTransformation, InputFocus, List, Pipal, PipalEdit, PipalMutate, PipalOverlayMutant, PipalOps, PipalPaint, PipalReal, Rope = BEGIN <> OverlayMutant: TYPE = PipalOverlayMutant.OverlayMutant; overlayEditorClass: Pipal.Class _ Pipal.RegisterClass[name: "OverlayEditor", type: CODE [OverlayEditorRec]]; OverlayEditor: TYPE = REF OverlayEditorRec; OverlayEditorRec: TYPE = RECORD [ overlayMutant: OverlayMutant, mouseNow: PipalReal.Position _ PipalReal.zeroVector, -- mouse position now mouseDown: PipalReal.Position _ PipalReal.zeroVector, -- mouse position when a button went down previousTrackingArea: PipalPaint.Area _ Pipal.void, -- previous area modified by tracking; should be cleaned up at every paint if non nil! moving: BOOL _ FALSE ]; OverlayEditorSize: PipalReal.SizeProc ~ { oe: OverlayEditor = NARROW [object]; size _ PipalReal.ObjectSize[oe.overlayMutant]; }; OverlayEditorPaint: PipalPaint.PaintProc = { oe: OverlayEditor = NARROW [object]; PipalPaint.Paint[oe.overlayMutant, context]; }; EditOverlay: PipalEdit.EditProc = { om: OverlayMutant _ NARROW [mutant]; editor _ NEW [OverlayEditorRec _ [overlayMutant: om]]; PipalEdit.CreateBiscroller[editor, Rope.Cat[PipalOps.wDir, "PipalOverlayEditor.TIP"], Notify, TRUE]; }; <<>> Test: PROC [om: OverlayMutant] RETURNS [oe: OverlayEditor] = { oe _ NARROW [PipalEdit.Edit[om]]; }; TranslateArea: PROC [area: PipalPaint.Area, delta: PipalReal.Vector] RETURNS [new: PipalPaint.Area] = { new _ PipalReal.TransformObject[ImagerTransformation.Translate[delta], area]; }; Notify: PipalEdit.NotifyProc = { oe: OverlayEditor _ NARROW [editor]; om: OverlayMutant = oe.overlayMutant; atom: ATOM = NARROW [input.first]; result: REF; resultType: PipalMutate.ResultType; newMutant: Pipal.Object; newEditor _ oe; -- we return the same, i.e. we do not have immutability here! IF oe.previousTrackingArea#Pipal.void THEN { PipalPaint.Enqueue[queue, [type: clearAndPaint, area: oe.previousTrackingArea, data: oe.overlayMutant]]; oe.previousTrackingArea _ Pipal.void; }; SELECT atom FROM $MouseDown => { oe.mouseDown _ NARROW [input.rest.first, REF Imager.VEC]^; InputFocus.SetInputFocus[viewer]; }; $TrackSelected => { clipArea: PipalPaint.Area; outlines: Pipal.Object; IF NOT oe.moving THEN oe.mouseDown _ NARROW [input.rest.first, REF Imager.VEC]^; oe.mouseNow _ NARROW [input.rest.first, REF Imager.VEC]^; [resultType, result, newMutant] _ PipalMutate.ApplyCommand[om, $SelectedOutlines]; IF newMutant#om THEN ERROR; IF resultType#selectionArea THEN ERROR; outlines _ TranslateArea[result, PipalReal.Sub[oe.mouseNow, oe.mouseDown]]; clipArea _ PipalPaint.ChildArea[outlines, edgesChildren]; <<-- Paint the data structure>> PipalPaint.Enqueue[queue, [type: clearAndPaint, area: clipArea, data: oe.overlayMutant]]; PipalPaint.Enqueue[queue, [type: paintArea, area: clipArea, data: PipalPaint.CreatePaintAreaOutline[outlines]]]; oe.previousTrackingArea _ clipArea; }; $Scrolling => PipalEdit.EnqueueSetCursor[queue, move]; $Scroll => { cc: PipalReal.Position _ NARROW [input.rest.first, REF Imager.VEC]^; delta: Imager.Transformation = ImagerTransformation.Translate[[cc.x-oe.mouseDown.x, cc.y-oe.mouseDown.y]]; PipalPaint.Enqueue[queue, [type: scale, data: delta]]; PipalEdit.EnqueueSetCursor[queue, textPointer]; }; ENDCASE => { arguments: LIST OF REF _ NIL; FOR list: LIST OF REF _ input.rest, list.rest WHILE list#NIL DO WITH list.first SELECT FROM cc: REF Imager.VEC => { oe.mouseNow _ cc^; arguments _ CONS [cc, arguments]; }; atom: ATOM => SELECT atom FROM $DownCoords => arguments _ CONS [NEW [PipalReal.Size _ oe.mouseDown], arguments]; ENDCASE => arguments _ CONS [atom, arguments]; ENDCASE => arguments _ CONS [atom, arguments]; ENDLOOP; [resultType, result, newMutant] _ PipalMutate.ApplyCommand[om, atom, List.Reverse[arguments]]; oe.overlayMutant _ NARROW [newMutant]; -- forgetting immutability ... SELECT resultType FROM none => PipalPaint.Enqueue[queue, [type: clearAndPaint, area: PipalPaint.fullArea, data: newMutant]]; changedArea => PipalPaint.Enqueue[queue, [type: clearAndPaint, area: result, data: newMutant]]; ENDCASE => ERROR; -- including object }; oe.moving _ atom=$TrackSelected; }; <> PushCommand: PipalMutate.CommandProc = { mutants: LIST OF Pipal.Object; [mutants, new] _ PipalOverlayMutant.Push[NARROW [mutant]]; WHILE mutants#NIL DO <<[] _ Test[mutants.first, Rope.Cat[PipalOps.wDir, "PipalOverlayEditor.TIP"]]; -- AAAARRRGH>> mutants _ mutants.rest; ENDLOOP; }; PopCommand: PipalMutate.CommandProc = { <> <> <> }; <> PassOverlayMutantCommand: PipalMutate.CommandProc ~ { oe: OverlayEditor = NARROW [mutant]; newOM: Pipal.Object; newOE: OverlayEditor; [resultType, result, newOM] _ PipalMutate.ApplyCommand[oe.overlayMutant, name, arguments, issuer]; newOE _ NEW [OverlayEditorRec _ oe^]; newOE.overlayMutant _ NARROW [newOM]; new _ newOE; }; <> PipalMutate.RegisterCommand[PipalOverlayMutant.overlayMutantClass, $Push, PushCommand]; PipalMutate.RegisterCommand[PipalOverlayMutant.overlayMutantClass, $Pop, PopCommand]; PipalMutate.RegisterCommand[overlayEditorClass, $Reset, PassOverlayMutantCommand]; PipalMutate.RegisterCommand[overlayEditorClass, $Undo, PassOverlayMutantCommand]; PipalMutate.RegisterCommand[overlayEditorClass, $Redo, PassOverlayMutantCommand]; PipalMutate.RegisterCommand[overlayEditorClass, $Flush, PassOverlayMutantCommand]; Pipal.PutClassMethod[overlayEditorClass, PipalReal.sizeMethod, NEW [PipalReal.SizeProc _ OverlayEditorSize]]; Pipal.PutClassMethod[overlayEditorClass, PipalPaint.paintMethod, NEW [PipalPaint.PaintProc _ OverlayEditorPaint]]; Pipal.PutClassMethod[PipalOverlayMutant.overlayMutantClass, PipalEdit.editMethod, NEW [PipalEdit.EditProc _ EditOverlay]]; END. ToBits: PROC [lines: ARRAY [0..16) OF Rope.ROPE] RETURNS [bits: Cursors.CursorArray] ~ { FOR line: NAT IN [0..16) DO bits[line] _ 0; FOR i: NAT IN [0..16) DO bits[line] _ 2*bits[line]; IF Rope.Equal[lines[line][i], "X"] THEN bits[line] _ bits[line]+1 ENDLOOP; ENDLOOP; }; HandCursor: PROC RETURNS [Cursors.CursorType] ~ { dots: ARRAY [0..16) Rope.ROPE; dots[0] = "................"; dots[1] = "................"; dots[2] = "................"; dots[3] = "................"; dots[4] = "................"; dots[5] = "................"; dots[6] = "................"; dots[7] = "................"; dots[8] = "................"; dots[9] = "................"; dots[10] = "................"; dots[11] = "................"; dots[12] = "................"; dots[13] = "................"; dots[14] = "................"; dots[15] = "................"; RETURN [Cursors.NewCursor[ToBits[dots]]]; }; invertingGray: Imager.Color _ ImagerBackdoor.MakeStipple[5A5AH, TRUE]; -- XOR ??? PaintSelected: PROC [context: Imager.Context, object: Pipal.Object, base: PipalReal.Vector, color: Imager.Color _ invertingGray] ~ { size: PipalReal.Vector _ PipalReal.ObjectSize[object]; Imager.SetColor[context, color]; Imager.MaskRectangle[context, [base.x, base.y, size.x, size.y]]; };