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