-- file: IntBoundaryCom.Mesa
-- edited by Brotz, May 3, 1982 5:32 PM
-- edited by Levin, October 24, 1979 4:08 PM
-- edited by Taft, May 16, 1983 10:26 AM

DIRECTORY
displayCommon USING [bitMapPtr, firstDCB, patchDCBPtr],
dsD: FROM "DisplayDefs" USING [BlackenRectangle, bmWidth, ClearRectangle, DCB,
DCBorg, DCBptr, lineHeight, longDcbSeal, machineFlavor,
MoveFullWidthRectangleVertically, PaintPicture, replace, ScreenYCoord,
xOrigin, yOrigin],
Editor USING [RefreshSoThatFirstCharStartsLine],
exD: FROM "ExceptionDefs" USING [SysBug],
inD: FROM "InteractorDefs" USING [BoundaryLineNbrPtr, BoundaryPadNbrPtr, CharIndex,
CommandNbrPtr, DisplayTOCTail, HousePtr, leftMargin, LinePair, LinePtr, LineState,
MessageTextNbrPtr, RegionPtr, RegionType, rightMargin, ScreenParametersArray,
ScreenYCoord, ThumbLineNbrPtr, TOCTextNbrPtr, UpdateTOCThumbLine],
Inline USING [LowHalf],
intCommon USING [cmCommandNbr, CMCommandRegion, CMRegion, cmTextNbr,
copyMenuSegment, dmcmBoundaryPadNbr, DMRegion, dmTextNbr, editorMenuState,
exceptionsRegion, findMenuSegment, getPutMenuSegment, linePoolPtr,
mailCommandRegion, numScanLines, regions, runMenuSegment, source,
substituteMenuSegment, TOCCommandRegion, tocdmBoundaryPadNbr, TOCRegion, tocTextNbr],
LaurelBitmapDefs USING [BitmapNotifyProc],
lmD: FROM "LaurelMenuDefs" USING [ReleaseMenu],
vmD: FROM "VirtualMgrDefs" USING [TOCHandle, UnlockTOC, WaitForLock];

IntBoundaryCom: PROGRAM
IMPORTS disC: displayCommon, dsD, Editor, exD, inD, Inline, intC: intCommon, lmD, vmD
EXPORTS inD, LaurelBitmapDefs =

BEGIN
OPEN inD;

bitmapNotifyProc: LaurelBitmapDefs.BitmapNotifyProc ← NIL;


MoveTOCDMBoundary: PUBLIC PROCEDURE [bnp: BoundaryPadNbrPtr, y: ScreenYCoord] =
-- Changes cursor to boundary-moving shape, tracks cursor anywhere on screen. While left
-- button is down do: Read curser y-position, compute new boundaries for TOC and DM
-- (not to go outside the area bounded by TOC top and DM bottom), call
-- SetNominalBufferPool to establish nominal number of pages for TOC and DM, call
-- ChangeTOCPosition and ChangeDMPosition to update screen. Returns when left button
-- goes up.
BEGIN
topAllowableY, bottomAllowableY, tocdmY, dmcmY: ScreenYCoord;
tocCommandHeight: CARDINAL =
intC.TOCCommandRegion.bottomY - intC.TOCCommandRegion.topY;
cmCommandHeight: CARDINAL =
intC.CMCommandRegion.bottomY - intC.CMCommandRegion.topY;
lineDeltaY: CARDINAL = dsD.yOrigin MOD dsD.lineHeight;

topAllowableY ← intC.tocTextNbr.topY;
bottomAllowableY ← intC.exceptionsRegion.topY - tocCommandHeight - cmCommandHeight;

tocdmY ← ((y - lineDeltaY) / dsD.lineHeight) * dsD.lineHeight + lineDeltaY;
tocdmY ← MIN[MAX[tocdmY, topAllowableY], bottomAllowableY];
IF tocdmY = bnp.topY THEN
{dsD.PaintPicture[bnp.leftX, bnp.topY, boundaryPad, dsD.replace]; RETURN};
dmcmY ← MAX[intC.CMCommandRegion.topY, tocdmY + tocCommandHeight];
AdjustBoundaries[tocdmY, dmcmY];
END; -- of MoveTOCDMBoundary --


MoveDMCMBoundary: PUBLIC PROCEDURE [bnp: BoundaryPadNbrPtr, y: ScreenYCoord] =
-- Changes cursor to boundary-moving shape, tracks cursor anywhere on screen. While left
-- button is down do: Read curser y-position, compute new boundaries for DM and CM
-- (not to go outside the area bounded by DM top and CM bottom), call
-- SetNominalBufferPool to establish nominal number of pages for DM and CM, call
-- ChangeDMPosition and ChangeCMPosition to update screen. Returns when left button
-- goes up.
BEGIN
topAllowableY, bottomAllowableY, tocdmY, dmcmY: ScreenYCoord;
tocCommandHeight: CARDINAL =
intC.TOCCommandRegion.bottomY - intC.TOCCommandRegion.topY;
cmCommandHeight: CARDINAL =
intC.CMCommandRegion.bottomY - intC.CMCommandRegion.topY;
lineDeltaY: CARDINAL = dsD.yOrigin MOD dsD.lineHeight;

topAllowableY ← intC.tocTextNbr.topY + tocCommandHeight;
bottomAllowableY ← intC.exceptionsRegion.topY - cmCommandHeight;

dmcmY ← ((y - lineDeltaY) / dsD.lineHeight) * dsD.lineHeight + lineDeltaY;
dmcmY ← MIN[MAX[dmcmY, topAllowableY], bottomAllowableY];
IF dmcmY = bnp.topY THEN
{dsD.PaintPicture[bnp.leftX, bnp.topY, boundaryPad, dsD.replace]; RETURN};
tocdmY ← MIN[intC.TOCCommandRegion.topY, dmcmY - tocCommandHeight];
AdjustBoundaries[tocdmY, dmcmY];
END; -- of MoveDMCMBoundary --


AdjustBoundaries: PUBLIC PROCEDURE [tocdmY, dmcmY: ScreenYCoord] =
-- Adjust screen so that the boundary pads will be at tocdmY and dmcmY.
BEGIN
dcb: dsD.DCBptr;
oldTocdmY: ScreenYCoord = intC.tocdmBoundaryPadNbr.topY;
oldDmcmY: ScreenYCoord = intC.dmcmBoundaryPadNbr.topY;
tocCommandHeight: CARDINAL =
intC.TOCCommandRegion.bottomY - intC.TOCCommandRegion.topY;
cmCommandHeight: CARDINAL =
intC.CMCommandRegion.bottomY - intC.CMCommandRegion.topY;
tocCommandLines: CARDINAL = tocCommandHeight / dsD.lineHeight;
cmCommandLines: CARDINAL = cmCommandHeight / dsD.lineHeight;
tocDeltaHeight: INTEGER = tocdmY - oldTocdmY;
cmDeltaHeight: INTEGER = oldDmcmY - dmcmY;
dmDeltaHeight: INTEGER = -(tocDeltaHeight + cmDeltaHeight);
tocDeltaLines: INTEGER = tocDeltaHeight / dsD.lineHeight;
cmDeltaLines: INTEGER = cmDeltaHeight / dsD.lineHeight;
dmDeltaLines: INTEGER = dmDeltaHeight / dsD.lineHeight;
IF oldTocdmY = tocdmY AND oldDmcmY = dmcmY THEN RETURN;

disC.patchDCBPtr↑ ← dsD.DCB
[next: intC.exceptionsRegion.dcb,
resolution: high,
background: intC.mailCommandRegion.dcb.background,
indenting: dsD.xOrigin / 16,
width: dsD.bmWidth,
bitmap: intC.TOCRegion.dcb.bitmap,
tag: intC.TOCRegion.dcb.tag,
height: (intC.exceptionsRegion.topY - intC.TOCRegion.topY) / 2,
longBitmap: intC.TOCRegion.dcb.longBitmap];
intC.mailCommandRegion.dcb.next ← disC.patchDCBPtr;
IF tocDeltaLines < 0 THEN
MoveRegion
[intC.TOCRegion, intC.TOCRegion.topY, intC.tocTextNbr.nLines + tocDeltaLines];
IF cmDeltaLines < 0 THEN
BEGIN
MoveRegion
[intC.CMRegion, intC.CMRegion.topY - cmDeltaHeight,
intC.cmTextNbr.nLines + cmDeltaLines];
MoveRegion[intC.CMCommandRegion, dmcmY, cmCommandLines];
END;
IF oldTocdmY > tocdmY THEN -- dm moving up
MoveRegion[intC.TOCCommandRegion, tocdmY, tocCommandLines];
MoveRegion
[intC.DMRegion, tocdmY + tocCommandHeight, intC.dmTextNbr.nLines + dmDeltaLines];
IF oldTocdmY < tocdmY THEN -- dm moving down
MoveRegion[intC.TOCCommandRegion, tocdmY, tocCommandLines];
IF tocDeltaLines > 0 THEN
MoveRegion
[intC.TOCRegion, intC.TOCRegion.topY, intC.tocTextNbr.nLines + tocDeltaLines];
IF cmDeltaLines > 0 THEN
BEGIN
MoveRegion[intC.CMCommandRegion, dmcmY, cmCommandLines];
MoveRegion
[intC.CMRegion, intC.CMRegion.topY - cmDeltaHeight,
intC.cmTextNbr.nLines + cmDeltaLines];
END;
-- Relink dcb’s taking into account that a zero height dcb doesn’t work right on the Alto.
dcb ← intC.exceptionsRegion.dcb;
IF intC.CMRegion.dcb.height > 0 THEN
{intC.CMRegion.dcb.next ← dcb; dcb ← intC.CMRegion.dcb};
IF intC.CMCommandRegion.dcb.height > 0 THEN
{intC.CMCommandRegion.dcb.next ← dcb; dcb ← intC.CMCommandRegion.dcb};
IF intC.DMRegion.dcb.height > 0 THEN
{intC.DMRegion.dcb.next ← dcb; dcb ← intC.DMRegion.dcb};
IF intC.TOCCommandRegion.dcb.height > 0 THEN
{intC.TOCCommandRegion.dcb.next ← dcb; dcb ← intC.TOCCommandRegion.dcb};
IF intC.TOCRegion.dcb.height > 0 THEN
{intC.TOCRegion.dcb.next ← dcb; dcb ← intC.TOCRegion.dcb};
intC.mailCommandRegion.dcb.next ← dcb;
IF bitmapNotifyProc # NIL THEN bitmapNotifyProc[];
END; -- of AdjustBoundaries --


SetScreenParameters: PUBLIC PROCEDURE [screenParameters: ScreenParametersArray] =
-- Sets all Y dependent parameters for the screen. Links DCB’s into the hardware display
-- chain.
BEGIN
rp: RegionPtr;
y: ScreenYCoord ← dsD.yOrigin;
totalLines: CARDINAL ← 0;
r: RegionType;

FOR r IN RegionType DO
totalLines ← totalLines + screenParameters[r];
ENDLOOP;
IF totalLines * dsD.lineHeight > intC.numScanLines THEN exD.SysBug[];

disC.firstDCB.height ← y/2;

FOR rp ← intC.regions, rp.nextRegion UNTIL rp = NIL DO
MoveRegion[rp, y, screenParameters[rp.regionType]];
y ← y + dsD.lineHeight * screenParameters[rp.regionType];
ENDLOOP;

dsD.DCBorg↑ ← disC.firstDCB;
END; -- of SetScreenParameters --


MoveRegion: PROCEDURE [rp: RegionPtr, topY: ScreenYCoord, nLines: CARDINAL] =
-- Sets all Y dependent parameters within a region. Sets DCB data for the region.
BEGIN
rp.topY ← topY;
rp.bottomY ← topY + nLines * dsD.lineHeight;
rp.dcb.bitmap ← IF dsD.machineFlavor # dmachine
THEN LOOPHOLE[Inline.LowHalf[disC.bitMapPtr] + (topY - dsD.yOrigin) * dsD.bmWidth, POINTER] ELSE dsD.longDcbSeal;
rp.dcb.tag ← IF dsD.machineFlavor # dmachine THEN short ELSE long;
rp.dcb.height ← nLines * dsD.lineHeight / 2;
rp.dcb.longBitmap ← disC.bitMapPtr + (topY - dsD.yOrigin) * dsD.bmWidth;
rp.dcb.width ← dsD.bmWidth;
rp.dcb.indenting ← dsD.xOrigin / 16;

SELECT rp.regionType FROM
mailCommandRegion =>
BEGIN
MoveCommandNbr[LOOPHOLE[rp.nbrs, CommandNbrPtr], topY, nLines - 1];
MoveThumbLineNbr[LOOPHOLE[rp.nbrs.nextNbr, ThumbLineNbrPtr],
topY + LOOPHOLE[nLines - 1, CARDINAL] * dsD.lineHeight,
IF nLines > 0 THEN 1 ELSE 0];
END;
tocCommandRegion, cmCommandRegion =>
BEGIN
MoveCommandNbr[LOOPHOLE[rp.nbrs.nextNbr.nextNbr, CommandNbrPtr],
topY + dsD.lineHeight, nLines - 2];
MoveBoundaryLineNbr
[LOOPHOLE[rp.nbrs, BoundaryLineNbrPtr], topY, IF nLines > 0 THEN 1 ELSE 0];
MoveBoundaryPadNbr[LOOPHOLE[rp.nbrs.nextNbr, BoundaryPadNbrPtr],
topY, IF nLines > 0 THEN 1 ELSE 0];
MoveThumbLineNbr[LOOPHOLE[rp.nbrs.nextNbr.nextNbr.nextNbr, ThumbLineNbrPtr],
topY + LOOPHOLE[nLines - 1, CARDINAL] * dsD.lineHeight,
IF nLines > 0 THEN 1 ELSE 0];
END;
tocRegion => MoveTOCTextNbr[LOOPHOLE[rp.nbrs, TOCTextNbrPtr], topY, nLines];
dmRegion, cmRegion =>
MoveMessageTextNbr[LOOPHOLE[rp.nbrs, MessageTextNbrPtr], topY, nLines];
exceptionsRegion =>
BEGIN
MoveMessageTextNbr
[LOOPHOLE[rp.nbrs.nextNbr, MessageTextNbrPtr], topY + dsD.lineHeight, nLines - 1];
MoveBoundaryLineNbr
[LOOPHOLE[rp.nbrs, BoundaryLineNbrPtr], topY, IF nLines > 0 THEN 1 ELSE 0];
END;
ENDCASE;
END; -- of MoveRegion --


MoveCommandNbr: PROCEDURE [cnp: CommandNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all Y position dependent parameters within a CommandNbr data structure.
BEGIN
oldNLines: CARDINAL ← cnp.nLines;
oldTopY: ScreenYCoord ← cnp.topY;
hp: HousePtr;

dsD.MoveFullWidthRectangleVertically
[top: oldTopY, bottom: oldTopY + dsD.lineHeight * MIN[oldNLines, nLines], newTop: topY];
cnp.topY ← topY;
cnp.bottomY ← topY + nLines * dsD.lineHeight;
cnp.nLines ← nLines;
FOR hp ← cnp.houses, hp.nextHouse UNTIL hp = NIL DO
hp.bottomY ← (hp.topY ← topY + hp.lineNumber * dsD.lineHeight) + dsD.lineHeight;
ENDLOOP;

IF nLines > oldNLines THEN
BEGIN
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, topY + oldNLines * dsD.lineHeight,
topY + nLines * dsD.lineHeight];
DisplayCommandTail[cnp: cnp, startLineNumber: MIN[oldNLines, nLines],
endLineNumber: nLines];
END;
END; -- of MoveCommandNbr --


DisplayCommandTail: PROCEDURE [cnp: CommandNbrPtr, startLineNumber,
endLineNumber: CARDINAL] =
-- Paints all houses of cnp whose line numbers are within
-- [startLineNumber .. endLineNumber).
BEGIN
hp: HousePtr;

FOR hp ← cnp.houses, hp.nextHouse UNTIL hp = NIL DO
IF hp.lineNumber IN [startLineNumber .. endLineNumber) THEN hp.houseRefresher[hp];
ENDLOOP;
END; -- of DisplayCommandTail --


MoveBoundaryLineNbr: PROCEDURE [bnp: BoundaryLineNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all Y position dependent parameters within a BoundaryLineNbr data structure.
BEGIN
bnp.topY ← topY + dsD.lineHeight/2 - 1;
bnp.bottomY ← IF nLines = 0 THEN 0 ELSE topY + dsD.lineHeight/2 + 1;
bnp.nLines ← nLines;
IF nLines > 0 THEN
BEGIN
dsD.ClearRectangle
[inD.leftMargin, inD.rightMargin, topY, topY + nLines * dsD.lineHeight];
dsD.BlackenRectangle[bnp.leftX, bnp.rightX, bnp.topY, bnp.bottomY];
END;
END; -- of MoveBoundaryLineNbr --


MoveBoundaryPadNbr: PROCEDURE [bnp: BoundaryPadNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all Y position dependent parameters within a BoundaryPadNbr data structure.
BEGIN
bnp.topY ← topY;
bnp.bottomY ← topY + nLines * dsD.lineHeight;
bnp.nLines ← nLines;
IF nLines > 0 THEN
BEGIN
dsD.ClearRectangle[bnp.leftX, bnp.rightX, bnp.topY, bnp.bottomY];
dsD.PaintPicture[bnp.leftX, bnp.topY, boundaryPad, dsD.replace];
END;
END; -- of MoveBoundaryPadNbr --


MoveThumbLineNbr: PROCEDURE [tlnp: ThumbLineNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all Y position dependent parameters within a ThumbLineNbr data structure.
BEGIN
tlnp.topY ← topY;
tlnp.bottomY ← topY + nLines * dsD.lineHeight;
tlnp.nLines ← nLines;
IF nLines > 0 THEN
BEGIN
dsD.ClearRectangle
[inD.leftMargin, inD.rightMargin, topY, topY + nLines * dsD.lineHeight];
dsD.BlackenRectangle[tlnp.leftX, tlnp.rightX, tlnp.topY+5, tlnp.topY+7];
END;
tlnp.exists ← FALSE;
tlnp.startX ← tlnp.endX ← tlnp.selectionX ← tlnp.leftX;
END; -- of MoveThumbPadNbr --


MoveTOCTextNbr: PROCEDURE [tnp: TOCTextNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all y dependent values for a TOCTextNbr based on topY and nLines. Increases or
-- decreases the number of lines held on the line chain according to the number of lines
-- held by the Nbr at entry and according to nLines. Moves Bitmap area to new
-- placement if necessary.
BEGIN
oldNLines: CARDINAL ← tnp.nLines;
oldTopY: ScreenYCoord ← tnp.topY;
oldFirstLineOffScreen: LinePtr ← tnp.firstLineOffScreen;
oldState: LineState ← oldFirstLineOffScreen.state;
oldLinePair: LinePair ← oldFirstLineOffScreen.linePair;
line: LinePtr;
y: ScreenYCoord;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL ← 0;
holdLock: BOOLEAN ← FALSE;

dsD.MoveFullWidthRectangleVertically
[top: oldTopY, bottom: oldTopY +dsD.lineHeight * MIN[oldNLines, nLines], newTop: topY];
tnp.topY ← y ← topY;
tnp.bottomY ← topY + nLines * dsD.lineHeight;
tnp.nLines ← nLines;
IF nLines >= oldNLines THEN
BEGIN
line ← oldFirstLineOffScreen;
line.nextLine ← intC.linePoolPtr;
THROUGH [1 .. nLines - oldNLines] DO
line ← line.nextLine;
line.state ← empty;
line.linePair ← oldLinePair;
ENDLOOP;
intC.linePoolPtr ← line.nextLine;
line.nextLine ← NIL;
tnp.firstLineOffScreen ← line;
END
ELSE BEGIN
line ← tnp.lines;
oldFirstLineOffScreen.nextLine ← intC.linePoolPtr;
THROUGH [1 .. nLines] DO
line ← line.nextLine;
ENDLOOP;
tnp.firstLineOffScreen ← line;
intC.linePoolPtr ← line.nextLine;
line.nextLine ← NIL;
END;
y ← topY;
FOR line ← tnp.lines, line.nextLine UNTIL line = NIL DO
line.y ← y;
y ← y + dsD.lineHeight;
ENDLOOP;
IF intC.source.key # 0 THEN key ← intC.source.key
ELSE IF toc#NIL THEN {key ← vmD.WaitForLock[toc]; holdLock ← TRUE};
IF nLines > oldNLines THEN
BEGIN
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, topY + oldNLines * dsD.lineHeight,
topY + nLines * dsD.lineHeight];
IF oldState # empty THEN
DisplayTOCTail
[tnp, key, oldFirstLineOffScreen, oldLinePair.index, oldLinePair.lineNumber];
END;
UpdateTOCThumbLine[tnp, key];
IF holdLock THEN vmD.UnlockTOC[toc, key];
END; -- of MoveTOCTextNbr --


MoveMessageTextNbr: PROCEDURE [mnp: MessageTextNbrPtr, topY: ScreenYCoord,
nLines: CARDINAL] =
-- Sets all y dependent values for a MessageTextNbr based on topY and nLines. Increases or
-- decreases the number of lines held on the line chain according to the number of lines
-- held by the Nbr at entry and according to nLines. Moves Bitmap area to new
-- placement if necessary.
BEGIN
oldNLines: CARDINAL ← mnp.nLines;
oldTopY: ScreenYCoord ← mnp.topY;
oldFirstLineOffScreen: LinePtr ← mnp.firstLineOffScreen;
oldState: LineState ← oldFirstLineOffScreen.state;
oldFirstCharIndex: CharIndex ← oldFirstLineOffScreen.firstCharIndex;
line: LinePtr;
y: ScreenYCoord;

dsD.MoveFullWidthRectangleVertically
[top: oldTopY, bottom: oldTopY +dsD.lineHeight * MIN[oldNLines, nLines], newTop: topY];
mnp.topY ← y ← topY;
mnp.bottomY ← topY + nLines * dsD.lineHeight;
mnp.nLines ← nLines;
IF nLines >= oldNLines THEN
BEGIN
line ← mnp.firstLineOffScreen;
line.nextLine ← intC.linePoolPtr;
THROUGH [1 .. nLines - oldNLines] DO
line ← line.nextLine;
line.state ← trailingBlankLine;
line.rightX ← inD.leftMargin;
line.firstCharIndex ← oldFirstCharIndex;
ENDLOOP;
intC.linePoolPtr ← line.nextLine;
line.nextLine ← NIL;
mnp.firstLineOffScreen ← line;
END
ELSE BEGIN
line ← mnp.lines;
mnp.firstLineOffScreen.nextLine ← intC.linePoolPtr;
THROUGH [1 .. nLines] DO
line ← line.nextLine;
ENDLOOP;
mnp.firstLineOffScreen ← line;
intC.linePoolPtr ← line.nextLine;
line.nextLine ← NIL;
END;
y ← topY;
FOR line ← mnp.lines, line.nextLine UNTIL line = NIL DO
line.y ← y;
y ← y + dsD.lineHeight;
ENDLOOP;
IF nLines > oldNLines THEN
BEGIN
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, topY + oldNLines * dsD.lineHeight,
topY + nLines * dsD.lineHeight];
IF oldState # trailingBlankLine THEN
Editor.RefreshSoThatFirstCharStartsLine[oldFirstCharIndex, oldFirstLineOffScreen, mnp];
END;
END; -- of MoveMessageTextNbr --


ChangeCommandMenu: PUBLIC PROCEDURE
[cnp: CommandNbrPtr, region: RegionPtr, linesToKeep: CARDINAL] =
-- The list of houses pointed to by cnp has changed. linesToKeep is the number of line of
-- the cnp that have not changed. Changes the menu on screen to display all houses now
-- in cnp’s houses list. Rearranges screen if necessary to accommodate changed command
-- neighborhood height.
BEGIN
nLines: CARDINAL ← 0;
prevDCB: dsD.DCBptr;
totalLinesForRegion: CARDINAL;
oldNLines, nLinesNeeded, nLinesToGrab, deltaY, nLinesOfNextRegion: CARDINAL;
h: HousePtr;
-- First, find out how many lines the new command nbr will cover.
FOR h ← cnp.houses, h.nextHouse UNTIL h = NIL DO
nLines ← MAX[nLines, h.lineNumber];
ENDLOOP;
nLines ← nLines + 1;
oldNLines ← cnp.nLines;
IF nLines > oldNLines THEN
BEGIN
-- If next lower region doesn’t have enough lines to spare, then adjust boundaries so
-- that it does.
nLinesNeeded ← nLines - oldNLines;
nLinesOfNextRegion ← region.nextRegion.nbrs.nLines;
IF nLinesOfNextRegion <= nLinesNeeded THEN
BEGIN
nLinesToGrab ← nLinesNeeded - nLinesOfNextRegion + 1;
deltaY ← nLinesToGrab * dsD.lineHeight;
SELECT region.regionType FROM
mailCommandRegion =>
MoveTOCDMBoundary
[bnp: intC.tocdmBoundaryPadNbr, y: intC.tocdmBoundaryPadNbr.topY + deltaY];
tocCommandRegion =>
IF intC.cmTextNbr.nLines > nLinesToGrab THEN
MoveDMCMBoundary
[bnp: intC.dmcmBoundaryPadNbr, y: intC.dmcmBoundaryPadNbr.topY + deltaY]
ELSE MoveTOCDMBoundary
[bnp: intC.tocdmBoundaryPadNbr, y: intC.tocdmBoundaryPadNbr.topY - deltaY];
cmCommandRegion =>
MoveDMCMBoundary
[bnp: intC.dmcmBoundaryPadNbr, y: intC.dmcmBoundaryPadNbr.topY - deltaY];
ENDCASE => ERROR;
END;
END;
cnp.nLines ← linesToKeep;
IF oldNLines = nLines THEN
{MoveCommandNbr[cnp: cnp, topY: cnp.topY, nLines: nLines]; RETURN};
-- In the following cases, regions will change heights. Since DCB’s will be adjusted,
-- patch in a dummy DCB to keep the screen tidy.
disC.patchDCBPtr↑ ← dsD.DCB
[next: region.nextRegion.nextRegion.dcb,
resolution: high,
background: intC.exceptionsRegion.dcb.background,
indenting: dsD.xOrigin / 16,
width: dsD.bmWidth,
bitmap: region.dcb.bitmap,
tag: region.dcb.tag,
height: region.dcb.height + region.nextRegion.dcb.height,
longBitmap: region.dcb.longBitmap];
totalLinesForRegion ← nLines + 2;
SELECT region.regionType FROM
mailCommandRegion => {prevDCB ← disC.firstDCB; totalLinesForRegion ← nLines + 1};
tocCommandRegion => prevDCB ← intC.TOCRegion.dcb;
cmCommandRegion => prevDCB ← intC.DMRegion.dcb;
ENDCASE => ERROR;
prevDCB.next ← disC.patchDCBPtr;
IF nLines > oldNLines THEN
-- command nbr will get bigger. Take from next lower region.
BEGIN
MoveRegion[region.nextRegion, region.nextRegion.topY + nLinesNeeded * dsD.lineHeight,
region.nextRegion.nbrs.nLines - nLinesNeeded];
MoveRegion[region, region.topY, totalLinesForRegion];
END
ELSE -- command nbr will get smaller. Add to next lower region.
BEGIN
MoveRegion[region, region.topY, totalLinesForRegion];
MoveRegion
[region.nextRegion, region.bottomY, region.nextRegion.nbrs.nLines + oldNLines - nLines];
-- The next Region may have been 0 lines, thus its dcb was not linked in.
-- the following links it in in any case.
region.dcb.next ← region.nextRegion.dcb;
END;
prevDCB.next ← region.dcb;
IF cnp = intC.cmCommandNbr THEN
BEGIN
SELECT intC.editorMenuState FROM
singleLine => NULL;
getPut => lmD.ReleaseMenu[intC.getPutMenuSegment];
run => lmD.ReleaseMenu[intC.runMenuSegment];
find => lmD.ReleaseMenu[intC.findMenuSegment];
substitute => lmD.ReleaseMenu[intC.substituteMenuSegment];
copy => lmD.ReleaseMenu[intC.copyMenuSegment];
ENDCASE => exD.SysBug[];
intC.editorMenuState ← singleLine;
END;
IF bitmapNotifyProc # NIL THEN bitmapNotifyProc[];
END; -- of ChangeCommandMenu --


NullCommand: PUBLIC PROCEDURE [hp: POINTER, confirmed: BOOLEAN] =
-- Does nothing. Purely a placeholder for information houses and boundaryLine
-- neighborhoods.
BEGIN
END; -- of NullCommand --


DestroyDM: PUBLIC PROCEDURE =
-- Clears the displayed message area on the Laurel screen and makes Laurel
-- believe that no displayed message exists.
BEGIN
dm: MessageTextNbrPtr ← intC.dmTextNbr;
dm.haveMessage ← FALSE;
dsD.ClearRectangle[leftMargin, rightMargin, dm.topY, dm.bottomY];
END; -- of DestroyDM --


DestroyTOC: PUBLIC PROCEDURE =
-- Clears the table of contents area on the Laurel screen and makes Laurel
-- believe that no table of contents exists.
BEGIN
tnp: TOCTextNbrPtr ← intC.tocTextNbr;
dsD.ClearRectangle[leftMargin, rightMargin, tnp.topY, tnp.bottomY];
END; -- of DestroyTOC --


DMBitmapLocation: PUBLIC PROCEDURE RETURNS
[base: LONG POINTER, wordsPerLine, bitsX, bitsY: CARDINAL] =
-- Returns the location of the bitmap in the displayed message area of the
-- Laurel screen.
BEGIN
dmDcb: dsD.DCBptr ← intC.DMRegion.dcb;
RETURN[dmDcb.longBitmap, dsD.bmWidth, dsD.bmWidth * 16,
dmDcb.height * 2];
END; -- of DMBitmapLocation --


TOCBitmapLocation: PUBLIC PROCEDURE RETURNS
[base: LONG POINTER, wordsPerLine, bitsX, bitsY: CARDINAL] =
-- Returns the location of the bitmap in the table of contents area of the
-- Laurel screen.
BEGIN
tocDcb: dsD.DCBptr ← intC.TOCRegion.dcb;
RETURN[tocDcb.longBitmap, dsD.bmWidth, dsD.bmWidth * 16,
tocDcb.height * 2];
END; -- of TOCBitmapLocation --


SetBitmapNotifyProc: PUBLIC PROCEDURE [p: LaurelBitmapDefs.BitmapNotifyProc] =
{bitmapNotifyProc ← p};

END. -- of IntBoundaryCom --