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