-- TEditEditingClassImpl.mesa Edited by McGregor on 14-Sep-81 11:06:19

DIRECTORY

  TextEdit USING [FetchChar, Offset, RefTextNode, Size],
  TextNode USING [FirstChild, LastChild, Location, NarrowToTextNode],
  TEditDocument USING [TEditDocumentData],
  TEditEditingClass,
  TEditInputOps USING [Delete, InsertChar],
  TEditSelection USING [MakeSelection, pSel, tSel],
  ViewerOps USING [PaintViewer],
  ViewerClasses USING [Viewer];
  
TEditEditingClassImpl: PROGRAM

IMPORTS TextEdit, TextNode, TEditInputOps, TEditSelection, ViewerOps
EXPORTS TEditEditingClass
SHARES TEditEditingClass =

BEGIN OPEN TEditEditingClass;

Insert: PUBLIC PROC [self: ViewerClasses.Viewer, char: CHARACTER ← 0C, insertion: REF ANY,
	adr: DocAdr ← NIL, repaint: BOOLEAN ← TRUE] =
	BEGIN OPEN TEditSelection;
	IF pSel.viewer#self OR pSel.start.pos#adr↑ OR pSel.insertion#before OR pSel.granularity#point
	    THEN BEGIN
		tSel.viewer ← self;
		tSel.insertion ← before;
		tSel.granularity ← point;
		tSel.start.pos ← tSel.end.pos ← adr↑;
		MakeSelection[primary, tSel];	-- finalised so that metrics are valid
		END;
	IF insertion # NIL THEN
	    FOR lst: LIST OF CHARACTER ← NARROW[insertion], lst.rest UNTIL lst = NIL DO
		TEditInputOps.InsertChar[lst.first];
		adr.where ← adr.where+1;
		ENDLOOP
	ELSE BEGIN
		TEditInputOps.InsertChar[char];
		adr.where ← adr.where+1;
		END;
	IF repaint THEN ViewerOps.PaintViewer[self];
	END;

Get: PUBLIC PROC [self: ViewerClasses.Viewer, from, to: DocAdr ← NIL,
	advanceAdr: BOOLEAN ← TRUE] RETURNS [REF ANY]= BEGIN
	lst: LIST OF CHARACTER ← NIL;
	IF to.node#from.node THEN ERROR;	-- not solving multi-node reads yet
	FOR i: TextEdit.Offset DECREASING IN [from.where..to.where) DO
		lst ← CONS[TextEdit.FetchChar[TextNode.NarrowToTextNode[from.node], i], lst];
		ENDLOOP;
	IF advanceAdr THEN from.where ← to.where;
	RETURN[lst];
	END;

Delete: PUBLIC PROC [self: ViewerClasses.Viewer, from, to: DocAdr ← NIL,
	repaint: BOOLEAN ← TRUE] = BEGIN OPEN TEditSelection;
	tSel.viewer ← self;
	tSel.start.pos ← from↑;
	tSel.insertion ← before;
	tSel.granularity ← char;
	tSel.end.pos ← IF to=NIL THEN from↑ ELSE [to.node, to.where-1];
	MakeSelection[primary, tSel];	-- finalised so that metrics are valid for Delete
	TEditInputOps.Delete[];
	IF repaint THEN ViewerOps.PaintViewer[self];
	-- no need to update fromAdr since virtual adr is unchanged
	END;

Bounds: PUBLIC PROC [self: ViewerClasses.Viewer] RETURNS [top, bottom: DocAdr] =
	BEGIN OPEN TextNode;
	tdd: TEditDocument.TEditDocumentData ← NARROW[self.data];
	firstChild: TextEdit.RefTextNode = NarrowToTextNode[FirstChild[tdd.text]];
	lastChild: TextEdit.RefTextNode = NarrowToTextNode[LastChild[tdd.text]];
	top ← NEW[TextNode.Location ← [firstChild, 0]];
	bottom ← NEW[TextNode.Location ← [lastChild, TextEdit.Size[lastChild]-1]];
	END;

CompareAdr: PUBLIC PROC [self: ViewerClasses.Viewer, adr1, adr2: DocAdr ← NIL]
	RETURNS [Comparison] = BEGIN
	RETURN[SELECT TRUE FROM
		adr1.node#adr2.node	=> notEqual,	-- not comparing nodes for now
		adr1.where=adr2.where	=> equal,
		adr1.where>adr2.where	=> greater,
		ENDCASE			=> less
		];
	END;

AssignAdr: PUBLIC PROC [self: ViewerClasses.Viewer, from, into: DocAdr ← NIL] = BEGIN
	into↑ ← from↑;
	END;

OutOfBoundsDocAdr: PUBLIC SIGNAL = CODE ;

MoveAdr: PUBLIC PROC [self: ViewerClasses.Viewer, n: LONG INTEGER, adr: DocAdr ← NIL] = BEGIN 
	adr.where ← adr.where+n;
	-- for now, assume addr must stay within the node
	IF adr.where<0 OR adr.where>TextEdit.Size[TextNode.NarrowToTextNode[adr.node]]
		THEN ERROR OutOfBoundsDocAdr;
	END;

NewAdr: PUBLIC PROC [self: ViewerClasses.Viewer, adr: DocAdr ← NIL] RETURNS [DocAdr] = BEGIN 
	newAdr: DocAdr ← NEW[TextNode.Location];
	AssignAdr[self, adr, newAdr];
	RETURN[newAdr];
	END;

END.