Textarea, Undo

BlitzMax Forums/BlitzMax Beginners Area/Textarea, Undo

Crovean(Posted 2010) [#1]
Hello everyone.

I'm having big time trouble getting a Undo function to work correctly for a textarea...

If I type "This is a undo test" in the textarea and click "undo" from the menu, this is how it will look:

This is a undo testThis is a undo test
This is a undo tesThis is a undo test
This is a undo teThis is a undo test
This is a undo tThis is a undo test
This is a undo This is a undo test
This is a undThis is a undo test
This is a unThis is a undo test


...well, you get the picture. So, it somehow works but still it don't... :-)

CalculateDiff Method:
	Method CalculateDiff:TDiff(src:String)
		Local d:TDiff
		
		d = New TDiff
		
		' Store the new cursor position
		d.pos0	 = 	cursorpos
		d.count0	 = 	cursorlen
		
		' And the previous cursor position
		
		' The following works in most instances
		d.del		 = 	cleansrc[oldpos..oldpos + oldlen]
		d.add		 = 	src[oldpos..cursorpos + cursorlen]
		d.pos1	 = 	oldpos
		
		If src.length = cleansrc.length
			If cursorpos > oldpos
				d.del		 = 	cleansrc[oldpos..cursorpos]
				d.add		 = 	src[oldpos..cursorpos]
				d.pos1	 = 	oldpos
			ElseIf cursorpos < oldpos
				d.del		 = 	cleansrc[cursorpos..oldpos]
				d.add		 = 	src[cursorpos..oldpos]
				d.pos1	 = 	oldpos
			Else
			EndIf
		ElseIf cursorlen = 0 And cursorpos = oldpos
			d.del		 = 	cleansrc[cursorpos..cursorpos + cleansrc.length - src.length]
			d.add		 = 	""
		ElseIf cursorlen = 0 And cursorpos < oldpos
			d.del		 = 	cleansrc[cursorpos..cursorpos + cleansrc.length - src.length]
			d.add		 = 	""
			d.pos1	 = 	cursorpos
		EndIf
		
		If d.del.length = 0 And d.add.length = 0 d = Null
		Return d
	EndMethod


Undo Method:
	Method Undo()
		Local d:TDiff
		If Not undolist.isEmpty()
			
			' Take the diff out of the undo-list, and put it in the redo-list
			d = TDiff(undolist.RemoveLast() )
			redolist.AddLast d
			
			' Replace the added text (d.add) at the correct position (d.pos1) with the deleted text (d.del)
			SetTextAreaText textarea , d.del , d.pos1 , d.add.length
			
			' Move the cursor and select what was selected before
			SelectTextAreaText(textarea , d.pos , d.count)
			
			' Update the view
			SetDocument TextAreaText(textarea), d
			UpdateCursor
			UpdateDocument
		EndIf
	EndMethod


UpdateDocument Method:
	Method UpdateDocument(makeundo:Int = True)
		Local cpos:Int , src$
		Local d:TDiff
		
		src = TextAreaText(textarea)
		d = CalculateDiff(src)
		If d Then
			If makeundo Then
				AddToUndoList d
				redolist.clear
			EndIf
			SetDocument src , d
		Else
			SetDocument src
		EndIf
	EndMethod


SetDocument Method:
	Method SetDocument:Int(src$ , diff:TDiff = Null)
		Local result:Int = False
		
		Local p:Int , p1:Int
		Local cpos:Int , clen:Int
		
		CheckDirty src
		
		If src = cleansrc result = True
		
		If Not result Then
			cpos = TextAreaCursor(textarea , TEXTAREA_CHARS)
			clen = TextAreaSelLen(textarea)
		
			SelectTextAreaText textarea , cpos , clen , TEXTAREA_CHARS
		EndIf
				
		cleansrc = src
		Return result
	EndMethod