#include-once

; #INDEX# ============================================================================================================
; Title .........: GUIListViewEx
; AutoIt Version : 3.3.10 +
; Language ......: English
; Description ...: Permits insertion, deletion, moving, dragging, sorting, editing and colouring of items within ListViews
; Remarks .......: - It is important to use _GUIListViewEx_Close when a enabled ListView is deleted to free the memory used
;                    by the $aGLVEx_Data array which shadows the ListView contents.
;                  - Windows message handlers required:
;                     - WM_NOTIFY: All UDF functions
;                     - WM_MOUSEMOVE and WM_LBUTTONUP: Only needed if dragging
;                     - WM_SYSCOMMAND: Permits [X] GUI closure while editing
;                  - If the script already has WM_NOTIFY, WM_MOUSEMOVE, WM_LBUTTONUP or WM_SYSCOMMAND handlers then only set
;                    unregistered messages in _GUIListViewEx_MsgRegister and call the relevant _GUIListViewEx_WM_#####_Handler
;                    from within the existing handler
;                  - Uses 2 undocumented functions within GUIListView UDF to set and colour insert mark (thanks rover)
;                  - Enabling user colours significantly slows ListView redrawing
; Author ........: Melba23
; Credits .......: martin (basic drag code), Array.au3 authors (array functions), KaFu and ProgAndy (font function)
;                  LarsJ (colouring code)
; ====================================================================================================================

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7

; #INCLUDES# =========================================================================================================
#include <GuiListView.au3>
#include <GUIImageList.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Array to hold registered ListView data
Global $aGLVEx_Data[1][26] = [[0, 0, -1, "", -1, -1, -1, -1, _WinAPI_GetSystemMetrics(2), False, -1, -1, False, "", 0, True, 0, -1, -1, 0, 0, 0, 0, "08"]]
; [0][0]  = ListView Count      [n][0]  = ListView handle
; [0][1]  = Active Index        [n][1]  = Native ListView ControlID / 0
; [0][2]  = Active Column       [n][2]  = Shadow array
; [0][3]  = Row Depth           [n][3]  = Shadow array count element (0/1) & 2D return (+ 2)
; [0][4]  = Curr ToolTip Row    [n][4]  = Sort status
; [0][5]  = Curr ToolTip Col    [n][5]  = Drag image flag
; [0][6]  = Prev ToolTip Row    [n][6]  = Checkbox array flag
; [0][7]  = Prev ToolTip Col    [n][7]  = Editable columns data
; [0][8]  = VScrollbar width    [n][8]  = Editable header flag
; [0][9]  = SysClose flag       [n][9]  = Continue edit on click flag
; [0][10] = RtClick Row         [n][10] = Item depth for scrolling
; [0][11] = RtClick Col         [n][11] = Do not "select all" on edit flag
; [0][12] = Colour Handler Flag [n][12] = External dragdrop flag
; [0][13] = Active Colour Array [n][13] = Header drag style flag
; [0][14] = Curr Redraw Handle  [n][14] = Edit width array
; [0][15] = Allow Redraw Flag   [n][15] = ToolTip column range
; [0][16] = KeyCode             [n][16] = ToolTip display time
; [0][17] = Active Row          [n][17] = ToolTip mode
; [0][18] = Active Column       [n][18] = Colour array
; [0][19] = Sort Flag           [n][19] - Colour flag
; [0][20] = Curr header handle  [n][20] - Active row
; [0][21] = Curr header font    [n][21] - Active column
; [0][22] = Colour redraw flag  [n][22] - Single cell flag
; [0][23] = Start edit keycode  [n][23] - Default user colours
; [0][24] = Separator char      [n][24] - Header handle
;                               [n][25] - Header data array

; Variables for UDF handlers
Global $hGLVEx_SrcHandle, $cGLVEx_SrcID, $iGLVEx_SrcIndex, $aGLVEx_SrcArray, $aGLVEx_SrcColArray
Global $hGLVEx_TgtHandle, $cGLVEx_TgtID, $iGLVEx_TgtIndex, $aGLVEx_TgtArray, $aGLVEx_TgtColArray
Global $iGLVEx_Dragging = 0, $iGLVEx_DraggedIndex, $hGLVEx_DraggedImage = 0, $sGLVEx_DragEvent
Global $iGLVEx_InsertIndex = -1, $iGLVEx_LastY, $fGLVEx_BarUnder
; Variables for UDF edit
Global $hGLVEx_Editing, $cGLVEx_EditID = 9999, $fGLVEx_EditClickFlag = 0, $fGLVEx_HeaderEdit = False
; Predefined user colours [Normal text, normal field, selected cell text, selected cell field] - BGR
Global $aGLVEx_DefColours[4] = ["0x000000", "0xFEFEFE", "0xFFFFFF", "0xCC6600"]

; #CURRENT# ==========================================================================================================
; _GUIListViewEx_Init:                  Enables UDF functions for the ListView and sets various flags
; _GUIListViewEx_Close:                 Disables all UDF functions for the specified ListView and clears all memory used
; _GUIListViewEx_SetActive:             Set specified ListView as active for UDF functions
; _GUIListViewEx_GetActive:             Get index number of active ListView for UDF functions
; _GUIListViewEx_ReadToArray:           Creates an array from the current ListView content to be loaded in _Init function
; _GUIListViewEx_ReturnArray:           Returns an array of the current content, checkbox state, colour of the ListView
; _GUIListViewEx_SaveListView:          Saves ListView headers, content, checkbox state, colour data to file
; _GUIListViewEx_LoadListView:          Loads ListView headers, content, checkbox state, colour data from file
; _GUIListViewEx_Up:                    Moves selected row(s) in active ListView up 1 row
; _GUIListViewEx_Down:                  Moves selected row(s) in active ListView down 1 row
; _GUIListViewEx_Insert:                Inserts data in row below selected row in active ListView
; _GUIListViewEx_InsertSpec:            Inserts data in specified row in specified ListView
; _GUIListViewEx_Delete:                Deletes selected row(s) in active ListView
; _GUIListViewEx_DeleteSpec:            Deletes specified row(s) in specified ListView
; _GUIListViewEx_InsertCol:             Inserts blank column to right of selected column in active ListView
; _GUIListViewEx_InsertColSpec:         Inserts specified blank column in specified ListView
; _GUIListViewEx_DeleteCol:             Deletes selected column in active ListView
; _GUIListViewEx_DeleteColSpec:         Deletes specified column in specified ListView
; _GUIListViewEx_SortCol:               Sort specified column in specified ListView
; _GUIListViewEx_SetEditStatus:         Sets edit on doubleclick mode for specified column(s)
; _GUIListViewEx_SetEditKey:            Sets key(s) required to begin edit of selected item
; _GUIListViewEx_EditOnClick:           Allow content of editable ListView items to be modified when doubleclicked
; _GUIListViewEx_EditItem:              Manual edit of specified ListView item
; _GUIListViewEx_EditWidth:             Set required widths for column edit/combo when editing
; _GUIListViewEx_ChangeItem:            Programatic change of specified ListView item
; _GUIListViewEx_LoadHdrData:           Sets header title, text and back colour (if enabled), and sets edit mode (if enabled)
; _GUIListViewEx_EditHeader:            Manual edit of specified ListView header
; _GUIListViewEx_LoadColour:            Uses array to set text/back colours for user colour enabled ListViews
; _GUIListViewEx_SetDefColours:         Sets default colours for user colour/single cell select enabled ListViews
; _GUIListViewEx_SetColour:             Sets text and/or back colour for user colour enabled ListViews
; _GUIListViewEx_BlockReDraw:           Prevents ListView redrawing during looped Insert/Delete/Change calls
; _GUIListViewEx_DragEvent:             Returns index of ListView(s) involved in a drag-drop event
; _GUIListViewEx_SortEvent:             Redraws a colour-enabled ListView after a column sort event
; _GUIListViewEx_ContextPos:            Returns LV index and row/col of last right click
; _GUIListViewEx_ToolTipInit:           Defines column(s) which will display a tooltip when clicked
; _GUIListViewEx_ToolTipShow:           Show tooltips when defined columns clicked
; _GUIListViewEx_MsgRegister:           Registers Windows messages required for the UDF
; _GUIListViewEx_WM_NOTIFY_Handler:     Windows message handler for WM_NOTIFY - needed for all UDF functions
; _GUIListViewEx_WM_MOUSEMOVE_Handler:  Windows message handler for WM_MOUSEMOVE - needed for drag
; _GUIListViewEx_WM_LBUTTONUP_Handler:  Windows message handler for WM_LBUTTONUP - needed for drag
; _GUIListViewEx_WM_SYSCOMMAND_Handler: Windows message handler for WM_SYSCOMMAND - speeds GUI closure when editing
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; __GUIListViewEx_ExpandRange:  Expands ranges into an array of values
; __GUIListViewEx_HighLight:    Highlights specified ListView item and ensures it is visible
; __GUIListViewEx_EditProcess:  Runs ListView editing process
; __GUIListViewEx_GetLVFont:    Gets font details for ListView to be edited
; __GUIListViewEx_EditCoords:   Ensures item in view then locates and sizes edit control
; __GUIListViewEx_ReWriteLV:    Deletes all ListView content and refills to match array
; __GUIListViewEx_GetLVCoords:  Gets screen coords for ListView
; __GUIListViewEx_GetCursorWnd: Gets handle of control under the mouse cursor
; __GUIListViewEx_Array_Add:    Adds a specified value at the end of an array
; __GUIListViewEx_Array_Insert: Adds a value at the specified index of an array
; __GUIListViewEx_Array_Delete: Deletes a specified index from an array
; __GUIListViewEx_Array_Swap:   Swaps specified elements within an array
; __GUIListViewEx_ToolTipHide:  Called by Adlib to hide tooltip displayed by _GUIListViewEx_ToolTipShow
; __GUIListViewEx_MakeString:   Convert data/check/colour arrays to strings for saving
; __GUIListViewEx_MakeArray:    Convert data/check/colour strings to arrays for loading
; __GUIListViewEx_ColSort:      Sort columns even if colour enabled
; __GUIListViewEx_RedrawWindow: Redraw ListView after update
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Init
; Description ...: Enables UDF functions for the ListView and sets various flags
; Syntax.........: _GUIListViewEx_Init($hLV, [$aArray = ""[, $iStart = 0[, $iColour[, $fImage[, $iAdded]]]]])
; Parameters ....: $hLV       - Handle or ControlID of ListView
;                  $aArray    - Name of array used to fill ListView.  "" for empty ListView
;                  $iStart    - 0 = ListView data starts in [0] element of array (default)
;                               1 = Count in [0] element
;                  $iColour   - RGB colour for insert mark (default = black)
;                  $fImage    - True  = Shadow image of dragged item when dragging
;                               False = No shadow image (default)
;                  $iAdded    - 0      - No added features (default).  To get added features add any of the following values
;                               + 1    - Sortable by clicking on column headers
;                               + 2    - Do not "select all" when editing text
;                               + 4    - Edit continues within same ListView by triple mouse-click on editable column
;                               + 8    - Headers editable by Ctrl-click (only if column editable)
;                               + 16   - User coloured header
;                               + 32   - User coloured items
;                               + 64   - No external drag
;                               + 128  - No external drop
;                               + 256  - No delete on external drag/drop
;                               + 512  - Single cell selection (force single selection)
; Requirement(s).: v3.3.10 +
; Return values .: Index number of ListView for use in other GUIListViewEx functions
; Author ........: Melba23
; Modified ......:
; Remarks .......: - If the ListView is the only one enabled, it is automatically set as active
;                  - If no array is passed a shadow array is created automatically
;                  - The $iStart parameter determines if a count element will be returned by other GUIListViewEx functions
;                  - The _GUIListViewEx_ReadToArray function will read an existing ListView into an array
;                  - Only first item of a multiple selection is shadow imaged when dragging (API limitation)
;                  - Use the _GUIListViewEx_EditStatus/ComboData/DTPData functions to make columns editable
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Init($hLV, $aArray = "", $iStart = 0, $iColour = 0, $fImage = False, $iAdded = 0)

	Local $iLV_Index = 0

	; See if there is a blank line available in the array
	For $i = 1 To $aGLVEx_Data[0][0]
		If $aGLVEx_Data[$i][0] = 0 Then
			$iLV_Index = $i
			ExitLoop
		EndIf
	Next
	; If no blank line found then increase array size
	If $iLV_Index = 0 Then
		$aGLVEx_Data[0][0] += 1
		ReDim $aGLVEx_Data[$aGLVEx_Data[0][0] + 1][UBound($aGLVEx_Data, 2)]
		$iLV_Index = $aGLVEx_Data[0][0]
	EndIf

	; Store ListView handle and ControlID (if it exists)
	If IsHWnd($hLV) Then
		$aGLVEx_Data[$iLV_Index][0] = $hLV
		$aGLVEx_Data[$iLV_Index][1] = 0
	Else
		$aGLVEx_Data[$iLV_Index][0] = GUICtrlGetHandle($hLV)
		$aGLVEx_Data[$iLV_Index][1] = $hLV
	EndIf

	; Store separator char
	$aGLVEx_Data[0][24] = Opt("GUIDataSeparatorChar")

	; Store ListView content in shadow array
	$aGLVEx_Data[$iLV_Index][2] = _GUIListViewEx_ReadToArray($hLV, 1)

	;Set no selected row or column
	$aGLVEx_Data[$iLV_Index][20] = -1
	$aGLVEx_Data[$iLV_Index][21] = -1

	; Store array count flag
	$aGLVEx_Data[$iLV_Index][3] = $iStart
	; Store 1D/2D array return type flag
	If IsArray($aArray) Then
		If UBound($aArray, 0) = 2 Then $aGLVEx_Data[$iLV_Index][3] += 2
	EndIf

	; Create and store editable array
	Local $aEditable[3][UBound($aGLVEx_Data[$iLV_Index][2], 2)]
	$aGLVEx_Data[$iLV_Index][7] = $aEditable

	; Set insert mark colour after conversion to BGR
	_GUICtrlListView_SetInsertMarkColor($hLV, BitOR(BitShift(BitAND($iColour, 0x000000FF), -16), BitAND($iColour, 0x0000FF00), BitShift(BitAND($iColour, 0x00FF0000), 16)))
	; If drag image required
	If $fImage Then
		$aGLVEx_Data[$iLV_Index][5] = 1
	EndIf

	; If sortable, store sort array
	If BitAND($iAdded, 1) Then
		Local $aLVSortState[_GUICtrlListView_GetColumnCount($hLV)]
		$aGLVEx_Data[$iLV_Index][4] = $aLVSortState
	Else
		$aGLVEx_Data[$iLV_Index][4] = 0
	EndIf

	; If do not "select all" on opening edit
	If BitAND($iAdded, 2) Then
		; Set flag
		$aGLVEx_Data[$iLV_Index][11] = 1
	EndIf

	; If continue edit on click
	If BitAND($iAdded, 4) Then
		; Set flag
		$aGLVEx_Data[$iLV_Index][9] = 1
	EndIf

	; If header editable on Ctrl-click set flag
	If BitAND($iAdded, 8) Then
		$aGLVEx_Data[$iLV_Index][8] = 1
	EndIf

	; Create default header data array
	Local $iCols = _GUICtrlListView_GetColumnCount($hLV)
	Local $aHdrData[3][$iCols], $aRet
	; If user coloured headers
	If BitAND($iAdded, 16) Then
		; Get header handle to act as flag
		Local $hHeader = _GUICtrlListView_GetHeader($hLV)
		$aGLVEx_Data[$iLV_Index][24] = $hHeader
		; Read in current header titles
		For $i = 0 To $iCols - 1
			$aRet = _GUICtrlListView_GetColumn($hLV, $i)
			$aHdrData[0][$i] = $aRet[5]
		Next
	EndIf
	; Store array
	$aGLVEx_Data[$iLV_Index][25] = $aHdrData

	; Load default colours
	$aGLVEx_Data[$iLV_Index][23] = $aGLVEx_DefColours
	; If user coloured items
	If BitAND($iAdded, 32) Then
		Local $aColArray = $aGLVEx_Data[$iLV_Index][2]
		For $i = 1 To UBound($aColArray, 1) - 1
			For $j = 0 To UBound($aColArray, 2) - 1
				$aColArray[$i][$j] = ";"
			Next
		Next
		$aGLVEx_Data[$iLV_Index][18] = $aColArray
		; Set user colour flag
		$aGLVEx_Data[$iLV_Index][19] = 1
	EndIf

	; If no external drag
	If BitAND($iAdded, 64) Then
		$aGLVEx_Data[$iLV_Index][12] = 1
	EndIf

	; If no external drop
	If BitAND($iAdded, 128) Then
		$aGLVEx_Data[$iLV_Index][12] += 2
	EndIf

	; If no delete on external drag/drop
	If BitAND($iAdded, 256) Then
		$aGLVEx_Data[$iLV_Index][12] += 4
	EndIf

	; If single cell selection
	If BitAND($iAdded, 512) Then
		; Force single selection style
		Local $iStyle = _WinAPI_GetWindowLong($aGLVEx_Data[$iLV_Index][0], $GWL_STYLE)
		_WinAPI_SetWindowLong($aGLVEx_Data[$iLV_Index][0], $GWL_STYLE, BitOR($iStyle, $LVS_SINGLESEL))
		; Set flag
		$aGLVEx_Data[$iLV_Index][22] = 1
		; Load default colours
		$aGLVEx_Data[$iLV_Index][23] = $aGLVEx_DefColours
	EndIf

	;  If checkbox extended style
	If BitAND(_GUICtrlListView_GetExtendedListViewStyle($hLV), 4) Then ; $LVS_EX_CHECKBOXES
		$aGLVEx_Data[$iLV_Index][6] = 1
	EndIf

	;  If header drag extended style
	If BitAND(_GUICtrlListView_GetExtendedListViewStyle($hLV), 0x00000010) Then ; $LVS_EX_HEADERDRAGDROP
		$aGLVEx_Data[$iLV_Index][13] = 1
	EndIf

	; Measure item depth for scroll - if empty reset when filled later
	Local $aRect = _GUICtrlListView_GetItemRect($aGLVEx_Data[$iLV_Index][0], 0)
	$aGLVEx_Data[$iLV_Index][10] = $aRect[3] - $aRect[1]

	; If only 1 current ListView then activate
	Local $iListView_Count = 0
	For $i = 1 To $iLV_Index
		If $aGLVEx_Data[$i][0] Then $iListView_Count += 1
	Next
	If $iListView_Count = 1 Then _GUIListViewEx_SetActive($iLV_Index)

	; Return ListView index
	Return $iLV_Index

EndFunc   ;==>_GUIListViewEx_Init

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Close
; Description ...: Disables all UDF functions for the specified ListView and clears all memory used
; Syntax.........: _GUIListViewEx_Close($iLV_Index)
; Parameters ....: $iLV_Index - Index number of ListView to close as returned by _GUIListViewEx_Init
;                            0 (default) = Closes all ListViews
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and @error set to 1 - Invalid index number
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Close($iLV_Index = 0)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

	If $iLV_Index = 0 Then
		; Remove all ListView data
		Global $aGLVEx_Data[1][UBound($aGLVEx_Data, 2)] = [[0, 0]]
	Else
		; Reset all data for ListView
		For $i = 0 To UBound($aGLVEx_Data, 2) - 1
			$aGLVEx_Data[$iLV_Index][$i] = 0
		Next

		; Cancel active index if set to this ListView
		If $aGLVEx_Data[0][1] = $iLV_Index Then
			$aGLVEx_Data[0][1] = 0
		EndIf

	EndIf

	Return 1

EndFunc   ;==>_GUIListViewEx_Close

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetActive
; Description ...: Set specified ListView as active for UDF functions
; Syntax.........: _GUIListViewEx_SetActive($iLV_Index)
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  An index of 0 clears any current setting
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns previous active index number, 0 = no previously active ListView
;                  Failure: -1 and @error set to 1 - Invalid index number
; Author ........: Melba23
; Modified ......:
; Remarks .......: ListViews can also be activated by clicking on them
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SetActive($iLV_Index)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, -1)

	Local $iCurr_Index = $aGLVEx_Data[0][1]

	If $iLV_Index Then
		; Store index of specified ListView
		$aGLVEx_Data[0][1] = $iLV_Index
		; Set values for specified ListView
		$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
		$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Else
		; Clear active index
		$aGLVEx_Data[0][1] = 0
		$hGLVEx_SrcHandle = 0
		$cGLVEx_SrcID = 0
	EndIf

	Return $iCurr_Index

EndFunc   ;==>_GUIListViewEx_SetActive

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_GetActive
; Description ...: Get index number of ListView active for UDF functions
; Syntax.........: _GUIListViewEx_GetActive()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: Success: Index number as returned by _GUIListViewEx_Init, 0 = no active ListView
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_GetActive()

	Return $aGLVEx_Data[0][1]

EndFunc   ;==>_GUIListViewEx_GetActive

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ReadToArray
; Description ...: Creates an array from the current ListView content to be loaded in _Init function
; Syntax.........: _GUIListViewEx_ReadToArray($hLV[, $iCount = 0])
; Parameters ....: $hLV    - ControlID or handle of ListView
;                  $iCount - 0 (default) = ListView data starts in [0] element of array, 1 = Count in [0] element
; Requirement(s).: v3.3.10 +
; Return values .: Success: 2D array of current ListView content
;                           Empty string if ListView empty and no count element
;                  Failure: Returns null string and sets @error as follows:
;                           1 = Invalid ListView ControlID or handle
; Author ........: Melba23
; Modified ......:
; Remarks .......: If returned array is used in _GUIListViewEx_Init the $iStart parameters must match in the 2 functions
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ReadToArray($hLV, $iStart = 0)

	Local $aLVArray = "", $aRow

	; Use the ListView handle
	If Not IsHWnd($hLV) Then
		$hLV = GUICtrlGetHandle($hLV)
		If Not IsHWnd($hLV) Then
			Return SetError(1, 0, "")
		EndIf
	EndIf
	; Get ListView row count
	Local $iRows = _GUICtrlListView_GetItemCount($hLV)
	; Get ListView column count
	Local $iCols = _GUICtrlListView_GetColumnCount($hLV)
	; Check for empty ListView with no count
	If ($iRows + $iStart <> 0) And $iCols <> 0 Then
		; Create 2D array to hold ListView content and add count - count overwritten if not needed
		Local $aLVArray[$iRows + $iStart][$iCols] = [[$iRows]]
		; Read ListView content into array
		For $i = 0 To $iRows - 1
			; Read the row content
			$aRow = _GUICtrlListView_GetItemTextArray($hLV, $i)
			For $j = 1 To $aRow[0]
				; Add to the ListView content array
				$aLVArray[$i + $iStart][$j - 1] = $aRow[$j]
			Next
		Next
	Else
		Local $aLVArray[1][1] = [[0]]
	EndIf
	; Return array or empty string
	Return $aLVArray

EndFunc   ;==>_GUIListViewEx_ReadToArray

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ReturnArray
; Description ...: Returns an array reflecting the current content of an activated ListView
; Syntax.........: _GUIListViewEx_ReturnArray($iLV_Index[, $iMode])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $iMode  - 0 = Content of ListView
;                            1 - State of the checkboxes
;                            2 - User colours (if initialised)
;                            3 - Content of ListView forced to 2D for saving
;                            4 - ListView headers
;                            5 - Header colours (if initialised)
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of current ListView content - _GUIListViewEx_Init parameters determine:
;                               For modes 0/1:
;                                   Count in [0]/[0][0] element if $iStart = 1 when intialised
;                                   1D/2D array type - as array used to initialise
;                                   If no array passed then single col => 1D; multiple column => 2D
;                               For mode 2/3
;                                   Always 0-based 2D array
;                               For mode 4/5
;                                   Always 0-based 1D array
;                  Failure: Returns empty string and sets @error as follows:
;                               1 = Invalid index number
;                               2 = Empty array (no items in ListView)
;                               3 = $iMode set to 1 but no checkbox style
;                               4 = $iMode set to 2 but user colours not initialised
;                               5 = $iMode set to 5 but header colours not initialised
;                               6 = Invalid $iMode
; Author ........: Melba23
; Modified ......:
; Remarks .......: Colours returned as "text;back" - empty values use default colours
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ReturnArray($iLV_Index, $iMode = 0)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")
	; Get ListView handle
	Local $hLV = $aGLVEx_Data[$iLV_Index][0]
	; Get column order
	Local $aColOrder = StringSplit(_GUICtrlListView_GetColumnOrder($hLV), $aGLVEx_Data[0][24])
	; Extract array and get size
	Local $aData_Colour = $aGLVEx_Data[$iLV_Index][2]
	Local $iDim_1 = UBound($aData_Colour, 1), $iDim_2 = UBound($aData_Colour, 2)
	Local $aCheck[$iDim_1], $aHeader[$iDim_2], $aHdrData

	; Adjust array depending on mode required
	Switch $iMode
		Case 0, 3 ; Content
			; Array already filled

		Case 1 ; Checkbox state
			If $aGLVEx_Data[$iLV_Index][6] Then
				For $i = 1 To $iDim_1 - 1
					$aCheck[$i] = _GUICtrlListView_GetItemChecked($hLV, $i - 1)
				Next
				; Remove count element if required
				If BitAND($aGLVEx_Data[$iLV_Index][3], 1) = 0 Then
					; Delete count element
					__GUIListViewEx_Array_Delete($aCheck, 0)
				EndIf
				Return $aCheck
			Else
				Return SetError(3, 0, "")
			EndIf

		Case 2 ; Colour values
			If $aGLVEx_Data[$iLV_Index][19] Then
				; Load colour array
				$aData_Colour = $aGLVEx_Data[$iLV_Index][18]
				; Convert to RGB
				For $i = 0 To UBound($aData_Colour, 1) - 1
					For $j = 0 To UBound($aData_Colour, 2) - 1
						$aData_Colour[$i][$j] = StringRegExpReplace($aData_Colour[$i][$j], "0x(.{2})(.{2})(.{2})", "0x$3$2$1")
					Next
				Next
				$aData_Colour[0][0] = $iDim_1 - 1
			Else
				Return SetError(4, 0, "")
			EndIf

		Case 4 ; Headers
			If $aGLVEx_Data[$iLV_Index][24] Then
				; Header colour enabled, so read from header data
				$aHdrData = $aGLVEx_Data[$iLV_Index][25]
				For $i = 0 To $iDim_2 - 1
					$aHeader[$i] = $aHdrData[0][$i]
				Next
			Else
				; Read normal headers
				Local $aRet
				For $i = 0 To $iDim_2 - 1
					$aRet = _GUICtrlListView_GetColumn($hLV, $i)
					$aHeader[$i] = $aRet[5]
				Next
			EndIf

		Case 5 ; Header colours
			If $aGLVEx_Data[$iLV_Index][24] Then
				; Header colour enabled, so read from header data
				$aHdrData = $aGLVEx_Data[$iLV_Index][25]
				For $i = 0 To $iDim_2 - 1
					$aHeader[$i] = $aHdrData[1][$i]
				Next
			Else
				Return SetError(5, 0, "")
			EndIf

		Case Else
			Return SetError(6, 0, "")
	EndSwitch

	; Check if columns can be reordered
	If $aGLVEx_Data[$iLV_Index][13] Then
		Switch $iMode
			Case 0, 2, 3 ; 2D data/colour array
				; Create temp array
				Local $aData_Colour_Ordered[$iDim_1][$iDim_2]
				; Fill temp array in correct column order
				$aData_Colour_Ordered[0][0] = $aData_Colour[0][0]
				For $i = 1 To $iDim_1 - 1
					For $j = 0 To $iDim_2 - 1
						$aData_Colour_Ordered[$i][$j] = $aData_Colour[$i][$aColOrder[$j + 1]]
					Next
				Next
				; Reset main and delete temp
				$aData_Colour = $aData_Colour_Ordered
				$aData_Colour_Ordered = ""

			Case 4, 5 ; 1D header array
				; Create return array
				Local $aHeader_Ordered[$iDim_2]
				; Fill return array in correct column order
				For $i = 0 To $iDim_2 - 1
					$aHeader_Ordered[$i] = $aHeader[$aColOrder[$i + 1]]
				Next
				; Return reordered array
				Return $aHeader_Ordered
		EndSwitch
	Else
		; No reordering
		If $iMode = 4 Then
			; Return header array
			Return $aHeader
		EndIf
	EndIf

	; Remove count element of array if required - always for colour return
	Local $iCount = 1
	If BitAND($aGLVEx_Data[$iLV_Index][3], 1) = 0 Or $iMode = 2 Then
		$iCount = 0
		; Delete count element
		__GUIListViewEx_Array_Delete($aData_Colour, 0, True)
	EndIf

	; Now check if 1D array to be returned - always 2D for colour return and forced content
	If BitAND($aGLVEx_Data[$iLV_Index][3], 2) = 0 And $iMode < 2 Then
		If UBound($aData_Colour, 1) = 0 Then
			Local $aData_Colour[0]
		Else
			; Get number of 2D elements
			Local $iCols = UBound($aData_Colour, 2)
			; Create 1D array - count will be overwritten if not needed
			Local $aData_Colour_1D[UBound($aData_Colour)] = [$aData_Colour[0][0]]
			; Fill with concatenated lines
			For $i = $iCount To UBound($aData_Colour_1D) - 1
				Local $aLine = ""
				For $j = 0 To $iCols - 1
					$aLine &= $aData_Colour[$i][$j] & $aGLVEx_Data[0][24]
				Next
				$aData_Colour_1D[$i] = StringTrimRight($aLine, 1)
			Next
			; Reset array
			$aData_Colour = $aData_Colour_1D
		EndIf
	EndIf

	; Return array
	Return $aData_Colour

EndFunc   ;==>_GUIListViewEx_ReturnArray

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SaveListView
; Description ...: Saves ListView headers, content, checkbox state, colour data to file
; Syntax.........: _GUIListViewEx_SaveListView($iLV_Index, $sFileName)
; Parameters ....: $iLV_Index    - Index number of ListView as returned by _GUIListViewEx_Init
;                  $sFileName - File in which to save data
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                               1 = Invalid index number
;                               2 = File not written - @extended set:
;                                   1 = File not opened
;                                   2 = Data not written
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SaveListView($iLV_Index, $sFileName)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

	; Get ListView parameters
	Local $hLV_Handle = $aGLVEx_Data[$iLV_Index][0]
	Local $iStart = BitAND($aGLVEx_Data[$iLV_Index][3], 1)

	; Get header data
	Local $sHeader = "", $aRet
	If $aGLVEx_Data[$iLV_Index][24] Then
		; Header colour enabled, so also read from header data
		Local $aHdrData = $aGLVEx_Data[$iLV_Index][25]
		; Create string
		For $i = 0 To _GUICtrlListView_GetColumnCount($hLV_Handle) - 1
			$aRet = _GUICtrlListView_GetColumn($hLV_Handle, $i)
			$sHeader &= $aHdrData[0][$i] & @CR & $aRet[4] & @CR & $aHdrData[1][$i] & @CR & $aHdrData[2][$i] & @LF
		Next
	Else
		; Read normal headers
		For $i = 0 To _GUICtrlListView_GetColumnCount($hLV_Handle) - 1
			$aRet = _GUICtrlListView_GetColumn($hLV_Handle, $i)
			$sHeader &= $aRet[5] & @CR & $aRet[4] & @LF
		Next
	EndIf
	$sHeader = StringTrimRight($sHeader, 1)

	; Get data/check/colour content
	Local $aData = _GUIListViewEx_ReturnArray($iLV_Index, 3) ; Force 2D return
	If $iStart Then
		_ArrayDelete($aData, 0)
	EndIf
	Local $aCheck = _GUIListViewEx_ReturnArray($iLV_Index, 1)
	If $iStart Then
		_ArrayDelete($aCheck, 0)
	EndIf
	Local $aColour = _GUIListViewEx_ReturnArray($iLV_Index, 2)

	; Get edit data
	Local $aEditable = $aGLVEx_Data[$iLV_Index][7]

	; Get sort data
	Local $aSortable = $aGLVEx_Data[$iLV_Index][4]

	; Convert to strings
	Local $sData = "", $sCheck = "", $sColour = "", $sEditable = "", $sSortable = ""
	If IsArray($aData) Then
		$sData = __GUIListViewEx_MakeString($aData)
	EndIf
	If IsArray($aCheck) Then
		$sCheck = __GUIListViewEx_MakeString($aCheck)
	EndIf
	If IsArray($aColour) Then
		$sColour = __GUIListViewEx_MakeString($aColour)
	EndIf
	If IsArray($aEditable) Then
		$sEditable = __GUIListViewEx_MakeString($aEditable)
	EndIf
	If IsArray($aSortable) Then
		$sSortable = __GUIListViewEx_MakeString($aSortable)
	EndIf

	; Write data to file
	Local $iError = 0
	Local $hFile = FileOpen($sFileName, $FO_OVERWRITE)
	If @error Then
		$iError = 1
	Else
		FileWrite($hFile, $sHeader & ChrW(0xEF0F) & $sData & ChrW(0xEF0F) & $sCheck & ChrW(0xEF0F) & $sColour & ChrW(0xEF0F) & $sEditable & ChrW(0xEF0F) & $sSortable)
		If @error Then
			$iError = 2
		EndIf
	EndIf
	FileClose($hFile)

	If $iError Then Return SetError(2, $iError, 0)

	Return 1

EndFunc   ;==>_GUIListViewEx_SaveListView

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_LoadListView
; Description ...: Loads ListView headers, content, checkbox state, colour data from file
; Syntax.........: _GUIListViewEx_LoadListView($iLV_Index, $sFileName[, $iDims = 2])
; Parameters ....: $iLV_Index    - Index number of ListView as returned by _GUIListViewEx_Init
;                  $sFileName - File from which to load data
;                  $iDims     - Force 1/2D return array - normally set by initialising array
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                               1 = Invalid index number
;                               2 = Invalid $iDims parameter
;                               3 = File not read
;                               4 = No data to load
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_LoadListView($iLV_Index, $sFileName, $iDims = 2)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)
	; Check valid $iDims parameter
	Switch $iDims
		Case 1, 2
			; OK
		Case Else
			Return SetError(2, 0, 0)
	EndSwitch

	; Get ListView parameters
	Local $hLV_Handle = $aGLVEx_Data[$iLV_Index][0]
	Local $cLV_CID = $aGLVEx_Data[$iLV_Index][1]
	Local $iStart = BitAND($aGLVEx_Data[$iLV_Index][3], 1)

	; Read content
	Local $sContent = FileRead($sFileName)
	If @error Then Return SetError(3, 0, 0)

	; Split into separate sections
	Local $aSplit = StringSplit($sContent, ChrW(0xEF0F), $STR_ENTIRESPLIT)

	; Check there is data to load
	If $aSplit[1] = "" Then Return SetError(4, 0, 0)

	; Convert to arrays
	Local $aHeader = __GUIListViewEx_MakeArray($aSplit[1])

	Local $aData = __GUIListViewEx_MakeArray($aSplit[2])
	Local $aCheck = __GUIListViewEx_MakeArray($aSplit[3])
	Local $aColour = __GUIListViewEx_MakeArray($aSplit[4])
	Local $aEditable = __GUIListViewEx_MakeArray($aSplit[5])
	Local $aSortable = __GUIListViewEx_MakeArray($aSplit[6])

	; If required, convert data and colour arrays into 2D for load
	If UBound($aData, 0) = 1 Then
		Local $aTempData[UBound($aData)][1]
		Local $aTempCol[UBound($aData)][1]
		For $i = 0 To UBound($aData) - 1
			$aTempData[$i][0] = $aData[$i]
			$aTempCol[$i][0] = $aColour[$i]
		Next
		$aData = $aTempData
		$aColour = $aTempCol
	EndIf

	; Set no colour redraw flag and prevent any normal redraw
	$aGLVEx_Data[0][12] = 1
	$aGLVEx_Data[0][15] = False
	_GUICtrlListView_BeginUpdate($hLV_Handle)

	; Clear current content of ListView
	_GUICtrlListView_DeleteAllItems($hLV_Handle)

	; Check correct number of columns
	Local $iCol_Count = _GUICtrlListView_GetColumnCount($hLV_Handle)
	If $iCol_Count < UBound($aHeader) Then
		; Add columns
		For $i = $iCol_Count To UBound($aHeader) - 1
			_GUICtrlListView_AddColumn($hLV_Handle, "", 100)
		Next
	EndIf
	If $iCol_Count > UBound($aHeader) Then
		; Delete columns
		For $i = $iCol_Count To UBound($aHeader) Step -1
			_GUICtrlListView_DeleteColumn($hLV_Handle, $i)
		Next
	EndIf

	; Reset header titles and widths
	For $i = 0 To UBound($aHeader) - 1
		_GUICtrlListView_SetColumn($hLV_Handle, $i, $aHeader[$i][0], $aHeader[$i][1])
	Next

	; Load ListView content
	If $cLV_CID Then
		; Native ListView
		Local $sLine, $iLastCol = UBound($aData, 2) - 1
		For $i = 0 To UBound($aData) - 1
			$sLine = ""
			For $j = 0 To $iLastCol
				$sLine &= $aData[$i][$j] & "|"
			Next
			GUICtrlCreateListViewItem(StringTrimRight($sLine, 1), $cLV_CID)
		Next
	Else
		; UDF ListView
		_GUICtrlListView_AddArray($hLV_Handle, $aData)
	EndIf

	_GUICtrlListView_EndUpdate($hLV_Handle)

	; Add required count row to shadow array
	_ArrayInsert($aData, 0, UBound($aData))
	; Store content array
	$aGLVEx_Data[$iLV_Index][2] = $aData
	; Store editable array
	$aGLVEx_Data[$iLV_Index][7] = $aEditable
	; Store sortable array
	$aGLVEx_Data[$iLV_Index][4] = $aSortable

	; Set 1/2D return flag as required
	$aGLVEx_Data[$iLV_Index][3] = $iStart + (($iDims = 2) ? (2) : (0))

	; Reset checkboxes if required
	If IsArray($aCheck) Then
		; Reset checkboxes
		For $i = 0 To UBound($aCheck) - 1
			If $aCheck[$i] = "True" Then
				_GUICtrlListView_SetItemChecked($hLV_Handle, $i, True)
			EndIf
		Next
	EndIf

	; Clear no colour redraw flag and allow normal redraw
	$aGLVEx_Data[0][12] = 0
	$aGLVEx_Data[0][15] = True

	; Reset header data if required
	If $aGLVEx_Data[$iLV_Index][24] Then
		; Create and fill header data array
		Local $aHdrData[3][UBound($aHeader, 2)]
		For $i = 0 To UBound($aHeader, 2) - 1
			$aHdrData[0][$i] = $aHeader[$i][0]
			$aHdrData[1][$i] = $aHeader[$i][2]
			$aHdrData[2][$i] = $aHeader[$i][3]
		Next
		; Store array
		$aGLVEx_Data[$iLV_Index][25] = $aHdrData
	EndIf

	; Reset data colours if required
	If $aGLVEx_Data[$iLV_Index][19] Then
		; Load colour
		_GUIListViewEx_LoadColour($iLV_Index, $aColour)
		If Not @error Then
			__GUIListViewEx_RedrawWindow($iLV_Index)
		EndIf
	EndIf

	; Set active
	$aGLVEx_Data[0][1] = $iLV_Index

	Return 1

EndFunc   ;==>_GUIListViewEx_LoadListView

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Up
; Description ...: Moves selected item(s) in active ListView up 1 row
; Syntax.........: _GUIListViewEx_Up()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView with count in [0] element
;                  Failure: Returns "" and sets @error as follows:
;                      1 = No ListView active
;                      2 = No item selected
;                      3 = Item already at top
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, only the top consecutive block is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Up()

	Local $iGLVExMove_Index, $iGLVEx_Moving = 0

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, 0)

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy array for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	; Check for selected items
	Local $iIndex
	; Check if colour single cell selection enabled
	If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
		; Use stored value
		$iIndex = $aGLVEx_Data[$iLV_Index][20]
	Else
		; Check actual values
		$iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_SrcHandle)
	EndIf
	If $iIndex == "" Then
		Return SetError(2, 0, "")
	EndIf
	Local $aIndex = StringSplit($iIndex, "|")
	$iGLVExMove_Index = $aIndex[1]
	; Check if item is part of a multiple selection
	If $aIndex[0] > 1 Then
		; Check for consecutive items
		For $i = 1 To $aIndex[0] - 1
			If $aIndex[$i + 1] = $aIndex[1] + $i Then
				$iGLVEx_Moving += 1
			Else
				ExitLoop
			EndIf
		Next
	Else
		$iGLVExMove_Index = $aIndex[1]
	EndIf

	; Check not top item
	If $iGLVExMove_Index < 1 Then
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, 0)
		Return SetError(3, 0, "")
	EndIf

	; Remove all highlighting
	_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, -1, False)

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Move consecutive items
	For $iIndex = $iGLVExMove_Index To $iGLVExMove_Index + $iGLVEx_Moving
		; Swap array elements
		__GUIListViewEx_Array_Swap($aGLVEx_SrcArray, $iIndex, $iIndex + 1)
		__GUIListViewEx_Array_Swap($aCheck_Array, $iIndex, $iIndex + 1)
		__GUIListViewEx_Array_Swap($aGLVEx_SrcColArray, $iIndex, $iIndex + 1)
	Next

	; Amend stored row
	$aGLVEx_Data[$iLV_Index][20] -= 1

	; Rewrite ListView
	__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)

	; Set highlight
	For $i = 0 To $iGLVEx_Moving
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iGLVExMove_Index + $i - 1)
	Next

	; Store amended array
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_Up

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Down
; Description ...: Moves selected item(s) in active ListView down 1 row
; Syntax.........: _GUIListViewEx_Down()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView with count in [0] element
;                  Failure: Returns "" and sets @error as follows:
;                      1 = No ListView active
;                      2 = No item selected
;                      3 = Item already at bottom
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, only the bottom consecutive block is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Down()

	Local $iGLVExMove_Index, $iGLVEx_Moving = 0

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, 0)

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy array for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	; Check for selected items
	Local $iIndex
	; Check if colour or single cell selection enabled
	If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
		; Use stored value
		$iIndex = $aGLVEx_Data[$iLV_Index][20]
	Else
		; Check actual values
		$iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_SrcHandle)
	EndIf
	If $iIndex == "" Then
		Return SetError(2, 0, "")
	EndIf
	Local $aIndex = StringSplit($iIndex, "|")
	; Check if item is part of a multiple selection
	If $aIndex[0] > 1 Then
		$iGLVExMove_Index = $aIndex[$aIndex[0]]
		; Check for consecutive items
		For $i = 1 To $aIndex[0] - 1
			If $aIndex[$aIndex[0] - $i] = $aIndex[$aIndex[0]] - $i Then
				$iGLVEx_Moving += 1
			Else
				ExitLoop
			EndIf
		Next
	Else
		$iGLVExMove_Index = $aIndex[1]
	EndIf

	; Remove all highlighting
	_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, -1, False)

	; Check not last item
	If $iGLVExMove_Index = _GUICtrlListView_GetItemCount($hGLVEx_SrcHandle) - 1 Then
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iIndex)
		Return SetError(3, 0, "")
	EndIf

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Move consecutive items
	For $iIndex = $iGLVExMove_Index To $iGLVExMove_Index - $iGLVEx_Moving Step -1
		; Swap array elements
		__GUIListViewEx_Array_Swap($aGLVEx_SrcArray, $iIndex + 1, $iIndex + 2)
		__GUIListViewEx_Array_Swap($aCheck_Array, $iIndex + 1, $iIndex + 2)
		__GUIListViewEx_Array_Swap($aGLVEx_SrcColArray, $iIndex + 1, $iIndex + 2)
	Next

	; Amend stored row
	$aGLVEx_Data[$iLV_Index][20] += 1

	; Rewrite ListView
	__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)

	; Set highlight
	For $i = 0 To $iGLVEx_Moving
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iGLVExMove_Index - $iGLVEx_Moving + $i + 1)
	Next

	; Store amended array
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_Down

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Insert
; Description ...: Inserts data just below selected item in active ListView - if no selection, data added at end
; Syntax.........: _GUIListViewEx_Insert($vData[, $fRetainWidth = False])
; Parameters ....: $vData        - Data to insert, can be in array or delimited string format
;                  $fMultiRow    - (Optional) If $vData is a 1D array:
;                                     - False (default) - elements added as subitems to a single row
;                                     - True - elements added as rows containing a single item
;                                  Ignored if $vData is a single item or a 2D array
;                  $fRetainWidth - (Optional) True  = native ListView column width is retained on insert
;                                  False = native ListView columns expand to fit data (default)
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of current ListView content with count in [0] element
;                  Failure: If no ListView active then returns "" and sets @error to 1
; Author ........: Melba23
; Modified ......:
; Remarks .......: - New data is inserted after the selected item.  If no item is selected then the data is added at
;                  the end of the ListView.  If multiple items are selected, the data is inserted after the first
;                  - $vData can be passed in string or array format - it is automatically transformed if required
;                  - $vData as single item - item added to all columns
;                  - $vData as 1D array - see $fMultiRow above
;                  - $vData as 2D array - added as rows/columns
;                  - Native ListViews automatically expand subitem columns to fit inserted data.  Setting the
;                  $fRetainWidth parameter resets the original width after insertion
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Insert($vData, $fMultiRow = False, $fRetainWidth = False)

	;Local $vInsert

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, "")

	; Check for selected items
	Local $iIndex
	; Check if colour or single cell selection enabled
	If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
		; Use stored value
		$iIndex = $aGLVEx_Data[$iLV_Index][20]
	Else
		; Check actual values
		$iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_SrcHandle)
	EndIf
	Local $iInsert_Index = $iIndex
	; If no selection
	If $iIndex == "" Then $iInsert_Index = -1

	; Check for multiple selections
	If StringInStr($iIndex, "|") Then
		Local $aIndex = StringSplit($iIndex, "|")
		; Use first selection
		$iIndex = $aIndex[1]
		; Cancel all other selections
		For $i = 2 To $aIndex[0]
			_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, $aIndex[$i], False)
		Next
	EndIf

	Local $vRet = _GUIListViewEx_InsertSpec($iLV_Index, $iInsert_Index + 1, $vData, $fMultiRow, $fRetainWidth)

	Return SetError(@error, 0, $vRet)

EndFunc   ;==>_GUIListViewEx_Insert

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_InsertSpec
; Description ...: Inserts data in specified row in specified ListView
; Syntax.........: _GUIListViewEx_InsertSpec($iLV_Index, $iRow, $vData[, $fRetainWidth = False])
; Parameters ....: $iLV_Index    - Index of ListView as returned by _GUIListViewEx_Init
;                  $iRow         - Row which will be inserted - setting -1 adds at end
;                  $vData        - Data to insert, can be in array or delimited string format
;                  $fMultiRow    - (Optional) If $vData is a 1D array:
;                                     - False (default) - elements added as subitems to a single row
;                                     - True - elements added as rows containing a single item
;                                  Ignored if $vData is a single item or a 2D array
;                  $fRetainWidth - (Optional) True  = native ListView column width is retained on insert
;                                  False = native ListView columns expand to fit data (default)
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of specified ListView content with count in [0] element
;                  Failure: Returns "" and sets @error to 1
; Author ........: Melba23
; Modified ......:
; Remarks .......: - New data is inserted after the specified row.
;                  - $vData can be passed in string or array format - it is automatically transformed if required
;                  - $vData as single item - item added to all columns
;                  - $vData as 1D array - see $fMultiRow above
;                  - $vData as 2D array - added as rows/columns
;                  - Native ListViews automatically expand subitem columns to fit inserted data.  Setting the
;                  - $fRetainWidth parameter resets the original width after insertion
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_InsertSpec($iLV_Index, $iRow, $vData, $fMultiRow = False, $fRetainWidth = False)

	Local $vInsert

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy array for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	Local $aCol_Width, $iColCount
	; If width retain required and native ListView
	If $fRetainWidth And $cGLVEx_SrcID Then
		$iColCount = _GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle)
		; Store column widths
		Local $aCol_Width[$iColCount]
		For $i = 1 To $iColCount - 1
			$aCol_Width[$i] = _GUICtrlListView_GetColumnWidth($hGLVEx_SrcHandle, $i)
		Next
	EndIf

	; If empty array insert at 0
	If $aGLVEx_SrcArray[0][0] = 0 Then $iRow = 0
	; Get data into array format for insert
	If IsArray($vData) Then
		$vInsert = $vData
	Else
		Local $aData = StringSplit($vData, $aGLVEx_Data[0][24])
		Switch $aData[0]
			Case 1
				$vInsert = $aData[1]
			Case Else
				Local $vInsert[$aData[0]]
				For $i = 0 To $aData[0] - 1
					$vInsert[$i] = $aData[$i + 1]
				Next
		EndSwitch
	EndIf

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Insert data into arrays
	If $iRow = -1 Then
		__GUIListViewEx_Array_Add($aGLVEx_SrcArray, $vInsert, $fMultiRow)
		__GUIListViewEx_Array_Add($aCheck_Array, $vInsert, $fMultiRow)
		__GUIListViewEx_Array_Add($aGLVEx_SrcColArray, ";", $fMultiRow)
	Else
		__GUIListViewEx_Array_Insert($aGLVEx_SrcArray, $iRow + 1, $vInsert, $fMultiRow)
		__GUIListViewEx_Array_Insert($aCheck_Array, $iRow + 1, $vInsert, $fMultiRow)
		__GUIListViewEx_Array_Insert($aGLVEx_SrcColArray, $iRow + 1, ";", $fMultiRow)
	EndIf

	; If Loop No Redraw flag set
	If $aGLVEx_Data[0][15] Then
		; Rewrite ListView
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)
	EndIf

	; Set highlight
	If $iRow = -1 Then
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, _GUICtrlListView_GetItemCount($hGLVEx_SrcHandle) - 1)
	Else
		__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iRow)
	EndIf

	; Store amended array
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; Restore column widths if required
	If $fRetainWidth And $cGLVEx_SrcID Then
		For $i = 1 To $iColCount - 1
			$aCol_Width[$i] = _GUICtrlListView_SetColumnWidth($hGLVEx_SrcHandle, $i, $aCol_Width[$i])
		Next
	EndIf

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_InsertSpec

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Delete
; Description ...: Deletes selected row(s) in active ListView
; Syntax.........: _GUIListViewEx_Delete($vRange)
; Parameters ....: $vRange - items to delete.  if no parameter passed any selected items are deleted
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView content with count in [0] element
;                  Failure: Returns "" and sets @error as follows:
;                      1 = No ListView active
;                      2 = No row selected
;                      3 = No items to delete
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, all are deleted
;                  $vRange must be semicolon-delimited with hypenated consecutive values.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Delete($vRange = "")

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, "")

	Local $vRet = _GUIListViewEx_DeleteSpec($iLV_Index, $vRange)

	Return SetError(@error, 0, $vRet)

EndFunc   ;==>_GUIListViewEx_Delete

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DeleteSpec
; Description ...: Deletes specified row(s) in specified ListView
; Syntax.........: _GUIListViewEx_DeleteSpec($iLV_Index, $vRange = "")
; Parameters ....: $iLV_Index - Index of ListView as returned by _GUIListViewEx_Init
;                  $vRange    - Items to delete.
;                                   If no parameter passed any selected items are deleted
;                                   If -1 passed last row is deleted
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of specified ListView content with count in [0] element
;                  Failure: Returns "" and sets @error as follows:
;                      1 = Invalid ListView index
;                      2 = No row selected if no range passed
;                      3 = No items to delete
;                      4 = Invaid range parameter
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, all are deleted
;                  $vRange must be semicolon-delimited with hypenated consecutive values.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DeleteSpec($iLV_Index, $vRange = "")

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	If UBound($hGLVEx_SrcHandle) = 1 Then Return SetError(3, 0, "")
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy array for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	If $vRange = "-1" Then
		$vRange = UBound($aGLVEx_SrcArray) - 2
	EndIf

	Local $iIndex, $aIndex

	; Check for range
	If String($vRange) <> "" Then
		$aIndex = __GUIListViewEx_ExpandRange($vRange, $iLV_Index, 0) ; Rows not columns
		If @error Then Return SetError(4, 0, 0)
	Else
		; Check if colour or single cell selection enabled
		If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
			; Use stored value
			$iIndex = $aGLVEx_Data[$iLV_Index][20]
		Else
			; Check actual values
			$iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_SrcHandle)
		EndIf

		If $iIndex == "" Then
			Return SetError(2, 0, "")
		EndIf
		; Extract all selected items
		$aIndex = StringSplit($iIndex, $aGLVEx_Data[0][24])
	EndIf

	For $i = 1 To $aIndex[0]
		; Remove highlighting from items
		_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, $i, False)
	Next

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Delete elements from array - start from bottom
	For $i = $aIndex[0] To 1 Step -1
		; Check element exists in array
		If $aIndex[$i] <= UBound($aGLVEx_SrcArray) - 2 Then
			__GUIListViewEx_Array_Delete($aGLVEx_SrcArray, $aIndex[$i] + 1)
			__GUIListViewEx_Array_Delete($aCheck_Array, $aIndex[$i] + 1)
			__GUIListViewEx_Array_Delete($aGLVEx_SrcColArray, $aIndex[$i] + 1)
		EndIf
	Next

	; If Loop No Redraw flag set
	If $aGLVEx_Data[0][15] Then
		; Rewrite ListView
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)
		; Set highlight
		If $aIndex[1] = 0 Then
			__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, 0)
		Else
			__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $aIndex[1] - 1)
		EndIf
	EndIf

	; Store amended array
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_DeleteSpec

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_InsertCol
; Description ...: Inserts blank column to right of selected column in active ListView
; Syntax.........: _GUIListViewEx_InsertCol([$sTitle = ""[, $iWidth = 50]])
; Parameters ....: $sTitle - (Optional) Title of column - default none
;                  $iWidth - (Optional) Width of new column - default = 50
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView content with count in [0] element
;                  Failure: If no ListView active then returns "" and sets @error to 1
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_InsertCol($sTitle = "", $iWidth = 50)

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, "")

	; Pass active column
	Local $vRet = _GUIListViewEx_InsertColSpec($iLV_Index, $aGLVEx_Data[0][2] + 1, $sTitle, $iWidth)

	Return SetError(@error, 0, $vRet)

EndFunc   ;==>_GUIListViewEx_InsertCol

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_InsertColSpec
; Description ...: Inserts specified blank column in specified ListView
; Syntax.........: _GUIListViewEx_InsertColSpec($iLV_Index[, $iCol = -1[, $sTitle = ""[, $iWidth = 50]]])
; Parameters ....: $iLV_Index - Index of ListView as returned by _GUIListViewEx_Init
;                  $iCol      - (Optional) Column to be be inserted - default -1 adds at right
;                  $sTitle    - (Optional) Title of column - default none
;                  $iWidth    - (Optional) Width of new column - default = 50
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView content with count in [0] element
;                  Failure: Empty string sets @error to
;                      1 = Invalid ListView index
;                      2 = invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_InsertColSpec($iLV_Index, $iCol = -1, $sTitle = "", $iWidth = 75)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy arrays for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]
	Local $aEditable = $aGLVEx_Data[$iLV_Index][7]
	Local $aHdrData[3][UBound($aGLVEx_SrcArray, 2)]
	If $aGLVEx_Data[$iLV_Index][24] Then ; Header colour enabled
		$aHdrData = $aGLVEx_Data[$iLV_Index][25]
	EndIf

	; Check if valid column
	Local $iMax_Col = UBound($aGLVEx_SrcArray, 2) - 1
	If $iCol = -1 Then $iCol = $iMax_Col + 1
	If $iCol < 0 Or $iCol > $iMax_Col + 1 Then Return SetError(2, 0, "")

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Add column to array
	ReDim $aGLVEx_SrcArray[UBound($aGLVEx_SrcArray)][UBound($aGLVEx_SrcArray, 2) + 1]
	ReDim $aGLVEx_SrcColArray[UBound($aGLVEx_SrcColArray)][UBound($aGLVEx_SrcColArray, 2) + 1]
	; Move data and blank new column
	For $i = 0 To UBound($aGLVEx_SrcArray) - 1
		For $j = UBound($aGLVEx_SrcArray, 2) - 2 To $iCol Step -1
			$aGLVEx_SrcArray[$i][$j + 1] = $aGLVEx_SrcArray[$i][$j]
			$aGLVEx_SrcColArray[$i][$j + 1] = $aGLVEx_SrcColArray[$i][$j]
		Next
		$aGLVEx_SrcArray[$i][$iCol] = ""
		$aGLVEx_SrcColArray[$i][$iCol] = ";"
	Next

	; And now for the editable columns and header data (fixed number of rows)
	ReDim $aEditable[3][UBound($aEditable, 2) + 1]
	ReDim $aHdrData[3][UBound($aHdrData, 2) + 1]

	For $i = 0 To 2
		For $j = UBound($aEditable, 2) - 2 To $iCol Step -1
			$aEditable[$i][$j + 1] = $aEditable[$i][$j]
			$aHdrData[$i][$j + 1] = $aHdrData[$i][$j]
		Next
		$aEditable[$i][$iCol] = ""
	Next
	; Set new column title with default colours
	$aHdrData[0][$iCol] = $sTitle
	$aHdrData[1][$iCol] = ";"
	$aHdrData[2][$iCol] = ""

	; Store amended arrays
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	$aGLVEx_Data[$iLV_Index][7] = $aEditable
	If $aGLVEx_Data[$iLV_Index][24] Then ; Header colour enabled
		$aGLVEx_Data[$iLV_Index][25] = $aHdrData
	EndIf

	; Add column to ListView
	_GUICtrlListView_InsertColumn($hGLVEx_SrcHandle, $iCol, $sTitle, $iWidth)

	; If Loop No Redraw flag set
	If $aGLVEx_Data[0][15] Then
		; Rewrite ListView
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)
	EndIf

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Reset sort array
	Local $aLVSortState[_GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle)]
	$aGLVEx_Data[$iLV_Index][4] = $aLVSortState

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_InsertColSpec

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DeleteCol
; Description ...: Deletes selected column in active ListView
; Syntax.........: _GUIListViewEx_DeleteCol()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView content with count in [0] element
;                  Failure: If no ListView active then returns "" and sets @error to 1
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DeleteCol()

	; Set data for active ListView
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; If no ListView active then return
	If $iLV_Index = 0 Then Return SetError(1, 0, "")

	; Delete active column
	Local $vRet = _GUIListViewEx_DeleteColSpec($iLV_Index, $aGLVEx_Data[0][2])

	Return SetError(@error, 0, $vRet)

EndFunc   ;==>_GUIListViewEx_DeleteCol

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DeleteColSpec
; Description ...: Deletes specified column in specified ListView
; Syntax.........: _GUIListViewEx_DeleteCol($iLV_Index[, $iCol = -1])
; Parameters ....: $iLV_Index - Index of ListView as returned by _GUIListViewEx_Init
;                  $iCol      - (Optional) Column to delete - default -1 deletes rightmost column
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array of active ListView content with count in [0] element
;                  Failure: Empty string and sets @error to
;                      1 = Invalid ListView index
;                      2 = Invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DeleteColSpec($iLV_Index, $iCol = -1)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]

	; Copy array for manipulation
	$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	$aGLVEx_SrcColArray = $aGLVEx_Data[$iLV_Index][18]
	Local $aEditable = $aGLVEx_Data[$iLV_Index][7]
	Local $aHdrData[3][UBound($aGLVEx_SrcArray, 2)]
	If $aGLVEx_Data[$iLV_Index][24] Then ; Header colour enabled
		$aHdrData = $aGLVEx_Data[$iLV_Index][25]
	EndIf

	; Check if valid column
	Local $iMax_Col = UBound($aGLVEx_SrcArray, 2) - 1
	If $iCol = -1 Then $iCol = $iMax_Col
	If $iCol < 0 Or $iCol > $iMax_Col Then Return SetError(2, 0, "")

	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next

	; Set no redraw flag - prevents problems while colour arrays are updated
	$aGLVEx_Data[0][12] = True

	; Move data
	For $i = 0 To UBound($aGLVEx_SrcArray) - 1
		For $j = $iCol To UBound($aGLVEx_SrcArray, 2) - 2
			$aGLVEx_SrcArray[$i][$j] = $aGLVEx_SrcArray[$i][$j + 1]
			$aGLVEx_SrcColArray[$i][$j] = $aGLVEx_SrcColArray[$i][$j + 1]
		Next
	Next
	; Resize arrays
	ReDim $aGLVEx_SrcArray[UBound($aGLVEx_SrcArray)][UBound($aGLVEx_SrcArray, 2) - 1]
	ReDim $aGLVEx_SrcColArray[UBound($aGLVEx_SrcColArray)][UBound($aGLVEx_SrcColArray, 2) - 1]
	; And now for the editable columns and header data (fixed number of rows)
	For $i = 0 To 2
		For $j = $iCol To UBound($aEditable, 2) - 2
			$aEditable[$i][$j] = $aEditable[$i][$j + 1]
			$aHdrData[$i][$j] = $aHdrData[$i][$j + 1]
		Next
	Next
	ReDim $aEditable[3][UBound($aEditable, 2) - 1]
	ReDim $aHdrData[3][UBound($aHdrData, 2) - 1]

	; Delete column from ListView
	_GUICtrlListView_DeleteColumn($hGLVEx_SrcHandle, $iCol)

	; Store amended arrays
	$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
	$aGLVEx_Data[$iLV_Index][18] = $aGLVEx_SrcColArray
	$aGLVEx_Data[$iLV_Index][7] = $aEditable
	If $aGLVEx_Data[$iLV_Index][24] Then ; Header colour enabled
		$aGLVEx_Data[$iLV_Index][25] = $aHdrData
	EndIf

	; If Loop No Redraw flag set
	If $aGLVEx_Data[0][15] Then
		; Rewrite ListView
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iLV_Index, $fCheckBox)
	EndIf

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iLV_Index)

	; Delete copied array
	$aGLVEx_SrcArray = 0
	$aGLVEx_SrcColArray = 0

	; Reset sort array
	Local $aLVSortState[_GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle)]
	$aGLVEx_Data[$iLV_Index][4] = $aLVSortState

	; Return amended array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_DeleteColSpec

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SortCol
; Description ...: Sort specified column in specified ListView
; Syntax.........: _GUIListViewEx_SortCol($iLV_Index[, $iCol = -1])
; Parameters ....: $iLV_Index - Index of ListView as returned by _GUIListViewEx_Init
;                  $iCol      - (Optional) Column to sort - default -1 sorts active column
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error to
;                      1 = Invalid ListView index
;                      2 = Invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SortCol($iLV_Index, $iCol = -1)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

	; Load array
	Local $aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
	; Check if valid column
	Local $iMax_Col = UBound($aGLVEx_SrcArray, 2) - 1
	If $iCol = -1 Then
		; Use active column
		$iCol = $aGLVEx_Data[$iLV_Index][21]
	EndIf
	If $iCol < 0 Or $iCol > $iMax_Col Then Return SetError(2, 0, 0)

	; Load current ListView sort state array
	Local $aLVSortState = $aGLVEx_Data[$iLV_Index][4]
	; Sort column
	__GUIListViewEx_ColSort($aGLVEx_Data[$iLV_Index][0], $iLV_Index, $aLVSortState, $iCol)

	Return 1

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetEditStatus
; Description ...: Sets edit on doubleclick mode for specified column(s)
; Syntax.........: _GUIListViewEx_SetEditStatus($iLV_Index, $vCol [, $iMode = 1 ], $vParam1 = Default [, $vParam2 = Default]]])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $vCol      - Column of ListView to set (string or number)
;                                   All columns: "*"
;                                   Range string example: "1;2;5-6;8-9;10" - expanded automatically
;                  $iMode     - 0 = Not editable
;                                   $vParam1 & $vParam2 ignored
;                  $iMode     - 1 = Editable using manual input
;                                   $vParam1 & $vParam2 ignored
;                  $iMode     - 2 = Editable using combo
;                                   $vParam1 = Content of combo - either delimited string or 0-based array
;                                   $vParam2 = True: readonly, False: editable combo (default)
;                  $iMode     - 3 = Editable using date control
;                                   $vParam1 = Preselected date f(yyyy\MM\dd) - default current date
;                                   $vParam2 = Required display format for DTP control (see below) - default system date setting
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - Invalid column parameter
;                           3 - Invalid mode
;                           4 - Invalid $vParam1/2 - @extended set as follows
;                               1 = Mode 2: $vParam1 not string or array
;                               2 = Mode 2: $vParam2 not boolean
;                               3 = Mode 3: $vParam1 date string incorrectly formatted
; Author ........: Melba23
; Modified ......:
; Remarks .......: - Overrides all previous edit settings for the specified column(s).
;                  - Columns are non-editable by default so function only required to set editable columns
;                  - {ENTER} accepts edit - {TAB} accepts and moves to next cell if EditMode allows
;                  - {ESCAPE} abandons edit, and possibly all text edits if EditMode negative
;                  - Ctrl-{LEFT}{RIGHT}{UP}{DOWN} moves to next cell if EditMode allows
;                        - Accepts input for manual text
;                        - Abandons input for combo and date (because they use arrow keys to modify their data)
;                  - Display format string for date control uses any of following plus required punctuation/spacing:
;                       "d"    - One/two digit day
;                       "dd"   - Two digit day padded with leading zero if required
;                       "ddd"  - 3-char weekday abbreviation
;                       "dddd" - Full weekday name
;                       "h"    - One/two digit hour - 12-hour format
;                       "hh"   - Two digit hour padded with leading zero if required - 12-hour format
;                       "H"    - One/two digit hour - 24-hour format
;                       "HH"   - Two digit hour padded with leading zero if required - 24 hour format
;                       "m"    - One/two digit minute
;                       "mm"   - Two digit minute padded with leading zero if required
;                       "M"    - One/two digit month number
;                       "MM"   - Two digit month number padded with leading zero if required
;                       "MMM"  - 3-char month abbreviation
;                       "MMMM" - Full month name
;                       "t"    - One letter AM/PM abbreviation
;                       "tt"   - Two letter AM/PM abbreviation
;                       "yy"   - Last two digits of year
;                       "yyyy" - Full year
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SetEditStatus($iLV_Index, $vCol, $iMode = 1, $vParam1 = Default, $vParam2 = Default)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then
		Return SetError(1, 0, 0)
	EndIf

	; Check column index
	Local $aRange = __GUIListViewEx_ExpandRange($vCol, $iLV_Index)
	If @error Then Return SetError(2, 0, 0)

	; Extract editable array
	Local $aEditable = $aGLVEx_Data[$iLV_Index][7]

	Switch $iMode
		Case 0, 1 ; Not editable/editable
			For $i = 1 To $aRange[0]
				; Set/clear status and clear any other edit data
				$aEditable[0][$aRange[$i]] = $iMode
				$aEditable[1][$aRange[$i]] = ""
				$aEditable[2][$aRange[$i]] = ""
			Next

		Case 2
			If Not (IsArray($vParam1) Or IsString($vParam1)) Then
				Return SetError(4, 1, 0)
			EndIf
			If $vParam2 = Default Then $vParam2 = False
			If Not IsBool($vParam2) Then
				Return SetError(4, 2, 0)
			EndIf
			For $i = 1 To $aRange[0]
				; Set status and combo data/format
				$aEditable[0][$aRange[$i]] = 2
				$aEditable[1][$aRange[$i]] = $vParam1
				$aEditable[2][$aRange[$i]] = $vParam2
			Next

		Case 3
			If $vParam1 = Default Then
				$vParam1 = ""
			EndIf
			If $vParam1 <> "" And (Not StringRegExp($vParam1, "\d{4}\/\d{2}\/\d{2}")) Then
				Return SetError(4, 3, 0)
			EndIf
			If $vParam2 = Default Then
				$vParam2 = ""
			EndIf
			For $i = 1 To $aRange[0]
				; Set status and date default/format
				$aEditable[0][$aRange[$i]] = 3
				$aEditable[1][$aRange[$i]] = $vParam1
				$aEditable[2][$aRange[$i]] = $vParam2
			Next

		Case Else
			Return SetError(3, 0, 0)
	EndSwitch

	; Store amended array
	$aGLVEx_Data[$iLV_Index][7] = $aEditable

	; Show success
	Return 1

EndFunc   ;==>_GUIListViewEx_SetEditStatus

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetEditKey
; Description ...: Sets key(s) required to begin edit of selected item
; Syntax.........: _GUIListViewEx_SetEditKey([$sKey = Default])
; Parameters ....: $sKey - String of key(s): 0/1/2 modifiers (^ = Ctrl, ! = Alt) plus single main key code from _IsPressed
;                          Default - reset default key = BackSpace
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                           1 - Invalid string
; Author ........: Melba23
; Modified ......:
; Remarks .......: Shift key not available as modifier
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SetEditKey($sKey = Default)

	; Check for default reset
	If $sKey = Default Then
		$aGLVEx_Data[0][23] = "08"
		Return 1
	EndIf
	; Check string format
	If Not StringregExp($sKey, "(?i)^([!^]){0,2}([0-9a-f]{2})$") Then
		Return SetError(1, 0, 0)
	EndIf
	; Replace modifier(s) and store code
	$aGLVEx_Data[0][23] = StringReplace(StringReplace($sKey, "^", "11;"), "!", "12;")
	Return 1

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_EditOnClick
; Description ...: Allow content of editable ListView items to be modified when doubleclicked
; Syntax.........: _GUIListViewEx_EditOnClick([$iEditMode = 0[, $iDelta_X = 0[, $iDelta_Y = 0]]])
; Parameters ....: $iEditMode - Only used if using Edit control:
;                                    Return after single edit - 0 (default)
;                                    {TAB} and ctrl-arrow keys move to next item - 2-digit code (row mode/column mode)
;                                        0 = Cannot move
;                                        1 = Reaching edge terminates edit process
;                                        2 = Reaching edge remains in place
;                                        3 = Reaching edge loops to opposite edge
;                               	     Positive value = ESC abandons current edit only, previous edits remain
;                                        Negative value = ESC resets all edits in current session
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3.10 +
; Return values .: If no double-click: Empty string
; Return values .: Success: 2D array of items edited
;                              - Total number of edits in [0][0] element, with each edit following:
;                              - [zero-based row][zero-based column][original content][new content]
;                  After double-click just above ListView header:
;                      2D array  [column edited][original header text][new header text]
;                  Failure: Sets @error as follows:
;                      1 - ListView not editable
;                      2 - Empty ListView
;                      3 - Column not editable
; Author ........: Melba23
; Modified ......:
; Remarks .......: - This function must be placed within the script idle loop.
;                  - Once item edit process started, all other script activity is suspended until following occurs:
;                      {ENTER}  = Current edit confirmed and editing process ended
;                      {ESCAPE} = Current or all edits cancelled and editing process ended
;                      If $iEditMode non-zero then {TAB} and ctrl-arrow keys =
;                          For edit controls: Current edit confirmed & continue editing
;                          For cother controls: Current edit cancelled & continue editing
;                      If using Edit control:
;                          Click outside edit = Editing process ends and
;                              If $iAdded + 4 : Current edit accepted
;                              Else           : Current edit cancelled
;                      If using Combo control:
;                          Combo actioned     = Combo selection accepted and editing process ended
;                          Click outside edit = Edit process ended and editing process ended
;                  For header edit only {ENTER}, {ESCAPE} and mouse click are actioned - single edit only
;                  - The function only returns an array after an edit process launched by a double-click.  If no
;                  double-click has occurred, the function returns an empty string.  The user should check that a
;                  valid array is present before attempting to access it.
;                  - If header edited [0][1] element of returned array exists - if items edited this element is empty
;                  - Returned array allows verification of new value(s) - _GUIListViewEx_ChangeItem can reset original)s
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_EditOnClick($iEditMode = 0, $iDelta_X = 0, $iDelta_Y = 0)

	Local $aEdited

	; If an item was double clicked
	If $fGLVEx_EditClickFlag <> 0 Then

		; Set active ListView
		Local $iLV_Index = $fGLVEx_EditClickFlag
		$aGLVEx_Data[0][1] = $iLV_Index

		; Clear flag
		$fGLVEx_EditClickFlag = 0

		; Check Type parameter
		Switch Abs($iEditMode)
			Case 0, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33 ; Single edit or both axes set to valid parameter
				; Allow
			Case Else
				Return SetError(1, 0, "")
		EndSwitch

		; Get clicked item info
		Local $aLocation[2] = [$aGLVEx_Data[0][17], $aGLVEx_Data[0][18]]
		; Check valid row
		If $aLocation[0] = -1 Then
			Return SetError(3, 0, "")
		EndIf

		; Check for valid editable colum
		Local $aEditable = $aGLVEx_Data[$iLV_Index][7]
		If $aEditable[0][$aLocation[1]] = 0 Then
			Return SetError(1, 0, "")
		EndIf

		; Start edit
		$aEdited = __GUIListViewEx_EditProcess($iLV_Index, $aLocation, $iDelta_X, $iDelta_Y, $iEditMode)
		; Return result array
		Return SetError(@error, 0, $aEdited)

	EndIf

	; If a header was Ctrl-clicked
	If $fGLVEx_HeaderEdit Then

		; Clear the flag
		$fGLVEx_HeaderEdit = False

		; Wait until mouse button released as click occurs outside the control or Ctrl key still pressed
		While _WinAPI_GetAsyncKeyState(0x01) Or _WinAPI_GetAsyncKeyState(0x11)
			Sleep(10)
		WEnd

		; Edit header using the default values set by the handler
		$aEdited = _GUIListViewEx_EditHeader()
		; Return result
		Return SetError(@error, 0, $aEdited)

	EndIf

	; If nothing was clicked
	Return ""

EndFunc   ;==>_GUIListViewEx_EditOnClick

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_EditItem
; Description ...: Open ListView items for editing programatically
; Syntax.........: _GUIListViewEx_EditItem($iLV_Index, $iRow, $iCol[, $iEditMode = 0[, $iDelta_X = 0[, $iDelta_Y = 0]]])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $iRow      - Zero-based row of item to edit
;                  $iCol      - Zero-based column of item to edit
;                  $iEditMode - Only used if using Edit control:
;                                    Return after single edit - 0 (default)
;                                    {TAB} and arrow keys move to next item - 2-digit code (row mode/column mode)
;                                        1 = Reaching edge terminates edit process
;                                        2 = Reaching edge remains in place
;                                        3 = Reaching edge loops to opposite edge
;                               	     Positive value = ESC abandons current edit only, previous edits remain
;                                        Negative value = ESC resets all edits in current session
;                               Ignored if using Combo control - return after single edit
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3.10 +
; Return values .: Success: 2D array of items edited
;                              - Total number of edits in [0][0] element, with each edit following:
;                              - [zero-based row][zero-based column][original content][new content]
;                           @extended set depending on key used to end edit:
;							   - True = {ENTER} pressed
;							   - False = {ESC} pressed
;                  Failure: Sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - ListView not editable
;                           3 - Invalid row
;                           4 - Invalid column
;                           5 - Invalid edit mode
; Author ........: Melba23
; Modified ......:
; Remarks .......: - Once edit started, all other script activity is suspended as explained for _GUIListViewEx_EditOnClick
;                  - Returned array allows for verification of new value - _GUIListViewEx_ChangeItem can reset original
;                  - @extended value can be used to determine if to continue in a loop post-edit
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_EditItem($iLV_Index, $iRow, $iCol, $iEditMode = 0, $iDelta_X = 0, $iDelta_Y = 0)

	; Activate the ListView
	_GUIListViewEx_SetActive($iLV_Index)
	If @error Then
		Return SetError(1, 0, "")
	EndIf
	; Check row and col values
	Local $iMax = _GUICtrlListView_GetItemCount($hGLVEx_SrcHandle)
	If $iRow < 0 Or $iRow > $iMax - 1 Then
		Return SetError(3, 0, "")
	EndIf
	$iMax = _GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle)
	If $iCol < 0 Or $iCol > $iMax - 1 Then
		Return SetError(4, 0, "")
	EndIf
	; Check edit mode parameter
	Switch Abs($iEditMode)
		Case 0, 11, 12, 13, 21, 22, 23, 31, 32, 33 ; Single edit or both axes set to valid parameter
			; Allow
		Case Else
			Return SetError(5, 0, "")
	EndSwitch
	; Declare location array
	Local $aLocation[2] = [$iRow, $iCol]
	; Start edit - force text edit type
	Local $aEdited = __GUIListViewEx_EditProcess($iLV_Index, $aLocation, $iDelta_X, $iDelta_Y, $iEditMode, True)
	; Determine key used to exit
	Local $iKeyCode = @extended
	; Wait until return key no longer pressed
	While _WinAPI_GetAsyncKeyState($iKeyCode)
		Sleep(10)
	WEnd
	; Unselect row
	_GUICtrlListView_SetItemSelected($aGLVEx_Data[$iLV_Index][0], -1, False)
	; Set extended value
	SetExtended(($iKeyCode = 0x0D) ? (True) : (False))
	; Return result array
	Return $aEdited

EndFunc   ;==>_GUIListViewEx_EditItem

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_EditWidth
; Description ...: Set required widths for column edit/combo when editing
; Syntax.........: _GUIListViewEx_EditWidth($iLV_Index, $aWidth)
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $aWidth    - Zero-based 1D array of required edit/combo widths where array index = column
;                               0/Default/empty = use actual column width
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - Invalid $aWidth array
; Author ........: Melba23
; Modified ......:
; Remarks .......: $aWidth will be ReDimmed to match columns - all values converted to Number datatype.
;                  Negative value resizes read-only combo edit control, otherwise only dropdown resized.
;                  Actual column width used if wider than set value
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_EditWidth($iLV_Index, $aWidth)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then
		Return SetError(1, 0, 0)
	EndIf
	; Check valid array
	If (Not IsArray($aWidth)) Or (UBound($aWidth, 0) <> 1) Then Return SetError(2, 0, 0)
	; Resize array
	ReDim $aWidth[_GUICtrlListView_GetColumnCount($aGLVEx_Data[$iLV_Index][0])]
	; Store array
	$aGLVEx_Data[$iLV_Index][14] = $aWidth

EndFunc   ;==>_GUIListViewEx_EditWidth

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ChangeItem
; Description ...: Change ListView item content programatically
; Syntax.........: _GUIListViewEx_ChangeItem($iLV_Index, $iRow, $iCol, $vValue)
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $iRow      - Zero-based row of item to change
;                  $iCol      - Zero-based column of item to change
;                  $vValue    - Content to place in ListView item
; Requirement(s).: v3.3.10 +
; Return values .: Success: Success: Array of current ListView content as returned by _GUIListViewEx_ReturnArray
;                  Failure: Sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - ListView not editable
;                           3 - Invalid row
;                           4 - Invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ChangeItem($iLV_Index, $iRow, $iCol, $vValue)

	; Activate the ListView
	_GUIListViewEx_SetActive($iLV_Index)
	If @error Then
		Return SetError(1, 0, "")
	EndIf
	; Check ListView is editable
	If $aGLVEx_Data[$iLV_Index][7] = "" Then
		Return SetError(2, 0, "")
	EndIf
	; Check row and col values
	Local $iMax = _GUICtrlListView_GetItemCount($hGLVEx_SrcHandle)
	If $iRow < 0 Or $iRow > $iMax - 1 Then
		Return SetError(3, 0, "")
	EndIf
	$iMax = _GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle)
	If $iCol < 0 Or $iCol > $iMax - 1 Then
		Return SetError(4, 0, "")
	EndIf
	; Load array
	Local $aData_Array = $aGLVEx_Data[$iLV_Index][2]
	Local $fCheckBox = $aGLVEx_Data[$iLV_Index][6]
	; Create Local array for checkboxes (if no checkboxes makes no difference)
	Local $aCheck_Array[UBound($aData_Array)]
	For $i = 1 To UBound($aCheck_Array) - 1
		$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
	Next
	If Not BitAND($aGLVEx_Data[$iLV_Index][3], 1) Then
		_ArrayInsert($aCheck_Array, 0, $aData_Array[0][0])
	EndIf
	; Change item in array
	$aData_Array[$iRow + 1][$iCol] = $vValue
	; Store modified array
	$aGLVEx_Data[$iLV_Index][2] = $aData_Array
	; If Loop No Redraw flag set
	If $aGLVEx_Data[0][15] Then
		; Rewrite ListView
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aData_Array, $aCheck_Array, $iLV_Index, $fCheckBox)
	EndIf
	; Return changed array
	Return _GUIListViewEx_ReturnArray($iLV_Index)

EndFunc   ;==>_GUIListViewEx_ChangeItem

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_LoadHdrData
; Description ...: Sets header title, text and back colour (if enabled), and sets edit mode (if enabled)
; Syntax.........: _GUIListViewEx_LoadHdrData($iLV_Index, $aHdrData)
; Parameters ....: $iLV_Index - Index of ListView
;                  $aColArray - 0-based 3-row 2D array containing titles, semicolon delimited colour strings in RGB hex
;                                 [0][RowIndex] = Title - only needed if headers colour enabled
;                                 [1][RowIndex] = Colour strings in RGB hex - only if header colour enabled
;                                                    "text;back"        = both colours set
;                                                    "text;" or ";back" = one colour set
;                                                    ";" or ""          = use default colours
;                                 [2][RowIndex] = Delimited string = Edit header with combo - leading @TAB = read only
;                                                 Empty string     = Edit header as text
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 1
;                  Failure: Returns 0 and sets @error as follows:
;                      1 = Invalid index
;                      2 = Array not 2D (@extended = 0) or not correct size for LV (@extended = 1)
;                      3 = Header colour not enabled but colour set
;                      4 = Invalid colour string
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_LoadHdrData($iLV_Index, $aHdrData)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)
	; Check only 3 rows
	If UBound($aHdrData, 0) <> 2 Then
		Return SetError(2, 0, 0)
	EndIf
	; Compare number of columns
	If (UBound($aHdrData, 2) <> UBound($aGLVEx_Data[$iLV_Index][2], 2)) Or (UBound($aHdrData) <> 3) Then
		Return SetError(2, 1, 0)
	EndIf
	; Convert colours to BGR
	Local $sColSet, $aColSplit
	For $i = 0 To UBound($aHdrData, 2) - 1
		; Force empty colour to ;
		$sColSet = $aHdrData[1][$i]
		If $sColSet = "" Then
			$sColSet = ";"
		EndIf
		; Check valid colour string
		If Not StringRegExp($sColSet, "^(\Q0x\E[0-9A-Fa-f]{6})?;(\Q0x\E[0-9A-Fa-f]{6})?$") Then
			Return SetError(4, 0, 0)
		EndIf
		$aColSplit = StringSplit($sColSet, ";")
		; Convert colours to BGR
		For $j = 1 To 2
			; If colour set check header colour enabled
			If $aColSplit[$j] And Not $aGLVEx_Data[$iLV_Index][24] Then
				Return SetError(3, 0, 0)
			Else
				$aColSplit[$j] = StringRegExpReplace($aColSplit[$j], "0x(.{2})(.{2})(.{2})", "0x$3$2$1")
			EndIf
		Next
		; Reset to converted colour
		$aHdrData[1][$i] = $aColSplit[1] & ";" & $aColSplit[2]
	Next

	; Store header data
	$aGLVEx_Data[$iLV_Index][25] = $aHdrData

	; Force redraw
	__GUIListViewEx_RedrawWindow($iLV_Index, True)

	Return 1

EndFunc   ;==>_GUIListViewEx_LoadHdrData

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_EditHeader
; Description ...: Manual edit of specified ListView header
; Syntax.........: _GUIListViewEx_EditHeader([$iLV_Index = Default[, $iCol = Default[, $iDelta_X = 0[, $iDelta_Y = 0]]]])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init - default active ListView
;                  $iCol      - Zero-based column of header to edit
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3.10 +
; Return values .: Success: Array: 2D array [column][original header text][new header text]
;                  Failure: Empty string and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - ListView headers not editable
;                           3 - Invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......: Once edit started, all other script activity is suspended until following occurs:
;                      {ENTER}  = Current edit confirmed and editing ended
;                      {ESCAPE} or click on other control = Current edit cancelled and editing ended
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_EditHeader($iLV_Index = Default, $iCol = Default, $iDelta_X = 0, $iDelta_Y = 0)

	Local $aRet = ""

	If $iLV_Index = Default Then
		$iLV_Index = $aGLVEx_Data[0][1]
	EndIf
	; Activate the ListView
	_GUIListViewEx_SetActive($iLV_Index)
	If @error Then
		Return SetError(1, 0, $aRet)
	EndIf

	Local $hLV_Handle = $aGLVEx_Data[$iLV_Index][0]
	Local $cLV_CID = $aGLVEx_Data[$iLV_Index][1]

	; Check ListView headers are editable
	If $aGLVEx_Data[$iLV_Index][8] = "" Then
		Return SetError(2, 0, $aRet)
	EndIf
	; Check col value
	If $iCol = Default Then
		$iCol = $aGLVEx_Data[0][2]
	EndIf
	Local $iMax = _GUICtrlListView_GetColumnCount($hLV_Handle)
	If $iCol < 0 Or $iCol > $iMax - 1 Then
		Return SetError(3, 0, $aRet)
	EndIf

	Local $tLVPos = DllStructCreate("struct;long X;long Y;endstruct")
	; Get position of ListView within GUI client area
	__GUIListViewEx_GetLVCoords($hLV_Handle, $tLVPos)
	; Get ListView client area to allow for scrollbars
	Local $aLVClient = WinGetClientSize($hLV_Handle)
	; Get ListView font details
	Local $aLV_FontDetails = __GUIListViewEx_GetLVFont($hLV_Handle)
	; Disable ListView
	WinSetState($hLV_Handle, "", @SW_DISABLE)
	; Load header data
	Local $aHdrData = $aGLVEx_Data[$iLV_Index][25]
	; Get current text of header
	Local $aColData, $sHeaderOrgText
	; Check if header colour enabled
	If $aGLVEx_Data[$iLV_Index][24] Then
		$sHeaderOrgText = $aHdrData[0][$iCol]
	Else
		$aColData = _GUICtrlListView_GetColumn($hLV_Handle, $iCol)
		$sHeaderOrgText = $aColData[5]
	EndIf
	; Get required edit coords for 0 item
	Local $aLocation[2] = [0, $iCol]
	Local $aEdit_Coords = __GUIListViewEx_EditCoords($hLV_Handle, $cLV_CID, $aLocation, $tLVPos, $aLVClient[0] - 5, $iDelta_X, $iDelta_Y)
	; Now get header size and adjust coords for header
	Local $hHeader = _GUICtrlListView_GetHeader($hLV_Handle)
	Local $aHeader_Pos = WinGetPos($hHeader)
	$aEdit_Coords[0] -= 2
	$aEdit_Coords[1] -= $aHeader_Pos[3]
	$aEdit_Coords[3] = $aHeader_Pos[3]

	Local $hCombo, $hTemp_Edit, $hTemp_List, $hTemp_Combo, $sCombo_Data

	; Check edit mode
	If $aHdrData[2][$iCol] Then ; Combo
		$sCombo_Data = $aHdrData[2][$iCol]
		; Create temporary combo
		If StringLeft($sCombo_Data, 1) = @TAB Then ; Read only combo
			$cGLVEx_EditID = GUICtrlCreateCombo("", $aEdit_Coords[0], $aEdit_Coords[1], $aEdit_Coords[2], $aEdit_Coords[3], 0x00200043) ; $CBS_DROPDOWNLIST, $CBS_AUTOHSCROLL, $WS_VSCROLL
			$sCombo_Data = StringTrimLeft($sCombo_Data, 1)
		Else ; Normal combo
			$cGLVEx_EditID = GUICtrlCreateCombo("", $aEdit_Coords[0], $aEdit_Coords[1], $aEdit_Coords[2], $aEdit_Coords[3], 0x00200042) ; $CBS_DROPDOWN, $CBS_AUTOHSCROLL, $WS_VSCROLL
		EndIf
		GUICtrlSetData($cGLVEx_EditID, $sCombo_Data)
		; Get combo data
		$hCombo = GUICtrlGetHandle($cGLVEx_EditID)
		Local $tInfo = DllStructCreate("dword Size;struct;long EditLeft;long EditTop;long EditRight;long EditBottom;endstruct;" & _
						"struct;long BtnLeft;long BtnTop;long BtnRight;long BtnBottom;endstruct;dword BtnState;hwnd hCombo;hwnd hEdit;hwnd hList")
		Local $iInfo = DllStructGetSize($tInfo)
		DllStructSetData($tInfo, "Size", $iInfo)
		_SendMessage($hCombo, 0x164, 0, $tInfo, 0, "wparam", "struct*") ; $CB_GETCOMBOBOXINFO
		$hTemp_Edit = DllStructGetData($tInfo, "hEdit")
		$hTemp_List = DllStructGetData($tInfo, "hList")
		$hTemp_Combo = DllStructGetData($tInfo, "hCombo")
	Else ; Edit
		; Create temporary edit
		$cGLVEx_EditID = GUICtrlCreateEdit($sHeaderOrgText, $aEdit_Coords[0], $aEdit_Coords[1], $aEdit_Coords[2], $aEdit_Coords[3], 0)
		$hTemp_Edit = GUICtrlGetHandle($cGLVEx_EditID)
	EndIf
	; Set font size
	GUICtrlSetFont($cGLVEx_EditID, $aLV_FontDetails[0], Default, Default, $aLV_FontDetails[1])
	; Give keyboard focus
	_WinAPI_SetFocus($hTemp_Edit)
	; Check "select all" flag state
	If Not $aGLVEx_Data[$iLV_Index][11] Then
		GUICtrlSendMsg($cGLVEx_EditID, 0xB1, 0, -1) ; $EM_SETSEL
	EndIf

	Local $tMouseClick = DllStructCreate($tagPOINT)

	; Valid keys to action (ENTER, ESC)
	Local $aKeys[2] = [0x0D, 0x1B]
	; Clear key code flag
	Local $iKey_Code = 0
	Local $iCombo_State = False
	; Prevent GUI closure on ESC as needed to exit edit
	Local $iOldESC = Opt("GUICloseOnESC", 0)

	; Wait for a key press
	While 1
		; Check for SYSCOMMAND Close Event
		If $aGLVEx_Data[0][9] Then
			$aGLVEx_Data[0][9] = False
			ExitLoop
		EndIf
		; Check for valid key or mouse button pressed or combo open/close
		For $i = 0 To 1
			If _WinAPI_GetAsyncKeyState($aKeys[$i]) Then
				; Set key pressed flag
				$iKey_Code = $aKeys[$i]
				ExitLoop 2
			EndIf
		Next
		; Temp input loses focus
		If _WinAPI_GetFocus() <> $hTemp_Edit Then
			ExitLoop
		EndIf
		; Check for mouse pressed outside edit
		If _WinAPI_GetAsyncKeyState(0x01) Then
			; Look for clicks outside edit/combo control
			DllStructSetData($tMouseClick, "x", MouseGetPos(0))
			DllStructSetData($tMouseClick, "y", MouseGetPos(1))
			Switch _WinAPI_WindowFromPoint($tMouseClick)
				Case $hTemp_Combo, $hTemp_Edit, $hTemp_List
					; Over edit/combo
				Case Else
					ExitLoop
			EndSwitch
			; Wait for mouse button release
			While _WinAPI_GetAsyncKeyState(0x01)
				Sleep(10)
			WEnd
		EndIf
		If $hCombo Then
			; Check for dropdown open and close
			Switch _SendMessage($hCombo, 0x157) ; $CB_GETDROPPEDSTATE
				Case 0
					; If opened and closed
					If $iCombo_State = True Then
						; If no content
						If GUICtrlRead($cGLVEx_EditID) = "" Then
							; Ignore
							$iCombo_State = False
						Else
							; Act as if Enter pressed
							$iKey_Code = 0x0D
							ExitLoop
						EndIf
					EndIf
				Case 1
					; Set flag if opened
					If Not $iCombo_State Then
						$iCombo_State = True
					EndIf
			EndSwitch
		EndIf
		; Save CPU
		Sleep(10)
	WEnd
	; Action keypress
	Switch $iKey_Code
		Case 0x0D
			; Change column header text
			Local $sHeaderNewText = GUICtrlRead($cGLVEx_EditID)
			If $sHeaderNewText <> $sHeaderOrgText Then
				; Check if header colour enabled
				If $aGLVEx_Data[$iLV_Index][24] Then
					$aHdrData[0][$iCol] = $sHeaderNewText
					$aGLVEx_Data[$iLV_Index][25] = $aHdrData
				Else
					_GUICtrlListView_SetColumn($hLV_Handle, $iCol, $sHeaderNewText)
					Local $aRet[1][3] = [[$iCol, $sHeaderOrgText, $sHeaderNewText]]
				EndIf
			EndIf
		Case Else
	EndSwitch
	; Wait until key no longer pressed
	While _WinAPI_GetAsyncKeyState($iKey_Code)
		Sleep(10)
	WEnd

	; Reset user value
	Opt("GUICloseOnESC", $iOldESC)
	; Delete Edit
	GUICtrlDelete($cGLVEx_EditID)
	; Reenable ListView
	WinSetState($hLV_Handle, "", @SW_ENABLE)

	Return $aRet

EndFunc   ;==>_GUIListViewEx_EditHeader

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_LoadColour
; Description ...: Uses array to set text and back colour for a user colour enabled ListView
; Syntax.........: _GUIListViewEx_LoadColour($iLV_Index, $aColArray)
; Parameters ....: $iLV_Index - Index of ListView
;                  $aColArray - 0-based 2D array containing colour strings in RGB hex
;                                    "text;back"        = both user colours set
;                                    "text;" or ";back" = one user colour set
;                                    ";" or ""          = default colours
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 1
;                  Failure: Returns 0 and sets @error as follows:
;                      1 = Invalid index
;                      2 = ListView not user colour enabled
;                      3 = Array not 2D (@extended = 0) or not correct size for LV (@extended = 1)
;                      4 = Invalid colour string in array
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_LoadColour($iLV_Index, $aColArray)

	Local $sColSet

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)
	; Check ListView is user colour enabled
	If Not $aGLVEx_Data[$iLV_Index][19] Then
		Return SetError(2, 0, 0)
	EndIf
	If UBound($aColArray, 0) <> 2 Then
		Return SetError(3, 0, 0)
	EndIf

	; Add a 0-line to match the stored data array
	_ArrayInsert($aColArray, 0)
	; Compare sizes
	If (UBound($aColArray) <> UBound($aGLVEx_Data[$iLV_Index][2])) Or (UBound($aColArray, 2) <> UBound($aGLVEx_Data[$iLV_Index][2], 2)) Then
		Return SetError(3, 1, 0)
	EndIf
	; Convert all colours to BGR
	For $i = 1 To UBound($aColArray, 1) - 1
		For $j = 0 To UBound($aColArray, 2) - 1
			$sColSet = $aColArray[$i][$j]
			If $sColSet = "" Then
				$sColSet = ";"
				$aColArray[$i][$j] = ";"
			EndIf
			If Not StringRegExp($sColSet, "^(\Q0x\E[0-9A-Fa-f]{6})?;(\Q0x\E[0-9A-Fa-f]{6})?$") Then
				Return SetError(4, 0, 0)
			EndIf
			$aColArray[$i][$j] = StringRegExpReplace($sColSet, "0x(.{2})(.{2})(.{2})", "0x$3$2$1")
		Next
	Next
	$aGLVEx_Data[$iLV_Index][18] = $aColArray

	Return 1

EndFunc   ;==>_GUIListViewEx_LoadColour

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetDefColours
; Description ...: Sets default colours for user colour/single cell select enabled ListViews
; Syntax.........: _GUIListViewEx_SetDefColours($aDefCols)
; Parameters ....: $aDefCols - 1D 4-element array of hex RGB default colour strings
;                                (Normal text, Normal field, Selected text, Selected field)
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 1
;                  Failure: Returns 0 and sets @error as follows:
;                      1 = Invalid index
;                      2 = Not user colour or single cell selection enabled
;                      3 = Invalid array
;                      4 - Invalid colour
; Author ........: Melba23
; Modified ......:
; Remarks .......: Setting an element to Default resets the original default colour
;                  Setting an element to "" maintains current default colour
;                  Normal colours are used for all non-user coloured ListView items
;                  Selected colours used for row/single cell selection
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SetDefColours($iLV_Index, $aDefCols)

	; Check valid index
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)
	; Check colour or single cell enabled
	If Not ($aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22]) Then Return SetError(2, 0, 0)
	; Check valid array
	If Not IsArray($aDefCols) Or UBound($aDefCols) <> 4 Or UBound($aDefCols, 0) <> 1 Then Return SetError(3, 0, 0)

	; Load current colours
	Local $aCurCols = $aGLVEx_Data[$iLV_Index][23]
	; Loop through array
	Local $sCol
	For $i = 0 To 3
		If $aDefCols[$i] = Default Then
			; Reset default colour
			$aDefCols[$i] = $aGLVEx_DefColours[$i]
		ElseIf $aDefCols[$i] = "" Then
			; Maintain current colour
			$aDefCols[$i] = $aCurCols[$i]
		Else
			Switch Number($aDefCols[$i])
				; Check valid colour
				Case 0 To 0xFFFFFF
					; Convert to BGR
					$sCol = '0x' & StringMid($aDefCols[$i], 7, 2) & StringMid($aDefCols[$i], 5, 2) & StringMid($aDefCols[$i], 3, 2)
					; Save in array
					$aDefCols[$i] = $sCol
				Case Else
					Return SetError(4, 0, 0)
			EndSwitch
		EndIf
	Next
	; Store array
	$aGLVEx_Data[$iLV_Index][23] = $aDefCols

	; Force reload of redraw colour array
	__GUIListViewEx_RedrawWindow($iLV_Index, True)

	Return 1

EndFunc   ;==>_GUIListViewEx_SetDefColours

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetColour
; Description ...: Sets text and/or back colour for a user colour enabled ListView item
; Syntax.........: _GUIListViewEx_SetColour($iLV_Index, $sColSet, $iRow, $iCol)
; Parameters ....: $iLV_Index - Index of ListView
;                  $sColSet   - Colour string in RGB hex (0xRRGGBB)
;                                   "text;back"        = both user colours set
;                                   "text;" or ";back" = one user colour set, no change to other
;                                   ";" or ""          = reset both to default colours
;                  $iRow      - Row index (0-based)
;                  $iCol      - Column index (0-based)
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 1
;                  Failure: Returns 0 and sets @error as follows:
;                      1 = Invalid index
;                      2 = Not user colour enabled
;                      3 = Invalid colour
;                      4 - Invalid row/col
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SetColour($iLV_Index, $sColSet, $iRow, $iCol)

	; Activate the ListView
	_GUIListViewEx_SetActive($iLV_Index)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	; Check ListView is user colour enabled
	If Not $aGLVEx_Data[$iLV_Index][19] Then
		Return SetError(2, 0, 0)
	EndIf
	; Check colour
	If $sColSet = "" Then
		$sColSet = ";"
	EndIf
	; Check for default colour setting and set flag
	Local $fDefCol = (($sColSet = ";") ? (True) : (False))
	; Check for valid colour strings
	If Not StringRegExp($sColSet, "^(\Q0x\E[0-9A-Fa-f]{6})?;(\Q0x\E[0-9A-Fa-f]{6})?$") Then
		Return SetError(3, 0, 0)
	EndIf
	; Load current array
	Local $aColArray = $aGLVEx_Data[$iLV_Index][18]
	; Check position exists in ListView
	If $iRow < 0 Or $iCol < 0 Or $iRow > UBound($aColArray) - 2 Or $iCol > UBound($aColArray, 2) - 1 Then
		Return SetError(4, 0, 0)
	EndIf
	; Current colour
	Local $aCurrSplit = StringSplit($aColArray[$iRow + 1][$iCol], ";")
	; New colour
	Local $aNewSplit = StringSplit($sColSet, ";")
	; Replace if required
	For $i = 1 To 2
		If $aNewSplit[$i] Then
			; Convert to BGR
			$aCurrSplit[$i] = '0x' & StringMid($aNewSplit[$i], 7, 2) & StringMid($aNewSplit[$i], 5, 2) & StringMid($aNewSplit[$i], 3, 2)
		EndIf
		If $fDefCol Then
			; Reset default
			$aCurrSplit[$i] = ""
		EndIf
	Next
	; Store new colour
	$aColArray[$iRow + 1][$iCol] = $aCurrSplit[1] & ";" & $aCurrSplit[2]
	; Store amended array
	$aGLVEx_Data[$iLV_Index][18] = $aColArray

	; Force reload of redraw colour array
	$aGLVEx_Data[0][14] = 0
	; Redraw listView item to show colour
	_GUICtrlListView_RedrawItems($aGLVEx_Data[$iLV_Index][0], $iRow, $iRow)

	Return 1

EndFunc   ;==>_GUIListViewEx_SetColour

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_BlockReDraw
; Description ...: Prevents ListView redrawing during looped Insert/Delete/Change calls
; Syntax.........: _GUIListViewEx_BlockReDraw($iLV_Index, $fMode)
; Parameters ....: $iLV_Index - Index number of ListView as returned by _GUIListViewEx_Init
;                  $fMode     - True  = Prevent redrawing during Insert/Delete/Change calls
;                             - False = Allow future redrawing and force a redraw
; Requirement(s).: v3.3.10 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - Invalid $fMode
; Author ........: Melba23
; Modified ......:
; Remarks .......: Allows multiple items to be inserted/deleted/changed programatically without redrawing the ListView
;                  after each call. When block removed, ListView is redrawn to update with new content
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_BlockReDraw($iLV_Index, $bMode)

	; Check valid index
	If $iLV_Index < 1 Or $iLV_Index > $aGLVEx_Data[0][0] Then
		Return SetError(1, 0, 0)
	EndIf
	Switch $bMode
		Case True
			; Clear redraw flag
			$aGLVEx_Data[0][15] = False

		Case False
			; Set redraw flag
			$aGLVEx_Data[0][15] = True
			; Force ListView redraw to current content
			Local $aData_Array = $aGLVEx_Data[$iLV_Index][2]
			Local $aCheck_Array[UBound($aData_Array)]
			For $i = 1 To UBound($aCheck_Array) - 1
				$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
			Next
			__GUIListViewEx_ReWriteLV($aGLVEx_Data[$iLV_Index][0], $aData_Array, $aCheck_Array, $iLV_Index, $aGLVEx_Data[$iLV_Index][6])

		Case Else
			Return SetError(2, 0, 0)
	EndSwitch
	Return 1

EndFunc   ;==>_GUIListViewEx_BlockReDraw

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DragEvent
; Description ...: Returns index of ListView(s) involved in a drag-drop event
; Syntax.........: _GUIListViewEx_DragEvent()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: If a drag-drop event has taken place - colon-delimited string giving "Drag" and "Drop" indices
;                  If no event - an empty string
; Author ........: Melba23
; Modified ......:
; Remarks .......: This function must be placed within the script idle loop.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DragEvent()

	; Save DragEvent details
	Local $vRet = $sGLVEx_DragEvent
	If $vRet <> "" Then
		; Clear flag
		$sGLVEx_DragEvent = ""
	EndIf
	; Return drag/drop index string
	Return $vRet

EndFunc   ;==>_GUIListViewEx_DragEvent

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SortEvent
; Description ...: Returns the ListView index after a column sort event
; Syntax.........: _GUIListViewEx_SortEvent()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: If a sort event has taken place - index of sorted ListView
;                  If no event - an empty string
; Author ........: Melba23
; Modified ......:
; Remarks .......: This function must be placed within the script idle loop.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_SortEvent()

	; Save Sort event return
	Local $vRet = $aGLVEx_Data[0][19]
	; If sort event flag set
	If $vRet <> "" Then
		; Clear flag
		$aGLVEx_Data[0][19] = ""
	EndIf
	Return $vRet

EndFunc   ;==>_GUIListViewEx_SortEvent

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ColourEvent
; Description ...: Redraw a colour-enabled ListView after a column sort or drag/drop event
; Syntax.........: _GUIListViewEx_SortEvent()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: This function must be placed within the script idle loop.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ColourEvent()

	; Look for Colour Event flag
	If $aGLVEx_Data[0][22] <> "" Then
		; Check if sort or drag/drop
		Local $aIndex = StringSplit($aGLVEx_Data[0][22], ":")
		If @error Then
			; Sort event
			__GUIListViewEx_RedrawWindow($aGLVEx_Data[0][22], True)
		Else
			; Drag/drop event
			__GUIListViewEx_RedrawWindow($aIndex[1], True)
			; Check if second ListView involved
			If $aIndex[2] <> $aIndex[1] Then
				__GUIListViewEx_RedrawWindow($aIndex[2], True)
			EndIf
		EndIf
		; Clear flag
		$aGLVEx_Data[0][22] = ""
	EndIf

EndFunc   ;==>_GUIListViewEx_ColourEvent

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ContextPos
; Description ...: Returns index and row/col of last right click
; Syntax.........: _GUIListViewEx_ContextPos()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 3 element array: [ListView_index, Row, Column]
; Author ........: Melba23
; Modified ......:
; Remarks .......: Allows user colours to be set via a context menu
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ContextPos()

	Local $aPos[3] = [$aGLVEx_Data[0][1], $aGLVEx_Data[0][10], $aGLVEx_Data[0][11]]
	Return $aPos

EndFunc   ;==>_GUIListViewEx_ContextPos

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ToolTipInit
; Description ...: Defines column(s) which will display a tooltip when clicked
; Syntax.........: _GUIListViewEx_ToolTipInit($iLV_Index, $vRange [, $iTime = 1000 ], $iMode = 1]])
; Parameters ....: $iLV_Index - Index of ListView holding columns
;                  $vRange    - Range of columns - see remarks
;                  $iTime     - Time for tooltip to display (default = 1000)
;                  $iMode     - Display: 1 (default) = cell content, 2 = 0 column
; Requirement(s).: v3.3.10 +
; Return values .: Success: Returns 1
;                  Failure: Returns 0 and sets @error as follows:
;                      1 = Invalid index
;                      2 = Invalid range
;                      3 = Invalid time
; Author ........: Melba23
; Modified ......:
; Remarks .......: Function is designed to show:
;                      Mode 1: ListView content if column is too narrow for data within
;                      Mode 2: 0 column data to allow for row identification when right scrolled
;                  $vRange is a string containing the rows which show tooltips.
;                  It can be a single number or a range separated by a hyphen (-).
;                  Multiple items are separated by a semi-colon (;).
;                  "*" = all columns
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ToolTipInit($iLV_Index, $vRange, $iTime = 1000, $iMode = 1)

	; Check valid parameters
	If $iLV_Index < 0 Or $iLV_Index > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)
	Local $aRange = __GUIListViewEx_ExpandRange($vRange, $iLV_Index)
	If @error Then Return SetError(2, 0, 0)
	If Not IsInt($iTime) Then Return SetError(3, 0, 0)

	; Store data
	$aGLVEx_Data[$iLV_Index][15] = $aRange
	$aGLVEx_Data[$iLV_Index][16] = $iTime
	$aGLVEx_Data[$iLV_Index][17] = $iMode

	Return 1

EndFunc   ;==>_GUIListViewEx_ToolTipInit

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_ToolTipShow
; Description ...: Show tooltips when defined columns clicked
; Syntax.........: _GUIListViewEx_ToolTipShow()
; Parameters ....: None
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: This function must be placed within the script idle loop.
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_ToolTipShow()

	; Get Index
	Local $iLV_Index = $aGLVEx_Data[0][1]
	; Get mode
	Local $iMode = $aGLVEx_Data[$iLV_Index][17]
	; If tooltips initiated
	If $iMode Then
		Local $fToolTipCol = False
		; Get active cell if single cell selection
		If $aGLVEx_Data[$iLV_Index][21] Then
			$aGLVEx_Data[0][4] = $aGLVEx_Data[0][17]
			$aGLVEx_Data[0][5] = $aGLVEx_Data[0][18]
		EndIf
		; If new item clicked
		If $aGLVEx_Data[0][4] <> $aGLVEx_Data[0][6] Or $aGLVEx_Data[0][5] <> $aGLVEx_Data[0][7] Then
			; Check range
			If $aGLVEx_Data[$iLV_Index][15] = "*" Then
				$fToolTipCol = True
			Else
				If IsArray($aGLVEx_Data[$iLV_Index][15]) Then
					Local $vRange = $aGLVEx_Data[$iLV_Index][15]
					For $i = 1 To $vRange[0]
						; If initiated column
						If $aGLVEx_Data[0][2] = $vRange[$i] Then
							$fToolTipCol = True
							ExitLoop
						EndIf
					Next
				EndIf
			EndIf
		EndIf
		If $fToolTipCol Then
			; Read all row text
			Local $aItemText = _GUICtrlListView_GetItemTextArray($aGLVEx_Data[$iLV_Index][0], $aGLVEx_Data[0][4])
			Local $sText
			Switch $iMode
				Case 1
					$sText = $aItemText[$aGLVEx_Data[0][5] + 1]
				Case 2
					$sText = $aItemText[1]
			EndSwitch
			; Create ToolTip
			ToolTip($sText)
			; Set up clearance
			AdlibRegister("__GUIListViewEx_ToolTipHide", $aGLVEx_Data[$iLV_Index][16])
		EndIf
		; Store location
		$aGLVEx_Data[0][6] = $aGLVEx_Data[0][4]
		$aGLVEx_Data[0][7] = $aGLVEx_Data[0][5]

	EndIf

EndFunc   ;==>_GUIListViewEx_ToolTipShow

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_MsgRegister
; Description ...: Registers Windows messages required for the UDF
; Syntax.........: _GUIListViewEx_MsgRegister([$fNOTIFY = True, [$fMOUSEMOVE = True, [$fLBUTTONUP = True, [ $fSYSCOMMAND = True]]]])
; Parameters ....: $fNOTIFY     - True = Register WM_NOTIFY message
;                  $fMOUSEMOVE  - True = Register WM_MOUSEMOVE message
;                  $fLBUTTONUP  - True = Register WM_LBUTTONUP message
;                  $fSYSCOMMAND - True = Register WM_SYSCOMAMND message
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If message handlers already registered, then call the relevant handler function from within that handler
;                  WM_NOTIFY handler required for all UDF functions
;                  WM_MOUSEMOVE and WM_LBUTTONUP handlers required for drag
;                  WM_SYSCOMMAND required for single click [X] GUI closure while editing
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_MsgRegister($fNOTIFY = True, $fMOUSEMOVE = True, $fLBUTTONUP = True, $fSYSCOMMAND = True)

	; Register required messages
	If $fNOTIFY Then GUIRegisterMsg(0x004E, "_GUIListViewEx_WM_NOTIFY_Handler") ; $WM_NOTIFY
	If $fMOUSEMOVE Then GUIRegisterMsg(0x0200, "_GUIListViewEx_WM_MOUSEMOVE_Handler") ; $WM_MOUSEMOVE
	If $fLBUTTONUP Then GUIRegisterMsg(0x0202, "_GUIListViewEx_WM_LBUTTONUP_Handler") ; $WM_LBUTTONUP
	If $fSYSCOMMAND Then GUIRegisterMsg(0x0112, "_GUIListViewEx_WM_SYSCOMMAND_Handler") ; $WM_SYSCOMMAND

EndFunc   ;==>_GUIListViewEx_MsgRegister

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_NOTIFY_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_NOTIFY_Handler()
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_NOTIFY handler already registered, then call this function from within that handler
;                  If user colours are enabled, the handler return value must be returned on handler exit
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)

	#forceref $hWnd, $iMsg, $wParam

	Local $dwDrawStage

	; Struct = $tagNMHDR and "int Item;int SubItem" from $tagNMLISTVIEW
	Local $tStruct = DllStructCreate("hwnd;uint_ptr;int_ptr;int;int", $lParam)
	If @error Then Return

	Local $hLV = DllStructGetData($tStruct, 1)
	Local $iItem = DllStructGetData($tStruct, 4)
	Local $iCode = BitAND(DllStructGetData($tStruct, 3), 0xFFFFFFFF)

	; Deal with drawing quickly
	If $iCode = -12 Then ; $NM_CUSTOMDRAW

		; Prevent redraw if still changing ListView arrays
		If $aGLVEx_Data[0][12] Then Return

		; Check if enabled ListView
		For $iLV_Index = 1 To $aGLVEx_Data[0][0]
			If $aGLVEx_Data[$iLV_Index][0] = DllStructGetData($tStruct, 1) Then
				ExitLoop
			EndIf
		Next

		; It is an enabled ListView
		If $iLV_Index <= $aGLVEx_Data[0][0] Then

			Local Static $aDefCols = $aGLVEx_DefColours

			; Check if ListView to be redrawn has changed
			If $aGLVEx_Data[0][14] <> DllStructGetData($tStruct, 1) Then
				; Store new handle
				$aGLVEx_Data[0][14] = DllStructGetData($tStruct, 1)
				If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
					; Copy new colour array
					$aGLVEx_Data[0][13] = $aGLVEx_Data[$iLV_Index][18]
					; Set new default colours
					$aDefCols = $aGLVEx_Data[$iLV_Index][23]
				EndIf
			EndIf
			; If colour or single cell selection
			If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
				Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
				$dwDrawStage = DllStructGetData($tNMLVCUSTOMDRAW, "dwDrawStage")
				Switch $dwDrawStage ; Holds a value that specifies the drawing stage
					Case 1 ; $CDDS_PREPAINT
						; Before the paint cycle begins
						Return 32 ; $CDRF_NOTIFYITEMDRAW - Notify the parent window of any item-related drawing operations

					Case 65537 ; $CDDS_ITEMPREPAINT
						; Before painting an item
						Return 32 ; $CDRF_NOTIFYSUBITEMDRAW - Notify the parent window of any subitem-related drawing operations

					Case 196609 ; BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
						; Before painting a subitem
						$iItem = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec") ; Row index
						Local $iSubItem = DllStructGetData($tNMLVCUSTOMDRAW, "iSubItem") ; Column index
						; Check if selected row
						Local $bSelColour = False
						If $iItem = $aGLVEx_Data[$iLV_Index][20] Then
							; If single sel also check for column
							If $aGLVEx_Data[$iLV_Index][22] Then
								If $iSubItem = $aGLVEx_Data[$iLV_Index][21] Then
									$bSelColour = True
								EndIf
							Else
								$bSelColour = True
							EndIf
						EndIf
						; Set default colours
						Local $iTextColour = $aDefCols[0]
						Local $iBackColour = $aDefCols[1]
						; Set selected colours if required
						If $bSelColour Then
							; Set selected item colours
							$iTextColour = $aDefCols[2]
							$iBackColour = $aDefCols[3]
						Else
							; If colour enabled
							If $aGLVEx_Data[$iLV_Index][19] Then
								; Check for user colours
								If StringInStr(($aGLVEx_Data[0][13])[$iItem + 1][$iSubItem], ";") Then
									; Get required user colours
									Local $aSplitColour = StringSplit(($aGLVEx_Data[0][13])[$iItem + 1][$iSubItem], ";")
									If $aSplitColour[1] Then $iTextColour = $aSplitColour[1]
									If $aSplitColour[2] Then $iBackColour = $aSplitColour[2]
								EndIf
							EndIf
						EndIf

						; Set required colours
						DllStructSetData($tNMLVCUSTOMDRAW, "ClrText", $iTextColour)
						DllStructSetData($tNMLVCUSTOMDRAW, "ClrTextBk", $iBackColour)
						Return 2 ; $CDRF_NEWFONT must be returned after changing font or colors
				EndSwitch
			EndIf

		Else

			; Check if colour enabled header
			For $iLV_Index = 1 To $aGLVEx_Data[0][0]
				If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$iLV_Index][24] Then
					ExitLoop
				EndIf
			Next
			; It is a colour enabled header
			If $iLV_Index <= $aGLVEx_Data[0][0] Then

				Local $tNMCustomDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
				Local $hDC = DllStructGetData($tNMCustomDraw, "hdc")

				; Check if ListView to be redrawn has changed
				If $aGLVEx_Data[0][20] <> DllStructGetData($tStruct, 1) Then
					; Store new handle
					$aGLVEx_Data[0][20] = DllStructGetData($tStruct, 1)
					; Get header font
					Local $hFont = _SendMessage(DllStructGetData($tStruct, 1), 0x0031) ; $WM_GETFONT
					Local $hObject = _WinAPI_SelectObject($hDC, $hFont)
					Local $tLogFont = DllStructCreate($tagLOGFONT)
					; Get header font
					_WinAPI_GetObject($hFont, DllStructGetSize($tLogFont), DllStructGetPtr($tLogFont))
					_WinAPI_SelectObject($hDC, $hObject)
					_WinAPI_ReleaseDC(DllStructGetData($tStruct, 1), $hDC)
					; Set to medium weight
					DllStructSetData($tLogFont, "Weight", 600) ; $FW_SEMIBOLD
					; Store font handle
					$aGLVEx_Data[0][21] = _WinAPI_CreateFontIndirect($tLogFont)
				EndIf

				; Check drawing stage
				$dwDrawStage = DllStructGetData($tNMCustomDraw, "dwDrawStage")
				Switch $dwDrawStage
					Case 1 ; $CDDS_PREPAINT ; Before the paint cycle begins
						Return 32 ; $CDRF_NOTIFYITEMDRAW ; Notify parent window of coming item related drawing operations

					Case 65537 ; $CDDS_ITEMPREPAINT ; Before an item is drawn: Default painting (frames and background)
						Return 0x00000010 ; $CDRF_NOTIFYPOSTPAINT ; Notify parent window of coming post item related drawing operations

					Case 0x00010002 ; $CDDS_ITEMPOSTPAINT ; After an item is drawn: Custom painting
						Local $iColumnIndex = DllStructGetData($tNMCustomDraw, "dwItemSpec") ; Column
						Local $aHdrData = $aGLVEx_Data[$iLV_Index][25] ; Header data
						Local $aColSplit = StringSplit($aHdrData[1][$iColumnIndex], ";")
						; Set default colours
						Local $aHdrDefCols = $aGLVEx_Data[$iLV_Index][23]
						Local $iHdrTextColour, $iHdrBackColour
						; Set user or default colours
						If $aColSplit[1] == "" Then
							$iHdrTextColour = $aHdrDefCols[0]
						Else
							$iHdrTextColour = $aColSplit[1]
						EndIf
						If $aColSplit[2] == "" Then
							$iHdrBackColour = $aHdrDefCols[1]
						Else
							$iHdrBackColour = $aColSplit[2]
						EndIf
						; Set header section size
						Local $tRECT = DllStructCreate($tagRECT)
						DllStructSetData($tRECT, 1, DllStructGetData($tNMCustomDraw, 6) + 1)
						DllStructSetData($tRECT, 2, DllStructGetData($tNMCustomDraw, 7) + 1)
						DllStructSetData($tRECT, 3, DllStructGetData($tNMCustomDraw, 8) - 2)
						DllStructSetData($tRECT, 4, DllStructGetData($tNMCustomDraw, 9) - 2)
						; Set transparent background
						_WinAPI_SetBkMode($hDC, 1) ; $TRANSPARENT
						; Set text font and colour
						_WinAPI_SelectObject($hDC, $aGLVEx_Data[0][21])
						_WinAPI_SetTextColor($hDC, $iHdrTextColour)
						; Set and draw back colour
						Local $hBrush = _WinAPI_CreateSolidBrush($iHdrBackColour)
						_WinAPI_FillRect($hDC, $tRECT, $hBrush)
						; Write text
						If $iColumnIndex < _GUICtrlListView_GetColumnCount($aGLVEx_Data[$iLV_Index][0]) Then
							; Get column alignment
							Local $aRet = _GUICtrlListView_GetColumn($aGLVEx_Data[$iLV_Index][0], $iColumnIndex)
							Local $iColAlign = 2 * $aRet[0]
							_WinAPI_DrawText($hDC, $aHdrData[0][$iColumnIndex], $tRECT, $iColAlign)
						EndIf
						Return 2 ; $CDRF_NEWFONT must be returned after changing font or colors
				EndSwitch
			EndIf
		EndIf

	Else ; Not a drawing message

		; Check if enabled ListView
		For $iLV_Index = 1 To $aGLVEx_Data[0][0]
			If $aGLVEx_Data[$iLV_Index][0] = DllStructGetData($tStruct, 1) Then
				ExitLoop
			EndIf
		Next

		; It is an enabled ListView
		If $iLV_Index <= $aGLVEx_Data[0][0] Then

			; Set selected row and column
			$aGLVEx_Data[0][17] = $aGLVEx_Data[$iLV_Index][20]
			$aGLVEx_Data[0][18] = $aGLVEx_Data[$iLV_Index][21]
			; Check message
			Switch $iCode

				Case $LVN_BEGINSCROLL

					; if editing then abandon
					If $cGLVEx_EditID <> 9999 Then
						; Delete temp edit control and set placeholder
						GUICtrlDelete($cGLVEx_EditID)
						$cGLVEx_EditID = 9999
						; Reactivate ListView
						WinSetState($hGLVEx_Editing, "", @SW_ENABLE)
					EndIf

				Case $LVN_BEGINDRAG

					; Set values for this ListView
					$aGLVEx_Data[0][1] = $iLV_Index

					; Store source & target ListView data for eventual inter-LV drag
					$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
					$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
					$iGLVEx_SrcIndex = $iLV_Index
					$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
					$hGLVEx_TgtHandle = $hGLVEx_SrcHandle
					$cGLVEx_TgtID = $cGLVEx_SrcID
					$iGLVEx_TgtIndex = $iGLVEx_SrcIndex
					$aGLVEx_TgtArray = $aGLVEx_SrcArray

					; Copy array for manipulation
					$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]

					; Set drag image flag
					Local $fImage = $aGLVEx_Data[$iLV_Index][5]

					; Check if Native or UDF and set focus
					If $cGLVEx_SrcID Then
						GUICtrlSetState($cGLVEx_SrcID, 256) ; $GUI_FOCUS
					Else
						_WinAPI_SetFocus($hGLVEx_SrcHandle)
					EndIf

					; Get dragged item index
					$iGLVEx_DraggedIndex = DllStructGetData($tStruct, 4) ; Item
					; Set dragged item count
					$iGLVEx_Dragging = 1

					; Check for selected items
					Local $iIndex
					; Check if colour or single cell selection enabled
					If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
						; Use stored value
						$iIndex = $aGLVEx_Data[$iLV_Index][20]
					Else
						; Check actual values
						$iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_SrcHandle)
					EndIf
					; Check if item is part of a multiple selection
					If StringInStr($iIndex, $iGLVEx_DraggedIndex) And StringInStr($iIndex, "|") Then
						; Extract all selected items
						Local $aIndex = StringSplit($iIndex, "|")
						For $i = 1 To $aIndex[0]
							If $aIndex[$i] = $iGLVEx_DraggedIndex Then ExitLoop
						Next
						; Now check for consecutive items
						If $i <> 1 Then ; Up
							For $j = $i - 1 To 1 Step -1
								; Consecutive?
								If $aIndex[$j] <> $aIndex[$j + 1] - 1 Then ExitLoop
								; Adjust dragged index to this item
								$iGLVEx_DraggedIndex -= 1
								; Increase number to drag
								$iGLVEx_Dragging += 1
							Next
						EndIf
						If $i <> $aIndex[0] Then ; Down
							For $j = $i + 1 To $aIndex[0]
								; Consecutive
								If $aIndex[$j] <> $aIndex[$j - 1] + 1 Then ExitLoop
								; Increase number to drag
								$iGLVEx_Dragging += 1
							Next
						EndIf
					Else ; Either no selection or only a single
						; Set flag
						$iGLVEx_Dragging = 1
					EndIf

					; Remove all highlighting
					_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, -1, False)

					; Create drag image
					If $fImage Then
						Local $aImageData = _GUICtrlListView_CreateDragImage($hGLVEx_SrcHandle, $iGLVEx_DraggedIndex)
						$hGLVEx_DraggedImage = $aImageData[0]
						_GUIImageList_BeginDrag($hGLVEx_DraggedImage, 0, 0, 0)
					EndIf

				Case $LVN_COLUMNCLICK, -2 ; $NM_CLICK

					; Set values for active ListView
					$aGLVEx_Data[0][1] = $iLV_Index
					$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
					$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]
					; Get and store row index
					$aGLVEx_Data[0][4] = DllStructGetData($tStruct, 4)
					; Get column index
					Local $iCol = DllStructGetData($tStruct, 5)
					; Store it - for normal and tooltip use
					$aGLVEx_Data[0][2] = $iCol
					$aGLVEx_Data[0][5] = $iCol

					; If a column was clicked
					If $iCode = $LVN_COLUMNCLICK Then
						; Scroll column into view
						; Get X coord of first item in column
						Local $aRect = _GUICtrlListView_GetSubItemRect($hGLVEx_SrcHandle, 0, $iCol)
						; Get col width
						Local $aLV_Pos = WinGetPos($hGLVEx_SrcHandle)
						; Scroll to left edge if all column not in view
						If $aRect[0] < 0 Or $aRect[2] > $aLV_Pos[2] - $aGLVEx_Data[0][8] Then ; Reduce by scrollbar width
							_GUICtrlListView_Scroll($hGLVEx_SrcHandle, $aRect[0], 0)
						EndIf

						; Look for Ctrl key pressed
						_WinAPI_GetAsyncKeyState(0x11) ; Needed to avoid double setting
						If _WinAPI_GetAsyncKeyState(0x11) Then
							; Load editable column array
							Local $aEditable = $aGLVEx_Data[$iLV_Index][7]
							; Check column is editable
							If $aEditable[0][$iCol] Then
								; Set header edit flag
								$fGLVEx_HeaderEdit = True
							EndIf
						Else
							; If ListView sortable
							If IsArray($aGLVEx_Data[$iLV_Index][4]) Then
								; Load array
								$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
								; Load current ListView sort state array
								Local $aLVSortState = $aGLVEx_Data[$iLV_Index][4]
								; Sort the ListView
								__GUIListViewEx_ColSort($hGLVEx_SrcHandle, $iLV_Index, $aLVSortState, $iCol)
								; Store new ListView sort state array
								$aGLVEx_Data[$iLV_Index][4] = $aLVSortState
								; Reread listview items into array
								Local $iDim2 = UBound($aGLVEx_SrcArray, 2) - 1
								For $j = 1 To $aGLVEx_SrcArray[0][0]
									For $k = 0 To $iDim2
										$aGLVEx_SrcArray[$j][$k] = _GUICtrlListView_GetItemText($hGLVEx_SrcHandle, $j - 1, $k)
									Next
								Next
								; Store amended array
								$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
								; Delete array
								$aGLVEx_SrcArray = 0
							EndIf
						EndIf
					EndIf

				Case $LVN_KEYDOWN

					; Determine which key pressed
					Local $tKey = DllStructCreate($tagNMHDR & ";WORD KeyCode", $lParam)
					; Store key value
					$aGLVEx_Data[0][16] = DllStructGetData($tKey, "KeyCode")
					; Check if manual edit key(s) pressed
					If __GUIListViewEx_CheckUserEditKey() Then
						ContinueCase
					EndIf
					; Remove selected state if single cell selection
					If $aGLVEx_Data[$iLV_Index][22] Then _GUICtrlListView_SetItemSelected($hLV, $aGLVEx_Data[0][17], False)
					; Act on left/right keys
					Switch $aGLVEx_Data[0][16]
						Case 37 ; Left
							; Adjust column and prevent overrun
							If $aGLVEx_Data[0][18] > 0 Then $aGLVEx_Data[0][18] -= 1
							; Store new column
							$aGLVEx_Data[$iLV_Index][21] = $aGLVEx_Data[0][18]
							; Redraw row
							_GUICtrlListView_RedrawItems($hLV, $aGLVEx_Data[0][17], $aGLVEx_Data[0][17])
						Case 39 ; Right
							If $aGLVEx_Data[0][18] < _GUICtrlListView_GetColumnCount($hLV) - 1 Then $aGLVEx_Data[0][18] += 1
							$aGLVEx_Data[$iLV_Index][21] = $aGLVEx_Data[0][18]
							_GUICtrlListView_RedrawItems($hLV, $aGLVEx_Data[0][17], $aGLVEx_Data[0][17])
					EndSwitch

				Case -3 ; $NM_DBLCLK

					; Only if editable
					If $aGLVEx_Data[$iLV_Index][7] <> "" Then
						; Set values for active ListView
						$aGLVEx_Data[0][1] = $iLV_Index
						$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
						; Copy array for manipulation
						$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
						; Set editing flag
						$fGLVEx_EditClickFlag = $iLV_Index
					EndIf

				Case $LVN_ITEMCHANGED

					; Remove selection state if colour or single cell selection
					If $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
						_GUICtrlListView_SetItemSelected($hLV, $iItem, False)
					EndIf
					; If a key was used to change selection need to reset active row
					If $aGLVEx_Data[0][16] <> 0 Then
						; Check key used
						Switch $aGLVEx_Data[0][16]
							Case 38 ; Up
								If $aGLVEx_Data[0][17] > 0 Then $aGLVEx_Data[0][17] -= 1
								$aGLVEx_Data[$iLV_Index][20] = $aGLVEx_Data[0][17]
							Case 40 ; Down
								If $aGLVEx_Data[0][17] < _GUICtrlListView_GetItemCount($hLV) - 1 Then $aGLVEx_Data[0][17] += 1
								$aGLVEx_Data[$iLV_Index][20] = $aGLVEx_Data[0][17]
						EndSwitch
						; Clear key flag
						$aGLVEx_Data[0][16] = 0
					Else
						; If mouse button pressed
						If _WinAPI_GetAsyncKeyState(0x01) Then
							; Determine position of mouse within ListView
							Local $aMPos = MouseGetPos()
							Local $tPoint = DllStructCreate("int X;int Y")
							DllStructSetData($tPoint, "X", $aMPos[0])
							DllStructSetData($tPoint, "Y", $aMPos[1])
							_WinAPI_ScreenToClient($hLV, $tPoint)
							Local $aCurPos[2] = [DllStructGetData($tPoint, "X"), DllStructGetData($tPoint, "Y")]
							; Check for cell under mouse
							Local $aHitTest = _GUICtrlListView_SubItemHitTest($hLV, $aCurPos[0], $aCurPos[1])
							; If click on valid cell
							If $aHitTest[0] > -1 And $aHitTest[1] > -1 And $aHitTest[0] = $iItem Then
								; Redraw previously selected row
								If $aGLVEx_Data[0][17] <> $iItem Then _GUICtrlListView_RedrawItems($hLV, $aGLVEx_Data[0][17], $aGLVEx_Data[0][17])
								; Set new row and column
								$aGLVEx_Data[0][17] = $aHitTest[0]
								$aGLVEx_Data[0][18] = $aHitTest[1]
								$aGLVEx_Data[$iLV_Index][20] = $aGLVEx_Data[0][17]
								$aGLVEx_Data[$iLV_Index][21] = $aGLVEx_Data[0][18]
								; Redraw newly selected row
								_GUICtrlListView_RedrawItems($hLV, $iItem, $iItem)
							EndIf
						EndIf
					EndIf

				Case -5 ; $NM_RCLICK

					; Set active ListView
					$aGLVEx_Data[0][1] = $iLV_Index
					; Get position of right click within Listview
					$aGLVEx_Data[0][10] = DllStructGetData($tStruct, 4)
					$aGLVEx_Data[0][11] = DllStructGetData($tStruct, 5)
					; Redraw last selected row
					_GUICtrlListView_RedrawItems($hLV, $aGLVEx_Data[0][17], $aGLVEx_Data[0][17])
					; Set new active cell
					$aGLVEx_Data[0][17] = DllStructGetData($tStruct, 4)
					$aGLVEx_Data[0][18] = DllStructGetData($tStruct, 5)
					$aGLVEx_Data[$iLV_Index][20] = $aGLVEx_Data[0][17]
					$aGLVEx_Data[$iLV_Index][21] = $aGLVEx_Data[0][18]
					; Redraw newly selected row
					_GUICtrlListView_RedrawItems($hLV, $aGLVEx_Data[0][17], $aGLVEx_Data[0][17])

			EndSwitch
		EndIf
	EndIf

EndFunc   ;==>_GUIListViewEx_WM_NOTIFY_Handler

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_MOUSEMOVE_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_MOUSEMOVE_Handler()
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_MOUSEMOVE handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_MOUSEMOVE_Handler($hWnd, $iMsg, $wParam, $lParam)

	#forceref $hWnd, $iMsg, $wParam

	Local $iVertScroll

	If $iGLVEx_Dragging = 0 Then
		Return "GUI_RUNDEFMSG"
	EndIf

	; Get item depth to make sure scroll is enough to get next item into view
	If $aGLVEx_Data[$aGLVEx_Data[0][1]][10] Then
		$iVertScroll = $aGLVEx_Data[$aGLVEx_Data[0][1]][10]
	Else
		Local $aRect = _GUICtrlListView_GetItemRect($hGLVEx_SrcHandle, 0)
		$iVertScroll = $aRect[3] - $aRect[1]
	EndIf

	; Get window under mouse cursor
	Local $hCurrent_Wnd = __GUIListViewEx_GetCursorWnd()

	; If not over the current tgt ListView
	If $hCurrent_Wnd <> $hGLVEx_TgtHandle Then

		; Check if external drag permitted
		If BitAND($aGLVEx_Data[$iGLVEx_TgtIndex][12], 1) Then
			Return "GUI_RUNDEFMSG"
		EndIf

		; Is it another initiated ListView
		For $i = 1 To $aGLVEx_Data[0][0]
			If $aGLVEx_Data[$i][0] = $hCurrent_Wnd Then

				; Check if external drop permitted
				If BitAND($aGLVEx_Data[$i][12], 2) Then
					Return "GUI_RUNDEFMSG"
				EndIf

				; Check compatibility between Src and Tgt ListViews
				; Check neither has checkboxes
				If $aGLVEx_Data[$iGLVEx_SrcIndex][6] + $aGLVEx_Data[$i][6] = 0 Then
					; Check same column count
					If _GUICtrlListView_GetColumnCount($hGLVEx_SrcHandle) = _GUICtrlListView_GetColumnCount($hCurrent_Wnd) Then
						; Compatible so switch to new target
						; Clear insert mark in current tgt ListView
						_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, -1, True)
						; Set data for new tgt ListView
						$hGLVEx_TgtHandle = $hCurrent_Wnd
						$cGLVEx_TgtID = $aGLVEx_Data[$i][1]
						$iGLVEx_TgtIndex = $i
						$aGLVEx_TgtArray = $aGLVEx_Data[$i][2]
						$aGLVEx_Data[0][3] = $aGLVEx_Data[$i][10] ; Set item depth
						; No point in looping further
						ExitLoop
					EndIf
				EndIf
			EndIf
		Next
	EndIf

	; Get current mouse Y coord
	Local $iCurr_Y = BitShift($lParam, 16)

	; Set insert mark to correct side of items depending on sense of movement when cursor within range
	If $iGLVEx_InsertIndex <> -1 Then
		If $iGLVEx_LastY = $iCurr_Y Then
			Return "GUI_RUNDEFMSG"
		ElseIf $iGLVEx_LastY > $iCurr_Y Then
			$fGLVEx_BarUnder = False
			_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, $iGLVEx_InsertIndex, False)
		Else
			$fGLVEx_BarUnder = True
			_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, $iGLVEx_InsertIndex, True)
		EndIf
	EndIf

	; Store current Y coord
	$iGLVEx_LastY = $iCurr_Y

	; Get ListView item under mouse
	Local $aLVHit = _GUICtrlListView_HitTest($hGLVEx_TgtHandle)
	Local $iCurr_Index = $aLVHit[0]

	; If mouse is above or below ListView then scroll ListView
	If $iCurr_Index = -1 Then
		If $fGLVEx_BarUnder Then
			_GUICtrlListView_Scroll($hGLVEx_TgtHandle, 0, $iVertScroll)
		Else
			_GUICtrlListView_Scroll($hGLVEx_TgtHandle, 0, -$iVertScroll)
		EndIf
		Sleep(10)
	EndIf

	; Check if over same item
	If $iGLVEx_InsertIndex <> $iCurr_Index Then
		; Show insert mark on current item
		_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, $iCurr_Index, $fGLVEx_BarUnder)
		; Store current item
		$iGLVEx_InsertIndex = $iCurr_Index
	EndIf

	Return "GUI_RUNDEFMSG"

EndFunc   ;==>_GUIListViewEx_WM_MOUSEMOVE_Handler

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_LBUTTONUP_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_LBUTTONUP_Handler()
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_LBUTTONUP handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_LBUTTONUP_Handler($hWnd, $iMsg, $wParam, $lParam)

	#forceref $hWnd, $iMsg, $wParam, $lParam

	If Not $iGLVEx_Dragging Then
		Return "GUI_RUNDEFMSG"
	EndIf

	; Get item count
	Local $iMultipleItems = $iGLVEx_Dragging - 1

	; Reset flag
	$iGLVEx_Dragging = 0

	; Check for valid insert index (not set if dropping into empty space)
	If $iGLVEx_InsertIndex = -1 Then
		; Set to bottom
		$iGLVEx_InsertIndex = _GUICtrlListView_GetItemCount($hGLVEx_TgtHandle) + 1
	EndIf

	; Get window under mouse cursor
	Local $hCurrent_Wnd = __GUIListViewEx_GetCursorWnd()

	; Abandon if mouse not within tgt ListView
	If $hCurrent_Wnd <> $hGLVEx_TgtHandle Then
		; Clear insert mark
		_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, -1, True)
		; Reset highlight to original items in Src ListView
		For $i = 0 To $iMultipleItems
			__GUIListViewEx_HighLight($hGLVEx_TgtHandle, $cGLVEx_TgtID, $iGLVEx_DraggedIndex + $i)
		Next
		; Delete copied arrays
		$aGLVEx_SrcArray = 0
		$aGLVEx_TgtArray = 0
		Return
	EndIf

	; Clear insert mark
	_GUICtrlListView_SetInsertMark($hGLVEx_TgtHandle, -1, True)

	; Clear drag image
	If $hGLVEx_DraggedImage Then
		_GUIImageList_DragLeave($hGLVEx_SrcHandle)
		_GUIImageList_EndDrag()
		_GUIImageList_Destroy($hGLVEx_DraggedImage)
		$hGLVEx_DraggedImage = 0
	EndIf

	; Dropping within same ListView
	If $hGLVEx_SrcHandle = $hGLVEx_TgtHandle Then
		; Determine position to insert
		If $fGLVEx_BarUnder Then
			If $iGLVEx_DraggedIndex > $iGLVEx_InsertIndex Then $iGLVEx_InsertIndex += 1
		Else
			If $iGLVEx_DraggedIndex < $iGLVEx_InsertIndex Then $iGLVEx_InsertIndex -= 1
		EndIf

		; Check not dropping on dragged item(s)
		Switch $iGLVEx_InsertIndex
			Case $iGLVEx_DraggedIndex To $iGLVEx_DraggedIndex + $iMultipleItems
				; Reset highlight to original items
				For $i = 0 To $iMultipleItems
					__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iGLVEx_DraggedIndex + $i)
				Next
				; Delete copied arrays
				$aGLVEx_SrcArray = 0
				$aGLVEx_TgtArray = 0
				Return
		EndSwitch

		; Create Local array for checkboxes (if no checkboxes makes no difference)
		Local $aCheck_Array[UBound($aGLVEx_SrcArray)]
		For $i = 1 To UBound($aCheck_Array) - 1
			$aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $i - 1)
		Next

		; Create Local array for dragged items checkbox state
		Local $aCheckDrag_Array[$iMultipleItems + 1]

		; Create Local colour array
		$aGLVEx_SrcColArray = $aGLVEx_Data[$iGLVEx_SrcIndex][18]
		Local $bUserCol = ((IsArray($aGLVEx_SrcColArray)) ? (True) : (False))

		; Amend arrays
		; Get data from dragged element(s)
		If $iMultipleItems Then
			; Multiple dragged elements
			Local $aInsertData[$iMultipleItems + 1]
			Local $aColData[$iMultipleItems + 1]
			Local $aItemData[UBound($aGLVEx_SrcArray, 2)]
			For $i = 0 To $iMultipleItems
				; Data
				For $j = 0 To UBound($aGLVEx_SrcArray, 2) - 1
					$aItemData[$j] = $aGLVEx_SrcArray[$iGLVEx_DraggedIndex + 1 + $i][$j]
				Next
				$aInsertData[$i] = $aItemData
				; Colours if required
				If $bUserCol Then
					For $j = 0 To UBound($aGLVEx_SrcColArray, 2) - 1
						$aItemData[$j] = $aGLVEx_SrcColArray[$iGLVEx_DraggedIndex + 1 + $i][$j]
					Next
					$aColData[$i] = $aItemData
				EndIf
				; Checkboxes
				$aCheckDrag_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $iGLVEx_DraggedIndex + $i)
			Next
		Else
			; Single dragged element
			Local $aInsertData[1]
			Local $aColData[1]
			Local $aItemData[UBound($aGLVEx_SrcArray, 2)]
			For $i = 0 To UBound($aGLVEx_SrcArray, 2) - 1
				$aItemData[$i] = $aGLVEx_SrcArray[$iGLVEx_DraggedIndex + 1][$i]
			Next
			$aInsertData[0] = $aItemData
			If $bUserCol Then
				For $i = 0 To UBound($aGLVEx_SrcColArray, 2) - 1
					$aItemData[$i] = $aGLVEx_SrcColArray[$iGLVEx_DraggedIndex + 1][$i]
				Next
				$aColData[0] = $aItemData
			EndIf
			$aCheckDrag_Array[0] = _GUICtrlListView_GetItemChecked($hGLVEx_SrcHandle, $iGLVEx_DraggedIndex)
		EndIf

		; Set no redraw flag - prevents problems while colour arrays are updated
		$aGLVEx_Data[0][12] = True

		; Delete dragged element(s) from arrays
		For $i = 0 To $iMultipleItems
			__GUIListViewEx_Array_Delete($aGLVEx_SrcArray, $iGLVEx_DraggedIndex + 1)
			__GUIListViewEx_Array_Delete($aCheck_Array, $iGLVEx_DraggedIndex + 1)
			If $bUserCol Then __GUIListViewEx_Array_Delete($aGLVEx_SrcColArray, $iGLVEx_DraggedIndex + 1)
		Next

		; Amend insert positon for multiple items deleted above
		If $iGLVEx_DraggedIndex < $iGLVEx_InsertIndex Then
			$iGLVEx_InsertIndex -= $iMultipleItems
		EndIf

		; Re-insert dragged element(s) into array
		For $i = $iMultipleItems To 0 Step -1
			__GUIListViewEx_Array_Insert($aGLVEx_SrcArray, $iGLVEx_InsertIndex + 1, $aInsertData[$i])
			__GUIListViewEx_Array_Insert($aCheck_Array, $iGLVEx_InsertIndex + 1, $aCheckDrag_Array[$i])
			If $bUserCol Then __GUIListViewEx_Array_Insert($aGLVEx_SrcColArray, $iGLVEx_InsertIndex + 1, $aColData[$i], False, False)
		Next

		; Rewrite ListView to match array
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aCheck_Array, $iGLVEx_SrcIndex)

		; Set highlight to inserted item(s)
		For $i = 0 To $iMultipleItems
			__GUIListViewEx_HighLight($hGLVEx_SrcHandle, $cGLVEx_SrcID, $iGLVEx_InsertIndex + $i)
		Next

		; Store amended array
		$aGLVEx_Data[$aGLVEx_Data[0][1]][2] = $aGLVEx_SrcArray
		$aGLVEx_Data[$iGLVEx_SrcIndex][18] = $aGLVEx_SrcColArray

	Else ; Dropping in another ListView

		; Determine position to insert
		If $fGLVEx_BarUnder Then
			$iGLVEx_InsertIndex += 1
		EndIf

		; Colour arrays for manipulation
		$aGLVEx_SrcColArray = $aGLVEx_Data[$iGLVEx_SrcIndex][18]
		Local $bUserColSrc = ((IsArray($aGLVEx_SrcColArray)) ? (True) : (False))
		$aGLVEx_TgtColArray = $aGLVEx_Data[$iGLVEx_TgtIndex][18]
		Local $bUserColTgt = ((IsArray($aGLVEx_TgtColArray)) ? (True) : (False))

		; Amend arrays
		; Get data from dragged element(s)
		If $iMultipleItems Then
			; Multiple dragged elements
			Local $aInsertData[$iMultipleItems + 1]
			Local $aColData[$iMultipleItems + 1]
			Local $aItemData[UBound($aGLVEx_SrcArray, 2)]
			For $i = 0 To $iMultipleItems
				; Data
				For $j = 0 To UBound($aGLVEx_SrcArray, 2) - 1
					$aItemData[$j] = $aGLVEx_SrcArray[$iGLVEx_DraggedIndex + 1 + $i][$j]
				Next
				$aInsertData[$i] = $aItemData
				; Colours if required
				If $bUserColTgt Then
					For $j = 0 To UBound($aGLVEx_SrcArray, 2) - 1
						If $bUserColSrc Then
							$aItemData[$j] = $aGLVEx_SrcColArray[$iGLVEx_DraggedIndex + 1 + $i][$j]
						Else
							$aItemData[$j] = ";"
						EndIf
					Next
					$aColData[$i] = $aItemData
				EndIf
			Next
		Else
			; Single dragged element
			Local $aInsertData[1]
			Local $aColData[1]
			Local $aItemData[UBound($aGLVEx_SrcArray, 2)]
			For $i = 0 To UBound($aGLVEx_SrcArray, 2) - 1
				$aItemData[$i] = $aGLVEx_SrcArray[$iGLVEx_DraggedIndex + 1][$i]
			Next
			$aInsertData[0] = $aItemData
			If $bUserColTgt Then
				For $i = 0 To UBound($aGLVEx_SrcArray, 2) - 1
					If $bUserColSrc Then
						$aItemData[$i] = $aGLVEx_SrcColArray[$iGLVEx_DraggedIndex + 1][$i]
					Else
						$aItemData[$i] = ";"
					EndIf
				Next
				$aColData[0] = $aItemData
			EndIf
		EndIf

		; Set no redraw flag - prevents problems while colour arrays are updated
		$aGLVEx_Data[0][12] = True

		; Delete dragged element(s) from source array
		If Not BitAND($aGLVEx_Data[$iGLVEx_SrcIndex][12], 4) Then
			For $i = 0 To $iMultipleItems
				__GUIListViewEx_Array_Delete($aGLVEx_SrcArray, $iGLVEx_DraggedIndex + 1)
				If $bUserColSrc Then __GUIListViewEx_Array_Delete($aGLVEx_SrcColArray, $iGLVEx_DraggedIndex + 1)
			Next
		EndIf
		; Check if insert index is valid
		If $iGLVEx_InsertIndex < 0 Then
			$iGLVEx_InsertIndex = _GUICtrlListView_GetItemCount($hGLVEx_TgtHandle)
		EndIf

		; Insert dragged element(s) into target array
		For $i = $iMultipleItems To 0 Step -1
			__GUIListViewEx_Array_Insert($aGLVEx_TgtArray, $iGLVEx_InsertIndex + 1, $aInsertData[$i])
			If $bUserColTgt Then __GUIListViewEx_Array_Insert($aGLVEx_TgtColArray, $iGLVEx_InsertIndex + 1, $aColData[$i], False, False)
		Next

		; Rewrite ListViews to match arrays
		__GUIListViewEx_ReWriteLV($hGLVEx_SrcHandle, $aGLVEx_SrcArray, $aGLVEx_SrcArray, $iGLVEx_SrcIndex, False)
		__GUIListViewEx_ReWriteLV($hGLVEx_TgtHandle, $aGLVEx_TgtArray, $aGLVEx_TgtArray, $iGLVEx_TgtIndex, False)
		; Note no checkbox array needed ListViews with them are not interdraggable, so repass normal array and set final parameter

		; Set highlight to inserted item(s)
		_GUIListViewEx_SetActive($iGLVEx_TgtIndex)
		For $i = 0 To $iMultipleItems
			__GUIListViewEx_HighLight($hGLVEx_TgtHandle, $cGLVEx_TgtID, $iGLVEx_InsertIndex + $i)
		Next

		; Store amended arrays
		$aGLVEx_Data[$iGLVEx_SrcIndex][2] = $aGLVEx_SrcArray
		$aGLVEx_Data[$iGLVEx_SrcIndex][18] = $aGLVEx_SrcColArray
		$aGLVEx_Data[$iGLVEx_TgtIndex][2] = $aGLVEx_TgtArray
		$aGLVEx_Data[$iGLVEx_TgtIndex][18] = $aGLVEx_TgtColArray

	EndIf

	; Delete copied arrays
	$aGLVEx_SrcArray = 0
	$aGLVEx_TgtArray = 0
	$aGLVEx_SrcColArray = 0
	$aGLVEx_TgtColArray = 0

	; Set DragEvent details
	$sGLVEx_DragEvent = $iGLVEx_SrcIndex & ":" & $iGLVEx_TgtIndex
	; Set colour redraw flag
	$aGLVEx_Data[0][22] = $iGLVEx_SrcIndex & ":" & $iGLVEx_TgtIndex

	; Clear no redraw flag
	$aGLVEx_Data[0][12] = False

	; If colour used or single cell selection
	__GUIListViewEx_RedrawWindow($iGLVEx_SrcIndex)
	If $hGLVEx_TgtHandle <> $hGLVEx_SrcHandle Then
		__GUIListViewEx_RedrawWindow($iGLVEx_TgtIndex)
	EndIf

EndFunc   ;==>_GUIListViewEx_WM_LBUTTONUP_Handler

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_SYSCOMMAND_Handler
; Description ...: Windows message handler for WM_SYSCOMMAND
; Syntax.........: _GUIListViewEx_WM_SYSCOMMAND_Handler()
; Requirement(s).: v3.3.10 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_SYSCOMMAND handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_SYSCOMMAND_Handler($hWnd, $iMsg, $wParam, $lParam)

	#forceref $hWnd, $iMsg, $lParam, $lParam

	If $wParam = 0xF060 Then ; $SC_CLOSE
		$aGLVEx_Data[0][9] = True
	EndIf

EndFunc   ;==>_GUIListViewEx_WM_SYSCOMMAND_Handler

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_ExpandRange
; Description ...: Expands ranges into an array of values - $iMode determines if columns or rows
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_ExpandRange($vRange, $iLV_Index, $iMode = 1)

	; Check for valid range string
	If StringRegExp($vRange, "[^*0-9-;]") <> 0 Then
		Return SetError(1, 0, 0)
	EndIf

	; Get column/row count and create an array
	Local $iCount
	If $iMode = 1 Then
		$iCount = _GUICtrlListView_GetColumnCount($aGLVEx_Data[$iLV_Index][0])
	Else
		$iCount = _GUICtrlListView_GetItemCount($aGLVEx_Data[$iLV_Index][0])
	EndIf
	Local $aRet[$iCount + 1]

	; Strip any whitespace
	$vRange = StringStripWS($vRange, 8)
	; Check if "all"
	If $vRange = "*" Then
		$aRet[0] = $iCount
		For $i = 1 To $iCount
			$aRet[$i] = $i - 1
		Next
	Else
		; Check if there are ranges to be expanded
		If StringInStr($vRange, "-") Then
			; Parse string
			Local $aSplit_1, $aSplit_2, $iNumber
			; Split on ";"
			$aSplit_1 = StringSplit($vRange, ";")
			$vRange = ""
			; Check each element
			For $i = 1 To $aSplit_1[0]
				; Try and split on "-"
				$aSplit_2 = StringSplit($aSplit_1[$i], "-")
				; Add first value in all cases
				$vRange &= $aSplit_2[1] & ";"
				; If a valid range
				If ($aSplit_2[0]) > 1 Then
					; Check valid range
					If (Number($aSplit_2[2]) > Number($aSplit_2[1])) Then
						; Add the full range
						$iNumber = $aSplit_2[1]
						Do
							$iNumber += 1
							$vRange &= $iNumber & ";"
						Until $iNumber = $aSplit_2[2]
					Else
						Return SetError(1, 0, 0)
					EndIf
				EndIf
			Next
		EndIf
		; Split string into array
		Local $aSplit = StringSplit($vRange, ";")
		; Check for valid elements
		For $i = 1 To $aSplit[0]
			If $aSplit[$i] Then
				$aRet[0] += 1
				$aRet[$aRet[0]] = $aSplit[$i]
			EndIf
		Next
		; Remove empty elements
		ReDim $aRet[$aRet[0] + 1]
	EndIf
	; Return array of range values
	Return $aRet

EndFunc   ;==>__GUIListViewEx_ExpandRange

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_HighLight
; Description ...: Highlights first item and ensures visible, second item has highlight removed
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_HighLight($hLVHandle, $cLV_CID, $iIndexA, $iIndexB = -1)

	; Check if Native or UDF and set focus
	If $cLV_CID Then
		GUICtrlSetState($cLV_CID, 256) ; $GUI_FOCUS
	Else
		_WinAPI_SetFocus($hLVHandle)
	EndIf
	; Cancel highlight on other item - needed for multisel listviews
	If $iIndexB <> -1 Then _GUICtrlListView_SetItemSelected($hLVHandle, $iIndexB, False)
	; Set highlight to inserted item and ensure in view
	_GUICtrlListView_SetItemState($hLVHandle, $iIndexA, $LVIS_SELECTED, $LVIS_SELECTED)
	_GUICtrlListView_EnsureVisible($hLVHandle, $iIndexA)

EndFunc   ;==>__GUIListViewEx_HighLight

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_GetLVFont
; Description ...: Gets font details for ListView to be edited
; Author ........: Based on _GUICtrlGetFont by KaFu & Prog@ndy
; Modified ......: Melba23
; ===============================================================================================================================
Func __GUIListViewEx_GetLVFont($hLVHandle)

	Local $iError = 0, $aFontDetails[2] = [Default, Default]

	; Check handle
	If Not IsHWnd($hLVHandle) Then
		$hLVHandle = GUICtrlGetHandle($hLVHandle)
	EndIf
	If Not IsHWnd($hLVHandle) Then
		$iError = 1
	Else
		Local $hFont = _SendMessage($hLVHandle, 0x0031) ; WM_GETFONT
		If Not $hFont Then
			$iError = 2
		Else
			Local $hDC = _WinAPI_GetDC($hLVHandle)
			Local $hObjOrg = _WinAPI_SelectObject($hDC, $hFont)
			Local $tFONT = DllStructCreate($tagLOGFONT)
			Local $aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFont, 'int', DllStructGetSize($tFONT), 'ptr', DllStructGetPtr($tFONT))
			If @error Or $aRet[0] = 0 Then
				$iError = 3
			Else
				; Get font size
				$aFontDetails[0] = Round((-1 * DllStructGetData($tFONT, 'Height')) * 72 / _WinAPI_GetDeviceCaps($hDC, 90), 1) ; $LOGPIXELSY = 90 => DPI aware
				; Now look for font name
				$aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0)
				Local $iCount = $aRet[0]
				Local $tBuffer = DllStructCreate("wchar[" & $iCount & "]")
				Local $pBuffer = DllStructGetPtr($tBuffer)
				$aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $iCount, "ptr", $pBuffer)
				If @error Then
					$iError = 4
				Else
					$aFontDetails[1] = DllStructGetData($tBuffer, 1) ; FontFacename
				EndIf
			EndIf
			_WinAPI_SelectObject($hDC, $hObjOrg)
			_WinAPI_ReleaseDC($hLVHandle, $hDC)
		EndIf
	EndIf

	Return SetError($iError, 0, $aFontDetails)

EndFunc   ;==>__GUIListViewEx_GetLVFont

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_EditProcess
; Description ...: Runs ListView editing process
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_EditProcess($iLV_Index, $aLocation, $iDelta_X, $iDelta_Y, $iEditMode, $iForce = False)

	Local $hTemp_Combo = 9999, $hTemp_Edit = 9999, $hTemp_List = 9999, $iKey_Code, $iCombo_State, $aSplit, $sInsert
	Local $iEditType, $fEdit, $fCombo, $fRead_Only, $fDTP, $fClick_Move = False

	; Unselect item
	_GUICtrlListView_SetItemSelected($hGLVEx_SrcHandle, $aLocation[0], False)

	; Declare return array
	Local $aEdited[1][4] = [[0]] ; [[Number of edited items, blank, blank, blank]]

	; Load active ListView details
	$hGLVEx_SrcHandle = $aGLVEx_Data[$iLV_Index][0]
	$cGLVEx_SrcID = $aGLVEx_Data[$iLV_Index][1]

	; Store handle of ListView concerned
	$hGLVEx_Editing = $hGLVEx_SrcHandle
	Local $cEditingID = $cGLVEx_SrcID

	; Valid keys to action ; TAB, ENTER, ESC, left/right/up/down arrows
	Local $aKeys[7] = [0x09, 0x0D, 0x1B, 0x25, 0x27, 0x26, 0x28]

	; Set Reset-on-ESC mode
	Local $fReset_Edits = False
	If $iEditMode < 0 Then
		$fReset_Edits = True
		$iEditMode = Abs($iEditMode)
	EndIf

	; Set row/col edit mode - default single edit
	Local $iEditRow = 0, $iEditCol = 0
	If $iEditMode Then
		; Separate axis settings - force leading 0 if required
		$aSplit = StringSplit(StringFormat("%02s", $iEditMode), "")
		$iEditRow = $aSplit[1]
		$iEditCol = $aSplit[2]
	EndIf

	; Extract editable array
	Local $aEditable = $aGLVEx_Data[$iLV_Index][7]

	; Check if edit to move on click
	If $aGLVEx_Data[$iLV_Index][9] Then
		$fClick_Move = True
	EndIf

	Local $tLVPos = DllStructCreate("struct;long X;long Y;endstruct")
	; Get position of ListView within GUI client area
	__GUIListViewEx_GetLVCoords($hGLVEx_Editing, $tLVPos)
	; Get ListView client area to allow for scrollbars
	Local $aLVClient = WinGetClientSize($hGLVEx_Editing)
	; Get ListView font details
	Local $aLV_FontDetails = __GUIListViewEx_GetLVFont($hGLVEx_Editing)
	; Disable ListView
	WinSetState($hGLVEx_Editing, "", @SW_DISABLE)

	; Load edit width data array
	Local $aWidth = ($aGLVEx_Data[$iLV_Index][14])
	; Create dummy array if required
	If Not IsArray($aWidth) Then Local $aWidth[_GUICtrlListView_GetColumnCount($aGLVEx_Data[$iLV_Index][0])]

	; Define variables
	Local $iWidth, $fExitLoop, $tMouseClick = DllStructCreate($tagPOINT)
	; Set default mousecoordmode
	Local $iOldMouseOpt = Opt("MouseCoordMode", 1)
	; Prevent GUI closure on ESC as needed to exit edit
	Local $iOldESC = Opt("GUICloseOnESC", 0)

	; Start the edit loop
	While 1

		; Clear all type flags
		$fEdit = False
		$fCombo = False
		$fRead_Only = False
		$fDTP = False

		; Determine type of control required for this cell and extract data if required
		$iEditType = $aEditable[0][$aLocation[1]]
		Switch $iEditType
			Case 0, 1 ; Edit
				$fEdit = True
				If $iForce Then
					$iEditType = 1 ; Force text edit if called by _GUIListViewEx_EditItem
				EndIf

			Case 2 ; Combo
				$fCombo = True
				Local $sCombo_Data = $aEditable[1][$aLocation[1]]
				$fRead_Only = $aEditable[2][$aLocation[1]]

			Case 3 ; DTP
				$fDTP = True
				Local $sDTP_Default = $aEditable[1][$aLocation[1]]
				If $sDTP_Default = Default Then
					$sDTP_Default = @YEAR & "/" & @MON & "/" & @MDAY
				EndIf
				Local $sDTP_Format = $aEditable[2][$aLocation[1]]
				If $sDTP_Format = Default Then
					$sDTP_Format = ""
				EndIf
		EndSwitch

		; Read current text of clicked item
		Local $sItemOrgText = _GUICtrlListView_GetItemText($hGLVEx_Editing, $aLocation[0], $aLocation[1])
		; Ensure item is visible and get required edit coords
		Local $aEdit_Pos = __GUIListViewEx_EditCoords($hGLVEx_Editing, $cEditingID, $aLocation, $tLVPos, $aLVClient[0] - 5, $iDelta_X, $iDelta_Y)
		; Get required edit width - force to number so non-digits are set to 0
		$iWidth = Number($aWidth[$aLocation[1]])
		; Alter edit/combo width if required value less than current width
		If $iWidth > $aEdit_Pos[2] Then
			If $fRead_Only Then ; Only adjust read-only combo edit width if value is negative
				If $iWidth < 0 Then
					$aEdit_Pos[2] = Abs($iWidth)
				EndIf
			Else ; Always adjust for if manual input accepted
				$aEdit_Pos[2] = Abs($iWidth)
			EndIf
		EndIf

		; Create control
		Switch $iEditType
			Case 1 ; Edit
				; Create temporary edit - get handle, set font size, give keyboard focus and select all text
				$cGLVEx_EditID = GUICtrlCreateEdit($sItemOrgText, $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 128) ; $ES_AUTOHSCROLL
				$hTemp_Edit = GUICtrlGetHandle($cGLVEx_EditID)

			Case 2 ; Combo
				; Create temporary combo - get handle, set font size, give keyboard focus
				If $fRead_Only Then
					$cGLVEx_EditID = GUICtrlCreateCombo("", $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 0x00200043) ; $CBS_DROPDOWNLIST, $CBS_AUTOHSCROLL, $WS_VSCROLL
				Else
					$cGLVEx_EditID = GUICtrlCreateCombo("", $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 0x00200042) ; $CBS_DROPDOWN, $CBS_AUTOHSCROLL, $WS_VSCROLL
				EndIf
				GUICtrlSetData($cGLVEx_EditID, $sCombo_Data, $sItemOrgText)
				Local $tInfo = DllStructCreate("dword Size;struct;long EditLeft;long EditTop;long EditRight;long EditBottom;endstruct;" & _
						"struct;long BtnLeft;long BtnTop;long BtnRight;long BtnBottom;endstruct;dword BtnState;hwnd hCombo;hwnd hEdit;hwnd hList")
				Local $iInfo = DllStructGetSize($tInfo)
				DllStructSetData($tInfo, "Size", $iInfo)
				Local $hCombo = GUICtrlGetHandle($cGLVEx_EditID)
				; Set readonly combo dropped width if required
				If $fRead_Only And Abs($iWidth) > $aEdit_Pos[2] Then
					_SendMessage($hCombo, 0x160, Abs($iWidth)) ; $CB_SETDROPPEDWIDTH
				EndIf
				; Get combo data
				_SendMessage($hCombo, 0x164, 0, $tInfo, 0, "wparam", "struct*") ; $CB_GETCOMBOBOXINFO
				$hTemp_Edit = DllStructGetData($tInfo, "hEdit")
				$hTemp_List = DllStructGetData($tInfo, "hList")
				$hTemp_Combo = DllStructGetData($tInfo, "hCombo")

			Case 3 ; DTP
				; Create temp date picker
				$cGLVEx_EditID = GUICtrlCreateDate($sDTP_Default, $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3])
				$hTemp_Edit = GUICtrlGetHandle($cGLVEx_EditID)
				; Set format if required
				If $sDTP_Format Then
					GUICtrlSendMsg($cGLVEx_EditID, 0x1032, 0, $sDTP_Format) ; $DTM_SETFORMATW
				EndIf

		EndSwitch

		; Set font
		GUICtrlSetFont($cGLVEx_EditID, $aLV_FontDetails[0], Default, Default, $aLV_FontDetails[1])
		; Set focus to editing control
		_WinAPI_SetFocus($hTemp_Edit)
		; Check "select all" flag state
		If Not $aGLVEx_Data[$iLV_Index][11] Then
			GUICtrlSendMsg($cGLVEx_EditID, 0xB1, 0, -1) ; $EM_SETSEL
		EndIf

		; Copy array for manipulation
		$aGLVEx_SrcArray = $aGLVEx_Data[$iLV_Index][2]
		; Clear key code flag
		$iKey_Code = 0
		; Clear combo down/up flag
		$iCombo_State = False
		; Wait for a key press or combo down/up
		While 1
			; Clear flag
			$fExitLoop = False

			; Check for SYSCOMMAND Close Event
			If $aGLVEx_Data[0][9] Then
				$fExitLoop = True
				$aGLVEx_Data[0][9] = False
			EndIf

			; Mouse pressed
			If _WinAPI_GetAsyncKeyState(0x01) Then
				; Look for clicks outside edit/combo control
				DllStructSetData($tMouseClick, "x", MouseGetPos(0))
				DllStructSetData($tMouseClick, "y", MouseGetPos(1))
				Switch _WinAPI_WindowFromPoint($tMouseClick)
					Case $hTemp_Combo, $hTemp_Edit, $hTemp_List
						; Over edit/combo
					Case Else
						; Ignore if using date control
						If Not $fDTP Then
							$fExitLoop = True
						EndIf
				EndSwitch
				; Wait for mouse button release
				While _WinAPI_GetAsyncKeyState(0x01)
					Sleep(10)
				WEnd
			EndIf
			; Exit loop
			If $fExitLoop Then
				; If standard edit control
				If $fEdit Then
					; Set appropriate behaviour
					If $fClick_Move Then
						$iKey_Code = 0x02 ; Confirm edit and end process
					Else
						$iKey_Code = 0x01 ; Abandon editing
					EndIf
				EndIf
				ExitLoop
			EndIf

			If $fCombo Then
				; Check for dropdown open and close
				Switch _SendMessage($hCombo, 0x157) ; $CB_GETDROPPEDSTATE
					Case 0
						; If opened and closed
						If $iCombo_State = True Then
							; If no content
							If GUICtrlRead($cGLVEx_EditID) = "" Then
								; Ignore
								$iCombo_State = False
							Else
								; Act as if Enter pressed
								$iKey_Code = 0x0D
								ExitLoop
							EndIf
						EndIf
					Case 1
						; Set flag if opened
						If Not $iCombo_State Then
							$iCombo_State = True
						EndIf
				EndSwitch
			EndIf

			; Check for valid key pressed
			For $i = 0 To 2 ; TAB, ENTER, ESC
				If _WinAPI_GetAsyncKeyState($aKeys[$i]) Then
					; Set key pressed flag
					$iKey_Code = $aKeys[$i]
					ExitLoop 2
				EndIf
			Next
			For $i = 3 To 6 ; l/r/u/d with ctrl pressed
				If _WinAPI_GetAsyncKeyState($aKeys[$i]) And _WinAPI_GetAsyncKeyState(0x11) Then
					; Set key pressed flag
					$iKey_Code = $aKeys[$i]
					ExitLoop 2
				EndIf
			Next

			; Temp input lost focus
			If _WinAPI_GetFocus() <> $hTemp_Edit Then
				ExitLoop
			EndIf

			; Save CPU
			Sleep(10)
		WEnd

		; Check if edit to be confirmed
		Switch $iKey_Code
			Case 0x25, 0x26, 0x27, 0x28 ; arrow keys
				; If not standard edit control then abandon edit
				If $fEdit Then
					ContinueCase
				EndIf

			Case 0x02, 0x09, 0x0D ; Mouse (with Click=Move), TAB, ENTER
				; Read edit content
				Local $sItemNewText = GUICtrlRead($cGLVEx_EditID)
				; Check replacement required
				If $sItemNewText <> $sItemOrgText Then
					; Amend item text
					_GUICtrlListView_SetItemText($hGLVEx_Editing, $aLocation[0], $sItemNewText, $aLocation[1])
					; Amend array element
					$aGLVEx_SrcArray[$aLocation[0] + 1][$aLocation[1]] = $sItemNewText
					; Store amended array
					$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
					; Add item data to return array
					$aEdited[0][0] += 1
					ReDim $aEdited[$aEdited[0][0] + 1][4]
					; Save location & original content
					$aEdited[$aEdited[0][0]][0] = $aLocation[0]
					$aEdited[$aEdited[0][0]][1] = $aLocation[1]
					$aEdited[$aEdited[0][0]][2] = $sItemOrgText
					$aEdited[$aEdited[0][0]][3] = $sItemNewText
				EndIf
		EndSwitch

		; Delete temporary edit and set place holder
		GUICtrlDelete($cGLVEx_EditID)
		$cGLVEx_EditID = 9999
		; Reset user mousecoord mode
		Opt("MouseCoordMode", $iOldMouseOpt)
		; Check edit mode
		If $iEditMode = 0 Then ; Single edit
			; Exit edit process
			ExitLoop
		Else
			Switch $iKey_Code
				Case 0x00, 0x01, 0x02, 0x0D ; Edit lost focus, mouse button outside edit, ENTER pressed
					; Wait until key/button no longer pressed
					While _WinAPI_GetAsyncKeyState($iKey_Code)
						Sleep(10)
					WEnd
					; Exit Edit process
					ExitLoop

				Case 0x1B ; ESC pressed
					; Check Reset-on-ESC mode
					If $fReset_Edits Then
						; Reset previous confirmed edits starting with most recent
						For $i = $aEdited[0][0] To 1 Step -1
							_GUICtrlListView_SetItemText($hGLVEx_Editing, $aEdited[$i][0], $aEdited[$i][2], $aEdited[$i][1])
							Switch UBound($aGLVEx_SrcArray, 0)
								Case 1
									$aSplit = StringSplit($aGLVEx_SrcArray[$aEdited[$i][0] + 1], $aGLVEx_Data[0][24])
									$aSplit[$aEdited[$i][1] + 1] = $aEdited[$i][2]
									$sInsert = ""
									For $j = 1 To $aSplit[0]
										$sInsert &= $aSplit[$j] & $aGLVEx_Data[0][24]
									Next
									$aGLVEx_SrcArray[$aEdited[$i][0] + 1] = StringTrimRight($sInsert, 1)

								Case 2
									$aGLVEx_SrcArray[$aEdited[$i][0] + 1][$aEdited[$i][1]] = $aEdited[$i][2]
							EndSwitch
						Next
						; Store amended array
						$aGLVEx_Data[$iLV_Index][2] = $aGLVEx_SrcArray
						; Empty return array as no edits made
						ReDim $aEdited[1][4]
						$aEdited[0][0] = 0
					EndIf
					; Wait until key no longer pressed
					While _WinAPI_GetAsyncKeyState(0x1B)
						Sleep(10)
					WEnd
					; Exit Edit process
					ExitLoop

				Case 0x09, 0x27 ; TAB or right arrow
					While 1
						If $iEditCol <> 0 Then
							; Set next column
							$aLocation[1] += 1
							; Check column exists
							If $aLocation[1] = _GUICtrlListView_GetColumnCount($hGLVEx_Editing) Then
								; Does not exist so check required action
								Switch $iEditCol
									Case 1
										; Exit edit process
										ExitLoop 2
									Case 2
										; Stay on same location
										$aLocation[1] -= 1
										ExitLoop
									Case 3
										; Loop
										$aLocation[1] = 0
								EndSwitch
							EndIf
							; Check this column is editable
							If $aEditable[0][$aLocation[1]] <> 0 Then
								; Editable column
								ExitLoop
							Else
								; Not editable column
								ExitLoop 2
							EndIf
						Else
							; End edit
							ExitLoop 2
						EndIf
					WEnd

				Case 0x25 ; Left arrow
					While 1
						If $iEditCol <> 0 Then
							$aLocation[1] -= 1
							If $aLocation[1] < 0 Then
								Switch $iEditCol
									Case 1
										ExitLoop 2
									Case 2
										$aLocation[1] += 1
										ExitLoop
									Case 3
										$aLocation[1] = _GUICtrlListView_GetColumnCount($hGLVEx_Editing) - 1
								EndSwitch
							EndIf
							; Check this column is editable
							If $aEditable[0][$aLocation[1]] <> 0 Then
								ExitLoop
							Else
								ExitLoop 2
							EndIf
						Else
							; End edit
							ExitLoop 2
						EndIf
					WEnd

				Case 0x28 ; Down key
					While 1
						If $iEditRow <> 0 Then
							; Set next row
							$aLocation[0] += 1
							; Check column exists
							If $aLocation[0] = _GUICtrlListView_GetItemCount($hGLVEx_Editing) Then
								; Does not exist so check required action
								Switch $iEditRow
									Case 1
										; Exit edit process
										ExitLoop 2
									Case 2
										; Stay on same location
										$aLocation[0] -= 1
										ExitLoop
									Case 3
										; Loop
										$aLocation[0] = -1
								EndSwitch
							Else
								; All rows editable
								ExitLoop
							EndIf
						Else
							; End edit
							ExitLoop 2
						EndIf
					WEnd

				Case 0x26 ; Up key
					While 1
						If $iEditRow <> 0 Then
							$aLocation[0] -= 1
							If $aLocation[0] < 0 Then
								Switch $iEditRow
									Case 1
										ExitLoop 2
									Case 2
										$aLocation[0] += 1
										ExitLoop
									Case 3
										$aLocation[0] = _GUICtrlListView_GetItemCount($hGLVEx_Editing)
								EndSwitch
							Else
								ExitLoop
							EndIf
						Else
							; End edit
							ExitLoop 2
						EndIf
					WEnd
			EndSwitch
			; Wait until key no longer pressed
			While _WinAPI_GetAsyncKeyState($iKey_Code)
				Sleep(10)
			WEnd
			; Continue edit loop on next item
		EndIf
	WEnd
	; Delete copied array
	$aGLVEx_SrcArray = 0
	; Reenable ListView
	WinSetState($hGLVEx_Editing, "", @SW_ENABLE)
	; Reselect item
	_GUICtrlListView_SetItemState($hGLVEx_Editing, $aLocation[0], $LVIS_SELECTED, $LVIS_SELECTED)

	; Set extended to key value
	SetExtended($iKey_Code)
	; Reset user value
	Opt("GUICloseOnESC", $iOldESC)

	; Return array
	Return $aEdited

EndFunc   ;==>__GUIListViewEx_EditProcess

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_EditCoords
; Description ...: Ensures item in view then locates and sizes edit control
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_EditCoords($hLV_Handle, $cLV_CID, $aLocation, $tLVPos, $iLVWidth, $iDelta_X, $iDelta_Y)

	; Declare array to hold return data
	Local $aEdit_Data[4]
	; Ensure row visible
	_GUICtrlListView_EnsureVisible($hLV_Handle, $aLocation[0])
	; Get size of item
	Local $aRect = _GUICtrlListView_GetSubItemRect($hLV_Handle, $aLocation[0], $aLocation[1])
	; Set required edit height
	$aEdit_Data[3] = $aRect[3] - $aRect[1] + 1
	; Set required edit width
	$aEdit_Data[2] = _GUICtrlListView_GetColumnWidth($hLV_Handle, $aLocation[1])
	; Ensure column visible - scroll to left edge if all column not in view
	If $aRect[0] < 0 Or $aRect[2] > $iLVWidth Then
		_GUICtrlListView_Scroll($hLV_Handle, $aRect[0], 0)
		; Redetermine item coords
		$aRect = _GUICtrlListView_GetSubItemRect($hLV_Handle, $aLocation[0], $aLocation[1])
		; Check available column width and limit if required
		If $aRect[0] + $aEdit_Data[2] > $iLVWidth Then
			$aEdit_Data[2] = $iLVWidth - $aRect[0]
		EndIf
	EndIf
	; Adjust Y coord if Native ListView
	If $cLV_CID Then
		$iDelta_Y += 1
	EndIf
	; Determine screen coords for edit control
	$aEdit_Data[0] = DllStructGetData($tLVPos, "X") + $aRect[0] + $iDelta_X + 2
	$aEdit_Data[1] = DllStructGetData($tLVPos, "Y") + $aRect[1] + $iDelta_Y

	; Return edit data
	Return $aEdit_Data

EndFunc   ;==>__GUIListViewEx_EditCoords

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_ReWriteLV
; Description ...: Deletes all ListView content and refills to match array
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_ReWriteLV($hLVHandle, ByRef $aLV_Array, ByRef $aCheck_Array, $iLV_Index, $fCheckBox = True)

	Local $iVertScroll

	; Get item depth
	If $aGLVEx_Data[$iLV_Index][10] Then
		$iVertScroll = $aGLVEx_Data[$iLV_Index][10]
	Else
		; If not already set then ListView was empty so determine
		Local $aRect = _GUICtrlListView_GetItemRect($hLVHandle, 0)
		$aGLVEx_Data[$iLV_Index][10] = $aRect[3] - $aRect[1]
		; If still empty set a placeholder for this instance
		If $iVertScroll = 0 Then
			; And make sure scroll is likely to be enough to get next item into view
			$iVertScroll = 20
		EndIf
	EndIf

	; Get top item
	Local $iTopIndex_Org = _GUICtrlListView_GetTopIndex($hLVHandle)

	_GUICtrlListView_BeginUpdate($hLVHandle)

	; Empty ListView
	_GUICtrlListView_DeleteAllItems($hLVHandle)

	; Check array to fill ListView
	If UBound($aLV_Array, 2) Then

		; Remove count line from stored array
		Local $aArray = $aLV_Array
		_ArrayDelete($aArray, 0)

		; Load ListView content
		Local $cLV_CID = $aGLVEx_Data[$iLV_Index][1]
		If $cLV_CID Then
			; Native ListView
			Local $sLine, $iLastCol = UBound($aArray, 2) - 1
			For $i = 0 To UBound($aArray) - 1
				$sLine = ""
				For $j = 0 To $iLastCol
					$sLine &= $aArray[$i][$j] & "|"
				Next
				GUICtrlCreateListViewItem(StringTrimRight($sLine, 1), $cLV_CID)
			Next
		Else
			; UDF ListView
			_GUICtrlListView_AddArray($hLVHandle, $aArray)
		EndIf

		; Reset checkbox if required
		For $i = 1 To $aLV_Array[0][0]
			If $fCheckBox And $aCheck_Array[$i] Then
				_GUICtrlListView_SetItemChecked($hLVHandle, $i - 1)
			EndIf
		Next

		; Now scroll to same place or max possible
		Local $iTopIndex_Curr = _GUICtrlListView_GetTopIndex($hLVHandle)
		While $iTopIndex_Curr < $iTopIndex_Org
			_GUICtrlListView_Scroll($hLVHandle, 0, $iVertScroll)
			; If scroll had no effect then max scroll up
			If _GUICtrlListView_GetTopIndex($hLVHandle) = $iTopIndex_Curr Then
				ExitLoop
			Else
				; Reset current top index
				$iTopIndex_Curr = _GUICtrlListView_GetTopIndex($hLVHandle)
			EndIf
		WEnd
	EndIf

	_GUICtrlListView_EndUpdate($hLVHandle)

EndFunc   ;==>__GUIListViewEx_ReWriteLV

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_GetLVCoords
; Description ...: Gets screen coords for ListView
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_GetLVCoords($hLV_Handle, ByRef $tLVPos)

	; Get handle of ListView parent
	Local $aWnd = DllCall("user32.dll", "hwnd", "GetParent", "hwnd", $hLV_Handle)
	Local $hWnd = $aWnd[0]
	; Get position of ListView within GUI client area
	Local $aLVPos = WinGetPos($hLV_Handle)
	DllStructSetData($tLVPos, "X", $aLVPos[0])
	DllStructSetData($tLVPos, "Y", $aLVPos[1])
	_WinAPI_ScreenToClient($hWnd, $tLVPos)

EndFunc   ;==>__GUIListViewEx_GetLVCoords

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_GetCursorWnd
; Description ...: Gets handle of control under the mouse cursor
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func __GUIListViewEx_GetCursorWnd()

	Local $iOldMouseOpt = Opt("MouseCoordMode", 1)
	Local $tMPos = DllStructCreate("struct;long X;long Y;endstruct")
	DllStructSetData($tMPos, "X", MouseGetPos(0))
	DllStructSetData($tMPos, "Y", MouseGetPos(1))
	Opt("MouseCoordMode", $iOldMouseOpt)
	Return _WinAPI_WindowFromPoint($tMPos)

EndFunc   ;==>__GUIListViewEx_GetCursorWnd

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_Array_Add
; Description ...: Adds a specified value at the end of an existing 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_Array_Add(ByRef $avArray, $vAdd, $fMultiRow = False, $bCount = True)

	; Get size of the Array to modify
	Local $iIndex_Max = UBound($avArray)
	Local $iAdd_Dim

	; Get type of array
	Switch UBound($avArray, 0)
		Case 1 ; Checkbox array
			If UBound($vAdd, 0) = 2 Or $fMultiRow Then ; 2D or 1D as rows
				$iAdd_Dim = UBound($vAdd, 1)
				ReDim $avArray[$iIndex_Max + $iAdd_Dim]
			Else ; 1D as columns
				ReDim $avArray[$iIndex_Max + 1]
			EndIf

		Case 2 ; Data array
			; Get column count of data array
			Local $iDim2 = UBound($avArray, 2)
			If UBound($vAdd, 0) = 2 Then ; 2D add
				; Redim the Array
				$iAdd_Dim = UBound($vAdd, 1)
				ReDim $avArray[$iIndex_Max + $iAdd_Dim][$iDim2]
				$avArray[0][0] += $iAdd_Dim
				; Add new elements
				Local $iAdd_Max = UBound($vAdd, 2)
				For $i = 0 To $iAdd_Dim - 1
					For $j = 0 To $iDim2 - 1
						; If Insert array is too small to fill Array then continue with blanks
						If $j > $iAdd_Max - 1 Then
							$avArray[$iIndex_Max + $i][$j] = ""
						Else
							$avArray[$iIndex_Max + $i][$j] = $vAdd[$i][$j]
						EndIf
					Next
				Next

			ElseIf $fMultiRow Then ; 1D add as rows
				; Redim the Array
				$iAdd_Dim = UBound($vAdd, 1)
				ReDim $avArray[$iIndex_Max + $iAdd_Dim][$iDim2]
				$avArray[0][0] += $iAdd_Dim
				; Add new elements
				For $i = 0 To $iAdd_Dim - 1
					$avArray[$iIndex_Max + $i][0] = $vAdd[$i]
				Next

			Else ; 1D add as columns
				; Redim the Array
				ReDim $avArray[$iIndex_Max + 1][$iDim2]
				If $bCount Then
					$avArray[0][0] += 1
				EndIf
				; Add new elements
				If IsArray($vAdd) Then
					; Get size of Insert array
					Local $vAdd_Max = UBound($vAdd)
					For $j = 0 To $iDim2 - 1
						; If Insert array is too small to fill Array then continue with blanks
						If $j > $vAdd_Max - 1 Then
							$avArray[$iIndex_Max][$j] = ""
						Else
							$avArray[$iIndex_Max][$j] = $vAdd[$j]
						EndIf
					Next
				Else
					; Fill Array with variable
					For $j = 0 To $iDim2 - 1
						$avArray[$iIndex_Max][$j] = $vAdd
					Next
				EndIf
			EndIf

	EndSwitch

EndFunc   ;==>__GUIListViewEx_Array_Add

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_Array_Insert
; Description ...: Adds a value at the specified index of a 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_Array_Insert(ByRef $avArray, $iIndex, $vInsert, $fMultiRow = False, $bCount = True)

	; Get size of the Array to modify
	Local $iIndex_Max = UBound($avArray)
	Local $iInsert_Dim

	; Get type of array
	Switch UBound($avArray, 0)
		Case 1 ; Checkbox array
			If UBound($vInsert, 0) = 2 Or $fMultiRow Then ; 2D or 1D as rows
				; Resize array
				$iInsert_Dim = UBound($vInsert, 1)
				ReDim $avArray[$iIndex_Max + $iInsert_Dim]

				; Move down all elements below the new index
				For $i = $iIndex_Max + $iInsert_Dim - 1 To $iIndex + 1 Step -1
					$avArray[$i] = $avArray[$i - 1]
				Next
			Else ; 1D as columns
				; Resize array
				ReDim $avArray[$iIndex_Max + 1]

				; Move down all elements below the new index
				For $i = $iIndex_Max To $iIndex + 1 Step -1
					$avArray[$i] = $avArray[$i - 1]
				Next
			EndIf

		Case 2 ; Data array
			; If at end of array
			If $iIndex > $iIndex_Max - 1 Then
				__GUIListViewEx_Array_Add($avArray, $vInsert, $fMultiRow, $bCount)
				Return
			EndIf
			; Get column count of data array
			Local $iDim2 = UBound($avArray, 2)
			If UBound($vInsert, 0) = 2 Then ; 2D insert
				; Redim the Array
				$iInsert_Dim = UBound($vInsert, 1)
				ReDim $avArray[$iIndex_Max + $iInsert_Dim][$iDim2]
				If $bCount Then
					$avArray[0][0] += $iInsert_Dim
				EndIf
				; Move down all elements below the new index
				For $i = $iIndex_Max + $iInsert_Dim - 1 To $iIndex + $iInsert_Dim Step -1
					For $j = 0 To $iDim2 - 1
						$avArray[$i][$j] = $avArray[$i - $iInsert_Dim][$j]
					Next
				Next
				; Add new elements
				Local $iInsert_Max = UBound($vInsert, 2)
				For $i = 0 To $iInsert_Dim - 1
					For $j = 0 To $iDim2 - 1
						; If Insert array is too small to fill Array then continue with blanks
						If $j > $iInsert_Max - 1 Then
							$avArray[$iIndex + $i][$j] = ""
						Else
							$avArray[$iIndex + $i][$j] = $vInsert[$i][$j]
						EndIf
					Next
				Next

			ElseIf $fMultiRow Then ; 1D insert as rows
				; Redim the Array
				$iInsert_Dim = UBound($vInsert, 1)
				ReDim $avArray[$iIndex_Max + $iInsert_Dim][$iDim2]
				$avArray[0][0] += $iInsert_Dim
				; Move down all elements below the new index
				For $i = $iIndex_Max + $iInsert_Dim - 1 To $iIndex + $iInsert_Dim Step -1
					For $j = 0 To $iDim2 - 1
						$avArray[$i][$j] = $avArray[$i - $iInsert_Dim][$j]
					Next
				Next
				; Add new items
				For $i = 0 To $iInsert_Dim - 1
					$avArray[$iIndex + $i][0] = $vInsert[$i]
				Next

			Else ; 1D insert as columns
				; Redim the Array
				ReDim $avArray[$iIndex_Max + 1][$iDim2]
				$avArray[0][0] += 1
				; Move down all elements below the new index
				For $i = $iIndex_Max To $iIndex + 1 Step -1
					For $j = 0 To $iDim2 - 1
						$avArray[$i][$j] = $avArray[$i - 1][$j]
					Next
				Next
				; Insert new elements
				If IsArray($vInsert) Then
					; Get size of Insert array
					Local $vInsert_Max = UBound($vInsert)
					For $j = 0 To $iDim2 - 1
						; If Insert array is too small to fill Array then continue with blanks
						If $j > $vInsert_Max - 1 Then
							$avArray[$iIndex][$j] = ""
						Else
							$avArray[$iIndex][$j] = $vInsert[$j]
						EndIf
					Next
				Else
					; Fill Array with variable
					For $j = 0 To $iDim2 - 1
						$avArray[$iIndex][$j] = $vInsert
					Next
				EndIf
			EndIf

	EndSwitch

EndFunc   ;==>__GUIListViewEx_Array_Insert

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_Array_Delete
; Description ...: Deletes a specified index from an existing 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_Array_Delete(ByRef $avArray, $iIndex, $bDelCount = False)

	; Get size of the Array to modify
	Local $iIndex_Max = UBound($avArray)
	If $iIndex_Max = 0 Then Return

	; Get type of array
	Switch UBound($avArray, 0)
		Case 1 ; Checkbox array
			; Move up all elements below the new index
			For $i = $iIndex To $iIndex_Max - 2
				$avArray[$i] = $avArray[$i + 1]
			Next
			; Redim the Array
			ReDim $avArray[$iIndex_Max - 1]

		Case 2 ; Data array
			; Get size of second dimension
			Local $iDim2 = UBound($avArray, 2)
			; Move up all elements below the new index
			For $i = $iIndex To $iIndex_Max - 2
				For $j = 0 To $iDim2 - 1
					$avArray[$i][$j] = $avArray[$i + 1][$j]
				Next
			Next
			; Redim the Array
			ReDim $avArray[$iIndex_Max - 1][$iDim2]
			; If count element not being deleted
			If Not $bDelCount Then
				$avArray[0][0] -= 1
			EndIf

	EndSwitch

EndFunc   ;==>__GUIListViewEx_Array_Delete

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_Array_Swap
; Description ...: Swaps specified elements within a 1D or 2D array
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_Array_Swap(ByRef $avArray, $iIndex1, $iIndex2)

	Local $vTemp

	; Get type of array
	Switch UBound($avArray, 0)
		Case 1
			; Swap the elements via a temp variable
			$vTemp = $avArray[$iIndex1]
			$avArray[$iIndex1] = $avArray[$iIndex2]
			$avArray[$iIndex2] = $vTemp

		Case 2
			; Get size of second dimension
			Local $iDim2 = UBound($avArray, 2)
			; Swap the elements via a temp variable
			For $i = 0 To $iDim2 - 1
				$vTemp = $avArray[$iIndex1][$i]
				$avArray[$iIndex1][$i] = $avArray[$iIndex2][$i]
				$avArray[$iIndex2][$i] = $vTemp
			Next
	EndSwitch

	Return 0

EndFunc   ;==>__GUIListViewEx_Array_Swap

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_ToolTipHide
; Description ...: Called by Adlib to hide a tooltip displayed by _GUIListViewEx_ToolTipShow
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_ToolTipHide()
	; Cancel Adlib
	AdlibUnRegister("__GUIListViewEx_ToolTipHide")
	; Clear tooltip
	ToolTip("")
	; Reset tooltip row/col values
	$aGLVEx_Data[0][4] = -1
	$aGLVEx_Data[0][5] = -1
EndFunc   ;==>__GUIListViewEx_ToolTipHide

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_MakeString
; Description ...: Convert data/check/colour arrays to strings for saving
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_MakeString($aArray)

	If Not IsArray($aArray) Then Return SetError(1, 0, "")

	Local $sRet = ""
	Local $sDelim_Col = @CR
	Local $sDelim_Row = @LF

	Switch UBound($aArray, $UBOUND_DIMENSIONS)
		Case 1
			For $i = 0 To UBound($aArray, $UBOUND_ROWS) - 1
				$sRet &= $aArray[$i] & $sDelim_Row
			Next
			Return StringTrimRight($sRet, StringLen($sDelim_Col))

		Case 2
			For $i = 0 To UBound($aArray, $UBOUND_ROWS) - 1
				For $j = 0 To UBound($aArray, $UBOUND_COLUMNS) - 1
					$sRet &= $aArray[$i][$j] & $sDelim_Col
				Next
				$sRet = StringTrimRight($sRet, StringLen($sDelim_Col)) & $sDelim_Row
			Next
			Return StringTrimRight($sRet, StringLen($sDelim_Row))

		Case Else
			Return SetError(2, 0, "")
	EndSwitch

EndFunc   ;==>__GUIListViewEx_MakeString

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_MakeArray
; Description ...: Convert data/check/colour strings to arrays for loading
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_MakeArray($sString)

	If $sString = "" Then Return SetError(1, 0, "")

	Local $aRetArray, $aRows, $aItems
	Local $sRowDelimiter = @LF
	Local $sColDelimiter = @CR

	If StringInStr($sString, $sColDelimiter) Then
		; 2D array
		$aRows = StringSplit($sString, $sRowDelimiter)
		; Get column count
		StringReplace($aRows[1], $sColDelimiter, "")
		; Create array
		Local $aRetArray[$aRows[0]][@extended + 1]
		; Fill array
		For $i = 1 To $aRows[0]
			$aItems = StringSplit($aRows[$i], $sColDelimiter)
			For $j = 1 To $aItems[0]
				$aRetArray[$i - 1][$j - 1] = $aItems[$j]
			Next
		Next
	Else
		; 1D array
		$aRetArray = StringSplit($sString, $sRowDelimiter, $STR_NOCOUNT)
	EndIf

	Return $aRetArray

EndFunc   ;==>__GUIListViewEx_MakeArray

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_ColSort
; Description ...: Sort columns even if colour enabled
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_ColSort($hLV, $iLV_Index, ByRef $vSortSense, $iCol, $bToggleSense = True)

	Local $aListViewContent = $aGLVEx_Data[$iLV_Index][2]
	Local $aColourSettings = $aGLVEx_Data[$iLV_Index][18]
	; Check there are items to sort
	Local $iItemCount = $aListViewContent[0][0]
	If $iItemCount Then
		; Set sort order
		Local $iDescending = 0
		If UBound($vSortSense) Then
			$iDescending = $vSortSense[$iCol]
		Else
			$iDescending = $vSortSense
		EndIf
		; Get column count
		Local $iColumnCount = UBound($aListViewContent, 2)
		; Check if colour enabled
		Local $fColourEnabled = ((IsArray($aGLVEx_Data[$iLV_Index][18])) ? (True) : (False))
		If $fColourEnabled Then
			; ReDim data to add columns for index value, ItemParam and colour settings
			ReDim $aListViewContent[UBound($aListViewContent)][($iColumnCount * 2) + 2]
			; Add colour data to array
			For $i = 1 To $iItemCount
				For $j = 0 To $iColumnCount - 1
					$aListViewContent[$i][$iColumnCount + $j + 2] = $aColourSettings[$i][$j]
				Next
			Next
		Else
			; ReDim data to add coluns for index value and ItemParam
			ReDim $aListViewContent[UBound($aListViewContent)][$iColumnCount + 2]
		EndIf
		; Determine indices for index and param elements
		Local Enum $iIndexValue = $iColumnCount, $iItemParam
		; Get selected items
		Local $sSelectedItems = _GUICtrlListView_GetSelectedIndices($hLV)
		Local $aSelectedItems
		If $sSelectedItems = "" Then
			; If no selection (colour enabled) then use stored value
			Local $aSelectedItems[2] = [1, $aGLVEx_Data[0][17]]
		Else
			$aSelectedItems = StringSplit($sSelectedItems, Opt('GUIDataSeparatorChar'))
		EndIf
		; Get checked items
		Local $aCheckedItems[$iItemCount + 1] = [0]
		For $i = 0 To $iItemCount - 1
			If _GUICtrlListView_GetItemChecked($hLV, $i) Then
				$aCheckedItems[0] += 1
				$aCheckedItems[$aCheckedItems[0]] = $i
			EndIf
		Next
		ReDim $aCheckedItems[$aCheckedItems[0] + 1]
		; Clear current focused and selected items and save item data in array
		Local $iFocused = -1
		For $i = 0 To $iItemCount - 1
			If $iFocused = -1 Then
				If _GUICtrlListView_GetItemFocused($hLV, $i) Then $iFocused = $i
			EndIf
			_GUICtrlListView_SetItemSelected($hLV, $i, False)
			_GUICtrlListView_SetItemChecked($hLV, $i, False)
			; Store index and param values
			$aListViewContent[$i + 1][$iIndexValue] = $i
			$aListViewContent[$i + 1][$iItemParam] = _GUICtrlListView_GetItemParam($hLV, $i)
		Next

		; Sort the combined ListView array on the clicked column
		_ArraySort($aListViewContent, $iDescending, 1, 0, $iCol)

		; Enter the sorted ListView data
		For $i = 1 To $iItemCount ; Rows
			For $j = 0 To $iColumnCount - 1 ; Columns
				_GUICtrlListView_SetItemText($hLV, $i - 1, $aListViewContent[$i][$j], $j)
				; Reset the colour array if colour enabled
				If $fColourEnabled Then
					$aColourSettings[$i][$j] = $aListViewContent[$i][$iColumnCount + $j + 2]
				EndIf
			Next
			; Reset item param
			_GUICtrlListView_SetItemParam($hLV, $i - 1, $aListViewContent[$i][$iItemParam])
			; Reset selected states
			For $j = 1 To $aSelectedItems[0]
				If $aListViewContent[$i][$iIndexValue] = $aSelectedItems[$j] Then
					$aGLVEx_Data[0][17] = $i - 1
					$aGLVEx_Data[$iLV_Index][20] = $i - 1
					If Not ($aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22]) Then
						If $aListViewContent[$i - 1][$iIndexValue] = $iFocused Then
							_GUICtrlListView_SetItemSelected($hLV, $i - 1, True, True)
						Else
							_GUICtrlListView_SetItemSelected($hLV, $i - 1, True)
						EndIf
						ExitLoop
					EndIf
				EndIf
			Next
			; Reset checked states
			For $j = 1 To $aCheckedItems[0]
				If $aListViewContent[$i][$iIndexValue] = $aCheckedItems[$j] Then
					_GUICtrlListView_SetItemChecked($hLV, $i - 1, True)
					ExitLoop
				EndIf
			Next
		Next
		; Check automatic sort sense toggle and adjust if required
		If $bToggleSense Then
			If UBound($vSortSense) Then
				$vSortSense[$iCol] = Not $iDescending
			Else
				$vSortSense = Not $iDescending
			EndIf
		EndIf

		; ReDim content array to remove additional columns
		ReDim $aListViewContent[UBound($aListViewContent)][$iColumnCount]
		; Store sorted arrays
		$aGLVEx_Data[$iLV_Index][2] = $aListViewContent
		$aGLVEx_Data[$iLV_Index][18] = $aColourSettings

		; Set flags using ListView index
		$aGLVEx_Data[0][19] = $iLV_Index ; SortEvent
		$aGLVEx_Data[0][22] = $iLV_Index ; ColourEvent

	EndIf

EndFunc   ;==>__GUIListViewEx_ColSort

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_RedrawWindow
; Description ...: Redraw ListView after update
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_RedrawWindow($iLV_Index, $fForce = False)

	; Force redraw if colour used or single cell selection
	If $fForce Or $aGLVEx_Data[$iLV_Index][19] Or $aGLVEx_Data[$iLV_Index][22] Then
		; Force reload of redraw colour array
		$aGLVEx_Data[0][14] = 0
		; If Redraw flag set
		If $aGLVEx_Data[0][15] Then
			; Redraw ListView
			_WinAPI_RedrawWindow($aGLVEx_Data[$iLV_Index][0])
		EndIf
	EndIf

EndFunc

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __GUIListViewEx_CheckUserEditKey
; Description ...: Check keys pressed in ListView
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func __GUIListViewEx_CheckUserEditKey()

	Local $aKey = StringSplit($aGLVEx_Data[0][23], ";"), $iKeyValue
	; Set flag
	Local $fCheck = True
	; Check if keys required are pressed
	For $i = 1 To $aKey[0]
		; Convert to number
		$iKeyValue = Dec($aKey[$i])
		If Not _WinAPI_GetAsyncKeyState($iKeyValue) Then
			; Required key not pressed so clear flag
			$fCheck = False
			; No point in looking further
			ExitLoop
		EndIf
	Next

	Return $fCheck

EndFunc