-- 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.