PipalEditorImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Louis Monier February 3, 1988 11:33:05 am PST
Bertrand Serlet February 15, 1988 11:40:18 pm PST
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;
Readonly Viewers Creation
lastViewerPaintTime: BasicTime.Pulses;
Debugging only!
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]];
BiScroller Creation
ViewerData : TYPE = REF ViewerDataRec; -- what gets hung unto the viewer
ViewerDataRec: TYPE = RECORD [
mutant: Pipal.Object,
view: View,
notify: NotifyProc];
lastBiscrollerPaintTime: BasicTime.Pulses;
Hack for stats ...
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: REFNIL, buttons: BOOLFALSE] 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
];
whatChanged contains is either NIL (then the whole mutant should be repainted) or a REF to a request. This will have to change when there is a queue, and the cut between Notify and Paint will be different.
Paint: ViewerClasses.PaintProc = {
bs: BiScrollers.BiScroller ← BiScrollers.QuaBiScroller[self];
viewerData: ViewerData ← NARROW [BiScrollers.ClientDataOfViewer[self]];
mutant: Pipal.Object = viewerData.mutant;
lastBiscrollerPaintTime ← BasicTime.GetClockPulses[];
Coordinate axis
Imager.SetColor[context, Imager.black];
Imager.MaskVector[context, [-1000, 0], [1000, 0]];
Imager.MaskVector[context, [0, -1000], [0, 1000]];
extra things to paint
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]];
Undelicate duplication of code here, but that's probably due to BiScrollers.
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]];
is that FALSE a TRUE???
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;
};
};
Quick and Dirty Buttons
Debug: SIGNAL = CODE;
ResetClick: Menus.ClickProc ~ {
mutant: Pipal.Object ← NARROW [clientData, ViewerData].mutant];
-- Reset !!
};
UndoClick: Menus.ClickProc ~ {
mutant: Pipal.Object ← NARROW [clientData];
IF mutant.undoEvents=NIL
THEN TerminalIO.PutF["*** Cannot Undo.\n"]
ELSE PipalMutate.Undo[mutant];
ViewerOps.PaintViewer[parent, all];
};
RedoClick: Menus.ClickProc ~ {
mutant: Pipal.Object ← NARROW [clientData];
IF mutant.redoEvents=NIL
THEN TerminalIO.PutF["*** Cannot Redo.\n"]
ELSE PipalMutate.Redo[mutant];
ViewerOps.PaintViewer[parent, all];
};
FlushClick: Menus.ClickProc ~ {
mutant: Pipal.Object ← NARROW [clientData];
PipalMutate.Flush[mutant];
ViewerOps.PaintViewer[parent, all];
};
DebugClick: Menus.ClickProc ~ {
mutant: Pipal.Object ← NARROW [clientData];
SIGNAL Debug[];
ViewerOps.PaintViewer[parent, all];
};
Initialization
ViewerOps.RegisterViewerClass[$Pipal, viewerClass];
TerminalIO.PutRope["Pipal welcomes you\n"];
END.