<> <> <> <> <<>> DIRECTORY BasicTime, BiScrollers, Cursors, Geom2D, Imager, ImagerTransformation, InputFocus, IO, Menus, Pipal, PipalEditor, PipalMutate, PipalPaint, PipalReal, Process, Real, RefTab, TerminalIO, TIPUser, ViewerClasses, ViewerOps; PipalEditorImpl: CEDAR PROGRAM IMPORTS BasicTime, BiScrollers, Cursors, Geom2D, Imager, ImagerTransformation, InputFocus, IO, Menus, Pipal, PipalPaint, PipalReal, Process, TerminalIO, TIPUser, ViewerOps EXPORTS PipalEditor = BEGIN OPEN PipalEditor; <> lastViewerPaintTime: BasicTime.Pulses; <> CreateViewer: PUBLIC PROC [object: Pipal.Object] RETURNS [viewer: ViewerClasses.Viewer] ~ { viewer _ ViewerOps.CreateViewer[$Pipal, [name: "PipalViewer", data: object]]; }; ViewerPaint: ViewerClasses.PaintProc = { object: Pipal.Object = self.data; lastViewerPaintTime _ BasicTime.GetClockPulses[]; PipalPaint.Paint[object, context]; lastViewerPaintTime _ BasicTime.GetClockPulses[]-lastViewerPaintTime; }; viewerClass: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [paint: ViewerPaint]]; <> ViewerData : TYPE = REF ViewerDataRec; -- what gets hung unto the viewer ViewerDataRec: TYPE = RECORD [ mutant: Pipal.Object, view: View, notify: NotifyProc]; lastBiscrollerPaintTime: BasicTime.Pulses; <> <<>> MakeMenu: PROC [viewerData: ViewerData] RETURNS [menu: Menus.Menu] = { menu _ Menus.CreateMenu[2]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Reset", proc: ResetClick, clientData: viewerData, fork: FALSE, guarded: TRUE]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Undo", proc: UndoClick, clientData: viewerData, fork: FALSE]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Redo", proc: RedoClick, clientData: viewerData, fork: FALSE]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Flush", proc: FlushClick, clientData: viewerData, fork: FALSE]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Debug", proc: DebugClick, clientData: viewerData, fork: TRUE], 1]; }; CreateBiscroller: PUBLIC PROC [mutant: Pipal.Object, tipTable: Pipal.ROPE, notify: NotifyProc, state: REF _ NIL, buttons: BOOL _ FALSE] RETURNS [view: View] = { viewerData: ViewerData _ NEW [ViewerDataRec _ [mutant: mutant, view: NIL, notify: notify]]; style: BiScrollers.BiScrollerStyle _ BiScrollers.GetStyle["Buttonned"]; -- Buttonless class: BiScrollers.BiScrollerClass _ style.NewBiScrollerClass[[ flavor: $PipalBiscroller, -- Note: it has better not be the same as for creating a simple viewer ... [BS] extrema: Extrema, paint: Paint, notify: Notify, bsUserAction: ForkAndDo, finish: LIST [$Exit], menu: IF buttons THEN BiScrollers.CatenateMenus[BiScrollers.bsMenu, MakeMenu[viewerData]] ELSE BiScrollers.bsMenu, icon: fileCabinet, tipTable: TIPUser.InstantiateNewTIPTable[tipTable], cursor: textPointer, -- was bullseye mayStretch: FALSE, offsetsMustBeIntegers: TRUE, preferIntegerCoefficients: FALSE ]]; view _ NEW [ViewRec _ [state: state]]; viewerData.view _ view; [] _ class.style.CreateBiScroller[class: class, info: [ name: Pipal.ClassName[Pipal.ObjectClass[mutant]], iconic: TRUE, data: viewerData ]]; }; Extrema: BiScrollers.ExtremaProc = { viewerData: ViewerData _ NARROW[clientData]; size: PipalReal.Size _ PipalReal.ObjectSize[viewerData.mutant]; [min, max] _ Geom2D.ExtremaOfRect[[0, 0, size.x, size.y], direction]; }; WhatChanged: TYPE = REF WhatChangedRec; WhatChangedRec: TYPE = RECORD [ clipArea: Pipal.Object, -- redisplay the data structure inside these areas outlines: Pipal.Object -- then paint these outlines ]; <> Paint: ViewerClasses.PaintProc = { bs: BiScrollers.BiScroller _ BiScrollers.QuaBiScroller[self]; viewerData: ViewerData _ NARROW [BiScrollers.ClientDataOfViewer[self]]; mutant: Pipal.Object = viewerData.mutant; lastBiscrollerPaintTime _ BasicTime.GetClockPulses[]; <> Imager.SetColor[context, Imager.black]; Imager.MaskVector[context, [-1000, 0], [1000, 0]]; Imager.MaskVector[context, [0, -1000], [0, 1000]]; <> IF whatChanged=NIL THEN PipalPaint.Paint[mutant, context] ELSE { request: OutputRequest = NARROW [whatChanged, REF OutputRequest]^; SELECT request.type FROM clearAndRepaintArea => PipalPaint.ClipAndPaint[mutant, context, request.data]; paintOutline => PipalPaint.PaintAreaOutline[context, request.data]; ENDCASE => TRUSTED {Process.Detach[FORK TerminalIO.PutF["*** PipalEditorImpl: Unknown request: %g!\n", IO.int[ORD [request.type]]]]}; }; lastBiscrollerPaintTime _ BasicTime.GetClockPulses[]-lastBiscrollerPaintTime; }; ForkAndDo: BiScrollers.BSUserActionProc ~ TRUSTED {Process.Detach[FORK BiScrollers.DoBSUserAction[bs, input]]}; Notify: ViewerClasses.NotifyProc = { bs: BiScrollers.BiScroller _ BiScrollers.QuaBiScroller[self]; viewerData: ViewerData _ NARROW [BiScrollers.ClientDataOfViewer[self]]; <> viewerData.view.transformation _ bs.style.GetTransforms[bs].clientToViewer; viewerData.view.cursor _ bs.class.common.cursor; IF input.first#$Exit THEN { rs: LIST OF OutputRequest; new: Pipal.Object; [rs, new] _ viewerData.notify[viewerData.mutant, viewerData.view, input]; viewerData.mutant _ new; IF new=NIL THEN ERROR; -- trivial test avoiding many wedged viewers! FOR requests: LIST OF OutputRequest _ rs, requests.rest WHILE requests#NIL DO request: OutputRequest = requests.first; SELECT request.type FROM clearAndRepaintArea => ViewerOps.PaintViewer[self, client, FALSE, NEW [OutputRequest _ request]]; <> repaintAll => ViewerOps.PaintViewer[self, client]; -- until the day we have commands which change menus paintOutline => ViewerOps.PaintViewer[self, client, FALSE, NEW [OutputRequest _ request]]; changeCursor => Cursors.SetCursor[NARROW [request.data, REF Cursors.CursorType]^]; grabInputFocus => InputFocus.SetInputFocus[self]; translate, scale => { bitransf: BiScrollers.Transform _ bs.style.GetTransforms[bs].clientToViewer; bitransf _ ImagerTransformation.Concat[NARROW [request.data], bitransf]; bs.style.ChangeTransform[bs, bitransf, ignore]; Cursors.SetCursor[textPointer]; }; ENDCASE => ERROR; ENDLOOP; }; }; <> Debug: SIGNAL = CODE; ResetClick: Menus.ClickProc ~ { <> <<-- Reset !!>> }; UndoClick: Menus.ClickProc ~ { <> <> <> <> <> }; RedoClick: Menus.ClickProc ~ { <> <> <> <> <> }; FlushClick: Menus.ClickProc ~ { <> <> <> }; DebugClick: Menus.ClickProc ~ { <> <> <> }; <> ViewerOps.RegisterViewerClass[$Pipal, viewerClass]; TerminalIO.PutRope["Pipal welcomes you\n"]; END.