New Lexer:
;Title: TreeViewX
;		TreeViewX  extends standard TreeView control to support moving, deleting & inserting.

;----------------------------------------------------------------------------------------
; Function: TVX
;			Initialisation function. Mandatory to call before you show the TreeView.
; 
; Parameters:
;			pTree		- AHK name of the TreeView control
;			pSub		- Subroutine for TreeViewX, the same rules as in g.
;			pOptions	- String containing space delimited options for setting up TreeViewX
;			pUserData	- Base name of the array holding user data. 
;						  This array is indexed using tree view item handles.
;			
; Options: 
;			HasRoot		- TreeViewX has root item - the one containing all other items. 
;						  Root item can't be moved, edited or delited, and items can not
;						  be moved or created outside of it. This option need to be set 
;						  after root is already added to the menu, as TreeViewX need to
;						  know the root menu handle.
;						  
;		CollapseOnMove	- When moving item out of of its container, this option makes container collapse
;		EditOnInsert	- Automaticaly enters edit mode upon insertion of new item
;
; Example:
;>
;>	 	TVX("MyTree", "Handler", "HasRoot CollapseOnMove")
;>
TVX( pTree, pSub, pOptions="", pUserData="" ) {
	global

	if InStr(pOptions, "HasRoot")	{
		TVX_HasRoot  := 1
		TVX_root := TV_GetNext()
	}
	
	if InStr(pOptions, "CollapseOnMove")
	  	TVX_CollapseOnMove := 1

	if InStr(pOptions, "EditOnInsert")
		TVX_EditOnInsert	:= 	1

	TVX_userData := pUserData
	TVX_sub := pSub
	GuiControl, +AltSubmit -ReadOnly +gTVX_OnEvent, %pTree%

}

;----------------------------------------------------------------------------------------
; Function: Walk
;			Walk the menu and rise events
; 
; Parameters:
;			root		- menu to iterate, can be simple item also
;			label		- event handler
;			event_type	- event argument 1 - Event type
;			event_param	- event argument 2 - Item upon which event is rised
;			
;
;				   Type						  Param
;
;			+  - Iteration start,			root handle
;			M  - Menu item,					menu handle 
;			I  - Item,						item handle
;			E  - End of menu				menu handle			(pseudo item)
;			-  - Iteration end				root handle			(pseudo item)
;
TVX_Walk(root, label, ByRef event_type, ByRef event_param){
	local n, t, p, c,	pref, bSetEnd, lastParent, rootsParent, tmp

	; start event for menus
	event_type := "+"
	event_param := root
	GoSub %label%

		if !TV_GetChild(root)
		return
	
	; this will be exit condition. If we come to roots parent, stop walking.
	rootsParent := TV_GetParent(root)
	
	lastParent := root
	c := root
	loop {
			c := TV_GetNext(c, "Full")
		TV_GetText(tmp, c)

		; Check if this item is submenu. If so, set the lastParent
		if ( TV_GetChild(c) ){	
			lastParent := c
			event_type := "M"
		}
		else event_type := "I"			; not a submenu, it is normal item

			event_param := c
		GoSub %label%		
	

		; Check if c is the last item in the current submenu
			; Do so by taking the next item and checking its parent.
		; If the parent is different then "lastParent" current item is 
		;  at the end of the its submenu. 
		n := TV_GetNext(c, "FULL")
		if (n)
		{
			p := TV_GetParent(n)
			if ( p != lastParent){	
				t := lastParent
				lastParent := p
			}
			else continue

				; It is the last child
			Loop {	; rise "E" (end of menu) event 
					event_type := "E"
				event_param := t
				GoSub %label%

					t := TV_GetParent(t)
				if (t = rootsParent) {	; rise "-" (end of walk) event
					event_type := "-"
					event_param := t
					GoSub %label%
						return
				}
				if (p = t)
					break
				}

		} else 
			Loop {
				  ;this is the end of the complite menu, so close all open submenus, if any
				 if (lastParent = root)	 {
					event_type := "-" 
					event_param := root
					GoSub %label%
						return
				 }
				
				 event_type := "E"
				 event_param := lastParent
				 GoSub %label%
				  lastParent := TV_GetParent(lastParent)
			}	
	}
}

;----------------------------------------------------------------------------------------------
; Function:		Move
;				Moves tree view item up or down
;
; Parameters:
;				item		-	Handle of the item to move
;				direction	-   "u" or "d" (Up & Down)
;
; Returns:
;				Handle of the item
;
; Remarks:
;				Item to be moved is copied to the new place then source item is deleted. This
;				creates new handle for the moved item. New handle will be returned by the function.
;
TVX_Move(item, direction){
	local newc, newp, t, p, n

	p := TV_GetPrev(item)
	n := TV_GetNext(item)

	if (TVX_HasRoot)
	{
		 if	TV_GetNext()=item
				return

		 if (direction="u")
		 {
			 if (p = 0 && TV_GetParent(item)=TV_GetNext())			;don't let item go above root
			 {
				TV_Modify(item)
				TVX_sel:=item
				return
			 }
		 }
	 }


	; Do so by coping an item bellow calculated item and deleting the old one.
	; Return handle of new item
 	
	; newc - calculated child after which "item" should be created. 
	; newp -  ... and its parent

	; if moving down
	if (direction = "d")
	{
		; handle end of submenu
		if !n
		{
			newc := TV_GetParent(item)

			; check the end of the entire list
			if (TVX_HasRoot && newc = TVX_root)
				return

			if TVX_CollapseOnMove
				TV_Modify(newc, "-Expand")

			newp := TV_GetParent(newc)
		}
		; somewhere in the middle 
		else 
		{
   				; if submenu, go into it
			t := TV_Get(n, "E")
			if (t = n)
			{
				newp := n
				newc := "First"
			}
			; not a submenu
			else
				{
				newc := n
				newp := TV_GetParent(n)
			}    
		}
	}

	; if moving up
	if (direction = "u")
	{
		;going up - handle start of the submenu
		if !p
		{
			t := TV_GetParent(item)
			if TVX_CollapseOnMove
				TV_Modify(t, "-Expand")
																					  
			newc := TV_GetPrev(t)
																											  
			; handle start of the menu again
			if !newc
			{
				newp := TV_GetParent(t)
				newc := "First"
			}
			else
					newp := TV_GetParent(newc)
		}
		; somewhere in the middle
		else
			{
   			; if submenu is expanded, go into it
			t := TV_Get(p, "E")
			if (t = p)
			{
				newc := "First"
				newp := t
			}
			else
				{
				t := TV_GetPrev(p)
				;check the top of the list
				if !t
				{
					newc := "First"
					newp := TV_GetParent(p)				
				}
				else 
				{
						newc := t
					newp := TV_GetParent(newc)
				}
			}
		}
	}

	newc := TVX_CopyItem(newc, newp, item)
	TV_Delete(item)
	return newc
}


;---------------------------------------------------------------------------------------------
; TVX_Walk event handler wrapped in the function
;	
; Function that copies menu item to the destination item. 
; Handle of destination item is specified in the global variable TVX_copyDest.
; 
TVX_CopyProc(iType, item) {
	local c, txt
	static lastParent
	
	TV_GetText(txt, item)
	if iType in +
	{
		lastParent := TVX_copyDest
		TV_Modify(TVX_copyDest, "", txt)
		
		if TVX_userData
		{
			%TVX_userData%%TVX_copyDest% := %TVX_userData%%item%
			%TVX_userData%%item% := ""
		}
	}

	if iType in I,M
	{
		c := TV_Add(txt, lastParent)
		if iType = M
			lastParent := c

		if TVX_userData
		{
			%TVX_userData%%c% := %TVX_userData%%item%
			%TVX_userData%%item% := ""
		}
	}

	if iType = E
		lastParent := TV_GetParent(lastParent)	
}

;----------------------------------------------

_TVX_CopyProc:
	TVX_CopyProc(TVX_itemType, TVX_param)
return

;-----------------------------------------------------------------------------------------------
; Create new item after the child "destc" with parent "destp" and copy the "source" item into it
;
TVX_CopyItem(destc, destp, source){
	global 

	;create the holder and call the copy function
	TVX_copyDest := TV_Add("", destp , destc )
	TVX_Walk(source, "_TVX_CopyProc", TVX_itemType, TVX_param)

	return TVX_copyDest
}

;----------------------------------------------------------------------------------------------
; Used to control moving
;
TVX_OnItemSelect(pItemId){
	global

	if (TVX_bSelfSelect)	{	
		TVX_bSelfSelect := false
		return true
	}	

	TVX_prevSel := TVX_sel
	TVX_sel := pItemId

	if GetKeyState("Shift") && (TVX_lastKey=38 || TVX_lastKey=40)
	 if (pItemId != TVX_root)
	 {
	  	TVX_sel := TVX_Move( TVX_prevSel, TVX_lastKey=40 ? "d" : "u")
		TVX_prevSel := pItemId

		
		TVX_bSelfSelect := true
		TV_Modify(TVX_sel, "Select Bold")
		return true
	 }

	 return false
}

;----------------------------------------------------------------------------------------------

TVX_OnKeyPress(pKey){
	local tp, sel

	TVX_lastKey := pKey

	if (TVX_bSelfPress)	{	
		TVX_bSelfPress := false
		return true
	}	

	;delete
	if pKey = 46
	{
		; use GetSelection instead Editor_sel since if key is pressed and hold
		; TVX_OnSelect handler may not be called before delete to set the TVX_sel

		sel := TV_GetSelection()
		if (TVX_HasRoot && sel = TVX_root)
			return false

		; is shift delete is pressed return - some problems with this combination
		if (GetKeyState("Shift"))
			return false

		TV_Delete(sel)
		return true
	}

	;insert
	if pKey = 45
	{
		tp := TV_GetParent(TVX_sel)
		if (TVX_sel = TVX_root)
			tp := TVX_root

		tp := TV_Add("__ new item __", tp, "Bold " . TVX_sel)
		if GetKeyState("Shift")
		{
			TV_Add("__ new item __", tp, "Bold First ")
			TV_Modify(tp,"Expand", "__ new group __")
		}

		if (TVX_EditOnInsert)
		{
			TVX_bSelfPress := TVX_bSelfSelect := true
			TV_Modify(tp, "Select")
			Send, {F2}
			}

		return true
	}

	return false
}

;----------------------------------------------------------------------------------------------
; g soubroutine for Tree View
;
TVX_OnEvent:
	if (A_GuiEvent="S")
		if TVX_OnItemSelect(A_EventInfo)
			return

	if (A_GuiEvent="K")
		if TVX_OnKeyPress(A_EventInfo)
			return
	
	;if not the Xtended property send event to the caller
	gosub %TVX_sub%

return