SilDisplayImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Tracy Larrabee, March 29, 1984 1:39:44 pm PST
Last Edited by: Pier, December 18, 1985 5:50:54 pm PST
This module AND its companion SilDisplayImplA implement the routines which get user input, process it, and modify the Sil internal file structures. These modules will call on SilDisplayUtils and SilDisplayCursors and use data structures defined in SilDisplayInternal. To understand what is going on, look at the SilPaintProc in SilDisplayImplA.
DIRECTORY
Ascii USING
[BS],
BiScrollers USING
[Align, BiScroller, QuaViewer, Scale, ViewportBox],
Geom2D USING [id, Rect, Transform, Vec],
Imager USING
[Context, MaskRectangleI, SetColor, VEC, white],
ImagerTransformation USING
[PostScale, PostScale2, PostTranslate, Transform, TransformRectangle],
MessageWindow USING
[Append, Blink],
Process USING
[Detach],
Real USING
[RoundI],
RefText USING
[AppendChar, New],
Rope USING
[Fetch, FromChar, FromRefText, ToRefText, Cat, Equal],
ViewerClasses USING
[Viewer],
ViewerOps USING
[PaintViewer, SaveViewer, UserToScreenCoords],
SilDisplay,
SilDisplayCursors,
SilDisplayInternal,
SilDisplayPrivate,
SilDisplayUtils,
SilFile,
SilKernel,
SilUserInput
;
SilDisplayImpl: CEDAR MONITOR
IMPORTS BiScrollers, Geom2D, Imager, ImagerTransformation, MessageWindow, Process, Real, RefText, Rope, SilDisplay, SilDisplayCursors, SilDisplayUtils, SilFile, SilKernel, SilUserInput, ViewerOps
EXPORTS SilKernel, SilDisplayPrivate = BEGIN OPEN SilFile;
SilData: TYPE = SilKernel.SilData;
SilModel: TYPE = SilFile.SilModel;
SilUIData: TYPE = SilKernel.SilUIData;
SilDisplayData: TYPE = REF SilDisplayDataRec;
SilDisplayDataRec: PUBLIC TYPE = SilDisplayInternal.SilDisplayDataRec;
UInputRec: TYPE = SilUserInput.UInputRec;
SilSelection: TYPE = SilFile.SilSelection;
RebuildAreaRec: TYPE = RECORD[
xMin, yMin: INTEGERLAST[INTEGER],
xMax, yMax: INTEGERFIRST[INTEGER]
];
UpdateRebuildArea: PROC [s: SilObjectRec, a: RebuildAreaRec] RETURNS [r: RebuildAreaRec] = {
RETURN[[MIN[a.xMin, s.xMin], MIN[a.yMin, s.yMin], MAX[a.xMax, s.xMax], MAX[a.yMax, s.yMax]]];
};
MergeRebuildArea: PROC [data: SilDisplayData, model: SilModel, a: RebuildAreaRec] = {
IF a.xMin#LAST[INTEGER] THEN SilDisplayUtils.MergeRebuild[data, model, a.xMin, a.yMin, a.xMax, a.yMax];
};
Following are several procedures which take a UInputRec (a variant record, defined in SilUserInput). Following the real procedure definition there is a comment which indicates what this procedure is going to expect from ints variant record.
-------File and Control operations--------
InputFile: PUBLIC PROC [args: UInputRec.InputFile, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[];
Input a Sil file. Collect the file name from the user. (.Sil extention will be assumed if none is supplied). It should be noted that a Sil file maybe read in more than once, and will result in two copies of each file object existing in the Sil environment (any number of different files can also be read in and co-exist). args.mode specifies whether the Sil objects read in should be origined at (0,0), as usual [mode=absolute], or origined at (markX, markY) [mode=relative].
dData: SilDisplayData ← data.displayData;
SilDisplayCursors.DisableRopeInput[data, ctx];
dData.relativeInput ← args.mode=relative;
SilDisplayUtils.GuessFileName[data, input];
};
StoreFile: PUBLIC PROC [args: UInputRec.StoreFile, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[clip: BOOLTRUE, large: BOOLFALSE];
Output a Sil file. Collect the file name from the user. (.Sil extention will be assumed if none is supplied). If clip is true make sure that the output is clipped to the size of the old Alto screen when it is saved. If large is TRUE, then use the new CedarSil format, else output in the standard AltoSil format.
dData: SilDisplayData ← data.displayData;
SilDisplayCursors.DisableRopeInput[data, ctx];
dData.clipOutputFile ← args.clip;
dData.largeFormat ← args.large;
SilDisplayUtils.GuessFileName[data, output];
};
KillPicture: PUBLIC PROC [args: UInputRec.KillPicture, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[];
Kill the current picture so that any further drawing will be done with a clean slate.
dData: SilDisplayData ← data.displayData;
lViewer: ViewerClasses.Viewer ← SilUserInput.GetBiScroller[data.uiData].QuaViewer[].parent;
SilDisplayCursors.DisableRopeInput[data, ctx];
IF NOT dData.edited THEN SilDisplayUtils.KillConfirmedFile[data, ctx, lViewer]
ELSE {
dData.mode ← WaitingForKillConfirmation;
SilUserInput.InputingRope[data.uiData];
MessageWindow.Append["File has been edited, ", TRUE];
MessageWindow.Append["confirm with CR, ESC or any click, ", FALSE];
MessageWindow.Append["abort with DEL.", FALSE];
MessageWindow.Blink[];
};
};
SwapFonts: PUBLIC PROC [args: UInputRec.SwapFonts, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[];
SilDisplayUtils.SwapFonts[data: data, ctx: ctx]; --toggles between normal display and "hardcopy" mode
};
HardCopy: PUBLIC PROC [args: UInputRec.HardCopy, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[char: CHAR];
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayUtils.GuessHardFileName[data, args.char];
};
-----Tracking the mouse, and defining the mark, origin and current selection; scrolling to Mark
TrackMouse: PUBLIC PROC [args: UInputRec.TrackMouse, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[x: INTEGER ← 0, y: INTEGER ← 0];
Track the motion of the mouse (when a mouse button is depressed) for the command line.
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Pos, intArg1: args.x, intArg2: args.y];
};
SetCaret: PUBLIC PROC [args: UInputRec.SetCaret, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[caret: CaretSet, x: INTEGER ← 0, y: INTEGER ← 0, mode: Relation];
Set the desired caret. If mode is absolute, set the position to be <x, y>, otherwise, change only the y value of the caret, acording to the value of Yinc (ingnore x and y)
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT args.caret FROM
mark => {
SilDisplayCursors.AquireAndDisableTheMark[data, ctx];
SELECT args.mode FROM
absolute => {
SilDisplayCursors.SetMarkX[args.x];
SilDisplayCursors.SetMarkY[args.y];
};
relative => SilDisplayCursors.SetMarkY[SilDisplayCursors.GetMarkY[] + dData.yInc];
ENDCASE;
};
origin => {
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx];
SELECT args.mode FROM
absolute => {
SilDisplayCursors.SetOriginX[args.x];
SilDisplayCursors.SetOriginY[args.y];
};
relative => SilDisplayCursors.SetOriginY[SilDisplayCursors.GetOriginY[] + dData.yInc];
ENDCASE;
};
ENDCASE;
SilUserInput.SetCaretChange[uiData];
};
SetCursor: PUBLIC PROC [args: UInputRec.SetCursor, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[caret: CaretSet]; Set the cursor bitmap from the screen bitmap near the caret.
sx, sy: INTEGER;
viewerPos: Geom2D.Vec;
selection: SilFile.SilSelection;
dData: SilDisplayData ← data.displayData;
bs: BiScrollers.BiScroller ← SilUserInput.GetBiScroller[data.uiData];
IF (selection ← SilFile.CopySelection[]).numObjects = 0 THEN RETURN; --no selection
IF NOT (SilDisplayCursors.MarkAndSelectionInSameWindow[] AND SilDisplayCursors.OriginAndSelectionInSameWindow[]) THEN {
MessageWindow.Append["Mark, Origin, and Selection must be in same Window", TRUE];
MessageWindow.Blink[];
RETURN;
};
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx]; --get origin out of the bitmap
SilDisplayCursors.AquireAndDisableTheMark[data, ctx]; --get mark out of the bitmap
SilDisplayUtils.PaintAllSelectedAsDeselected[model: data.model, ctx: ctx]; --rebuild bitmap where origin and selection were
convert Sil coordinates to screen coordinates
viewerPos ← bs.style.GetTransforms[bs].clientToViewer.Transform[[
x: (SilDisplayCursors.GetOriginX[] + dData.xOffset) * dData.currentMagnification,
y: -(SilDisplayCursors.GetOriginY[] + dData.yOffset) * dData.currentMagnification]];
[sx, sy] ← ViewerOps.UserToScreenCoords[viewer, Real.RoundI[viewerPos.x], Real.RoundI[viewerPos.y]];
SELECT args.caret FROM
origin => SilDisplayCursors.BitmapToCursor[x: sx, y: sy, viewer: viewer];
mark => NULL; --not implemented
ENDCASE;
SilDisplayUtils.MergeRebuild[dData: data.displayData, model: data.model, xMin: selection.xMin, yMin: selection.yMin, xMax: selection.xMax, yMax: selection.yMax, selectedOnly: TRUE];
SilDisplayUtils.SilRebuild[data: data, ctx: ctx];
SilDisplayCursors.SilCursorsBlink[]; --turn origin back on
};
SelectWithPos: PUBLIC ENTRY PROC [args: UInputRec.SelectWithPos, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[x, y: INTEGER, mode: SelectMode ← change];
Each mode will cause the selection to change based on the current selection and the object at <x,y>. If there is more than one object at <x, y> the one we are concerned with is the element at <x, y> with the smallest perimeter.
If mode is change, the object at <x, y> becomes the only current selection.
If mode is add, the object at <x, y> is added to the previously selected objects. In both cases the origin is moved to the upper left corner of the selected object; if no object exists at <x, y> the origin is moved to <x, y>.
If mode is remove, the object at <x, y> is deselected; in this case the origin does not change.
If mode is relative, select all objects which are contained in the box defined by <x, y> and the last mark. The origin is moved to the upper left corner of the bounding box containing the selected objects.
If the mode is delete, delete the object at <x, y>.
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
markX: INTEGER ← SilDisplayCursors.GetMarkX[]; markY: INTEGER ← SilDisplayCursors.GetMarkY[];
originX: INTEGER ← SilDisplayCursors.GetOriginX[];
originY: INTEGER ← SilDisplayCursors.GetOriginY[];
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayCursors.CheckSelectionWindow[data];
SELECT args.mode FROM
relative => {
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx];
Deselect all the old stuff, then select the new stuff
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
[originX, originY] ← SilFile.DefineSelectWithBox[model, markX, markY, args.x, args.y];
SilDisplayUtils.MergeRebuild[dData, model, MIN[markX, args.x], MIN[markY, args.y],
MAX[markX, args.x], MAX[markY, args.y], TRUE];
SilUserInput.SetCaretChange[uiData];
};
change, add => {
sob: SilObject ← ObjectAtPos[model, args.x, args.y];
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx];
Only difference between change and add is whether to keep old selections
IF args.mode = change THEN SilDisplayUtils.DeselectAndPaintAll[model, ctx];
SilFile.DefineSelectWithObject[model, sob];
IF sob # NIL THEN { --Move origin to upper left of selected object
SilDisplayUtils.MergeRebuild[dData, model, sob.first.xMin, sob.first.yMin,
sob.first.xMax, sob.first.yMax, TRUE];
originX ← sob.first.xMin;
originY ← sob.first.yMin;
}
ELSE { --Move origin to place unsuccessfully selected
originX ← args.x;
originY ← args.y;
};
};
remove => {
sob: SilObject ← ObjectAtPos[model, args.x, args.y];
IF sob # NIL THEN {
SilFile.Deselect[model, sob];
SilDisplayUtils.MergeRebuild[dData, model, sob.first.xMin, sob.first.yMin, sob.first.xMax, sob.first.yMax, FALSE];
};
};
delete => {
sob: SilObject ← ObjectAtPos[model, args.x, args.y];
IF sob # NIL THEN {
SilDisplayUtils.PaintObject[model, sob.first, erase, ctx];
SilDisplayCursors.AquireAndDisableTheMark[data, ctx];
markX ← sob.first.xMin;
markY ← sob.first.yMin;
SilFile.DeleteAndCacheObject[model, sob];
In process of deleting might have written over selected object
SilDisplayUtils.MergeRebuild[dData, model, sob.first.xMin, sob.first.yMin, sob.first.xMax, sob.first.yMax];
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
};
};
ENDCASE;
SilDisplayCursors.SetOriginX[originX];
SilDisplayCursors.SetOriginY[originY];
SilDisplayCursors.SetMarkX[markX];
SilDisplayCursors.SetMarkY[markY];
SilUserInput.SetCaretChange[uiData];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
SelectForAttrib: PUBLIC ENTRY PROC [args: UInputRec.SelectForAttrib, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[mode: SelectMode, char: CHAR];
Two modes will cause the selection to change based on the current selection and which objects in the main picture have certain attributes. If mode is change, all objects in the picture which have the attribute indicated are selected. If mode is reduce, all objects which were previously selected and have the attribute indicated become the current selection. No selectMode other than these two is valid.
rebuildArea: RebuildAreaRec ← [];
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
AR: SilDisplayUtils.AttributeRec ← SilDisplayUtils.AttributeFromChar[args.char];
IF AR.referenced = invalid THEN {
MessageWindow.Append["Illegal attribute given.", TRUE]; MessageWindow.Blink;
RETURN;
}
ELSE MessageWindow.Append[Rope.FromChar[args.char], FALSE];
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayCursors.CheckSelectionWindow[data];
IF args.mode = change THEN { --Select the guys that pass inspection
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
FOR s: SilObject ← GetObjectList[model, fgnd], s.rest WHILE s # NIL DO
IF SilDisplayUtils.AttributeFilter[AR, s.first] THEN {
SilFile.DefineSelectWithObject[model, s];
rebuildArea ← UpdateRebuildArea[s.first, rebuildArea];
};
ENDLOOP;
}
ELSE { --Remove the guys that dont pass inspection
s: SilObject ← SilFile.GetSelection[].objects;
nextS: SilObject ← s;
WHILE s # NIL DO
nextS ← s.first.selectObj;
IF NOT SilDisplayUtils.AttributeFilter[AR, s.first] THEN {
SilFile.Deselect[model, s];
rebuildArea ← UpdateRebuildArea[s.first, rebuildArea];
};
s ← nextS;
ENDLOOP;
};
MergeRebuildArea[dData, model, rebuildArea]; -- rebuild area ONLY ONCE
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
CenterOnMark: PUBLIC PROC [args: UInputRec.CenterOnMark, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
The user has typed ControlArrow, and wants the center of the BiScroller viewport to move to the current Mark position. Also resets the BiScroller Scale to 1:1. Before calling BiScrollers.Align, the current ctx is used to clear the viewer.
ClientToSilXForm: PROC [] RETURNS [xform: Geom2D.Transform] = {
Sil coordinates = (ClientCoords/scale) - offset
xScale = gridMagnification; xOffset = dData.xOffset
yScale = - gridMagnification; yOffset = dData.yOffset
xform ← Geom2D.id.PostScale2[[1.0, -1.0]].PostScale[IF dData.magnificationOn AND dData.currentMagnification#1 THEN 1.0/dData.currentMagnification ELSE 1.0].PostTranslate[[-dData.xOffset, -dData.yOffset]];
};
SilToClientCoords: PROC [silCoordX, silCoordY: REAL] RETURNS [clientCoordX, clientCoordY: REAL] = {
ClientCoord = (SilCoord + offset) * scale
xScale = gridMagnification; xOffset = dData.xOffset
yScale = - gridMagnification; yOffset = dData.yOffset
point: Imager.VEC ← [silCoordX, silCoordY];
point.x ← point.x + dData.xOffset;
point.y ← point.y + dData.yOffset;
IF dData.magnificationOn AND dData.currentMagnification#1 THEN {
point.x ← point.x * dData.currentMagnification;
point.y ← point.y * dData.currentMagnification;
};
RETURN[point.x, -point.y]; --note inversion of y coord
};
bxMin, byMin, bxMax, byMax: INTEGER; -- for bounding box of context
rMarkX, rMarkY: REAL;
area: Geom2D.Rect;
dData: SilDisplayData ← data.displayData; -- used by local procs above
[rMarkX, rMarkY] ← SilToClientCoords[SilDisplayCursors.GetMarkX[], SilDisplayCursors.GetMarkY[]]; --BiScrollers wants Client coords
[bxMin, byMin, bxMax, byMax] ← SilDisplayUtils.BoundingBoxOfContext[ctx];
Imager.SetColor[ctx, Imager.white]; --clear the viewer
Imager.MaskRectangleI[ctx, bxMin, byMin, bxMax - bxMin, byMax - byMin];
BiScrollers.Align[bs: SilUserInput.GetBiScroller[data.uiData], client: [coord[x: rMarkX, y: rMarkY]], viewer: [fraction[fx: 0.5, fy: 0.5]], paint: FALSE]; --center the viewer on the Mark
BiScrollers.Scale[bs: SilUserInput.GetBiScroller[data.uiData], op: [reset[]], paint: FALSE]; --and reset the Scale to 1:1. Note: paint�LSE is CRITICAL !!
area ← BiScrollers.ViewportBox[bs: SilUserInput.GetBiScroller[data.uiData]]; --find area needing rebuilding
area ← ClientToSilXForm[].TransformRectangle[area]; --and convert to Sil coordinates
SilDisplayUtils.MergeRebuild[dData, data.model, Real.RoundI[area.x], Real.RoundI[area.y], Real.RoundI[area.x+area.w], Real.RoundI[area.y+area.h], FALSE];
};
-----Manipulation of the current selection--------
OperateOnSelected: PUBLIC ENTRY PROC [args: UInputRec.OperateOnSelected, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[op: OperationMode, rel: Relation ← relative, x: INTEGER ← 0, y: INTEGER ← 0];
Depending on op, either ignore or utilize <x, y> to copy, move, or delete the selected objects.
If op is delete, ignore rel and <x, y> and delete all selected objects.
If op is copy, copy the selected objects. If rel is absolute copy them such that the origin is at <x, y>. If rel is relative copy them such that the origin is at the mark and ignore <x, y>.
If op is moveStretch, move the selected objects. If rel is absolute move them such that the origin is at <x, y>. If rel is relative move them such that the origin is at the mark and ignore <x, y> As a feature, if the selected objects are thought of as defining a rectangular window, and if they are moved ONLY in X or in Y, the endpoints of any boxes which cross the window boundary are moved (by shortening or lengthening the box) so that the endpoints have the same relation to the selected objects as in the original view. If the box would be shortened to a non-posotive length, or if it is fully in the window but not selected, it is not modified.
If op is moveNoStretch, proceed as if it was moveStretch, but do not stretch any boxes (as described above).
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
sSel: SilSelection;
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT args.op FROM
delete => {
sSel ← SilFile.GetSelection[];
SilDisplayCursors.AquireAndDisableTheMark[data, ctx];
SilDisplayCursors.SetMarkX[sSel.xMin];
SilDisplayCursors.SetMarkY[sSel.yMin];
SilDisplayCursors.DeleteAndEraseSelection[data: data, ctx: ctx, cache: TRUE];
SilUserInput.SetCaretChange[uiData];
};
copy, moveStretch, moveNoStretch => {
xOffset, yOffset: INTEGER;
xMin, yMin, xMax, yMax: INTEGER;
IF NOT SilDisplayCursors.OriginAndSelectionInSameWindow[] THEN {
MessageWindow.Append["Origin and Selection must be in same window", TRUE];
MessageWindow.Blink;
RETURN;
};
SELECT args.rel FROM
relative => {
xOffset ← SilDisplayCursors.GetMarkX[] - SilDisplayCursors.GetOriginX[];
yOffset ← SilDisplayCursors.GetMarkY[] - SilDisplayCursors.GetOriginY[];
};
absolute => {
xOffset ← args.x - SilDisplayCursors.GetOriginX[];
yOffset ← args.y - SilDisplayCursors.GetOriginY[];
};
ENDCASE;
sSel ← SilFile.CopySelection[];
xMin ← sSel.xMin;
yMin ← sSel.yMin;
xMax ← sSel.xMax;
yMax ← sSel.yMax;
IF NOT CheckSelectionsForMacroDefs[model] THEN {
MessageWindow.Append["Selection contains macros undefined in destination window", TRUE];
MessageWindow.Blink;
RETURN;
};
IF args.op = copy THEN {
SilDisplayCursors.DeselectAndRedraw[];
IF args.rel = absolute THEN {
SilDisplayCursors.AquireAndDisableTheOrigin[data: data, ctx: ctx];
SilDisplayCursors.SetOriginX[args.x];
SilDisplayCursors.SetOriginY[args.y];
SilUserInput.SetCaretChange[uiData: uiData]
}
ELSE SilDisplayCursors.MoveOriginToMark[data, ctx];
}
ELSE { -- move (not copy)
SilDisplayCursors.DeleteAndEraseSelection[data: data, ctx: ctx, cache: FALSE];
SilDisplayCursors.InterchangeMarkAndOrigin[data, ctx];
IF args.rel = absolute THEN {
SilDisplayCursors.AquireAndDisableTheOrigin[data: data, ctx: ctx];
SilDisplayCursors.SetOriginX[args.x];
SilDisplayCursors.SetOriginY[args.y];
SilUserInput.SetCaretChange[uiData: uiData]
};
};
SilDisplayCursors.InitiateNewSelection[data];
FOR s: SilObject ← sSel.objects, s.rest WHILE s # sSel.lastObject DO
sobr: SilObjectRec ← s.first;
sobr.xMin ← sobr.xMin + xOffset;
sobr.yMin ← sobr.yMin + yOffset;
sobr.xMax ← sobr.xMax + xOffset;
sobr.yMax ← sobr.yMax + yOffset;
SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr] ];
SilDisplayUtils.PaintObject[model, sobr, select, ctx];
ENDLOOP;
IF args.op = moveStretch AND
(xOffset # 0 OR yOffset # 0) AND (xOffset = 0 OR yOffset = 0) THEN {
offsetDirection: SilDisplayUtils.Orientation ← IF xOffset = 0 THEN vertical ELSE horizontal;
offset: INTEGERIF xOffset = 0 THEN yOffset ELSE xOffset;
FOR s: SilObject ← GetObjectList[model, fgnd], s.rest WHILE s # NIL DO
IF NOT ObjectIsSelected[model, s] THEN {
bEnd: SilDisplayUtils.BoxEnd;
passed: BOOL;
[passed, bEnd] ← SilDisplayUtils.OffsetFilter[s.first, offsetDirection, offset, xMin, yMin, xMax, yMax];
IF passed THEN {
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
SilDisplayUtils.StretchBox[s, offsetDirection, bEnd, offset];
SilDisplayUtils.PaintObject[model, s.first, show, ctx];
};
};
ENDLOOP;
FOR s: SilObject ← GetObjectList[model, bkgnd], s.rest WHILE s # NIL DO
IF NOT ObjectIsSelected[model, s] THEN {
bEnd: SilDisplayUtils.BoxEnd;
passed: BOOL;
[passed, bEnd] ← SilDisplayUtils.OffsetFilter[s.first, offsetDirection, offset, xMin, yMin, xMax, yMax];
IF passed THEN {
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
SilDisplayUtils.StretchBox[s, offsetDirection, bEnd, offset];
SilDisplayUtils.PaintObject[model, s.first, show, ctx];
};
};
ENDLOOP;
IF offsetDirection = vertical THEN
SilDisplayUtils.MergeRebuild[dData, model, xMin, MIN[yMin, yMin + yOffset], xMax, MIN[yMax, yMax + yOffset], FALSE]
ELSE SilDisplayUtils.MergeRebuild[dData, model, MIN[xMin, xMin + xOffset], yMin, MIN[xMax, xMax + xOffset], yMax, FALSE]
};
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
};
ENDCASE;
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
ChangeSelected: PUBLIC ENTRY PROC [args: UInputRec.ChangeSelected, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[char: CHAR];
Some attribute of the objects in the current selection will change, depending on char.
rebuildArea: RebuildAreaRec ← [];
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
AR: SilDisplayUtils.AttributeRec ← SilDisplayUtils.AttributeFromChar[args.char];
IF AR.referenced = invalid THEN {
MessageWindow.Append["Illegal attribute given.", TRUE]; MessageWindow.Blink;
RETURN;
}
ELSE MessageWindow.Append[Rope.FromChar[args.char], FALSE];
SilDisplayCursors.DisableRopeInput[data, ctx];
FOR s: SilObject ← SilFile.GetSelection[].objects, s.first.selectObj WHILE s # NIL DO
SELECT AR.referenced FROM
color => {
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
s.first.color ← AR.color;
rebuildArea ← UpdateRebuildArea[s.first, rebuildArea];
};
font => IF s.first.font IN SilFile.InternalPresetFonts AND AR.font IN SilFile.PresetFonts THEN {
xMin, yMin, xMax, yMax: INTEGER;
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
s.first.font ←
IF SilFile.FontIsBold[s.first.font] THEN
SilFile.InternalFontFromUserFont[AR.font, TRUE]
ELSE
SilFile.InternalFontFromUserFont[AR.font, FALSE];
[xMin, yMin, xMax, yMax] ←
SilDisplayUtils.BoundingBoxOfObject[model, s.first];
s.first.xMax ← s.first.xMin + xMax;
s.first.yMax ← s.first.yMin + yMax;
s.first.xMin ← s.first.xMin + xMin;
s.first.yMin ← s.first.yMin + yMin;
rebuildArea ← UpdateRebuildArea[s.first, rebuildArea];
};
face => IF s.first.font IN SilFile.InternalPresetFonts THEN {
xMin, yMin, xMax, yMax: INTEGER;
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
SELECT AR.face FROM
italic => s.first.italic ← TRUE;
nonItalic => s.first.italic ← FALSE;
bold => s.first.font ←
SilFile.InternalFontFromUserFont[SilFile.UserFontFromInternalFont[s.first.font].font, TRUE];
nonBold => s.first.font ←
SilFile.InternalFontFromUserFont[SilFile.UserFontFromInternalFont[s.first.font].font, FALSE];
ENDCASE;
[xMin, yMin, xMax, yMax] ← SilDisplayUtils.BoundingBoxOfObject[model, s.first];
s.first.xMax ← s.first.xMin + xMax;
s.first.yMax ← s.first.yMin + yMax;
s.first.xMin ← s.first.xMin + xMin;
s.first.yMin ← s.first.yMin + yMin;
rebuildArea ← UpdateRebuildArea[s.first, rebuildArea];
};
ENDCASE;
ENDLOOP;
MergeRebuildArea[dData, model, rebuildArea]; -- rebuild area ONLY ONCE
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
};
-----Set Sil parameters--------
SetDefaultAttribs: PUBLIC PROC [args: UInputRec.SetDefaultAttribs, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[char: CHAR];
Set the current attributes for future picture additions as indicated. Depending on att, certain arguments will be ignored. If att is color, the font and face arguments will be ignored, and future objects will be of the given color. The obvious extentions with respect to font and face are made.
dData: SilDisplayData ← data.displayData;
AR: SilDisplayUtils.AttributeRec ← SilDisplayUtils.AttributeFromChar[args.char];
IF AR.referenced = invalid THEN {
MessageWindow.Append["Illegal attribute given.", TRUE]; MessageWindow.Blink;
RETURN;
}
ELSE MessageWindow.Append[Rope.FromChar[args.char], FALSE];
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT AR.referenced FROM
color => SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Color, intArg1: AR.color];
font => SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Font, intArg1: AR.font];
face => SELECT AR.face FROM
italic =>SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Italic, boolArg: TRUE];
nonItalic => SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Italic, boolArg: FALSE];
bold => SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Bold, boolArg: TRUE];
nonBold => SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Bold, boolArg: FALSE];
ENDCASE;
ENDCASE;
IF dData.currentFont IN SilFile.PresetFonts THEN {
dData.currentFontRef ← SilDisplayUtils.GetFont[
SilFile.InternalFontFromUserFont[dData.currentFont, dData.currentBoldState],
dData.currentItalicState];
};
};
SetDetails: PUBLIC PROC [args: UInputRec.SetDetails, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[detail: Details, char: CHAR];
Set the details as inidicated.
If detail is boxWidth, the char should be an integer argument used to set the boxWidth.
If detail is gridSize, the char should be an integer argument used to set the grid size.
dData: SilDisplayData ← data.displayData;
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT args.detail FROM
boxWidth => IF args.char - '0 > 9 OR args.char - '0 < 1 THEN {
MessageWindow.Append["Illegal line width given.", TRUE]; MessageWindow.Blink[];
}
ELSE {
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: LineWidth, intArg1: args.char - '0];
};
gridSize => IF args.char - '0 > 9 OR args.char - '0 < 0 THEN {
MessageWindow.Append["Illegal grid spacing given.", TRUE]; MessageWindow.Blink[];
}
ELSE {
grid: NAT ← 1;
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
FOR i: NAT IN [1..args.char - '0] DO
grid ← grid * 2;
ENDLOOP;
IF grid > 64 THEN grid ← 64;
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Grid, intArg1: grid];
SilUserInput.ChangeGridInterval[data.uiData, grid];
};
ENDCASE;
};
-----Manipulate Macros--------
ManipulateMacro: PUBLIC ENTRY PROC [args: UInputRec.ManipulateMacro, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[mode: MacroMode, char: CHAR];
If mode is expand, expand the macro with name such that its upper left corner is placed at the mark. Macros within name will not be expanded if the macro expansion level is set to oneLevel.
If mode is define, define the set of selected objects to be the macro with name name. The name and the selected objects must have been previously checked as valid macro definitions.
If mode is clear, delete all Macro definitions as well as all instances of them in the current picture (name will be ignored).
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT args.mode FROM
expand => {
markX: INTEGER ← SilDisplayCursors.GetMarkX[];
markY: INTEGER ← SilDisplayCursors.GetMarkY[];
IF NOT SilDisplayCursors.MouseAndMarkInSameWindow[data] THEN {
MessageWindow.Append["Input Focus must be in same window as mark", TRUE];
MessageWindow.Blink;
RETURN;
};
IF NOT args.char IN SilFile.MacroName THEN {
MessageWindow.Append["Illegal Macro Name: ", TRUE];
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
MessageWindow.Blink;
RETURN;
};
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
SilDisplayCursors.CheckSelectionWindow[data];
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
SilDisplayUtils.ExpandMacro[model, args.char, markX, markY,
dData.currentOneLevel, ctx];
};
define =>
IF CheckSelectionsForMacroDefs[model: data.model, disallowName: TRUE, name: args.char] AND args.char IN SilFile.MacroName THEN
IF SilFile.GetObjectList[model: model, mode: macro, c: args.char] = NIL THEN {
SilDisplayUtils.DefineConfirmedMacro[data, args.char, ctx];
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
}
ELSE {
dData.mode ← WaitingForMacroDefConfirmation;
SilUserInput.InputingRope[data.uiData];
dData.macroDefName ← args.char;
MessageWindow.Append["Macro def for ", TRUE];
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
MessageWindow.Append[" already exists. ", FALSE];
MessageWindow.Append["confirm with carriage return for overwrite.", FALSE];
MessageWindow.Blink;
}
ELSE {
MessageWindow.Append["Illegal Macro definition", TRUE];
MessageWindow.Blink;
};
clear => {
dData.mode ← WaitingForMacroDeleteConfirmation;
SilUserInput.InputingRope[data.uiData];
MessageWindow.Append["Confirm deletion of all macros ", TRUE];
MessageWindow.Append["with CR, ESC, or any click ", FALSE];
MessageWindow.Append["abort with DEL.", FALSE];
MessageWindow.Blink[];
};
ENDCASE;
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
-----Draw, Delete, and Show procedures--------
DrawBox: PUBLIC ENTRY PROC [args: UInputRec.DrawBox, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[markRel: Relation ← absolute, originRel: Relation ← absolute, x: INTEGER ← 0, y: INTEGER ← 0, background: BOOLFALSE];
Draw 1 or 4 boxes.
If markRel and originRel are both absolute and background is FALSE, draw 4 boxes, with the origin and the mark defining the 2 points between which all 4 possible horizontal and vertical boxes are drawn, with width defined by the current box width.
If markRel and originRel are both absolute and background is TRUE, draw 1 box in the background, with the origin and the mark defining the corners.
If only markRel is absolute, draw 1 box having width defined by the current BoxWidth and having the appearance of a horizontal line if the difference betweeen the 2 defining points is larger in x than in y, else having the appearance of a vertical line. <x, y> and the mark are the defining points. Move the mark to the end of the box nearest <x, y>.
In all cases the box is selected and the origin is moved to the upper left corner of the box.
Finite: PROC [sobr: SilObjectRec] RETURNS [BOOL] ~ {
RETURN[(sobr.xMin#sobr.xMax) AND (sobr.yMin#sobr.yMax)];
};
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
sobr: SilObjectRec;
foregroundBoxFont: INTEGER = SilFile.foregroundBoxFont;
backgroundBoxFont: INTEGER = SilFile.backgroundBoxFont;
markX: INTEGER ← SilDisplayCursors.GetMarkX[];
markY: INTEGER ← SilDisplayCursors.GetMarkY[];
originX: INTEGER ← SilDisplayCursors.GetOriginX[];
originY: INTEGER ← SilDisplayCursors.GetOriginY[];
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayCursors.CheckSelectionWindow[data];
IF NOT SilDisplayCursors.MouseAndMarkInSameWindow[data] THEN {
MessageWindow.Append["Can't draw lines across viewer boundaries", TRUE];
MessageWindow.Blink;
RETURN;
};
IF args.originRel=absolute AND NOT SilDisplayCursors.MarkAndOriginInSameWindow[] THEN {
MessageWindow.Append["Can't draw boxes across viewer boundaries", TRUE];
MessageWindow.Blink;
RETURN;
};
Preparation: mark and origin will be moved, and the new box(es) will be selected
SilDisplayCursors.AquireAndDisableTheMark[data, ctx];
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx];
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
sobr.color ← dData.currentColor;
sobr.font ← IF args.background THEN backgroundBoxFont ELSE foregroundBoxFont;
sobr.italic ← FALSE;
SELECT args.originRel FROM
relative => { --Draw simple box
IF ABS[markX - args.x] < ABS[markY - args.y] THEN {
Box is from mark to new y coordinate, vertical box
sobr.xMin ← markX;
sobr.yMin ← MIN[markY, args.y];
sobr.xMax ← sobr.xMin + dData.currentBoxWidth;
sobr.yMax ← MAX[markY, args.y];
markY ← args.y;
sobr ← SilDisplayUtils.FixBoxConnectivity[dData, sobr, vertical];
}
ELSE {
Box is from mark to new x coordinate, horizontal box:
sobr.xMin ← MIN[markX, args.x];
sobr.yMin ← markY;
sobr.xMax ← MAX[markX, args.x];
sobr.yMax ← markY + dData.currentBoxWidth;
markX ← args.x;
sobr ← SilDisplayUtils.FixBoxConnectivity[dData, sobr, horizontal];
};
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
};
absolute => { --The box will use mark AND origin for control
xMin, yMin, xMax, yMax: INTEGER;
xMin ← sobr.xMin ← MIN[markX, originX];
yMin ← sobr.yMin ← MIN[markY, originY];
xMax ← sobr.xMax ← MAX[markX, originX];
yMax ← sobr.yMax ← MAX[markY, originY];
IF args.background THEN { --The box will be one large one in background
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
}
ELSE { --There will be 4 boxes: 2 vertical, 2 horizontal
sobr.yMax ← yMin + dData.currentBoxWidth; --box 1
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
sobr.xMax ← xMin+ dData.currentBoxWidth; --box 2
sobr.yMax ← yMax;
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
sobr.xMin ← xMax; --box 3
sobr.xMax ← xMax + dData.currentBoxWidth;
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
sobr.xMin ← xMin; --box 4
sobr.yMin ← yMax;
sobr.xMax ← xMax + dData.currentBoxWidth;
sobr.yMax ← yMax + dData.currentBoxWidth;
IF Finite[sobr] THEN SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, sobr]];
now set dimensions of effective object just added to model
sobr.xMin ← xMin;
sobr.yMin ← yMin;
sobr.xMax ← xMax;
sobr.yMax ← yMax;
};
dData.lastBoxLeftToRight ← FALSE;
dData.lastBoxTopToBottom ← FALSE;
};
ENDCASE;
Display the results
FOR s: SilObject ← SilFile.GetSelection[].objects, s.first.selectObj WHILE s # NIL DO
SilDisplayUtils.PaintObject[model, s.first, select, ctx]; --shortcut MergeRebuild
ENDLOOP;
Move the origin to upper left hand corner of the new structure;
SilDisplayCursors.SetOriginX[sobr.xMin]; SilDisplayCursors.SetOriginY[sobr.yMin];
SilDisplayCursors.SetMarkX[markX]; SilDisplayCursors.SetMarkY[markY];
SilUserInput.SetCaretChange[uiData];
IF NOT dData.yLock THEN {
n: INTEGER ← (sobr.yMax - sobr.yMin) / dData.currentGridSpacing;
m: INTEGER ← (sobr.yMax - sobr.yMin) MOD dData.currentGridSpacing;
IF m # 0 THEN n ← n + 1;
dData.yInc ← n * dData.currentGridSpacing;
};
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
};
HandleInputChars: PUBLIC ENTRY PROC [args: UInputRec.UserChar, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[c: Char];
Handle this Input Char. Do the correct thing based on the current input mode of the system.
AbortInput: PROC [data: SilData] = {
Perform the correct actions to clean up after the user decides to abort the input
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SELECT dData.mode FROM
InputingRope => SilDisplayCursors.DisableRopeInput[data, ctx];
EditingExistingRope => {
SilDisplayUtils.PaintObject[model, dData.collectingObject, erase, ctx];
dData.collectingObject.value ← dData.oldText;
SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, dData.collectingObject]];
SilDisplayUtils.PaintObject[model, dData.collectingObject, select, ctx];
SilDisplayCursors.InitiateNewSelection[data: data]; --notify SilDisplayCursorsImpl of reselection old rope
SilUserInput.NotInputingRope[uiData];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
InputingInputFileName, EditingExistingInputFileName,
InputingOutputFileName, EditingExistingOutputFileName,
InputingHardFileName, EditingExistingHardFileName => {
MessageWindow.Append["", TRUE];
dData.collectingFileName.length ← 0;
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
};
WaitingForKillConfirmation, WaitingForMacroDefConfirmation,
WaitingForMacroDeleteConfirmation => {
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
MessageWindow.Append["", TRUE];
};
ENDCASE;
};
FinishInput: PROC [data: SilData] = {
Perform the correct actions upon completion of string input. Correct responses can include the input or output of a file, the creation of a new Sil string object, or the confirmation of an action which needed to be performed (such as killing a file - if the file has been edited the user must confirm the kill. The confirmation is treated as string input).
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
lViewer: ViewerClasses.Viewer ← SilUserInput.GetBiScroller[uiData].QuaViewer[].parent;
This viewer is of Class = $Abutter and contains the BiScroller
SELECT dData.mode FROM
InputingInputFileName, EditingExistingInputFileName,
InputingOutputFileName, EditingExistingOutputFileName,
InputingHardFileName, EditingExistingHardFileName =>
IF dData.collectingFileName.length > 0 THEN {
tName: ROPE ← Rope.FromRefText[dData.collectingFileName];
SELECT dData.mode FROM
InputingInputFileName, EditingExistingInputFileName =>
SilDisplayUtils.InputNamedFile[data, tName, ctx];
InputingOutputFileName, EditingExistingOutputFileName => {
ViewerOps.SaveViewer[viewer ! SilKernel.SilError => GOTO Done;]; --save inner viewer
lViewer.newVersion ← lViewer.newFile ← FALSE; --Abutter
lViewer.child.newVersion ← lViewer.child.newFile ← FALSE; --ViewRec viewer
lViewer.child.sibling.newVersion ← lViewer.child.sibling.newFile ← FALSE; --BiScroller
lViewer.icon ← SilDisplay.GetIcon[dirtyIcon: FALSE];
EXITS
Done => NULL;
};
InputingHardFileName, EditingExistingHardFileName =>
TRUSTED { Process.Detach[FORK SilDisplayUtils.HardcopyFile[data, tName]];};
ENDCASE;
dData.collectingFileName.length ← 0;
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
IF NOT Rope.Equal[(tName ← SilFile.GetActiveFileName[data.model]), ""] THEN lViewer.name ← tName;
MessageWindow.Append[Rope.Cat["File: ", tName, " completed"], TRUE];
ViewerOps.PaintViewer[lViewer, caption];
}
ELSE MessageWindow.Append["", TRUE];
InputingRope, EditingExistingRope => IF dData.collectingText.length > 0 THEN {
mxMin, myMin, mxMax, myMax: INTEGER;
SilDisplayCursors.CheckSelectionWindow[data];
dData.collectingObject.value ← Rope.FromRefText[dData.collectingText];
[mxMin, myMin, mxMax, myMax] ← SilDisplayUtils.BoundingBoxOfObject[model, dData.collectingObject];
dData.collectingObject.xMax ← dData.collectingObject.xMin + mxMax - mxMin;
dData.collectingObject.yMax ← dData.collectingObject.yMin + myMax - myMin;
IF mxMax#0 AND myMax#0 THEN { --this is not an "empty" object
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, dData.collectingObject]];
SilDisplayUtils.PaintObject[model, dData.collectingObject, select, ctx];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
IF NOT dData.yLock THEN {
n: INTEGER ← (dData.collectingObject.yMax - dData.collectingObject.yMin) / dData.currentGridSpacing;
m: INTEGER ← (dData.collectingObject.yMax - dData.collectingObject.yMin) MOD dData.currentGridSpacing;
IF m # 0 THEN n ← n + 1;
dData.yInc ← n * dData.currentGridSpacing;
};
SilDisplayCursors.AquireAndDisableTheMark[data, ctx];
SilDisplayCursors.AquireAndDisableTheOrigin[data, ctx];
SilDisplayCursors.SetMarkY[dData.collectingObject.yMin + dData.yInc];
SilDisplayCursors.SetMarkX[dData.collectingObject.xMin];
SilDisplayCursors.SetOriginX[dData.collectingObject.xMin];
SilDisplayCursors.SetOriginY[dData.collectingObject.yMin];
dData.collectingText.length ← 0;
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
SilDisplayUtils.MarkFileAsEdited[data, ctx, lViewer];
};
WaitingForKillConfirmation => {
SilDisplayUtils.KillConfirmedFile[data, ctx, lViewer];
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
MessageWindow.Append["", TRUE];
};
WaitingForMacroDefConfirmation => { -- assert: don't have to scan bkgnd list here
FOR s: SilObject ← GetObjectList[model, fgnd], s.rest WHILE s # NIL DO
IF s.first.font = InternalFileMacroFont AND Rope.Fetch[s.first.value] = dData.macroDefName THEN
SilDisplayUtils.PaintObject[model, s.first, erase, ctx];
ENDLOOP;
SilDisplayUtils.DefineConfirmedMacro[data, dData.macroDefName, ctx];
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
MessageWindow.Append["", TRUE];
};
WaitingForMacroDeleteConfirmation => {
SilDisplayUtils.ClearConfirmedMacroDefs[data, ctx];
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
MessageWindow.Append["", TRUE];
};
ENDCASE;
};
finished: BOOL;
aborted: BOOL;
backedUp: BOOL;
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SELECT dData.mode FROM
WaitingToInputRope =>
IF args.c = Ascii.BS THEN {
IF NOT SilDisplayCursors.MarkAndSelectionInSameWindow[] THEN {
MessageWindow.Append["Mark and Selection must be in same window", TRUE];
MessageWindow.Blink[];
RETURN;}
ELSE {
sSel: SilSelection ← SilFile.GetSelection[];
Only edit text if only one object is selected and it is a rope.
IF sSel.objects # NIL AND sSel.objects.first.font IN SilFile.InternalRopeFonts AND
sSel.objects.first.selectObj = sSel.lastObject THEN {
dData.mode ← EditingExistingRope;
dData.collectingObject ← sSel.objects.first;
dData.oldText ← sSel.objects.first.value;
dData.collectingText ← Rope.ToRefText[sSel.objects.first.value];
SilDisplayCursors.DeleteAndEraseSelection[data: data, ctx: ctx, cache: FALSE];
aborted ← finished ← backedUp ← FALSE;
SilUserInput.InputingRope[data.uiData];
}
ELSE RETURN;
};
}
ELSE {
dData.mode ← InputingRope;
SilUserInput.InputingRope[data.uiData];
SilDisplayUtils.DeselectAndPaintAll[model, ctx];
dData.collectingObject.xMin ← SilDisplayCursors.GetMarkX[];
dData.collectingObject.yMin ← SilDisplayCursors.GetMarkY[];
dData.collectingObject.color ← dData.currentColor;
dData.collectingObject.font ← SilFile.InternalFontFromUserFont[dData.currentFont, dData.currentBoldState];
dData.collectingObject.italic ← dData.currentItalicState;
dData.collectingObject.value ← "";
dData.collectingText.length ← 0;
[dData.collectingText, finished, aborted, backedUp] ← SilDisplayUtils.EditText[dData.collectingText, args.c];
};
InputingRope, EditingExistingRope,
WaitingForKillConfirmation, WaitingForMacroDefConfirmation,
WaitingForMacroDeleteConfirmation =>
[dData.collectingText, finished, aborted, backedUp] ← SilDisplayUtils.EditText[dData.collectingText, args.c];
InputingInputFileName, EditingExistingInputFileName,
InputingOutputFileName, EditingExistingOutputFileName,
InputingHardFileName, EditingExistingHardFileName =>
[dData.collectingFileName, finished, aborted, backedUp] ← SilDisplayUtils.EditText[dData.collectingFileName, args.c];
ENDCASE;
SELECT TRUE FROM
NOT aborted AND NOT finished => SELECT dData.mode FROM
InputingRope, EditingExistingRope => {
IF backedUp THEN SilDisplayUtils.PaintObject[model, dData.collectingObject, erase, ctx];
dData.collectingObject.value ← Rope.FromRefText[dData.collectingText];
SilDisplayUtils.PaintObject[model, dData.collectingObject, show, ctx];
};
InputingInputFileName => {
MessageWindow.Append["Input file: ", TRUE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
EditingExistingInputFileName => {
dData.mode ← InputingInputFileName;
IF NOT backedUp THEN {
dData.collectingFileName[0] ←
dData.collectingFileName[dData.collectingFileName.length - 1];
dData.collectingFileName.length ← 1;
};
MessageWindow.Append["Input file: ", TRUE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
InputingOutputFileName => {
MessageWindow.Append["Output", TRUE];
IF dData.largeFormat THEN MessageWindow.Append[" Large Format", FALSE];
MessageWindow.Append[" file: ", FALSE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
EditingExistingOutputFileName => {
dData.mode ← InputingOutputFileName;
IF NOT backedUp THEN {
dData.collectingFileName[0] ←
dData.collectingFileName[dData.collectingFileName.length - 1];
dData.collectingFileName.length ← 1;
};
MessageWindow.Append["Output", TRUE];
IF dData.largeFormat THEN MessageWindow.Append[" Large Format", FALSE];
MessageWindow.Append[" file: ", FALSE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
InputingHardFileName => {
MessageWindow.Append["Hardcopy file: ", TRUE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
EditingExistingHardFileName => {
dData.mode ← InputingHardFileName;
IF NOT backedUp THEN {
dData.collectingFileName[0] ←
dData.collectingFileName[dData.collectingFileName.length - 1];
dData.collectingFileName.length ← 1;
};
MessageWindow.Append["Hardcopy file: ", TRUE];
MessageWindow.Append[Rope.FromRefText[dData.collectingFileName], FALSE];
};
ENDCASE;
aborted => AbortInput[data];
finished => FinishInput[data];
ENDCASE;
};
Compliment: PUBLIC PROC [args: UInputRec.Compliment, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[mode: CompMode];
If mode is tics, compliment the tics state (show them if they are not shown, and vice versa).
If mode is frames, compliment the frames state (show them if they are not shown, and vice versa).
If mode is magnification, compliment the magnification state (if not magnifying fill the screen with the area defined by the last 2 marks, else display the entire drawing).
If mode is oneLevel compliment the oneLevel flag, which controls the depth of macro expansion. If the oneLevel flag is TRUE, macros will not be expanded past one level, and if it is FALSE, all macros contained in an expanded macro will also be expanded. The state of the oneLevel flag is shown in the CommandLine field MX (Macro eXpand).
If mode is yInc, set (or clear, if it is set) the ylock flag. At the time ylock is set (changed from FALSE to TRUE by this command), the difference between the Y coordinates of the mark and the origin is saved as yinc (yIncrement is used when setting a caret relative.).
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
SilDisplayCursors.DisableRopeInput[data, ctx];
SELECT args.mode FROM
tics => {
IF dData.ticsOn THEN
SilDisplayUtils.DisplayGrid[erase, dData, model, ctx];
dData.ticsOn ← NOT dData.ticsOn;
IF dData.ticsOn THEN
SilDisplayUtils.DisplayGrid[show, dData, model, ctx];
};
frames => {
IF dData.framesOn THEN
SilDisplayUtils.DisplayFrames[erase, dData, model, ctx];
dData.framesOn ← NOT dData.framesOn;
IF dData.framesOn THEN
SilDisplayUtils.DisplayFrames[show, dData, model, ctx];
};
magnification => {
xMin, yMin, xMax, yMax: INTEGER;
legalBox: BOOL;
[legalBox, xMin, yMin, xMax, yMax] ← SilDisplayCursors.GetBoundingBoxOfLast2Marks[data];
IF NOT legalBox THEN RETURN;
SilDisplayUtils.MagnifyDrawing[data, ctx, xMin, yMin, xMax, yMax];
};
oneLevel =>
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: MacExpand, boolArg: NOT dData.currentOneLevel];
yInc => {
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Ylock, boolArg: NOT dData.yLock];
IF dData.yLock THEN {
n: INTEGER ← (SilDisplayCursors.GetOriginY[] - SilDisplayCursors.GetMarkY[]) / dData.currentGridSpacing;
m: INTEGER ← (SilDisplayCursors.GetOriginY[] - SilDisplayCursors.GetMarkY[]) MOD dData.currentGridSpacing;
IF m # 0 THEN n ← n + 1;
dData.yInc ← n * dData.currentGridSpacing;
};
};
ENDCASE;
};
ShowMacros: PUBLIC PROC [args: UInputRec.ShowMacros, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[char: CHAR];
Show all the macros currently defined in font.
model: SilModel ← data.model;
font: InternalMacroFonts;
fonts: REF TEXT;
SilDisplayCursors.DisableRopeInput[data, ctx];
Only show macros if char was macro font
SELECT args.char FROM
'4, '5, '6, '7, '8, '9 => font ← SilFile.InternalFontFromUserFont[args.char - '0, FALSE];
ENDCASE => {MessageWindow.Append["Illegal Macro Name.", TRUE];
MessageWindow.Blink;
RETURN;
};
MessageWindow.Append["Font ", TRUE];
MessageWindow.Append[Rope.FromChar[args.char], FALSE];
MessageWindow.Append[": ", FALSE];
fonts ← RefText.New[SilFile.MacroNameSize]; --Maximum number of macro names
FOR c: MacroName IN MacroName DO
IF SilFile.GetObjectList[model, macro, font, c] # NIL THEN
fonts ← RefText.AppendChar[fonts, c];
ENDLOOP;
MessageWindow.Append[Rope.FromRefText[fonts], FALSE];
};
Undelete: PUBLIC ENTRY PROC [args: UInputRec.Undelete, data: SilData, viewer: ViewerClasses.Viewer, ctx: Imager.Context] = {
[];
Undelete the last set of objects deleted by any previous operation. The newly undeleted object(s) will be THE current selection. A special case of Undo.
xMin, yMin, xMax, yMax: INTEGER;
sob: SilObject;
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SilDisplayCursors.DisableRopeInput[data, ctx];
SilDisplayUtils.PaintAllSelectedAsDeselected[model, ctx];
SilDisplayCursors.CheckSelectionWindow[data];
sob ← SilFile.Undelete[model];
[xMin, yMin, xMax, yMax] ← SilDisplayUtils.BoundingBoxOfContext[ctx];
SilDisplayUtils.MergeRebuild[dData, model, xMin, yMin, xMax, yMax, TRUE];
SilDisplayUtils.MarkFileAsEdited[data, ctx, viewer];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
};
END.
August 13, 1985 3:00:44 pm PDT: added ENTRY to all PROC declarations that call GetSelection, to avoid changing a selection while the process is computing. If this serializes multiple viewers badly, will change back.
Pier, December 18, 1985 5:36:49 pm PST
changes to: HandleInputChars no longer erases existing file names when editing begins