-- DisplayArrayImpl.mesa
-- last edit March 8, 1983 12:34 pm Sturgis
DIRECTORY
IO USING[PutChar, STREAM],
Matrix USING[AddColumnAt, AddRowAt, CreateMatrix, DeleteColumnAt, DeleteRowAt, GetColumnInfoAt, GetElementAt, GetRowInfoAt, Matrix, SetColumnInfoAt, SetElementAt, SetRowInfoAt],
StructureNodes USING[PrePaintPass, StructureNode, StructureNodeBody, StructureNodeProcs];
DisplayArrayImpl: PROGRAM IMPORTS IO, Matrix EXPORTS StructureNodes =
BEGIN OPEN IO, StructureNodes;
DisplayArray: TYPE = REF DisplayArrayBody;
DisplayArrayBody: PUBLIC TYPE = RECORD[
da: DisplayArray ← NIL, -- of enclosing context
dac: DACell ← NIL, -- of enclosing context
sn: StructureNode, -- of parallel structure code
nColumns, nRows: CARDINAL ← 0,
matrix: Matrix.Matrix,
containsDirtyElements: BOOLEAN ← TRUE];
ColHandle: TYPE = REF ColHandleBody;
ColHandleBody: PUBLIC TYPE = RECORD[
I: CARDINAL,
clientInfo: REF ANY ← NIL,
textSpace, textL, textA, textB, textR, textW: INTEGER ← 0,
screenSpace, screenL, screenA, screenB, screenR, screenW: INTEGER ← 0
];
RowHandle: TYPE = REF RowHandleBody;
RowHandleBody: PUBLIC TYPE = RECORD[
J: CARDINAL,
clientInfo: REF ANY ← NIL,
textLead, textHeight: INTEGER ← 0,
screenLead, screenHeight: INTEGER ← 0
];
DACell: TYPE = REF DACellBody;
DACellBody: PUBLIC TYPE = RECORD[
da: DisplayArray,
sn: StructureNode ← NIL,
info: REF ANY ← NIL,
colInfo: ColHandle,
rowInfo: RowHandle];
StructureNodeProcs: REF StructureNodes.StructureNodeProcs ← NEW[StructureNodes.StructureNodeProcs ← [CheckForDirtyDataDA, PreShowDA, ShowLineDA, PrePrePaintDA, PrePaintDA, PaintDA, UnPaintDA, NoteEnclosingCellDA, NoteCoordinatesDA, NIL, NIL, NIL, NIL, VerifyDA]];
-- exported, display array
CreateDisplayArray: PUBLIC PROCEDURE[sn: StructureNode] RETURNS[StructureNode, DisplayArray] =
BEGIN
da: DisplayArray ← NEW[DisplayArrayBody ← [sn: sn, matrix: Matrix.CreateMatrix[]]];
daSn: StructureNode ← NEW[StructureNodeBody ← [ref: da, procs: StructureNodeProcs]];
RETURN[daSn, da];
END;
AbandonDisplayArray: PUBLIC PROCEDURE[DisplayArray] =
BEGIN
END;
AddColumnAt: PUBLIC PROCEDURE[da: DisplayArray, I: CARDINAL] =
BEGIN
colInfo: ColHandle ← NEW[ColHandleBody ← [I: I]];
da.nColumns ← da.nColumns+1;
Matrix.AddColumnAt[da.matrix, I];
Matrix.SetColumnInfoAt[da.matrix, I, colInfo];
FOR II: CARDINAL IN [I+1..da.nColumns] DO
iiColInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, II]];
IF iiColInfo.I # II-1 THEN ERROR;
iiColInfo.I ← II;
ENDLOOP;
FOR J: CARDINAL IN [1..da.nRows] DO
jRowHandle: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
IF jRowHandle.J # J THEN ERROR;
Matrix.SetElementAt[da.matrix, I, J, NEW[DACellBody ← [da: da, colInfo: colInfo, rowInfo: jRowHandle]]];
ENDLOOP;
NotifyElements[da, I, 1];
da.containsDirtyElements ← TRUE;
END;
AddRowAt: PUBLIC PROCEDURE[da: DisplayArray, J: CARDINAL] =
BEGIN
rowInfo: RowHandle ← NEW[RowHandleBody ← [J: J]];
da.nRows ← da.nRows+1;
Matrix.AddRowAt[da.matrix, J];
Matrix.SetRowInfoAt[da.matrix, J, rowInfo];
FOR JJ: CARDINAL IN [J+1..da.nRows] DO
jjRowHandle: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, JJ]];
IF jjRowHandle.J # JJ-1 THEN ERROR;
jjRowHandle.J ← JJ;
ENDLOOP;
FOR I: CARDINAL IN [1..da.nColumns] DO
iColInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
IF iColInfo.I # I THEN ERROR;
Matrix.SetElementAt[da.matrix, I, J, NEW[DACellBody ← [da: da, colInfo: iColInfo, rowInfo: rowInfo]]];
ENDLOOP;
NotifyElements[da, 1, J];
da.containsDirtyElements ← TRUE;
END;
DeleteColumnAt: PUBLIC PROCEDURE[da: DisplayArray, I: CARDINAL] =
BEGIN
FOR J: CARDINAL IN [1..da.nRows] DO
jRowHandle: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF jRowHandle.J # J THEN ERROR;
IF cell.sn # NIL THEN cell.sn.procs.Abandon[cell.sn];
ENDLOOP;
Matrix.DeleteColumnAt[da.matrix, I];
da.nColumns ← da.nColumns-1;
FOR II: CARDINAL IN [I..da.nColumns] DO
iiColInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, II]];
IF iiColInfo.I # II+1 THEN ERROR;
iiColInfo.I ← II;
ENDLOOP;
NotifyElements[da, I, 1];
da.containsDirtyElements ← TRUE;
END;
DeleteRowAt: PUBLIC PROCEDURE[da: DisplayArray, J: CARDINAL] =
BEGIN
FOR I: CARDINAL IN [1..da.nColumns] DO
iColInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF iColInfo.I # I THEN ERROR;
IF cell.sn # NIL THEN cell.sn.procs.Abandon[cell.sn];
ENDLOOP;
Matrix.DeleteRowAt[da.matrix, J];
da.nRows ← da.nRows-1;
FOR JJ: CARDINAL IN [J..da.nRows] DO
jjRowHandle: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, JJ]];
IF jjRowHandle.J # JJ+1 THEN ERROR;
jjRowHandle.J ← JJ;
ENDLOOP;
NotifyElements[da, 1, J];
da.containsDirtyElements ← TRUE;
END;
SetElementAt: PUBLIC PROCEDURE[da: DisplayArray, I, J: CARDINAL, sn: StructureNode, info: REF ANY] =
BEGIN
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF cell.sn # NIL THEN cell.sn.procs.Abandon[cell.sn];
cell.sn ← sn;
cell.info ← info;
IF sn # NIL THEN sn.procs.NoteEnclosingCell[sn, cell];
IF sn # NIL THEN sn.procs.NoteCoordinates[sn, da, I, J];
da.containsDirtyElements ← TRUE;
END;
GetElementAt: PUBLIC PROCEDURE[da: DisplayArray, I, J: CARDINAL] RETURNS[StructureNode, REF ANY] =
BEGIN
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
RETURN[cell.sn, cell.info];
END;
SetRowInfoAt: PUBLIC PROCEDURE[da: DisplayArray, J: CARDINAL, info: REF ANY] RETURNS[RowHandle] =
BEGIN
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
rowInfo.clientInfo ← info;
da.containsDirtyElements ← TRUE;
RETURN[rowInfo]
END;
GetRowInfoAt: PUBLIC PROCEDURE[da: DisplayArray, J: CARDINAL] RETURNS[REF ANY] =
BEGIN
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
RETURN[rowInfo.clientInfo]
END;
GetRowNumber: PUBLIC PROCEDURE[rowInfo: RowHandle] RETURNS[CARDINAL] =
{RETURN[rowInfo.J]};
SetColInfoAt: PUBLIC PROCEDURE[da: DisplayArray, I: CARDINAL, info: REF ANY] RETURNS[ColHandle] =
BEGIN
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
colInfo.clientInfo ← info;
da.containsDirtyElements ← TRUE;
RETURN[colInfo];
END;
GetColInfoAt: PUBLIC PROCEDURE[da: DisplayArray, I: CARDINAL] RETURNS[REF ANY] =
BEGIN
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
RETURN[colInfo.clientInfo];
END;
GetColNumber: PUBLIC PROCEDURE[colInfo: ColHandle] RETURNS[CARDINAL] =
{RETURN[colInfo.I]};
MarkElementDirty: PUBLIC PROCEDURE[da: DisplayArray, I, J: CARDINAL] =
BEGIN
da.containsDirtyElements ← TRUE;
IF da.da # NIL THEN MarkElementDirty[da.da, 0, 0];
END;
GetContextDA: PUBLIC PROCEDURE[da: DisplayArray] RETURNS[StructureNode, --I-- CARDINAL, --J-- CARDINAL] =
BEGIN
IF da.dac # NIL THEN
BEGIN
cSn: StructureNode; cI, cJ: CARDINAL;
[cSn, cI, cJ, ] ← GetContextDACell[da.dac];
RETURN[cSn, cI, cJ]
END
ELSE RETURN[NIL, 0, 0];
END;
-- exported, DACell
GetContextDACell: PUBLIC PROCEDURE[dac: DACell] RETURNS[StructureNode, --I-- CARDINAL, --J-- CARDINAL, --contents of dac-- StructureNode] =
BEGIN
RETURN[dac.da.sn, dac.colInfo.I, dac.rowInfo.J, dac.sn];
END;
-- exported error
BadFormatLoadFile: PUBLIC ERROR = CODE;
-- support code
NotifyElements: PROCEDURE[da: DisplayArray, firstI, firstJ: CARDINAL] =
BEGIN
FOR I: CARDINAL IN [firstI..da.nColumns] DO
FOR J: CARDINAL IN [firstJ..da.nRows] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF cell.sn # NIL THEN cell.sn.procs.NoteCoordinates[cell.sn, da, I, J];
ENDLOOP;
ENDLOOP;
END;
-- Display Node Procs
CheckForDirtyDataDA: PROCEDURE[node: StructureNode] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
IF NOT da.containsDirtyElements THEN RETURN;
da.containsDirtyElements ← FALSE; -- allows subsequent calls to cause it to be set true.
FOR I: CARDINAL IN [1..da.nColumns] DO
FOR J: CARDINAL IN [1..da.nRows] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF cell.sn # NIL THEN cell.sn.procs.CheckForDirtyData[cell.sn];
ENDLOOP;
ENDLOOP;
END;
PreShowDA: PROCEDURE[node: StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
lead ← height ← space ← L ← A ← B ← R ← W ← 0;
FOR J: CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
rowInfo.textLead ← rowInfo.textHeight ← 0;
ENDLOOP;
FOR I: CARDINAL IN [1..da.nColumns] DO
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
colInfo.textSpace ← colInfo.textL ← colInfo.textA ← colInfo.textB ← colInfo.textR ← colInfo.textW ← 0;
FOR J: CARDINAL IN [1..da.nRows] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF cell.sn # NIL THEN
BEGIN
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
cellLead, cellHeight, cellSpace, cellL, cellA, cellB, cellR, cellW: INTEGER ← 0;
[cellLead, cellHeight, cellSpace, cellL, cellA, cellB, cellR, cellW] ←
cell.sn.procs.PreShow[cell.sn];
colInfo.textSpace ← MAX[colInfo.textSpace, cellSpace];
colInfo.textL ← MAX[colInfo.textL, cellL];
colInfo.textA ← MAX[colInfo.textA, cellA];
colInfo.textB ← MAX[colInfo.textB, cellB];
colInfo.textR ← MAX[colInfo.textR, cellR];
colInfo.textW ← MAX[colInfo.textW, cellW];
rowInfo.textLead ← MAX[rowInfo.textLead, cellLead];
rowInfo.textHeight ← MAX[rowInfo.textHeight, cellHeight];
END;
ENDLOOP;
colInfo.textW ← MAX[colInfo.textW, colInfo.textL + colInfo.textA, colInfo.textB + colInfo.textR];
W ← W + colInfo.textSpace + colInfo.textW;
ENDLOOP;
FOR J : CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
height ← height + rowInfo.textLead + rowInfo.textHeight;
ENDLOOP;
END;
ShowLineDA: PROCEDURE[node: StructureNode, L, R, W: INTEGER, lineX: INTEGER, to: STREAM] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
spaceAbove: INTEGER ← 0;
FOR J: CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
IF spaceAbove+rowInfo.textLead >= lineX THEN -- we are in the lead above row J
BEGIN
FOR I: INTEGER IN [1..W] DO
IO.PutChar[to, ' ];
ENDLOOP;
RETURN;
END
ELSE IF spaceAbove+rowInfo.textLead+rowInfo.textHeight >= lineX THEN -- we are in body of row J
BEGIN
FOR I: CARDINAL IN [1..da.nColumns] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
FOR xx: INTEGER IN [1..colInfo.textSpace] DO
IO.PutChar[to, ' ];
ENDLOOP;
IF cell.sn # NIL THEN cell.sn.procs.ShowLine[cell.sn, colInfo.textL, colInfo.textR, colInfo.textW, lineX-spaceAbove-rowInfo.textLead, to]
ELSE
FOR xx: INTEGER IN [1..colInfo.textW] DO
IO.PutChar[to, ' ];
ENDLOOP;
ENDLOOP;
RETURN;
END
ELSE -- we are not in row J
BEGIN
spaceAbove ← spaceAbove + rowInfo.textLead + rowInfo.textHeight;
END;
ENDLOOP;
-- we must be in a blank area below the array of cells
FOR I: INTEGER IN [1..W] DO
IO.PutChar[to, ' ];
ENDLOOP;
END;
PrePrePaintDA: PROCEDURE[node: StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
lead ← height ← space ← L ← A ← B ← R ← W ← 0;
FOR J: CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
rowInfo.screenLead ← rowInfo.screenHeight ← 0;
ENDLOOP;
FOR I: CARDINAL IN [1..da.nColumns] DO
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
colInfo.screenSpace ← colInfo.screenL ← colInfo.screenA ← colInfo.screenB ← colInfo.screenR ← colInfo.screenW ← 0;
FOR J: CARDINAL IN [1..da.nRows] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
IF cell.sn # NIL THEN
BEGIN
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
cellLead, cellHeight, cellSpace, cellL, cellA, cellB, cellR, cellW: INTEGER ← 0;
[cellLead, cellHeight, cellSpace, cellL, cellA, cellB, cellR, cellW] ←
cell.sn.procs.PrePrePaint[cell.sn];
colInfo.screenSpace ← MAX[colInfo.screenSpace, cellSpace];
colInfo.screenL ← MAX[colInfo.screenL, cellL];
colInfo.screenA ← MAX[colInfo.screenA, cellA];
colInfo.screenB ← MAX[colInfo.screenB, cellB];
colInfo.screenR ← MAX[colInfo.screenR, cellR];
colInfo.screenW ← MAX[colInfo.screenW, cellW];
rowInfo.screenLead ← MAX[rowInfo.screenLead, cellLead];
rowInfo.screenHeight ← MAX[rowInfo.screenHeight, cellHeight];
END;
ENDLOOP;
colInfo.screenW ← MAX[colInfo.screenW, colInfo.screenL + colInfo.screenA, colInfo.screenB + colInfo.screenR];
W ← W + colInfo.screenSpace + colInfo.screenW;
ENDLOOP;
FOR J : CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
height ← height + rowInfo.screenLead + rowInfo.screenHeight;
ENDLOOP;
END;
PrePaintDA: PROCEDURE[node: StructureNode, y, x, L, R, W: INTEGER, pass: PrePaintPass] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
colX: INTEGER ← x;
FOR I: CARDINAL IN [1..da.nColumns] DO
colInfo: ColHandle ← NARROW[Matrix.GetColumnInfoAt[da.matrix, I]];
rowY: INTEGER ← y;
colX ← colX + colInfo.screenSpace;
FOR J: CARDINAL IN [1..da.nRows] DO
rowInfo: RowHandle ← NARROW[Matrix.GetRowInfoAt[da.matrix, J]];
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
rowY ← rowY + rowInfo.screenLead;
IF cell.sn # NIL THEN cell.sn.procs.PrePaint[cell.sn, rowY, colX, colInfo.screenL, colInfo.screenR, colInfo.screenW, pass];
rowY ← rowY + rowInfo.screenHeight;
ENDLOOP;
colX ← colX + colInfo.screenW;
ENDLOOP;
END;
PaintDA: PROCEDURE[node: StructureNode, dirtyOnly: BOOLEAN] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
FOR J: CARDINAL IN [1..da.nRows] DO
FOR I: CARDINAL IN [1..da.nColumns] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
cell.sn.procs.Paint[cell.sn, dirtyOnly];
ENDLOOP;
ENDLOOP;
END;
UnPaintDA: PROCEDURE[node: StructureNode] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
FOR J: CARDINAL IN [1..da.nRows] DO
FOR I: CARDINAL IN [1..da.nColumns] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
cell.sn.procs.UnPaint[cell.sn];
ENDLOOP;
ENDLOOP;
END;
NoteEnclosingCellDA: PROCEDURE[node: StructureNode, dac: DACell] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
da.dac ← dac;
END;
NoteCoordinatesDA: PROCEDURE[node: StructureNode, da: DisplayArray, I, J: CARDINAL] =
BEGIN
selfDa: DisplayArray ← NARROW[node.ref];
selfDa.da ← da;
IF selfDa.containsDirtyElements THEN MarkElementDirty[selfDa.da, I, J];
END;
VerifyDA: PROCEDURE[node: StructureNode] =
BEGIN
da: DisplayArray ← NARROW[node.ref];
FOR J: CARDINAL IN [1..da.nRows] DO
FOR I: CARDINAL IN [1..da.nColumns] DO
cell: DACell ← NARROW[Matrix.GetElementAt[da.matrix, I, J]];
cell.sn.procs.Verify[cell.sn];
ENDLOOP;
ENDLOOP;
END;
-- assorted subroutines
END..
-- remark: September 26, 1982 5:42 pm: Started DisplayArrayImpl
RTE: October 1, 1982 2:42 pm: setElementAt may be called with NIL DisplayNode.
-- RTE: October 1, 1982 4:44 pm: PrePrePaint was calling PreShow.
-- change: October 2, 1982 4:38 pm: replace exported procedure which returns enclosing dacell with a procdure to try an act on the ln contained in a da cell, if this fails, then return the enclosing context.
-- RTE: October 2, 1982 5:45 pm: dacells contained nil in dac.da. The NEW action did not complain about no assignment to that field either.
-- change: October 3, 1982 1:16 pm: add new code for maintaining and returning context information. GetContextDA, GetContextDACell. Remove DOActDAC.
RTE: October 3, 1982 4:34 pm: ShowLineDA did not return after finding the line in question, but went on and printed al the rest of thelines.
change: October 10, 1982 2:29 pm: export BadFOrmatLoadFIle.
change: October 11, 1982 1:41 pm: PreShow and PrePrePaint did not take into account prefix space to left of column. Noticed while reading the code.
-- change: October 22, 1982 3:47 pm: inorder to support row and column summers, add Row and Column handles, also assorted row and column info routines, also Get Row/Column Number, given a Handle.
-- February 27, 1983 3:32 pm: convert to StructureNode from DisplayNode. February 27, 1983 3:46 pm: took about 15 minutes.
-- February 28, 1983 10:32 am: in order to allow selection mechanism to continue, modify GetContextDACell to also return the sn of the contents.
-- February 28, 1983 2:27 pm: add dummy NoteCoordinates procedure.
-- February 28, 1983 2:36 pm: add code to notify elements of their (changed) coordinates.
-- March 8, 1983 11:43 am: add Unpaint.
-- March 8, 1983 11:57 am: add logic for dirty data flags. Requires that all button routines set the dirty flag.
-- RTE: March 8, 1983 12:27 pm: dirty flag not propogated upward? perhaps due to setting local dirty flag when upwards da = NIL?
-- RTE: March 8, 1983 12:34 pm: must propogate dirty flag upward on call informing self of containing da.