PipalDisplayImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Louis Monier February 3, 1988 11:33:05 am PST
Bertrand Serlet February 4, 1988 2:03:34 am PST
DIRECTORY BasicTime, BiScrollers, Cursors, Geom2D, Imager, ImagerBackdoor, ImagerTransformation, InputFocus, IO, List, Menus, Pipal, PipalDisplay, PipalEdit, PipalOverlayEditor, PipalPaint, PipalReal, Process, Real, RefTab, TerminalIO, TIPUser, ViewerClasses, ViewerOps;
PipalDisplayImpl: CEDAR PROGRAM
IMPORTS BasicTime, BiScrollers, Cursors, Geom2D, Imager, ImagerBackdoor, ImagerTransformation, InputFocus, List, Menus, Pipal, PipalEdit, PipalOverlayEditor, PipalPaint, PipalReal, Process, TerminalIO, TIPUser, ViewerOps
EXPORTS PipalDisplay =
BEGIN OPEN PipalDisplay;
Viewers
lastViewerPaintTime: BasicTime.Pulses;
Debugging only!
CreateObjectViewer: PUBLIC PROC [object: Pipal.Object] RETURNS [viewer: ViewerClasses.Viewer] ~ {
viewer ← ViewerOps.CreateViewer[$Pipal, [name: "Pipal", 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
ViewerData : TYPE = REF ViewerDataRec; -- what gets hung unto the viewer
ViewerDataRec: TYPE = RECORD [
editor: PipalEdit.Editor,
mouseNow: PipalReal.Position ← PipalReal.zeroVector, -- mouse position now
mouseDown: PipalReal.Position ← PipalReal.zeroVector, -- mouse position when a button went down
previousTrackingArea: Pipal.Object ← Pipal.void, -- previous area modified by tracking; should be cleaned up at every paint if non nil!
moving: BOOLFALSE,
cursor: ViewerClasses.CursorType ← textPointer
];
lastBiscrollerPaintTime: BasicTime.Pulses;
CreateEditorBiscroller: PUBLIC PROC [editor: PipalEdit.Editor, tipTable: Pipal.ROPE, menu: Menus.Menu ← NIL] RETURNS [bs: BiScrollers.BiScroller] ~ {
viewerData: ViewerData;
style: BiScrollers.BiScrollerStyle ← BiScrollers.GetStyle["Buttonned"]; -- Buttonless
class: BiScrollers.BiScrollerClass ← style.NewBiScrollerClass[[
flavor: $BiPipal, -- Note: it has better not be the same as for creating a simple viewer ... [BS]
extrema: Extrema,
paint: BiscrollerPaint,
notify: Notify,
bsUserAction: ForkAndDo,
finish: LIST [$Exit],
menu: IF menu=NIL THEN BiScrollers.bsMenu ELSE BiScrollers.CatenateMenus[BiScrollers.bsMenu, menu],
icon: fileCabinet,
tipTable: TIPUser.InstantiateNewTIPTable[tipTable],
cursor: textPointer, -- was bullseye
mayStretch: FALSE,
offsetsMustBeIntegers: TRUE,
preferIntegerCoefficients: FALSE
]];
info: ViewerClasses.ViewerRec ← [name: "Pipal",
iconic: TRUE,
data: NEW [ViewerDataRec ← [editor: editor]]];
bs ← class.style.CreateBiScroller[class: class, info: info];
viewerData ← NARROW[BiScrollers.ClientDataOf[bs]];
};
Extrema: BiScrollers.ExtremaProc = {
viewerData: ViewerData ← NARROW[clientData];
size: PipalReal.Size ← PipalReal.ObjectSize[viewerData.editor.object];
[min, max] ← Geom2D.ExtremaOfRect[[0, 0, size.x, size.y], direction];
};
PaintBBox: PROC [context: Imager.Context, object: Pipal.Object, color: Imager.Color ← Imager.black] ~ {
PipalPaint.PaintOutline[context, PipalReal.BBox[object], color];
};
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]];
};
WhatChanged: TYPE = REF WhatChangedRec;
WhatChangedRec: TYPE = RECORD [
clipArea: Pipal.Object, -- redisplay the data structure inside these areas
outlines: Pipal.Object -- then paint these outlines
];
BiscrollerPaint: ViewerClasses.PaintProc = {
viewerData: ViewerData ← NARROW [BiScrollers.ClientDataOfViewer[self]];
editor: PipalEdit.Editor = viewerData.editor;
lastBiscrollerPaintTime ← BasicTime.GetClockPulses[];
-- coordinate axis
Imager.SetColor[context, Imager.black];
Imager.MaskVector[context, [-1000, 0], [1000, 0]];
Imager.MaskVector[context, [0, -1000], [0, 1000]];
-- bbox of the editor
PaintBBox[context, editor.object];
-- extra things to paint
IF whatChanged=NIL THEN {
-- Paint the data structure
PipalPaint.Paint[editor, context];
viewerData.previousTrackingArea ← Pipal.void;
}
ELSE {
clipArea, outlines: Pipal.Object ← NIL;
[clipArea, outlines] ← NARROW [whatChanged, WhatChanged]^;
-- Paint the data structure
clipArea ← Pipal.CreateOverlay[LIST [clipArea, viewerData.previousTrackingArea]];
viewerData.previousTrackingArea ← Pipal.void;
PipalPaint.ClipAndPaint[editor, context, clipArea];
PipalPaint.PaintAreaOutline[context, outlines];
};
lastBiscrollerPaintTime ← BasicTime.GetClockPulses[]-lastBiscrollerPaintTime;
};
ForkAndDo: BiScrollers.BSUserActionProc
~ TRUSTED {Process.Detach[FORK BiScrollers.DoBSUserAction[bs, input]]};
Commands
TranslateArea: PROC [object: Pipal.Object, delta: PipalReal.Vector] RETURNS [new: Pipal.Object ← NIL] = {
new ← PipalReal.TransformObject[ImagerTransformation.Translate[delta], object];
};
Notify: ViewerClasses.NotifyProc = {
viewerData: ViewerData ← NARROW [BiScrollers.ClientDataOfViewer[self]];
atom: ATOM = NARROW [input.first];
result: REF;
resultType: PipalEdit.ResultType;
SELECT atom FROM
$Exit => NULL; -- only if the viewer has been "activated", whatever it means
$MouseDown => {
viewerData.mouseDown ← NARROW [input.rest.first, BiScrollers.ClientCoords]^;
InputFocus.SetInputFocus[self];
};
$TrackSelected => {
area: Pipal.Object;
clipArea: Pipal.Object;
IF NOT viewerData.moving THEN viewerData.mouseDown ← NARROW [input.rest.first, BiScrollers.ClientCoords]^;
viewerData.mouseNow ← NARROW [input.rest.first, BiScrollers.ClientCoords]^;
[resultType, result] ← PipalEdit.ApplyCommand[viewerData.editor, $SelectedOutlines, NIL, self];
IF resultType#selectionArea THEN ERROR;
area ← TranslateArea[result, PipalReal.Sub[viewerData.mouseNow, viewerData.mouseDown]];
clipArea ← PipalPaint.CreateAreaAnnotation[area, edgesChildren];
ViewerOps.PaintViewer[self, client, FALSE, NEW [WhatChangedRec ← [
clipArea: clipArea,
outlines: area
]]];
viewerData.previousTrackingArea ← clipArea;
};
$Scrolling => {
Cursors.SetCursor[move];
};
$Scroll => {
cc: PipalReal.Position ← NARROW [input.rest.first, BiScrollers.ClientCoords]^;
delta: ImagerTransformation.VEC ← [
cc.x-viewerData.mouseDown.x,
cc.y-viewerData.mouseDown.y];
bs: BiScrollers.BiScroller ← BiScrollers.QuaBiScroller[self];
tr: BiScrollers.Transform ← bs.style.GetTransforms[bs].clientToViewer;
tr ← ImagerTransformation.PreTranslate[tr, delta];
bs.style.ChangeTransform[bs, tr, ignore];
Cursors.SetCursor[textPointer];
};
ENDCASE => {
arguments: LIST OF REFNIL;
FOR list: LIST OF REF ← input.rest, list.rest WHILE list#NIL DO
WITH list.first SELECT FROM
cc: BiScrollers.ClientCoords => {
viewerData.mouseNow ← cc^;
arguments ← CONS [cc, arguments];
};
atom: ATOM => SELECT atom FROM
$DownCoords => arguments ← CONS [NEW [PipalReal.Size ← viewerData.mouseDown], arguments];
ENDCASE => arguments ← CONS [atom, arguments];
ENDCASE => arguments ← CONS [atom, arguments];
ENDLOOP;
[resultType, result] ← PipalEdit.ApplyCommand[viewerData.editor, atom, List.Reverse[arguments], self];
SELECT resultType FROM
none => ViewerOps.PaintViewer[self, client]; -- until the day we have commands which change menus
changedArea => ViewerOps.PaintViewer[self, client, FALSE, NEW [WhatChangedRec ← [clipArea: result, outlines: Pipal.void]]];
ENDCASE => ERROR; -- including object
};
viewerData.moving ← atom=$TrackSelected;
};
End: PROC [viewerData: ViewerData] ~ {
child: Pipal.Object;
translation: PipalInt.Vector ← [Real.Round[viewerData.mouseNow.x-viewerData.mouseDown.x], Real.Round[viewerData.mouseNow.y-viewerData.mouseDown.y]];
state: State ← NARROW [viewerData.editor.state];
IF state.selected=NIL THEN RETURN; -- no selection
child ← state.selected.first;
PipalEdit.ReplaceInEditor[viewerData.editor, child, PipalInt.TransformObject[[translation], child], state];
ViewerOps.PaintViewer[viewerData.v, all];
};
Exit: PROC [viewerData: ViewerData] ~ { -- when mouse exits the viewer
Cursors.SetCursor[textPointer];
};
Little Quick and Dirty Test
Debug: SIGNAL = CODE;
EditorTest: PROC [editor: PipalEdit.Editor, tipTable: Pipal.ROPE] RETURNS [bs: BiScrollers.BiScroller] = {
menu: Menus.Menu ← Menus.CreateMenu[2];
Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Reset", proc: ResetClick, clientData: editor, fork: FALSE, guarded: TRUE]];
Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Undo", proc: UndoClick, clientData: editor, fork: FALSE]];
Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Redo", proc: RedoClick, clientData: editor, fork: FALSE]];
Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Flush", proc: FlushClick, clientData: editor, fork: FALSE]];
Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Debug", proc: DebugClick, clientData: editor, fork: TRUE], 1];
bs ← CreateEditorBiscroller[editor, tipTable, menu];
};
ResetClick: Menus.ClickProc ~ {
editor: PipalEdit.Editor ← NARROW [clientData];
PipalEdit.Reset[editor];
ViewerOps.PaintViewer[parent, all];
};
UndoClick: Menus.ClickProc ~ {
editor: PipalEdit.Editor ← NARROW [clientData];
IF editor.undoEvents=NIL
THEN TerminalIO.PutF["*** Cannot Undo.\n"]
ELSE PipalEdit.Undo[editor];
ViewerOps.PaintViewer[parent, all];
};
RedoClick: Menus.ClickProc ~ {
editor: PipalEdit.Editor ← NARROW [clientData];
IF editor.redoEvents=NIL
THEN TerminalIO.PutF["*** Cannot Redo.\n"]
ELSE PipalEdit.Redo[editor];
ViewerOps.PaintViewer[parent, all];
};
FlushClick: Menus.ClickProc ~ {
editor: PipalEdit.Editor ← NARROW [clientData];
PipalEdit.Flush[editor];
ViewerOps.PaintViewer[parent, all];
};
DebugClick: Menus.ClickProc ~ {
editor: PipalEdit.Editor ← NARROW [clientData];
SIGNAL Debug[];
ViewerOps.PaintViewer[parent, all];
};
Push / Pop
PushCommand: PipalEdit.CommandProc = {
editors: LIST OF PipalEdit.Editor ← PipalOverlayEditor.Push[editor];
WHILE editors#NIL DO
[] ← EditorTest[editors.first, "[]<>Users>serlet.pa>Pipal.TIP"]; -- AAAARRRGH
editors ← editors.rest;
ENDLOOP;
};
PopCommand: PipalEdit.CommandProc = {
viewer: ViewerClasses.Viewer = NARROW [issuer];
TRUSTED {Process.Detach[FORK PipalEdit.DestroyEditor[editor]]}; -- believe it or not if you don't fork, you lock the viewers! (because of TerminalIO!)
ViewerOps.CloseViewer[viewer]; -- this one does very very strange things ...
};
PipalEdit.RegisterCommand[PipalOverlayEditor.overlayEditorClass, $Push, PushCommand];
PipalEdit.RegisterCommand[PipalOverlayEditor.overlayEditorClass, $Pop, PopCommand];
Initialization
ViewerOps.RegisterViewerClass[$Pipal, viewerClass];
TerminalIO.PutRope["Pipal welcomes you\n"];
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]]];
};