Jump to content
Sign in to follow this  
NunoBorges

Listview scrollbar and insertmark

Recommended Posts

NunoBorges

Viva,

In the research I did on listview and scroll, I found an example

that could meet my needs.

In the example I put in attachment a ListView, I can not have the correct scroll down, I would also have a "InsertMark."

Does someone could help me in this instance?

Sincerely

ListView Scroll 2_1.au3

Share this post


Link to post
Share on other sites
Melba23

NunuBorges,

If you look in the GUIListViewEx UDF in my sig you will see how to get an InsertMark - you use 2 undocumented function within GUIListView UDF: _GUICtrlListView_SetInsertMark and _GUICtrlListView_SetInsertMarkColor. :)

See if you can get what you want from the UDF and then please ask if you have any questions. :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

Now I see that did not include the your GUIListViewEx, I will fix and test.

thanks

Share this post


Link to post
Share on other sites
NunoBorges

Viva, Melba23

I have made the include but it is not working, can you once more take a look?

Best regards

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

can you once more take a look?

At what? Post what code you have using my UDF and I will see what I can do. :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

Sorry, :mellow:

Vou tornar a ver o codigo, pois pensava que eu estava a usar as tuas funções da GUIListViewEx, como as tinhas anunciado anteriormente.

Thanks

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

You have not used my UDF in the script you have posted. Try to recode using the UDF and see if it works for you - if not then post the code using my UDF and I will try and debug it for you. Ot just look at how I use the UDf to set the InsertMark - you will see you need the $WM_NOTIFY, $WM_MOUSEMOVE and $WM_LBUTTONUP messages registered. :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

Viva, M23

I have attached an example of my needs, I need to have the WM_NOTIFY, with the functions described.

I would like to keep the WM_LBUTTONUP to get the image of the selected item.

Without WM_MOUSEMOVE, the items covered by the mouse movement are not redrawn.

If you have opportunity, I would like these a look.

PS:

I think it could be quite useful to integrate on "GUIListViewEx" the option to associate the "InsertMark" an image of the selected item(s).

Sincerely

- LVtest.au3

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

I am looking at the script. At first glance I see a number of problems integrating your code with the extant UDF, not least the _GUIImageList_Drag* functions. I think these would have to be integrated within the UDF handlers or you will get into serious difficulties. :)

Give me a while and I will see what I can do - no promises though as I have a lot on at the moment. :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

Rainy afternoon, so no golf and no flying. :)

But lucky you - I have developed a slightly modified version of GUIListViewEx to give you drag images (if you set the parameter in the _Init function :)) and your script seems to work quite well with it:

#include-once

; #INDEX# ============================================================================================================
; Title .........: GUIListViewEx
; AutoIt Version : 3.3 +
; Language ......: English
; Description ...: Permits insertion, deletion, moving, dragging and sorting of items within activated 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.
;                  - If the script already has WM_NOTIFY, WM_MOUSEMOVE or WM_LBUTTONUP handlers then only set the
;                    unregistered messages in _GUIListViewEx_DragRegister and call the relevant _GUIListViewEx_WM_#####_Handler from
;                    within the existing handler
;                  - Uses 2 undocumented function within GUIListView UDF to set and colour insert mark (thanks rover)
; Author ........: Melba23 - credit to martin (basic drag code), Array.au3 authors (original array functions)
; Modified ......;
; ====================================================================================================================

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <GuiListView.au3>
#include <GUIImageList.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Array to hold registered ListView data
Global $aGLVEx_Data[1][6] = [[0, 0]]
; [0][0] = Count            [n][0] = ListView handle
; [0][1] = Active Index     [n][1] = Native ListView ControlID / 0
;                           [n][2] = Content array
;                           [n][3] = [0] element is count
;                           [n][4] = Sorting array
;                           [n][5] = Drag image
; Variables for all UDF functions
Global $hGLVEx_Handle, $hGLVEx_CID, $aGLVEx_Array
; Variables for UDF dragging handlers
Global $iGLVEx_Dragging = 0, $iGLVExDragged_Index, $hGLVEx_Image = 0, $iGLVExInsert_Index = -1, $iGLVExLast_Y, $fGLVEx_Bar_Under, $fGLVEx_MultipleDrag

; #CURRENT# ==========================================================================================================
; _GUIListViewEx_Init:                 Enables UDF button functions for the ListView and sets insert mark colour
; _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 ListView active for UDF functions
; _GUIListViewEx_Return_Array:         Returns an array reflecting the current state of the ListView
; _GUIListViewEx_Insert:               Inserts data just below selected item in active ListView
; _GUIListViewEx_Delete:               Deletes selected item in active ListView
; _GUIListViewEx_Up:                   Moves selected item in active ListView up 1 place
; _GUIListViewEx_Down                  Moves selected item in active ListView down 1 place
; _GUIListViewEx_DragRegister:         Registers Windows messages to enable item dragging for listed ListViews
; _GUIListViewEx_WM_NOTIFY_Handler:    Windows message handler for WM_NOTIFY
; _GUIListViewEx_WM_MOUSEMOVE_Handler: Windows message handler for WM_MOUSEMOVE
; _GUIListViewEx_WM_LBUTTONUP_Handler: Windows message handler for WM_LBUTTONUP
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _GUIListViewEx_HighLight:    Highlights specified ListView item and ensures it is visible
; _GUIListViewEx_Data_Change:  Resets ListView items within a defined range to the current values in the stored array
; _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
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Init
; Description ...: Enables UDF button functions for the ListView and sets insert mark colour for drag function
; Syntax.........: _GUIListViewEx_Init($hLV, [$aArray = "", [$iStart = 0, [$iColour, [$fSort, $fImage]]]]])
; Parameters ....: $hLV     - Handle or ControlID of ListView
;                  $a Array - Name of array used to fill ListView.  "" = empty ListView
;                  $iStart  - 0 (default) = ListView data starts in [0] element of array, 1 = Count in [0] element
;                  $iColour - RGB colour for insert mark (default = black)
;                  $fSort   - True = ListView can be sorted by click on column header - (Default = False)
;                  $fImage  - True = Shadow image of dragged item
; Requirement(s).: v3.3 +
; 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 - if the ListView has more than
;                  1 column this array is 2D with the second dimension set to the number of columns
;                  - The shadow array has a count in element [0] added if it does not exist. However, if the $iStart
;                  parameter is set to 0 this count element will not be returned by other GUIListViewEx functions
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Init($hLV, $aArray = "", $iStart = 0, $iColour = 0, $fSort = False, $fImage = False)

    ; Increase array size
    $aGLVEx_Data[0][0] += 1
    ReDim $aGLVEx_Data[$aGLVEx_Data[0][0] + 1][6]

    ; Store ListView handle and ControlID
    If IsHWnd($hLV) Then
        $aGLVEx_Data[$aGLVEx_Data[0][0]][0] = $hLV
        $aGLVEx_Data[$aGLVEx_Data[0][0]][1] = 0
    Else
        $aGLVEx_Data[$aGLVEx_Data[0][0]][0] = GUICtrlGetHandle($hLV)
        $aGLVEx_Data[$aGLVEx_Data[0][0]][1] = $hLV
    EndIf

    ; Create a shadow array if needed
    If $aArray = "" Then
        Local $iCols = _GUICtrlListView_GetColumnCount($aGLVEx_Data[$aGLVEx_Data[0][0]][0])
        Switch $iCols
            Case 1
                Local $aReplacement[1] = [0]
            Case Else
                Local $aReplacement[1][$iCols] = [[0]]
        EndSwitch
        $aArray = $aReplacement
    Else
        ; Add count element to shadow array if required
        If $iStart = 0 Then _GUIListViewEx_Array_Insert($aArray, 0, UBound($aArray))
    EndIf
    ; Store array
    $aGLVEx_Data[$aGLVEx_Data[0][0]][2] = $aArray
    ; Store [0] = count data
    $aGLVEx_Data[$aGLVEx_Data[0][0]][3] = $iStart
    ; If sortable, store sort array
    If $fSort Then
        Local $aLVSortState[_GUICtrlListView_GetColumnCount($hLV)]
        $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = $aLVSortState
    Else
        $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = 0
    EndIf
    ; If image required
    If $fImage Then
        $aGLVEx_Data[$aGLVEx_Data[0][0]][5] = 1
    EndIf

    ; 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 only 1 current ListView then activate
    Local $iListView_Count = 0
    For $i = 1 To $aGLVEx_Data[0][0]
        If $aGLVEx_Data[$i][0] Then $iListView_Count += 1
    Next
    If $iListView_Count = 1 Then _GUIListViewEx_SetActive($aGLVEx_Data[0][0])

    ; Return ListView index
    Return $aGLVEx_Data[0][0]

EndFunc   ;==>_GUIListViewEx_Init

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Close
; Description ...: Disables all UDF functions for the specified ListView and clears all memory used
; Syntax.........: _GUIListViewEx_Close($iIndex)
; Parameters ....: $iIndex - Index number of ListView to disable as returned by _GUIListViewEx_Init
;                            0 (default) = Disables all ListViews
; Requirement(s).: v3.3 +
; Return values .: Success: 1
;                  Failure: 0 and @error set to 1 - Invalid index number
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Close($iIndex = 0)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

    If $iIndex = 0 Then
        ; Remove all ListView data
        Global $aGLVEx_Data[1][5] = [[0, 0]]
    Else
        ; Reset all data for ListView
        $aGLVEx_Data[$iIndex][0] = 0
        $aGLVEx_Data[$iIndex][1] = 0
        $aGLVEx_Data[$iIndex][2] = 0
        $aGLVEx_Data[$iIndex][3] = 0

        ; Cancel active index if set to this ListView
        If $aGLVEx_Data[0][1] = $iIndex Then $aGLVEx_Data[0][1] = 0
    EndIf

    Return 1

EndFunc   ;==>_GUIListViewEx_Close

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetActive
; Description ...: Set specified ListView as active for UDF functions
; Syntax.........: _GUIListViewEx_SetActive($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
;                  An index of 0 clears any current setting
; Requirement(s).: v3.3 +
; 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($iIndex)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, -1)

    Local $iCurr_Index = $aGLVEx_Data[0][1]

    If $iIndex Then
        ; Store index of specified ListView
        $aGLVEx_Data[0][1] = $iIndex
        ; Set values for specified ListView
        $hGLVEx_Handle = $aGLVEx_Data[$iIndex][0]
        $hGLVEx_CID = $aGLVEx_Data[$iIndex][1]
    Else
        ; Clear active index
        $aGLVEx_Data[0][1] = 0
    EndIf

    Return $iCurr_Index

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_GetActive
; Description ...: Get index number of ListView active for UDF functions
; Syntax.........: _GUIListViewEx_GetActive()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Return_Array
; Description ...: Returns an array reflecting the current state of the ListView
; Syntax.........: _GUIListViewEx_Return_Array($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView - presence of count in [0] element determined by _GUIListViewEx_Init
;                  Failure: Empty array returns null string and sets @error as follows:
;                           1 = Invalid index number
;                           2 = Empty array (no items in ListView)
; Author ........: Melba23
; Modified ......:
; Remarks .......: The $iStart parameter from GUIListViewEx_Init determines  whether the [0] element is a count
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Return_Array($iIndex)

    ; Check valid index
    If $iIndex < 1 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

    ; Copy current array
    Local $aRetArray = $aGLVEx_Data[$iIndex][2]

    ; Remove count element if required
    If $aGLVEx_Data[$iIndex][3] = 0 Then
        ; Check at least one entry in 1D/2D array
        Switch UBound($aRetArray, 0)
            Case 1
                If $aRetArray[0] = 0 Then Return SetError(2, 0, "")
            Case 2
                If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
        EndSwitch
        ; Delete count element
        _GUIListViewEx_Array_Delete($aRetArray, 0)
    EndIf

    ; Return array
    Return $aRetArray

EndFunc   ;==>_GUIListViewEx_Return_Array

; #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)
; Parameters ....: $vData - Data to insert, can be in array or delimited string format
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView 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 datat 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
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Insert($vData)

    Local $vInsert

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Check if 1D/2D array
    Switch UBound($aGLVEx_Array, 0)
        Case 1
            ; If empty array insert at 0
            If $aGLVEx_Array[0] = 0 Then $iInsert_Index = 0
            ; Get data into string format for insert
            If IsArray($vData) Then
                $vInsert = ""
                For $i = 0 To UBound($vData) - 1
                    $vInsert &= $vData[$i] & "|"
                Next
                $vInsert = StringTrimRight($vInsert, 1)
            Else
                $vInsert = $vData
            EndIf
            ; Increase count
            $aGLVEx_Array[0] += 1
        Case 2
            ; If empty array insert at 0
            If $aGLVEx_Array[0][0] = 0 Then $iInsert_Index = 0
            ; Get data into array format for insert
            If IsArray($vData) Then
                $vInsert = $vData
            Else
                Local $aData = StringSplit($vData, "|")
                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]
                        Next
                EndSwitch
            EndIf
            ; Increase count
            $aGLVEx_Array[0][0] += 1
    EndSwitch

    ; Insert data into array
    If $iIndex = "" Then
        _GUIListViewEx_Array_Add($aGLVEx_Array, $vInsert)
    Else
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iInsert_Index + 2, $vInsert)
    EndIf

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Add new item at ListView end
        GUICtrlCreateListViewItem($vInsert, $hGLVEx_CID)
    Else
        ; Add new item at ListView end
        Local $iNewItem
        If IsArray($vInsert) Then
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert[0])
            ; Add new subitems
            For $i = 1 To UBound($vInsert) - 1
                _GUICtrlListView_AddSubItem($hGLVEx_Handle, $iNewItem, $vInsert[$i], $i)
            Next
        Else
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert)
        EndIf
    EndIf
    ; Check where item was to be inserted
    If $iIndex = "" Then
        _GUIListViewEx_Data_Change($iInsert_Index, $iInsert_Index)
        ; No moves required so set highlight
        _GUIListViewEx_Highlight(_GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
    Else
        ; Reset item contents below insert position
        _GUIListViewEx_Data_Change($iInsert_Index, _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
        ; Set highlight
        _GUIListViewEx_Highlight($iInsert_Index + 1, $iInsert_Index)
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Insert

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Delete
; Description ...: Deletes selected item in active ListView
; Syntax.........: _GUIListViewEx_Delete()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 = No items to delete
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, all are deleted
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Delete()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Check for selected items
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Determine final item
    Local $iLast = UBound($aGLVEx_Array) - 2

    ; Check if item is part of a multiple selection
    If StringInStr($iIndex, "|") Then
        ; Extract all selected items
        Local $aIndex = StringSplit($iIndex, "|")
        For $i = 1 To $aIndex[0]
            ; Remove highlighting from items
            _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $i, False)
        Next

        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= $aIndex[0]
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= $aIndex[0]
        EndSwitch

        ; Delete elements from array - start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUIListViewEx_Array_Delete($aGLVEx_Array, $aIndex[$i] + 1)
        Next

        ; Delete items from ListView - again start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUICtrlListView_DeleteItem($hGLVEx_Handle, $aIndex[$i])
        Next

    Else
        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= 1
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= 1
        EndSwitch
        ; Delete element from array
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iIndex + 1)

        ; Delete item from ListView
        _GUICtrlListView_DeleteItem($hGLVEx_Handle, $iIndex)
        ; Set highlight - up one if bottom deleted
        If $iIndex = $iLast Then
            _GUIListViewEx_Highlight($iIndex - 1)
        Else
            _GUIListViewEx_Highlight($iIndex)
        EndIf
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Delete

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Up
; Description ...: Moves selected item in active ListView up 1 place
; Syntax.........: _GUIListViewEx_Up()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Up()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not top item
    If $iIndex = "0" Then Return SetError(3, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex, $iIndex + 1)

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex - 1, $iIndex);, $aGLVEx_Array)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex - 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Up

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Down
; Description ...: Moves selected item in active ListView down 1 place
; Syntax.........: _GUIListViewEx_Down()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Down()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not last item
    If $iIndex = _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1 Then
        _GUIListViewEx_Highlight($iIndex)
        Return
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex + 1, $iIndex + 2)

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex, $iIndex + 1)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex + 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Down

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DragRegister
; Description ...: Registers Windows messages needed for the UDF
; Syntax.........: _GUIListViewEx_DragRegister([$fNOTIFY = True, [$fMOUSEMOVE = True, [$fLBUTTONUP = True]]])
; Parameters ....: $fNOTIFY    - True = Register WM_NOTIFY message
;                  $fMOUSEMOVE - True = Register WM_MOUSEMOVE message
;                  $fLBUTTONUP - True = Register WM_LBUTTONUP message
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If other handlers already registered, then call the relevant handler function from within that handler
;                  If no dragging is required, only the WM_NOTIFY handler needs to be registered
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DragRegister($fNOTIFY = True, $fMOUSEMOVE = True, $fLBUTTONUP = 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

EndFunc   ;==>_GUIListViewEx_DragRegister

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_NOTIFY_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_NOTIFY_Handler
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_NOTIFY handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam

    ; 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 $iCode = BitAND(DllStructGetData($tStruct, 3), 0xFFFFFFFF)

    Switch $iCode
        Case $LVN_COLUMNCLICK, -2 ; $NM_CLICK
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not enabled

            ; Set values for active ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Sort if a column header was clicked and ListView is sortable
            If $iCode = $LVN_COLUMNCLICK And IsArray($aGLVEx_Data[$i][4]) Then
                ; Load current ListView sort state array
                Local $aLVSortState = $aGLVEx_Data[$aGLVEx_Data[0][0]][4]
                ; Sort column - get column from from struct
                _GUICtrlListView_SimpleSort($hGLVEx_Handle, $aLVSortState, DllStructGetData($tStruct, 5))
                ; Store new ListView sort state array
                $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = $aLVSortState
                ; Reread listview items into array
                Switch UBound($aGLVEx_Array, 0) ; Check array format
                    Case 1
                        For $j = 1 To $aGLVEx_Array[0]
                            $aGLVEx_Array[$j] = _GUICtrlListView_GetItemTextString($hGLVEx_Handle, $j - 1)
                        Next
                    Case 2
                        Local $iDim2 = UBound($aGLVEx_Array, 2) - 1
                        For $j = 1 To $aGLVEx_Array[0][0]
                            For $k = 0 To $iDim2
                                $aGLVEx_Array[$j][$k] = _GUICtrlListView_GetItemText($hGLVEx_Handle, $j - 1, $k)
                            Next
                        Next
                EndSwitch
                ; Store amended array
                $aGLVEx_Data[$i][2] = $aGLVEx_Array
            EndIf

        Case $LVN_BEGINDRAG
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not registered

            ; Set values for ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            Local $fImage = $aGLVEx_Data[$i][5]
            ; Copy array for manipulation
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Check if Native or UDF and set focus
            If $hGLVEx_CID Then
                GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
            Else
                _WinAPI_SetFocus($hGLVEx_Handle)
            EndIf

            ; Get dragged item index
            $iGLVExDragged_Index = DllStructGetData($tStruct, 4) ; Item
            ; Set dragged item count
            $iGLVEx_Dragging = 1

            ; Check for selected items
            Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
            ; Check if item is part of a multiple selection
            If StringInStr($iIndex, $iGLVExDragged_Index) And StringInStr($iIndex, "|") Then
                ; Remove highlighting from item
                _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index, False)
                ; Extract all selected items
                Local $aIndex = StringSplit($iIndex, "|")
                For $i = 1 To $aIndex[0]
                    If $aIndex[$i] = $iGLVExDragged_Index 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
                        ; Remove highlighting from item
                        _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index - 1, False)
                        ; Adjust dragged index to this item
                        $iGLVExDragged_Index -= 1
                        ; Increase number to drag
                        $iGLVEx_Dragging += 1
                    Next
                EndIf
                If $i <> $aIndex[0] Then ; Down
                    Local $iCount = 1 ; How far we go down
                    For $j = $i + 1 To $aIndex[0]
                        ; Consecutive
                        If $aIndex[$j] <> $aIndex[$j - 1] + 1 Then ExitLoop
                        ; Remove highlighting from item
                        _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index + $iCount, False)
                        ; Increase number to drag
                        $iGLVEx_Dragging += 1
                        ; Increase counter
                        $iCount += 1
                    Next
                EndIf
            Else ; Either no selection or only a single
                ; Set flag
                $iGLVEx_Dragging = 1
                ; Remove highlighting from item
                _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index, False)
            EndIf

            ; Create drag image
            If $fImage Then
                Local $aImageData = _GUICtrlListView_CreateDragImage($hGLVEx_Handle, $iGLVExDragged_Index)
                $hGLVEx_Image = $aImageData[0]
                _GUIImageList_BeginDrag($hGLVEx_Image, 0, 0, 0)
            EndIf

    EndSwitch

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 +
; 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 $iMsg, $wParam

    If Not $iGLVEx_Dragging Then Return "GUI_RUNDEFMSG"

    Local $aLV_Pos, $tLVHITTESTINFO, $iCurr_Index

    ; 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 $iGLVExInsert_Index <> -1 Then
        If $iGLVExLast_Y = $iCurr_Y Then
            Return "GUI_RUNDEFMSG"
        ElseIf $iGLVExLast_Y > $iCurr_Y Then
            $fGLVEx_Bar_Under = False
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, False)
        Else
            $fGLVEx_Bar_Under = True
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, True)
        EndIf
    EndIf
    ; Store current Y coord
    $iGLVExLast_Y = $iCurr_Y

    ; Get ListView item under mouse - depends on ListView type
    If $hGLVEx_CID Then
        $aLV_Pos = ControlGetPos($hWnd, "", $hGLVEx_CID)
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iCurr_Y - $aLV_Pos[1])
        ; Get item under mouse
        $iCurr_Index = GUICtrlSendMsg($hGLVEx_CID, $LVM_HITTEST, 0, DllStructGetPtr($tLVHITTESTINFO))
    Else
        ; Get coords of client area
        Local $tPoint = DllStructCreate("int X;int Y")
        DllStructSetData($tPoint, "X", 0)
        DllStructSetData($tPoint, "Y", 0)
        Local $pPoint = DllStructGetPtr($tPoint)
        DllCall("user32.dll", "bool", "ClientToScreen", "hwnd", $hWnd, "ptr", $pPoint)
        ; Get coords of ListView
        $aLV_Pos = WinGetPos($hGLVEx_Handle)
        Local $iY = $iCurr_Y - $aLV_Pos[1] + DllStructGetData($tPoint, "Y")
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0] + DllStructGetData($tPoint, "X")
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iY)
        Local $pLVHITTESTINFO = DllStructGetPtr($tLVHITTESTINFO)
        ; Get item under mouse
        Local $aRet = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hGLVEx_Handle, "uint", $LVM_HITTEST, "wparam", 0, "lparam", $pLVHITTESTINFO)
        $iCurr_Index = $aRet[0]
    EndIf

    ; If mouse is above or below ListView then scroll ListView
    If $iCurr_Index = -1 Then
        If $fGLVEx_Bar_Under Then
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, 10)
            Sleep(100)
        Else
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, -10)
            Sleep(100)
        EndIf
    EndIf

    ; Check if over same item
    If $iGLVExInsert_Index = $iCurr_Index Then Return "GUI_RUNDEFMSG"

    ; Show insert mark on current item
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iCurr_Index, $fGLVEx_Bar_Under)
    ; Store current item
    $iGLVExInsert_Index = $iCurr_Index

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 +
; 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"

    ; Get item count
    Local $iMultipleItems = $iGLVEx_Dragging - 1

    ; Reset flag
    $iGLVEx_Dragging = 0

    ; Check mouse within ListView
    If $iGLVExInsert_Index = -1 Then
        ; Clear insert mark
        _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)
        ; Reset highlight to original items
        For $i = 0 To $iMultipleItems
            _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
        Next
        Return
    EndIf

    ; Determine position to insert
    If $fGLVEx_Bar_Under Then
        If $iGLVExDragged_Index > $iGLVExInsert_Index Then $iGLVExInsert_Index += 1
    Else
        If $iGLVExDragged_Index < $iGLVExInsert_Index Then $iGLVExInsert_Index -= 1
    EndIf

    ; Clear insert mark
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)

    ; Clear drag image
    If $hGLVEx_Image Then
        _GUIImageList_DragLeave($hGLVEx_Handle)
        _GUIImageList_EndDrag()
        _GUIImageList_Destroy($hGLVEx_Image)
        $hGLVEx_Image = 0
    EndIf


    ; Check not dropping on dragged item(s)
    Switch $iGLVExInsert_Index
        Case $iGLVExDragged_Index To $iGLVExDragged_Index + $iMultipleItems
            ; Reset highlight to original items
            For $i = 0 To $iMultipleItems
                _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
            Next
            Return
    EndSwitch

    ; Amend array
    ; Get data from dragged element(s)
    If $iMultipleItems Then
        ; Multiple dragged elements
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    $aInsertData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1 + $i]
                Next
            Case 2
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    Local $aItemData[UBound($aGLVEx_Array, 2)]
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $aItemData[$j] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$j]
                    Next
                    $aInsertData[$i] = $aItemData
                Next
        EndSwitch
    Else
        ; Single dragged element
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[1]
                $aInsertData[0] = $aGLVEx_Array[$iGLVExDragged_Index + 1]
            Case 2
                Local $aInsertData[1]
                Local $aItemData[UBound($aGLVEx_Array, 2)]
                For $i = 0 To UBound($aGLVEx_Array, 2) - 1
                    $aItemData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$i]
                Next
                $aInsertData[0] = $aItemData
        EndSwitch
    EndIf

    ; Delete dragged element(s) from array
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iGLVExDragged_Index + 1)
    Next
    ; Amend insert positon for multiple items deleted above
    If $iGLVExDragged_Index < $iGLVExInsert_Index Then
        $iGLVExInsert_Index -= $iMultipleItems
    EndIf
    ; Re-insert dragged element(s) into array
    For $i = $iMultipleItems To 0 Step -1
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iGLVExInsert_Index + 1, $aInsertData[$i])
    Next

    ; Amend ListView to match array
    If $iGLVExDragged_Index > $iGLVExInsert_Index Then
        _GUIListViewEx_Data_Change($iGLVExInsert_Index, $iGLVExDragged_Index + $iMultipleItems)
    Else
        _GUIListViewEx_Data_Change($iGLVExDragged_Index, $iGLVExInsert_Index + $iMultipleItems)
    EndIf

    ; Set highlight to inserted item(s)
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_HighLight($iGLVExInsert_Index + $i)
    Next

    ; Store amended array
    $aGLVEx_Data[$aGLVEx_Data[0][1]][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0

EndFunc   ;==>_GUIListViewEx_WM_LBUTTONUP_Handler

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_HighLight($iIndexA, $iIndexB)
; Description ...: Highlights first item and ensures visible while removing hightlight from second in multiple selection ListViews
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Highlight($iIndexA, $iIndexB = -1)

    ; Check if Native or UDF and set focus
    If $hGLVEx_CID Then
        GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
    Else
        _WinAPI_SetFocus($hGLVEx_Handle)
    EndIf
    ; Cancel highlight on other item - needed for multisel listviews
    If $iIndexB <> -1 Then _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iIndexB, False)
    ; Set highlight to inserted item and ensure in view
    _GUICtrlListView_SetItemState($hGLVEx_Handle, $iIndexA, $LVIS_SELECTED, $LVIS_SELECTED)
    _GUICtrlListView_EnsureVisible($hGLVEx_Handle, $iIndexA)

EndFunc   ;==>_GUIListViewEx_HighLight

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_Data_Change($iStart, $iEnd)
; Description ...: Resets ListView items within a defined range to the current values in the stored array
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Data_Change($iStart, $iEnd)

    Local $sInsert

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Native ListView
        For $i = $iStart To $iEnd
            ; Get CID of the item
            Local $iCID = _GUICtrlListView_GetItemParam($hGLVEx_Handle, $i)
            ; Check array type
            Switch UBound($aGLVEx_Array, 0)
                Case 1
                    $sInsert = $aGLVEx_Array[$i + 1]
                Case 2
                    $sInsert = ""
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $sInsert &= $aGLVEx_Array[$i + 1][$j] & "|"
                    Next
            EndSwitch
            ; Set data
            GUICtrlSetData($iCID, $sInsert)
        Next
    Else
        ; UDF ListView
        For $i = $iStart To $iEnd
            ; Check if multicolumn
            Local $iDim2 = UBound($aGLVEx_Array, 2)
            If @error Then
                _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1])
            Else
                ; For each column - or just once if not multicolumn
                For $j = 0 To $iDim2 - 1
                    ; Set data
                    _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1][$j], $j)
                Next
            EndIf
        Next
    EndIf

EndFunc   ;==>_GUIListViewEx_Data_Change

; #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 = "", $iStart = 0)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ReDim $avArray[$iIndex_Max + 1]
            $avArray[$iIndex_Max] = $vAdd

        Case 2

        ; Get size of second dimension
        Local $iDim2 = UBound($avArray, 2)

        ; Redim the Array
        ReDim $avArray[$iIndex_Max + 1][$iDim2]

        ; 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 - $iStart Then
                    $avArray[$iIndex_Max][$j] = ""
                Else
                    $avArray[$iIndex_Max][$j] = $vAdd[$j + $iStart]
                EndIf
            Next
        Else
            ; Fill Array with variable
            For $j = 0 To $iDim2 - 1
                $avArray[$iIndex_Max][$j] = $vAdd
            Next
        EndIf

    EndSwitch

    Return $iIndex_Max

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)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ; 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

            ; Add the value in the specified element
            $avArray[$iIndex] = $vInsert
            Return $iIndex_Max

        Case 2

            ; If at end of array
            If $iIndex > $iIndex_Max - 1 Then Return $iIndex_Max = _GUIListViewEx_Array_Add($avArray, $vInsert)

            ; Get size of second dimension
            Local $iDim2 = UBound($avArray, 2)

            ; Redim the Array
            ReDim $avArray[$iIndex_Max + 1][$iDim2]

            ; 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

    EndSwitch

    Return $iIndex_Max + 1

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)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ; 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

            ; 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]

    EndSwitch

    Return $iIndex_Max - 1

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

And here is a modified version of your script. A few explanations:

1. It is better to use the _GUICtrlListView_SetExtendedListViewStyle function to set extened style for a ListView - several of the values are identical to standard $WS_ constants and you can get AutoIt confused if you mix them in the creation function.

2. It is better to create the array you pass to the ListView as you create the items - I am not at all sure that _GUICtrlListView_GetItemTextArray gives you an array of the correct format.

3. You will see that the columns are already sortable from within the UDF (again you need to set the parameter in the _Init function :)) - you do not need to use your own sort code.

4. I have also cleared out the message handlers - there seemed no reason to add anything to the default $WM_MOUSEMOVE and $WM_LBUTTONUP handlers as the UDF now does everything you want. I have created a $WM_NOTIFY handler in the script so you can add the other codes you required.

5. Finally I slowed down the scroll a little so that you have a chance to see the intermediate items as with such a small ListView it was scrolling too fast - I may look at that code and try to get a variable value depending on the size of the ListView.

Try it and see how you get on:

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

#include "GUIListViewEx_Mod.au3" ; Save the new UDF under this name in the same folder as the script <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

$hGUI = GUICreate("LVEx Test", 390, 192, 193, 120)
GUICtrlCreateLabel("UDF ListView - single selection", 2, 15, 300, 20)

$ListView1 = GUICtrlCreateListView("Name|Phone Number", 2, 40, 300, 115, BitOR($WS_VSCROLL, $WS_BORDER, $LVS_SINGLESEL), BitOR($WS_EX_CLIENTEDGE, $WS_EX_DLGMODALFRAME))
_GUICtrlListView_SetExtendedListViewStyle($ListView1, BitOR($LVS_EX_DOUBLEBUFFER, $LVS_REPORT, $WS_EX_CLIENTEDGE, $LVS_EX_FULLROWSELECT, $LVS_EX_CHECKBOXES, $WS_EX_DLGMODALFRAME))
_GUICtrlListView_SetColumnWidth($ListView1, 0, 120)
_GUICtrlListView_SetColumnWidth($ListView1, 1, 150)

Global $aArray[12]
For $LV_Item = 0 To 11
    $aArray[$LV_Item] =  "Name " & $LV_Item & "|Phone No " & 11 - $LV_Item
    GUICtrlCreateListViewItem($aArray[$LV_Item], $ListView1)
Next

$ListView1_Index = _GUIListViewEx_Init($ListView1, $aArray, 0, 0x00FF00, True, True)

GUISetState(@SW_SHOW)

_GUIListViewEx_SetActive($ListView1_Index)

_GUIListViewEx_DragRegister(False)

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUIListViewEx_Close($ListView1_Index)
            Exit

    EndSwitch
WEnd

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

    _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)

EndFunc

Please ask if you have any questions or if the UDF could be further modified to meet your needs. I do not guarantee that I will be able or willing to provide everything that you might want - if the request is something generally useful like the drag image then there is more chance that I will work on it. :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

Viva, M23

You are the greatest :) , and I am very grateful.

I think that my needs are as many more people simply thought it might be useful, and I was lucky on a rainy day, my prayers have been heard so yes I COULD FLY.

thanks :mellow::):)

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

I see now that there are severe problems in using the GUIListViewEx UDF with the $LVS_EX_CHECKBOXES extended style. I will look into it, but at first glance it is not an easy fix and will require a fair bit of work, so do not hold you breath! :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

NunoBorges,

I see now that there are severe problems in using the GUIListViewEx UDF with the $LVS_EX_CHECKBOXES extended style. I will look into it, but at first glance it is not an easy fix and will require a fair bit of work, so do not hold you breath! :mellow:

M23

Viva,

Thank you for having warned that failure.

I await news, no urgency because I'm going on vacation, very close to the Porto Santo Golf, no play, no internet, but with many trips to the beach, and I hope many beers.

hug

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

Another rainy day. I will be glad when you are on holiday and I can get some nice weather here - every time you ask a question I get rain! :party:

It was not as difficult to change GUIListViewEx to work with the checkboxes as I feared once I had decided how to deal with them. Try this version of the UDF with your checkbox ListView script - it works for me: :)

#include-once

; #INDEX# ============================================================================================================
; Title .........: GUIListViewEx
; AutoIt Version : 3.3 +
; Language ......: English
; Description ...: Permits insertion, deletion, moving, dragging and sorting of items within activated 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.
;                  - If the script already has WM_NOTIFY, WM_MOUSEMOVE or WM_LBUTTONUP handlers then only set the
;                    unregistered messages in _GUIListViewEx_DragRegister and call the relevant _GUIListViewEx_WM_#####_Handler from
;                    within the existing handler
;                  - Uses 2 undocumented function within GUIListView UDF to set and colour insert mark (thanks rover)
; Author ........: Melba23 - credit to martin (basic drag code), Array.au3 authors (original array functions)
; Modified ......;
; ====================================================================================================================

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <GuiListView.au3>
#include <GUIImageList.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Array to hold registered ListView data
Global $aGLVEx_Data[1][7] = [[0, 0]]
; [0][0] = Count            [n][0] = ListView handle
; [0][1] = Active Index     [n][1] = Native ListView ControlID / 0
;                           [n][2] = Content array
;                           [n][3] = [0] element is count
;                           [n][4] = Sorting array
;                           [n][5] = Drag image
;                           [n][6] = Checkbox array
; Variables for all UDF functions
Global $hGLVEx_Handle, $hGLVEx_CID, $aGLVEx_Array
; Variables for UDF dragging handlers
Global $iGLVEx_Dragging = 0, $iGLVExDragged_Index, $hGLVExDragged_Image = 0, $iGLVExInsert_Index = -1, $iGLVExLast_Y, $fGLVEx_Bar_Under, $fGLVEx_MultipleDrag, $aGLVExDragCheck_Array

; #CURRENT# ==========================================================================================================
; _GUIListViewEx_Init:                 Enables UDF button functions for the ListView and sets insert mark colour
; _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 ListView active for UDF functions
; _GUIListViewEx_Return_Array:         Returns an array reflecting the current state of the ListView
; _GUIListViewEx_Insert:               Inserts data just below selected item in active ListView
; _GUIListViewEx_Delete:               Deletes selected item in active ListView
; _GUIListViewEx_Up:                   Moves selected item in active ListView up 1 place
; _GUIListViewEx_Down                  Moves selected item in active ListView down 1 place
; _GUIListViewEx_DragRegister:         Registers Windows messages to enable item dragging for listed ListViews
; _GUIListViewEx_WM_NOTIFY_Handler:    Windows message handler for WM_NOTIFY
; _GUIListViewEx_WM_MOUSEMOVE_Handler: Windows message handler for WM_MOUSEMOVE
; _GUIListViewEx_WM_LBUTTONUP_Handler: Windows message handler for WM_LBUTTONUP
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _GUIListViewEx_HighLight:    Highlights specified ListView item and ensures it is visible
; _GUIListViewEx_Data_Change:  Resets ListView items within a defined range to the current values in the stored array
; _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
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Init
; Description ...: Enables UDF button functions for the ListView and sets insert mark colour for drag function
; Syntax.........: _GUIListViewEx_Init($hLV, [$aArray = "", [$iStart = 0, [$iColour, [$fSort, $fImage]]]]])
; Parameters ....: $hLV     - Handle or ControlID of ListView
;                  $a Array - Name of array used to fill ListView.  "" = empty ListView
;                  $iStart  - 0 (default) = ListView data starts in [0] element of array, 1 = Count in [0] element
;                  $iColour - RGB colour for insert mark (default = black)
;                  $fSort   - True = ListView can be sorted by click on column header - (Default = False)
;                  $fImage  - True = Shadow image of dragged item
; Requirement(s).: v3.3 +
; 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 - if the ListView has more than
;                  1 column this array is 2D with the second dimension set to the number of columns
;                  - The shadow array has a count in element [0] added if it does not exist. However, if the $iStart
;                  parameter is set to 0 this count element will not be returned by other GUIListViewEx functions
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Init($hLV, $aArray = "", $iStart = 0, $iColour = 0, $fSort = False, $fImage = False)

    ; Increase array size
    $aGLVEx_Data[0][0] += 1
    ReDim $aGLVEx_Data[$aGLVEx_Data[0][0] + 1][7]

    ; Store ListView handle and ControlID
    If IsHWnd($hLV) Then
        $aGLVEx_Data[$aGLVEx_Data[0][0]][0] = $hLV
        $aGLVEx_Data[$aGLVEx_Data[0][0]][1] = 0
    Else
        $aGLVEx_Data[$aGLVEx_Data[0][0]][0] = GUICtrlGetHandle($hLV)
        $aGLVEx_Data[$aGLVEx_Data[0][0]][1] = $hLV
    EndIf

    ; Create a shadow array if needed
    If $aArray = "" Then
        Local $iCols = _GUICtrlListView_GetColumnCount($aGLVEx_Data[$aGLVEx_Data[0][0]][0])
        Switch $iCols
            Case 1
                Local $aReplacement[1] = [0]
            Case Else
                Local $aReplacement[1][$iCols] = [[0]]
        EndSwitch
        $aArray = $aReplacement
    Else
        ; Add count element to shadow array if required
        If $iStart = 0 Then _GUIListViewEx_Array_Insert($aArray, 0, UBound($aArray))
    EndIf
    ; Store array
    $aGLVEx_Data[$aGLVEx_Data[0][0]][2] = $aArray

    ; Store [0] = count data
    $aGLVEx_Data[$aGLVEx_Data[0][0]][3] = $iStart
    ; If sortable, store sort array
    If $fSort Then
        Local $aLVSortState[_GUICtrlListView_GetColumnCount($hLV)]
        $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = $aLVSortState
    Else
        $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = 0
    EndIf
    ; If image required
    If $fImage Then
        $aGLVEx_Data[$aGLVEx_Data[0][0]][5] = 1
    EndIf
    ;  If checkbox extended style
    If BitAnd(_GUICtrlListView_GetExtendedListViewStyle($hLV), 4) Then ; $LVS_EX_CHECKBOXES
        $aGLVEx_Data[$aGLVEx_Data[0][0]][6] = 1
    EndIf

    ; 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 only 1 current ListView then activate
    Local $iListView_Count = 0
    For $i = 1 To $aGLVEx_Data[0][0]
        If $aGLVEx_Data[$i][0] Then $iListView_Count += 1
    Next
    If $iListView_Count = 1 Then _GUIListViewEx_SetActive($aGLVEx_Data[0][0])

    ; Return ListView index
    Return $aGLVEx_Data[0][0]

EndFunc   ;==>_GUIListViewEx_Init

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Close
; Description ...: Disables all UDF functions for the specified ListView and clears all memory used
; Syntax.........: _GUIListViewEx_Close($iIndex)
; Parameters ....: $iIndex - Index number of ListView to disable as returned by _GUIListViewEx_Init
;                            0 (default) = Disables all ListViews
; Requirement(s).: v3.3 +
; Return values .: Success: 1
;                  Failure: 0 and @error set to 1 - Invalid index number
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Close($iIndex = 0)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

    If $iIndex = 0 Then
        ; Remove all ListView data
        Global $aGLVEx_Data[1][7] = [[0, 0]]
    Else
        ; Reset all data for ListView
        For $i = 0 To 6
            $aGLVEx_Data[$iIndex][$i] = 0
        Next

        ; Cancel active index if set to this ListView
        If $aGLVEx_Data[0][1] = $iIndex Then $aGLVEx_Data[0][1] = 0
    EndIf

    Return 1

EndFunc   ;==>_GUIListViewEx_Close

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetActive
; Description ...: Set specified ListView as active for UDF functions
; Syntax.........: _GUIListViewEx_SetActive($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
;                  An index of 0 clears any current setting
; Requirement(s).: v3.3 +
; 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($iIndex)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, -1)

    Local $iCurr_Index = $aGLVEx_Data[0][1]

    If $iIndex Then
        ; Store index of specified ListView
        $aGLVEx_Data[0][1] = $iIndex
        ; Set values for specified ListView
        $hGLVEx_Handle = $aGLVEx_Data[$iIndex][0]
        $hGLVEx_CID = $aGLVEx_Data[$iIndex][1]
    Else
        ; Clear active index
        $aGLVEx_Data[0][1] = 0
    EndIf

    Return $iCurr_Index

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_GetActive
; Description ...: Get index number of ListView active for UDF functions
; Syntax.........: _GUIListViewEx_GetActive()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Return_Array
; Description ...: Returns an array reflecting the current state of the ListView
; Syntax.........: _GUIListViewEx_Return_Array($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
;                  $iCheck - If non-zero then the state of the checkboxes is returned (Default = 0)
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView - presence of count in [0] element determined by _GUIListViewEx_Init
;                  Failure: Empty array returns null string and sets @error as follows:
;                           1 = Invalid index number
;                           2 = Empty array (no items in ListView)
;                           3 = $iCheck set to True but ListView does not have checkboxe style
; Author ........: Melba23
; Modified ......:
; Remarks .......: The $iStart parameter from GUIListViewEx_Init determines whether the [0] element is a count
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Return_Array($iIndex, $iCheck = 0)

    ; Check valid index
    If $iIndex < 1 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

    ; Copy current array
    Local $aRetArray = $aGLVEx_Data[$iIndex][2]

    ; Check if checkbox array
    If $iCheck Then
        If $aGLVEx_Data[$iIndex][6] Then
            Local $aCheck_Array[UBound($aRetArray)]
            For $i = 1 To UBound($aRetArray) - 1
                $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($aGLVEx_Data[$iIndex][0], $i - 1)
            Next
            ; Remove count element if required
            If $aGLVEx_Data[$iIndex][3] = 0 Then
                ; Check at least one entry in 1D/2D array
                Switch UBound($aRetArray, 0)
                    Case 1
                        If $aRetArray[0] = 0 Then Return SetError(2, 0, "")
                    Case 2
                        If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
                EndSwitch
                ; Delete count element
                _GUIListViewEx_Array_Delete($aCheck_Array, 0)
            EndIf
            Return $aCheck_Array
        Else
            Return SetError(3, 0, "")
        EndIf
    EndIf

    ; Remove count element of array if required
    If $aGLVEx_Data[$iIndex][3] = 0 Then
        ; Check at least one entry in 1D/2D array
        Switch UBound($aRetArray, 0)
            Case 1
                If $aRetArray[0] = 0 Then Return SetError(2, 0, "")
            Case 2
                If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
        EndSwitch
        ; Delete count element
        _GUIListViewEx_Array_Delete($aRetArray, 0)
    EndIf

    ; Return array
    Return $aRetArray

EndFunc   ;==>_GUIListViewEx_Return_Array

; #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)
; Parameters ....: $vData - Data to insert, can be in array or delimited string format
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView 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 datat 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
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Insert($vData)

    Local $vInsert

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Create Local array for checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $aCheck_Array[UBound($aGLVEx_Array)]
        For $i = 1 To UBound($aCheck_Array) - 1
            $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $i - 1)
        Next
    EndIf

    ; Check if 1D/2D array
    Switch UBound($aGLVEx_Array, 0)
        Case 1
            ; If empty array insert at 0
            If $aGLVEx_Array[0] = 0 Then $iInsert_Index = 0
            ; Get data into string format for insert
            If IsArray($vData) Then
                $vInsert = ""
                For $i = 0 To UBound($vData) - 1
                    $vInsert &= $vData[$i] & "|"
                Next
                $vInsert = StringTrimRight($vInsert, 1)
            Else
                $vInsert = $vData
            EndIf
            ; Increase count
            $aGLVEx_Array[0] += 1
        Case 2
            ; If empty array insert at 0
            If $aGLVEx_Array[0][0] = 0 Then $iInsert_Index = 0
            ; Get data into array format for insert
            If IsArray($vData) Then
                $vInsert = $vData
            Else
                Local $aData = StringSplit($vData, "|")
                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]
                        Next
                EndSwitch
            EndIf
            ; Increase count
            $aGLVEx_Array[0][0] += 1
    EndSwitch

    ; Insert data into array
    If $iIndex = "" Then
        _GUIListViewEx_Array_Add($aGLVEx_Array, $vInsert)
    Else
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iInsert_Index + 2, $vInsert)
        If $aGLVEx_Data[$iArray_Index][6] Then
            _GUIListViewEx_Array_Insert($aCheck_Array, $iInsert_Index + 2, False)
            ; Reset all checkboxes
            For $i = 1 To UBound($aCheck_Array) - 1
                _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $i - 1, $aCheck_Array[$i])
            Next
        EndIf
    EndIf

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Add new item at ListView end
        GUICtrlCreateListViewItem($vInsert, $hGLVEx_CID)
    Else
        ; Add new item at ListView end
        Local $iNewItem
        If IsArray($vInsert) Then
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert[0])
            ; Add new subitems
            For $i = 1 To UBound($vInsert) - 1
                _GUICtrlListView_AddSubItem($hGLVEx_Handle, $iNewItem, $vInsert[$i], $i)
            Next
        Else
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert)
        EndIf
    EndIf
    ; Check where item was to be inserted
    If $iIndex = "" Then
        _GUIListViewEx_Data_Change($iInsert_Index, $iInsert_Index)
        ; No moves required so set highlight
        _GUIListViewEx_Highlight(_GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
    Else
        ; Reset item contents below insert position
        _GUIListViewEx_Data_Change($iInsert_Index, _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
        ; Set highlight
        _GUIListViewEx_Highlight($iInsert_Index + 1, $iInsert_Index)
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Insert

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Delete
; Description ...: Deletes selected item in active ListView
; Syntax.........: _GUIListViewEx_Delete()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 = No items to delete
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, all are deleted
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Delete()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Check for selected items
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Determine final item
    Local $iLast = UBound($aGLVEx_Array) - 2

    ; Check if item is part of a multiple selection
    If StringInStr($iIndex, "|") Then
        ; Extract all selected items
        Local $aIndex = StringSplit($iIndex, "|")
        For $i = 1 To $aIndex[0]
            ; Remove highlighting from items
            _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $i, False)
        Next

        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= $aIndex[0]
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= $aIndex[0]
        EndSwitch

        ; Delete elements from array - start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUIListViewEx_Array_Delete($aGLVEx_Array, $aIndex[$i] + 1)
        Next

        ; Delete items from ListView - again start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUICtrlListView_DeleteItem($hGLVEx_Handle, $aIndex[$i])
        Next

    Else
        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= 1
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= 1
        EndSwitch
        ; Delete element from array
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iIndex + 1)

        ; Delete item from ListView
        _GUICtrlListView_DeleteItem($hGLVEx_Handle, $iIndex)
        ; Set highlight - up one if bottom deleted
        If $iIndex = $iLast Then
            _GUIListViewEx_Highlight($iIndex - 1)
        Else
            _GUIListViewEx_Highlight($iIndex)
        EndIf
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Delete

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Up
; Description ...: Moves selected item in active ListView up 1 place
; Syntax.........: _GUIListViewEx_Up()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Up()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not top item
    If $iIndex = "0" Then Return SetError(3, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex, $iIndex + 1)

    ; Swap checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $fTemp = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex)
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex, _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex - 1))
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex - 1, $fTemp)
    EndIf

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex - 1, $iIndex);, $aGLVEx_Array)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex - 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Up

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Down
; Description ...: Moves selected item in active ListView down 1 place
; Syntax.........: _GUIListViewEx_Down()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Down()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not last item
    If $iIndex = _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1 Then
        _GUIListViewEx_Highlight($iIndex)
        Return
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex + 1, $iIndex + 2)

    ; Swap checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $fTemp = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex)
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex, _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex + 1))
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex + 1, $fTemp)
    EndIf

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex, $iIndex + 1)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex + 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Down

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DragRegister
; Description ...: Registers Windows messages needed for the UDF
; Syntax.........: _GUIListViewEx_DragRegister([$fNOTIFY = True, [$fMOUSEMOVE = True, [$fLBUTTONUP = True]]])
; Parameters ....: $fNOTIFY    - True = Register WM_NOTIFY message
;                  $fMOUSEMOVE - True = Register WM_MOUSEMOVE message
;                  $fLBUTTONUP - True = Register WM_LBUTTONUP message
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If other handlers already registered, then call the relevant handler function from within that handler
;                  If no dragging is required, only the WM_NOTIFY handler needs to be registered
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DragRegister($fNOTIFY = True, $fMOUSEMOVE = True, $fLBUTTONUP = 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

EndFunc   ;==>_GUIListViewEx_DragRegister

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_NOTIFY_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_NOTIFY_Handler
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_NOTIFY handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam

    ; 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 $iCode = BitAND(DllStructGetData($tStruct, 3), 0xFFFFFFFF)

    Switch $iCode
        Case $LVN_COLUMNCLICK, -2 ; $NM_CLICK
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not enabled

            ; Set values for active ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Sort if a column header was clicked and ListView is sortable
            If $iCode = $LVN_COLUMNCLICK And IsArray($aGLVEx_Data[$i][4]) Then
                ; Load current ListView sort state array
                Local $aLVSortState = $aGLVEx_Data[$aGLVEx_Data[0][0]][4]
                ; Sort column - get column from from struct
                _GUICtrlListView_SimpleSort($hGLVEx_Handle, $aLVSortState, DllStructGetData($tStruct, 5))
                ; Store new ListView sort state array
                $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = $aLVSortState
                ; Reread listview items into array
                Switch UBound($aGLVEx_Array, 0) ; Check array format
                    Case 1
                        For $j = 1 To $aGLVEx_Array[0]
                            $aGLVEx_Array[$j] = _GUICtrlListView_GetItemTextString($hGLVEx_Handle, $j - 1)
                        Next
                    Case 2
                        Local $iDim2 = UBound($aGLVEx_Array, 2) - 1
                        For $j = 1 To $aGLVEx_Array[0][0]
                            For $k = 0 To $iDim2
                                $aGLVEx_Array[$j][$k] = _GUICtrlListView_GetItemText($hGLVEx_Handle, $j - 1, $k)
                            Next
                        Next
                EndSwitch
                ; Store amended array
                $aGLVEx_Data[$i][2] = $aGLVEx_Array
            EndIf

        Case $LVN_BEGINDRAG
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not registered

            ; Set values for this ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            Local $fImage = $aGLVEx_Data[$i][5]
            Local $fCheck = $aGLVEx_Data[$i][6]
            ; Copy array for manipulation
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Check if Native or UDF and set focus
            If $hGLVEx_CID Then
                GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
            Else
                _WinAPI_SetFocus($hGLVEx_Handle)
            EndIf

            ; Get dragged item index
            $iGLVExDragged_Index = DllStructGetData($tStruct, 4) ; Item
            ; Set dragged item count
            $iGLVEx_Dragging = 1

            ; Check for selected items
            Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
            ; Check if item is part of a multiple selection
            If StringInStr($iIndex, $iGLVExDragged_Index) And StringInStr($iIndex, "|") Then
                ; Remove highlighting from item
                ;_GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index, False)
                ; Extract all selected items
                Local $aIndex = StringSplit($iIndex, "|")
                For $i = 1 To $aIndex[0]
                    If $aIndex[$i] = $iGLVExDragged_Index 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
                        $iGLVExDragged_Index -= 1
                        ; Increase number to drag
                        $iGLVEx_Dragging += 1
                    Next
                EndIf
                If $i <> $aIndex[0] Then ; Down
                    Local $iCount = 1 ; How far we go 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
                        ; Increase counter
                        $iCount += 1
                    Next
                EndIf
            Else ; Either no selection or only a single
                ; Set flag
                $iGLVEx_Dragging = 1
            EndIf

            ; Remove all highlighting
            _GUICtrlListView_SetItemSelected($hGLVEx_Handle, -1, False)

            ; Create drag image
            If $fImage Then
                Local $aImageData = _GUICtrlListView_CreateDragImage($hGLVEx_Handle, $iGLVExDragged_Index)
                $hGLVExDragged_Image = $aImageData[0]
                _GUIImageList_BeginDrag($hGLVExDragged_Image, 0, 0, 0)
            EndIf

            ; Create Global array for checkboxes if required
            If $fCheck Then
                Global $aGLVExDragCheck_Array[UBound($aGLVEx_Array)]
                For $i = 1 To UBound($aGLVExDragCheck_Array) - 1
                    $aGLVExDragCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $i - 1)
                Next
            EndIf

    EndSwitch

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 +
; 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 $iMsg, $wParam

    If Not $iGLVEx_Dragging Then Return "GUI_RUNDEFMSG"

    Local $aLV_Pos, $tLVHITTESTINFO, $iCurr_Index

    ; 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 $iGLVExInsert_Index <> -1 Then
        If $iGLVExLast_Y = $iCurr_Y Then
            Return "GUI_RUNDEFMSG"
        ElseIf $iGLVExLast_Y > $iCurr_Y Then
            $fGLVEx_Bar_Under = False
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, False)
        Else
            $fGLVEx_Bar_Under = True
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, True)
        EndIf
    EndIf
    ; Store current Y coord
    $iGLVExLast_Y = $iCurr_Y

    ; Get ListView item under mouse - depends on ListView type
    If $hGLVEx_CID Then
        $aLV_Pos = ControlGetPos($hWnd, "", $hGLVEx_CID)
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iCurr_Y - $aLV_Pos[1])
        ; Get item under mouse
        $iCurr_Index = GUICtrlSendMsg($hGLVEx_CID, $LVM_HITTEST, 0, DllStructGetPtr($tLVHITTESTINFO))
    Else
        ; Get coords of client area
        Local $tPoint = DllStructCreate("int X;int Y")
        DllStructSetData($tPoint, "X", 0)
        DllStructSetData($tPoint, "Y", 0)
        Local $pPoint = DllStructGetPtr($tPoint)
        DllCall("user32.dll", "bool", "ClientToScreen", "hwnd", $hWnd, "ptr", $pPoint)
        ; Get coords of ListView
        $aLV_Pos = WinGetPos($hGLVEx_Handle)
        Local $iY = $iCurr_Y - $aLV_Pos[1] + DllStructGetData($tPoint, "Y")
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0] + DllStructGetData($tPoint, "X")
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iY)
        Local $pLVHITTESTINFO = DllStructGetPtr($tLVHITTESTINFO)
        ; Get item under mouse
        Local $aRet = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hGLVEx_Handle, "uint", $LVM_HITTEST, "wparam", 0, "lparam", $pLVHITTESTINFO)
        $iCurr_Index = $aRet[0]
    EndIf

    ; If mouse is above or below ListView then scroll ListView
    If $iCurr_Index = -1 Then
        If $fGLVEx_Bar_Under Then
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, 10)
        Else
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, -10)
        EndIf
        Sleep(100)
    EndIf

    ; Check if over same item
    If $iGLVExInsert_Index = $iCurr_Index Then Return "GUI_RUNDEFMSG"

    ; Show insert mark on current item
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iCurr_Index, $fGLVEx_Bar_Under)
    ; Store current item
    $iGLVExInsert_Index = $iCurr_Index

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 +
; 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"

    ; Get item count
    Local $iMultipleItems = $iGLVEx_Dragging - 1

    ; Reset flag
    $iGLVEx_Dragging = 0

    ; Check mouse within ListView
    If $iGLVExInsert_Index = -1 Then
        ; Clear insert mark
        _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)
        ; Reset highlight to original items
        For $i = 0 To $iMultipleItems
            _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
        Next
        Return
    EndIf

    ; Determine position to insert
    If $fGLVEx_Bar_Under Then
        If $iGLVExDragged_Index > $iGLVExInsert_Index Then $iGLVExInsert_Index += 1
    Else
        If $iGLVExDragged_Index < $iGLVExInsert_Index Then $iGLVExInsert_Index -= 1
    EndIf

    ; Clear insert mark
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)

    ; Clear drag image
    If $hGLVExDragged_Image Then
        _GUIImageList_DragLeave($hGLVEx_Handle)
        _GUIImageList_EndDrag()
        _GUIImageList_Destroy($hGLVExDragged_Image)
        $hGLVExDragged_Image = 0
    EndIf

    ; Check not dropping on dragged item(s)
    Switch $iGLVExInsert_Index
        Case $iGLVExDragged_Index To $iGLVExDragged_Index + $iMultipleItems
            ; Reset highlight to original items
            For $i = 0 To $iMultipleItems
                _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
            Next
            Return
    EndSwitch

    ; Amend array
    ; Get data from dragged element(s)
    If $iMultipleItems Then
        ; Multiple dragged elements
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    $aInsertData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1 + $i]
                Next
            Case 2
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    Local $aItemData[UBound($aGLVEx_Array, 2)]
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $aItemData[$j] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$j]
                    Next
                    $aInsertData[$i] = $aItemData
                Next
        EndSwitch
    Else
        ; Single dragged element
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[1]
                $aInsertData[0] = $aGLVEx_Array[$iGLVExDragged_Index + 1]
            Case 2
                Local $aInsertData[1]
                Local $aItemData[UBound($aGLVEx_Array, 2)]
                For $i = 0 To UBound($aGLVEx_Array, 2) - 1
                    $aItemData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$i]
                Next
                $aInsertData[0] = $aItemData
        EndSwitch
    EndIf

    ; Copy checkbox data from dragged elements
    If IsArray($aGLVExDragCheck_Array) Then
        If $iMultipleItems Then
            Local $aDragged_Data[$iMultipleItems + 1]
            For $i = 0 To $iMultipleItems
                $aDragged_Data[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iGLVExDragged_Index + $i)
            Next
        Else
            Local $aDragged_Data[1]
            $aDragged_Data[0] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iGLVExDragged_Index)
        EndIf
    EndIf

    ; Delete dragged element(s) from arrays
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iGLVExDragged_Index + 1)
        If IsArray($aGLVExDragCheck_Array) Then
            _GUIListViewEx_Array_Delete($aGLVExDragCheck_Array, $iGLVExDragged_Index + 1)
        EndIf
    Next

    ; Amend insert positon for multiple items deleted above
    If $iGLVExDragged_Index < $iGLVExInsert_Index Then
        $iGLVExInsert_Index -= $iMultipleItems
    EndIf
    ; Re-insert dragged element(s) into array
    For $i = $iMultipleItems To 0 Step -1
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iGLVExInsert_Index + 1, $aInsertData[$i])
        If IsArray($aGLVExDragCheck_Array) Then
            _GUIListViewEx_Array_Insert($aGLVExDragCheck_Array, $iGLVExInsert_Index + 1, $aDragged_Data[$i])
        EndIf
    Next

    ; Amend ListView to match array
    If $iGLVExDragged_Index > $iGLVExInsert_Index Then
        _GUIListViewEx_Data_Change($iGLVExInsert_Index, $iGLVExDragged_Index + $iMultipleItems)
    Else
        _GUIListViewEx_Data_Change($iGLVExDragged_Index, $iGLVExInsert_Index + $iMultipleItems)
    EndIf

    ; Reset checkbox data
    If IsArray($aGLVExDragCheck_Array) Then
        For $i = 1 To UBound($aGLVExDragCheck_Array) - 1
            _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $i - 1, $aGLVExDragCheck_Array[$i])
        Next
        ; Clear array
        $aGLVExDragCheck_Array = 0
    EndIf

    ; Set highlight to inserted item(s)
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_HighLight($iGLVExInsert_Index + $i)
    Next

    ; Store amended array
    $aGLVEx_Data[$aGLVEx_Data[0][1]][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0

EndFunc   ;==>_GUIListViewEx_WM_LBUTTONUP_Handler

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_HighLight($iIndexA, $iIndexB)
; Description ...: Highlights first item and ensures visible while removing hightlight from second in multiple selection ListViews
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Highlight($iIndexA, $iIndexB = -1)

    ; Check if Native or UDF and set focus
    If $hGLVEx_CID Then
        GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
    Else
        _WinAPI_SetFocus($hGLVEx_Handle)
    EndIf
    ; Cancel highlight on other item - needed for multisel listviews
    If $iIndexB <> -1 Then _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iIndexB, False)
    ; Set highlight to inserted item and ensure in view
    _GUICtrlListView_SetItemState($hGLVEx_Handle, $iIndexA, $LVIS_SELECTED, $LVIS_SELECTED)
    _GUICtrlListView_EnsureVisible($hGLVEx_Handle, $iIndexA)

EndFunc   ;==>_GUIListViewEx_HighLight

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_Data_Change($iStart, $iEnd)
; Description ...: Resets ListView items within a defined range to the current values in the stored array
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Data_Change($iStart, $iEnd)

    Local $sInsert

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Native ListView
        For $i = $iStart To $iEnd
            ; Get CID of the item
            Local $iCID = _GUICtrlListView_GetItemParam($hGLVEx_Handle, $i)
            ; Check array type
            Switch UBound($aGLVEx_Array, 0)
                Case 1
                    $sInsert = $aGLVEx_Array[$i + 1]
                Case 2
                    $sInsert = ""
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $sInsert &= $aGLVEx_Array[$i + 1][$j] & "|"
                    Next
            EndSwitch
            ; Set data
            GUICtrlSetData($iCID, $sInsert)
        Next
    Else
        ; UDF ListView
        For $i = $iStart To $iEnd
            ; Check if multicolumn
            Local $iDim2 = UBound($aGLVEx_Array, 2)
            If @error Then
                _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1])
            Else
                ; For each column - or just once if not multicolumn
                For $j = 0 To $iDim2 - 1
                    ; Set data
                    _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1][$j], $j)
                Next
            EndIf
        Next
    EndIf

EndFunc   ;==>_GUIListViewEx_Data_Change

; #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 = "", $iStart = 0)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ReDim $avArray[$iIndex_Max + 1]
            $avArray[$iIndex_Max] = $vAdd

        Case 2

        ; Get size of second dimension
        Local $iDim2 = UBound($avArray, 2)

        ; Redim the Array
        ReDim $avArray[$iIndex_Max + 1][$iDim2]

        ; 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 - $iStart Then
                    $avArray[$iIndex_Max][$j] = ""
                Else
                    $avArray[$iIndex_Max][$j] = $vAdd[$j + $iStart]
                EndIf
            Next
        Else
            ; Fill Array with variable
            For $j = 0 To $iDim2 - 1
                $avArray[$iIndex_Max][$j] = $vAdd
            Next
        EndIf

    EndSwitch

    Return $iIndex_Max

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)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ; 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

            ; Add the value in the specified element
            $avArray[$iIndex] = $vInsert
            Return $iIndex_Max

        Case 2

            ; If at end of array
            If $iIndex > $iIndex_Max - 1 Then Return $iIndex_Max = _GUIListViewEx_Array_Add($avArray, $vInsert)

            ; Get size of second dimension
            Local $iDim2 = UBound($avArray, 2)

            ; Redim the Array
            ReDim $avArray[$iIndex_Max + 1][$iDim2]

            ; 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

    EndSwitch

    Return $iIndex_Max + 1

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)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ; 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

            ; 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]

    EndSwitch

    Return $iIndex_Max - 1

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

Just 1 small change to the syntax - _GUIListViewEx_Return_Array now will return either the text of the ListView or the checkbox state.

And here is a new version of one of the GUIListViewEx example scripts showing how it also works with multiple selections (I hope!). :)

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

#include "GUIListViewEx_Mod.au3"

#include <Array.au3>

Global $iCount_Left = 20, $iCount_Right = 20, $vData, $sMsg, $aLV_List_Left, $aLV_List_Right

; Create GUI
$hGUI = GUICreate("LVEx Example 1", 640, 430)

; Create Left ListView
GUICtrlCreateLabel("Native ListView - Multiple selection - no count element - sortable", 10, 15, 300, 20)
$hListView_Left = GUICtrlCreateListView("Tom|Dick|Harry", 10, 40, 300, 300, $LVS_SHOWSELALWAYS)
_GUICtrlListView_SetExtendedListViewStyle($hListView_Left, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_CHECKBOXES))
_GUICtrlListView_SetColumnWidth($hListView_Left, 0, 93)
_GUICtrlListView_SetColumnWidth($hListView_Left, 1, 93)
_GUICtrlListView_SetColumnWidth($hListView_Left, 2, 93)

; Create array and fill Left listview
Global $aLV_List_Left[$iCount_Left]
For $i = 0 To UBound($aLV_List_Left) - 1
    $aLV_List_Left[$i] = "Tom " & $i & "|Dick " & $i & "|Harry " & $i
    GUICtrlCreateListViewItem($aLV_List_Left[$i], $hListView_Left)
Next

; Initiate LVEx - no count parameter - default insert mark colour (black)
$iLV_Left_Index = _GUIListViewEx_Init($hListView_Left, $aLV_List_Left, 0, 0, True, True)

; Create Right ListView
GUICtrlCreateLabel("UDF ListView - Single selection - count element - sortable", 330, 15, 300, 20)
$hListView_Right = _GUICtrlListView_Create($hGUI, "Peter", 330, 40, 300, 300, BitOR($LVS_DEFAULT, $WS_BORDER))
_GUICtrlListView_SetExtendedListViewStyle($hListView_Right, $LVS_EX_FULLROWSELECT)
_GUICtrlListView_AddColumn($hListView_Right, "Paul")
_GUICtrlListView_AddColumn($hListView_Right, "Mary")
_GUICtrlListView_SetColumnWidth($hListView_Right, 0, 93)
_GUICtrlListView_SetColumnWidth($hListView_Right, 1, 93)
_GUICtrlListView_SetColumnWidth($hListView_Right, 2, 93)

; Create Array to fill listview
Global $aLV_List_Right[$iCount_Right + 1][3] = [[$iCount_Right]]
For $i = 1 To UBound($aLV_List_Right) - 1
    $aLV_List_Right[$i][0] = "Peter " & $i -1
    $aLV_List_Right[$i][1] = "Paul " & $i -1
    $aLV_List_Right[$i][2] = "Mary " & $i -1
Next

; Fill listview
For $i = 1 To UBound($aLV_List_Right) - 1
    _GUICtrlListView_AddItem($hListView_Right, $aLV_List_Right[$i][0])
    _GUICtrlListView_AddSubItem($hListView_Right, $i - 1, $aLV_List_Right[$i][1], 1)
    _GUICtrlListView_AddSubItem($hListView_Right, $i - 1, $aLV_List_Right[$i][2], 2)
Next

; Initiate LVEx - count parameter set - red insert mark
$iLV_Right_Index = _GUIListViewEx_Init($hListView_Right, $aLV_List_Right, 1, 0xFF0000, True, True)

; Create buttons
$hInsert_Button = GUICtrlCreateButton("Insert", 10, 350, 200, 30)
$hDelete_Button = GUICtrlCreateButton("Delete", 10, 390, 200, 30)
$hUp_Button = GUICtrlCreateButton("Move Up", 220, 350, 200, 30)
$hDown_Button = GUICtrlCreateButton("Move Down", 220, 390, 200, 30)
$hDisplay_Left_Button = GUICtrlCreateButton("Show Left", 430, 350, 100, 30)
$hDisplay_Right_Button = GUICtrlCreateButton("Show Right", 530, 350, 100, 30)
$hExit_Button = GUICtrlCreateButton("Exit", 430, 390, 200, 30)

GUISetState()

; Register for dragging
_GUIListViewEx_DragRegister()

; Set the left ListView as active
_GUIListViewEx_SetActive(1)

Switch _GUIListViewEx_GetActive()
    Case 0
        $sMsg = "No ListView is active"
    Case 1
        $sMsg = "The LEFT ListView is active" & @CRLF & "<--------------------------"
    Case 2
        $sMsg = "The RIGHT ListView is active" & @CRLF & "---------------------------->"
EndSwitch
MsgBox(0, "Active ListView", $sMsg)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $hExit_Button
            Exit
        Case $hInsert_Button
            ; Prepare data  for insertion
            Switch $aGLVEx_Data[0][1]
                Case 1
                    ; String format with multi-column native ListView
                    $vData = "Tom " & $iCount_Left & "|Dick " & $iCount_Left & "|Harry " & $iCount_Left
                    $iCount_Left += 1
                    _GUIListViewEx_Insert($vData)
                Case 2
                    ; Array format with multi-column UDF ListView
                    Global $vData[3] = ["Peter " & $iCount_Right, "Paul " & $iCount_Right, "Mary " & $iCount_Right]
                    $iCount_Right += 1
                    _GUIListViewEx_Insert($vData)
            EndSwitch

        Case $hDelete_Button
            _GUIListViewEx_Delete()

        Case $hUp_Button
            _GUIListViewEx_Up()

        Case $hDown_Button
            _GUIListViewEx_Down()

        Case $hDisplay_Left_Button
            $aLV_List_Left = _GUIListViewEx_Return_Array($iLV_Left_Index)
            If Not @error Then
                _ArrayDisplay($aLV_List_Left, "Returned Left")
            Else
                MsgBox(0, "Left", "Empty Array")
            EndIf
            $aLV_List_Left = _GUIListViewEx_Return_Array($iLV_Left_Index, 1)
            If Not @error Then
                _ArrayDisplay($aLV_List_Left, "Returned Left Checkboxes")
            Else
                MsgBox(0, "Left", "Empty Check Array")
            EndIf

        Case $hDisplay_Right_Button
            $aLV_List_Right = _GUIListViewEx_Return_Array($iLV_Right_Index)
            If Not @error Then
                _ArrayDisplay($aLV_List_Right, "Returned Right")
            Else
                MsgBox(0, "Right", "Empty Array")
            EndIf
    EndSwitch

WEnd

I hope the UDF does what you want now - thanks for prodding me to improve it. If all is well with your testing and I cannot break it myself over the next few days I will consider releasing a new version. :mellow:

And if anyone else has any thoughts on teh changes please let me know as well. :)

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

Viva,

Is working, and it seems to me very well.

I'll do some more tests and then notice.

Thank you for taking the time.

I'm not a witch, but you'll see that tomorrow the weather will be phenomenal. ihihih

hug :mellow:

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

tomorrow the weather will be phenomenal

I hope so - I am taking my old Mum to the seaside for the day! :)

I am glad the UDF seems to be working. If it does fail, please try and reproduce the actions that caused the failure - it is a lot easier to debug if there is a series of steps to follow. But of course it will not fail..... :mellow:

M23


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
NunoBorges

NunoBorges,

I hope so - I am taking my old Mum to the seaside for the day! :)

I am glad the UDF seems to be working. If it does fail, please try and reproduce the actions that caused the failure - it is a lot easier to debug if there is a series of steps to follow. But of course it will not fail..... :mellow:

M23

Viva, Melba23

I have tested your example,

Added the hotkey F5 to make a refresh of the data on the left listview,

and found that after the refresh and when we move an item it brings us the old data.

Please see the attached file

Thanks for your time

Melba23_Example 20110818.au3

Share this post


Link to post
Share on other sites
Melba23

NunoBorges

If you look carefully at the $aGLVEx_Data array you display when you have reset the data, you will see that the listview handle in the [0] element is repeated - that is why it crashes as you have the same listview initialised 2 times. :)

Just add _GUIListViewEx_Close($iLV_Left_Index) at the beginning of your _NewData function to cancel the original initialisation of the ListView. Then when you use _GUIListViewEx_Init($hListView_Left...) in the function to reset the data, you have only one element in the $aGLVEx_Data array with that handle. That works fine for me. :mellow:

M23

P.S. Are you likely to refresh the data very much before restarting the script? If so I may have to adjust the _GUIListViewEx_Close function to remove the unused elements from the array. But do not send any rain to force me to work on it - I would like some sunshine for a few days! :)


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
Melba23

NunoBorges,

Thank you for letting me have a sunny day yesterday - my Mum enjoyed her day at the seaside very much. :)

I have rewritten the _GUIListViewEx_Init function to look for blank lines in the $aGLVEx_Data array rather than always adding a new line, so you can reset your ListView as often as you wish as long as you use _GUIListViewEx_Close to clear it first. :mellow:

Here is the current version which works fine with the test script you posted above:

#include-once

; #INDEX# ============================================================================================================
; Title .........: GUIListViewEx
; AutoIt Version : 3.3 +
; Language ......: English
; Description ...: Permits insertion, deletion, moving, dragging and sorting of items within activated 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.
;                  - If the script already has WM_NOTIFY, WM_MOUSEMOVE or WM_LBUTTONUP handlers then only set the
;                    unregistered messages in _GUIListViewEx_DragRegister and call the relevant _GUIListViewEx_WM_#####_Handler from
;                    within the existing handler
;                  - Uses 2 undocumented function within GUIListView UDF to set and colour insert mark (thanks rover)
; Author ........: Melba23 - credit to martin (basic drag code), Array.au3 authors (original array functions)
; Modified ......;
; ====================================================================================================================

;#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <GuiListView.au3>
#include <GUIImageList.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Array to hold registered ListView data
Global $aGLVEx_Data[1][7] = [[0, 0]]
; [0][0] = Count            [n][0] = ListView handle
; [0][1] = Active Index     [n][1] = Native ListView ControlID / 0
;                           [n][2] = Content array
;                           [n][3] = [0] element is count
;                           [n][4] = Sorting array
;                           [n][5] = Drag image
;                           [n][6] = Checkbox array
; Variables for all UDF functions
Global $hGLVEx_Handle, $hGLVEx_CID, $aGLVEx_Array
; Variables for UDF dragging handlers
Global $iGLVEx_Dragging = 0, $iGLVExDragged_Index, $hGLVExDragged_Image = 0, $iGLVExInsert_Index = -1, $iGLVExLast_Y
Global $fGLVEx_Bar_Under, $fGLVEx_MultipleDrag, $aGLVExDragCheck_Array

; #CURRENT# ==========================================================================================================
; _GUIListViewEx_Init:                 Enables UDF button functions for the ListView and sets insert mark colour
; _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 ListView active for UDF functions
; _GUIListViewEx_Return_Array:         Returns an array reflecting the current state of the ListView
; _GUIListViewEx_Insert:               Inserts data just below selected item in active ListView
; _GUIListViewEx_Delete:               Deletes selected item in active ListView
; _GUIListViewEx_Up:                   Moves selected item in active ListView up 1 place
; _GUIListViewEx_Down                  Moves selected item in active ListView down 1 place
; _GUIListViewEx_DragRegister:         Registers Windows messages to enable item dragging for listed ListViews
; _GUIListViewEx_WM_NOTIFY_Handler:    Windows message handler for WM_NOTIFY
; _GUIListViewEx_WM_MOUSEMOVE_Handler: Windows message handler for WM_MOUSEMOVE
; _GUIListViewEx_WM_LBUTTONUP_Handler: Windows message handler for WM_LBUTTONUP
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _GUIListViewEx_HighLight:    Highlights specified ListView item and ensures it is visible
; _GUIListViewEx_Data_Change:  Resets ListView items within a defined range to the current values in the stored array
; _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
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Init
; Description ...: Enables UDF button functions for the ListView and sets insert mark colour for drag function
; Syntax.........: _GUIListViewEx_Init($hLV, [$aArray = "", [$iStart = 0, [$iColour, [$fSort, $fImage]]]]])
; Parameters ....: $hLV     - Handle or ControlID of ListView
;                  $a Array - Name of array used to fill ListView.  "" = empty ListView
;                  $iStart  - 0 (default) = ListView data starts in [0] element of array, 1 = Count in [0] element
;                  $iColour - RGB colour for insert mark (default = black)
;                  $fSort   - True = ListView can be sorted by click on column header - (Default = False)
;                  $fImage  - True = Shadow image of dragged item when dragging
; Requirement(s).: v3.3 +
; 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 - if the ListView has more than
;                  1 column this array is 2D with the second dimension set to the number of columns
;                  - The shadow array has a count in element [0] added if it does not exist. However, if the $iStart
;                  parameter is set to 0 this count element will not be returned by other GUIListViewEx functions
;                  - Only first item of a multiple selection is shadow imaged when dragging (API limitation)
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Init($hLV, $aArray = "", $iStart = 0, $iColour = 0, $fSort = False, $fImage = False)

    Local $iIndex = 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
            $iIndex = $i
            ExitLoop
        EndIf
    Next
    ; If no blank line found then increase array size
    If $iIndex = 0 Then
        $aGLVEx_Data[0][0] += 1
        ReDim $aGLVEx_Data[$aGLVEx_Data[0][0] + 1][7]
        $iIndex = $aGLVEx_Data[0][0]
    EndIf

    ; Store ListView handle and ControlID
    If IsHWnd($hLV) Then
        $aGLVEx_Data[$iIndex][0] = $hLV
        $aGLVEx_Data[$iIndex][1] = 0
    Else
        $aGLVEx_Data[$iIndex][0] = GUICtrlGetHandle($hLV)
        $aGLVEx_Data[$iIndex][1] = $hLV
    EndIf

    ; Create a shadow array if needed
    If $aArray = "" Then
        Local $iCols = _GUICtrlListView_GetColumnCount($aGLVEx_Data[$iIndex][0])
        Switch $iCols
            Case 1
                Local $aReplacement[1] = [0]
            Case Else
                Local $aReplacement[1][$iCols] = [[0]]
        EndSwitch
        $aArray = $aReplacement
    Else
        ; Add count element to shadow array if required
        If $iStart = 0 Then _GUIListViewEx_Array_Insert($aArray, 0, UBound($aArray))
    EndIf
    ; Store array
    $aGLVEx_Data[$iIndex][2] = $aArray

    ; Store [0] = count data
    $aGLVEx_Data[$iIndex][3] = $iStart
    ; If sortable, store sort array
    If $fSort Then
        Local $aLVSortState[_GUICtrlListView_GetColumnCount($hLV)]
        $aGLVEx_Data[$iIndex][4] = $aLVSortState
    Else
        $aGLVEx_Data[$iIndex][4] = 0
    EndIf
    ; If image required
    If $fImage Then
        $aGLVEx_Data[$iIndex][5] = 1
    EndIf
    ;  If checkbox extended style
    If BitAnd(_GUICtrlListView_GetExtendedListViewStyle($hLV), 4) Then ; $LVS_EX_CHECKBOXES
        $aGLVEx_Data[$iIndex][6] = 1
    EndIf

    ; 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 only 1 current ListView then activate
    Local $iListView_Count = 0
    For $i = 1 To $iIndex
        If $aGLVEx_Data[$i][0] Then $iListView_Count += 1
    Next
    If $iListView_Count = 1 Then _GUIListViewEx_SetActive($iIndex)

    ; Return ListView index
    Return $iIndex

EndFunc   ;==>_GUIListViewEx_Init

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Close
; Description ...: Disables all UDF functions for the specified ListView and clears all memory used
; Syntax.........: _GUIListViewEx_Close($iIndex)
; Parameters ....: $iIndex - Index number of ListView to close as returned by _GUIListViewEx_Init
;                            0 (default) = Closes all ListViews
; Requirement(s).: v3.3 +
; Return values .: Success: 1
;                  Failure: 0 and @error set to 1 - Invalid index number
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Close($iIndex = 0)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, 0)

    If $iIndex = 0 Then
        ; Remove all ListView data
        Global $aGLVEx_Data[1][7] = [[0, 0]]
    Else
        ; Reset all data for ListView
        For $i = 0 To 6
            $aGLVEx_Data[$iIndex][$i] = 0
        Next

        ; Cancel active index if set to this ListView
        If $aGLVEx_Data[0][1] = $iIndex Then $aGLVEx_Data[0][1] = 0
    EndIf

    Return 1

EndFunc   ;==>_GUIListViewEx_Close

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_SetActive
; Description ...: Set specified ListView as active for UDF functions
; Syntax.........: _GUIListViewEx_SetActive($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
;                  An index of 0 clears any current setting
; Requirement(s).: v3.3 +
; 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($iIndex)

    ; Check valid index
    If $iIndex < 0 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, -1)

    Local $iCurr_Index = $aGLVEx_Data[0][1]

    If $iIndex Then
        ; Store index of specified ListView
        $aGLVEx_Data[0][1] = $iIndex
        ; Set values for specified ListView
        $hGLVEx_Handle = $aGLVEx_Data[$iIndex][0]
        $hGLVEx_CID = $aGLVEx_Data[$iIndex][1]
    Else
        ; Clear active index
        $aGLVEx_Data[0][1] = 0
    EndIf

    Return $iCurr_Index

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_GetActive
; Description ...: Get index number of ListView active for UDF functions
; Syntax.........: _GUIListViewEx_GetActive()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Return_Array
; Description ...: Returns an array reflecting the current state of the ListView
; Syntax.........: _GUIListViewEx_Return_Array($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _GUIListViewEx_Init
;                  $iCheck - If non-zero then the state of the checkboxes is returned (Default = 0)
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView - presence of count in [0] element determined by _GUIListViewEx_Init
;                  Failure: Empty array returns null string and sets @error as follows:
;                           1 = Invalid index number
;                           2 = Empty array (no items in ListView)
;                           3 = $iCheck set to True but ListView does not have checkbox style
; Author ........: Melba23
; Modified ......:
; Remarks .......: The $iStart parameter from GUIListViewEx_Init determines whether the [0] element is a count
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Return_Array($iIndex, $iCheck = 0)

    ; Check valid index
    If $iIndex < 1 Or $iIndex > $aGLVEx_Data[0][0] Then Return SetError(1, 0, "")

    ; Copy current array
    Local $aRetArray = $aGLVEx_Data[$iIndex][2]

    ; Check if checkbox array
    If $iCheck Then
        If $aGLVEx_Data[$iIndex][6] Then
            Local $aCheck_Array[UBound($aRetArray)]
            For $i = 1 To UBound($aRetArray) - 1
                $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($aGLVEx_Data[$iIndex][0], $i - 1)
            Next
            ; Remove count element if required
            If $aGLVEx_Data[$iIndex][3] = 0 Then
                ; Check at least one entry in 1D/2D array
                Switch UBound($aRetArray, 0)
                    Case 1
                        If $aRetArray[0] = 0 Then Return SetError(2, 0, "")
                    Case 2
                        If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
                EndSwitch
                ; Delete count element
                _GUIListViewEx_Array_Delete($aCheck_Array, 0)
            EndIf
            Return $aCheck_Array
        Else
            Return SetError(3, 0, "")
        EndIf
    EndIf

    ; Remove count element of array if required
    If $aGLVEx_Data[$iIndex][3] = 0 Then
        ; Check at least one entry in 1D/2D array
        Switch UBound($aRetArray, 0)
            Case 1
                If $aRetArray[0] = 0 Then Return SetError(2, 0, "")
            Case 2
                If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
        EndSwitch
        ; Delete count element
        _GUIListViewEx_Array_Delete($aRetArray, 0)
    EndIf

    ; Return array
    Return $aRetArray

EndFunc   ;==>_GUIListViewEx_Return_Array

; #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)
; Parameters ....: $vData - Data to insert, can be in array or delimited string format
; Requirement(s).: v3.3 +
; Return values .: Success: Array of current ListView 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 datat 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
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Insert($vData)

    Local $vInsert

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Create Local array for checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $aCheck_Array[UBound($aGLVEx_Array)]
        For $i = 1 To UBound($aCheck_Array) - 1
            $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $i - 1)
        Next
    EndIf

    ; Check if 1D/2D array
    Switch UBound($aGLVEx_Array, 0)
        Case 1
            ; If empty array insert at 0
            If $aGLVEx_Array[0] = 0 Then $iInsert_Index = 0
            ; Get data into string format for insert
            If IsArray($vData) Then
                $vInsert = ""
                For $i = 0 To UBound($vData) - 1
                    $vInsert &= $vData[$i] & "|"
                Next
                $vInsert = StringTrimRight($vInsert, 1)
            Else
                $vInsert = $vData
            EndIf
            ; Increase count
            $aGLVEx_Array[0] += 1
        Case 2
            ; If empty array insert at 0
            If $aGLVEx_Array[0][0] = 0 Then $iInsert_Index = 0
            ; Get data into array format for insert
            If IsArray($vData) Then
                $vInsert = $vData
            Else
                Local $aData = StringSplit($vData, "|")
                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]
                        Next
                EndSwitch
            EndIf
            ; Increase count
            $aGLVEx_Array[0][0] += 1
    EndSwitch

    ; Insert data into array
    If $iIndex = "" Then
        _GUIListViewEx_Array_Add($aGLVEx_Array, $vInsert)
    Else
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iInsert_Index + 2, $vInsert)
        If $aGLVEx_Data[$iArray_Index][6] Then
            _GUIListViewEx_Array_Insert($aCheck_Array, $iInsert_Index + 2, False)
            ; Reset all checkboxes
            For $i = 1 To UBound($aCheck_Array) - 1
                _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $i - 1, $aCheck_Array[$i])
            Next
        EndIf
    EndIf

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Add new item at ListView end
        GUICtrlCreateListViewItem($vInsert, $hGLVEx_CID)
    Else
        ; Add new item at ListView end
        Local $iNewItem
        If IsArray($vInsert) Then
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert[0])
            ; Add new subitems
            For $i = 1 To UBound($vInsert) - 1
                _GUICtrlListView_AddSubItem($hGLVEx_Handle, $iNewItem, $vInsert[$i], $i)
            Next
        Else
            $iNewItem = _GUICtrlListView_AddItem($hGLVEx_Handle, $vInsert)
        EndIf
    EndIf
    ; Check where item was to be inserted
    If $iIndex = "" Then
        _GUIListViewEx_Data_Change($iInsert_Index, $iInsert_Index)
        ; No moves required so set highlight
        _GUIListViewEx_Highlight(_GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
    Else
        ; Reset item contents below insert position
        _GUIListViewEx_Data_Change($iInsert_Index, _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1)
        ; Set highlight
        _GUIListViewEx_Highlight($iInsert_Index + 1, $iInsert_Index)
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Insert

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Delete
; Description ...: Deletes selected item in active ListView
; Syntax.........: _GUIListViewEx_Delete()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 = No items to delete
; Author ........: Melba23
; Modified ......:
; Remarks .......: If multiple items are selected, all are deleted
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Delete()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, "")

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Check for selected items
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Determine final item
    Local $iLast = UBound($aGLVEx_Array) - 2

    ; Check if item is part of a multiple selection
    If StringInStr($iIndex, "|") Then
        ; Extract all selected items
        Local $aIndex = StringSplit($iIndex, "|")
        For $i = 1 To $aIndex[0]
            ; Remove highlighting from items
            _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $i, False)
        Next

        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= $aIndex[0]
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= $aIndex[0]
        EndSwitch

        ; Delete elements from array - start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUIListViewEx_Array_Delete($aGLVEx_Array, $aIndex[$i] + 1)
        Next

        ; Delete items from ListView - again start from bottom
        For $i = $aIndex[0] To 1 Step -1
            _GUICtrlListView_DeleteItem($hGLVEx_Handle, $aIndex[$i])
        Next

    Else
        ; Check if 1D/2D array
        Switch UBound($aGLVEx_Array, 0)
            Case 1
                ; Decrease count
                $aGLVEx_Array[0] -= 1
            Case 2
                ; Decrease count
                $aGLVEx_Array[0][0] -= 1
        EndSwitch
        ; Delete element from array
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iIndex + 1)

        ; Delete item from ListView
        _GUICtrlListView_DeleteItem($hGLVEx_Handle, $iIndex)
        ; Set highlight - up one if bottom deleted
        If $iIndex = $iLast Then
            _GUIListViewEx_Highlight($iIndex - 1)
        Else
            _GUIListViewEx_Highlight($iIndex)
        EndIf
    EndIf

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Delete

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Up
; Description ...: Moves selected item in active ListView up 1 place
; Syntax.........: _GUIListViewEx_Up()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Up()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not top item
    If $iIndex = "0" Then Return SetError(3, 0, "")

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex, $iIndex + 1)

    ; Swap checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $fTemp = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex)
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex, _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex - 1))
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex - 1, $fTemp)
    EndIf

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex - 1, $iIndex);, $aGLVEx_Array)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex - 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Up

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_Down
; Description ...: Moves selected item in active ListView down 1 place
; Syntax.........: _GUIListViewEx_Down()
; Parameters ....: None
; Requirement(s).: v3.3 +
; 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 first is moved
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_Down()

    ; Set data for active ListView
    Local $iArray_Index = $aGLVEx_Data[0][1]
    ; If no ListView active then return
    If $iArray_Index = 0 Then Return SetError(1, 0, 0)

    ; Load active ListView details
    $hGLVEx_Handle = $aGLVEx_Data[$iArray_Index][0]
    $hGLVEx_CID = $aGLVEx_Data[$iArray_Index][1]

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
    If $iIndex = "" Then Return SetError(2, 0, "")
    ; 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_Handle, $aIndex[$i], False)
        Next
    EndIf

    ; Check not last item
    If $iIndex = _GUICtrlListView_GetItemCount($hGLVEx_Handle) - 1 Then
        _GUIListViewEx_Highlight($iIndex)
        Return
    EndIf

    ; Copy array for manipulation
    $aGLVEx_Array = $aGLVEx_Data[$iArray_Index][2]

    ; Swap array elements
    _GUIListViewEx_Array_Swap($aGLVEx_Array, $iIndex + 1, $iIndex + 2)

    ; Swap checkboxes if required
    If $aGLVEx_Data[$iArray_Index][6] Then
        Local $fTemp = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex)
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex, _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iIndex + 1))
        _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $iIndex + 1, $fTemp)
    EndIf

    ; Change data in affected items
    _GUIListViewEx_Data_Change($iIndex, $iIndex + 1)
    ; Set highlight and cancel existing one (needed for multiple selection ListViews)
    _GUIListViewEx_Highlight($iIndex + 1, $iIndex)

    ; Store amended array
    $aGLVEx_Data[$iArray_Index][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0
    ; Return amended array
    Return _GUIListViewEx_Return_Array($iArray_Index)

EndFunc   ;==>_GUIListViewEx_Down

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_DragRegister
; Description ...: Registers Windows messages needed for the UDF
; Syntax.........: _GUIListViewEx_DragRegister([$fNOTIFY = True, [$fMOUSEMOVE = True, [$fLBUTTONUP = True]]])
; Parameters ....: $fNOTIFY    - True = Register WM_NOTIFY message
;                  $fMOUSEMOVE - True = Register WM_MOUSEMOVE message
;                  $fLBUTTONUP - True = Register WM_LBUTTONUP message
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If other handlers already registered, then call the relevant handler function from within that handler
;                  If no dragging is required, only the WM_NOTIFY handler needs to be registered
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_DragRegister($fNOTIFY = True, $fMOUSEMOVE = True, $fLBUTTONUP = 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

EndFunc   ;==>_GUIListViewEx_DragRegister

; #FUNCTION# =========================================================================================================
; Name...........: _GUIListViewEx_WM_NOTIFY_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _GUIListViewEx_WM_NOTIFY_Handler
; Requirement(s).: v3.3 +
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If a WM_NOTIFY handler already registered, then call this function from within that handler
; Example........: Yes
;=====================================================================================================================
Func _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam

    ; 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 $iCode = BitAND(DllStructGetData($tStruct, 3), 0xFFFFFFFF)

    Switch $iCode
        Case $LVN_COLUMNCLICK, -2 ; $NM_CLICK
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not enabled

            ; Set values for active ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Sort if a column header was clicked and ListView is sortable
            If $iCode = $LVN_COLUMNCLICK And IsArray($aGLVEx_Data[$i][4]) Then
                ; Load current ListView sort state array
                Local $aLVSortState = $aGLVEx_Data[$aGLVEx_Data[0][0]][4]
                ; Sort column - get column from from struct
                _GUICtrlListView_SimpleSort($hGLVEx_Handle, $aLVSortState, DllStructGetData($tStruct, 5))
                ; Store new ListView sort state array
                $aGLVEx_Data[$aGLVEx_Data[0][0]][4] = $aLVSortState
                ; Reread listview items into array
                Switch UBound($aGLVEx_Array, 0) ; Check array format
                    Case 1
                        For $j = 1 To $aGLVEx_Array[0]
                            $aGLVEx_Array[$j] = _GUICtrlListView_GetItemTextString($hGLVEx_Handle, $j - 1)
                        Next
                    Case 2
                        Local $iDim2 = UBound($aGLVEx_Array, 2) - 1
                        For $j = 1 To $aGLVEx_Array[0][0]
                            For $k = 0 To $iDim2
                                $aGLVEx_Array[$j][$k] = _GUICtrlListView_GetItemText($hGLVEx_Handle, $j - 1, $k)
                            Next
                        Next
                EndSwitch
                ; Store amended array
                $aGLVEx_Data[$i][2] = $aGLVEx_Array
            EndIf

        Case $LVN_BEGINDRAG
            ; Check if enabled ListView
            For $i = 1 To $aGLVEx_Data[0][0]
                If DllStructGetData($tStruct, 1) = $aGLVEx_Data[$i][0] Then
                    ExitLoop
                EndIf
            Next
            If $i > $aGLVEx_Data[0][0] Then Return ; Not registered

            ; Set values for this ListView
            $aGLVEx_Data[0][1] = $i
            $hGLVEx_Handle = $aGLVEx_Data[$i][0]
            $hGLVEx_CID = $aGLVEx_Data[$i][1]
            Local $fImage = $aGLVEx_Data[$i][5]
            Local $fCheck = $aGLVEx_Data[$i][6]
            ; Copy array for manipulation
            $aGLVEx_Array = $aGLVEx_Data[$i][2]

            ; Check if Native or UDF and set focus
            If $hGLVEx_CID Then
                GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
            Else
                _WinAPI_SetFocus($hGLVEx_Handle)
            EndIf

            ; Get dragged item index
            $iGLVExDragged_Index = DllStructGetData($tStruct, 4) ; Item
            ; Set dragged item count
            $iGLVEx_Dragging = 1

            ; Check for selected items
            Local $iIndex = _GUICtrlListView_GetSelectedIndices($hGLVEx_Handle)
            ; Check if item is part of a multiple selection
            If StringInStr($iIndex, $iGLVExDragged_Index) And StringInStr($iIndex, "|") Then
                ; Remove highlighting from item
                ;_GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iGLVExDragged_Index, False)
                ; Extract all selected items
                Local $aIndex = StringSplit($iIndex, "|")
                For $i = 1 To $aIndex[0]
                    If $aIndex[$i] = $iGLVExDragged_Index 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
                        $iGLVExDragged_Index -= 1
                        ; Increase number to drag
                        $iGLVEx_Dragging += 1
                    Next
                EndIf
                If $i <> $aIndex[0] Then ; Down
                    Local $iCount = 1 ; How far we go 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
                        ; Increase counter
                        $iCount += 1
                    Next
                EndIf
            Else ; Either no selection or only a single
                ; Set flag
                $iGLVEx_Dragging = 1
            EndIf

            ; Remove all highlighting
            _GUICtrlListView_SetItemSelected($hGLVEx_Handle, -1, False)

            ; Create drag image
            If $fImage Then
                Local $aImageData = _GUICtrlListView_CreateDragImage($hGLVEx_Handle, $iGLVExDragged_Index)
                $hGLVExDragged_Image = $aImageData[0]
                _GUIImageList_BeginDrag($hGLVExDragged_Image, 0, 0, 0)
            EndIf

            ; Create Global array for checkboxes if required
            If $fCheck Then
                Global $aGLVExDragCheck_Array[UBound($aGLVEx_Array)]
                For $i = 1 To UBound($aGLVExDragCheck_Array) - 1
                    $aGLVExDragCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $i - 1)
                Next
            EndIf

    EndSwitch

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 +
; 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 $iMsg, $wParam

    If Not $iGLVEx_Dragging Then Return "GUI_RUNDEFMSG"

    Local $aLV_Pos, $tLVHITTESTINFO, $iCurr_Index

    ; 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 $iGLVExInsert_Index <> -1 Then
        If $iGLVExLast_Y = $iCurr_Y Then
            Return "GUI_RUNDEFMSG"
        ElseIf $iGLVExLast_Y > $iCurr_Y Then
            $fGLVEx_Bar_Under = False
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, False)
        Else
            $fGLVEx_Bar_Under = True
            _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iGLVExInsert_Index, True)
        EndIf
    EndIf
    ; Store current Y coord
    $iGLVExLast_Y = $iCurr_Y

    ; Get ListView item under mouse - depends on ListView type
    If $hGLVEx_CID Then
        $aLV_Pos = ControlGetPos($hWnd, "", $hGLVEx_CID)
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iCurr_Y - $aLV_Pos[1])
        ; Get item under mouse
        $iCurr_Index = GUICtrlSendMsg($hGLVEx_CID, $LVM_HITTEST, 0, DllStructGetPtr($tLVHITTESTINFO))
    Else
        ; Get coords of client area
        Local $tPoint = DllStructCreate("int X;int Y")
        DllStructSetData($tPoint, "X", 0)
        DllStructSetData($tPoint, "Y", 0)
        Local $pPoint = DllStructGetPtr($tPoint)
        DllCall("user32.dll", "bool", "ClientToScreen", "hwnd", $hWnd, "ptr", $pPoint)
        ; Get coords of ListView
        $aLV_Pos = WinGetPos($hGLVEx_Handle)
        Local $iY = $iCurr_Y - $aLV_Pos[1] + DllStructGetData($tPoint, "Y")
        $tLVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
        ; Force response even if off side of GUI - normal X coord = BitAND($lParam, 0xFFFF) - $aLV_Pos[0] + DllStructGetData($tPoint, "X")
        DllStructSetData($tLVHITTESTINFO, 1, 1)
        DllStructSetData($tLVHITTESTINFO, 2, $iY)
        Local $pLVHITTESTINFO = DllStructGetPtr($tLVHITTESTINFO)
        ; Get item under mouse
        Local $aRet = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hGLVEx_Handle, "uint", $LVM_HITTEST, "wparam", 0, "lparam", $pLVHITTESTINFO)
        $iCurr_Index = $aRet[0]
    EndIf

    ; If mouse is above or below ListView then scroll ListView
    If $iCurr_Index = -1 Then
        If $fGLVEx_Bar_Under Then
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, 10)
        Else
            _GUICtrlListView_Scroll($hGLVEx_Handle, 0, -10)
        EndIf
        Sleep(100)
    EndIf

    ; Check if over same item
    If $iGLVExInsert_Index = $iCurr_Index Then Return "GUI_RUNDEFMSG"

    ; Show insert mark on current item
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, $iCurr_Index, $fGLVEx_Bar_Under)
    ; Store current item
    $iGLVExInsert_Index = $iCurr_Index

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 +
; 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"

    ; Get item count
    Local $iMultipleItems = $iGLVEx_Dragging - 1

    ; Reset flag
    $iGLVEx_Dragging = 0

    ; Check mouse within ListView
    If $iGLVExInsert_Index = -1 Then
        ; Clear insert mark
        _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)
        ; Reset highlight to original items
        For $i = 0 To $iMultipleItems
            _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
        Next
        Return
    EndIf

    ; Determine position to insert
    If $fGLVEx_Bar_Under Then
        If $iGLVExDragged_Index > $iGLVExInsert_Index Then $iGLVExInsert_Index += 1
    Else
        If $iGLVExDragged_Index < $iGLVExInsert_Index Then $iGLVExInsert_Index -= 1
    EndIf

    ; Clear insert mark
    _GUICtrlListView_SetInsertMark($hGLVEx_Handle, -1, True)

    ; Clear drag image
    If $hGLVExDragged_Image Then
        _GUIImageList_DragLeave($hGLVEx_Handle)
        _GUIImageList_EndDrag()
        _GUIImageList_Destroy($hGLVExDragged_Image)
        $hGLVExDragged_Image = 0
    EndIf

    ; Check not dropping on dragged item(s)
    Switch $iGLVExInsert_Index
        Case $iGLVExDragged_Index To $iGLVExDragged_Index + $iMultipleItems
            ; Reset highlight to original items
            For $i = 0 To $iMultipleItems
                _GUIListViewEx_HighLight($iGLVExDragged_Index + $i)
            Next
            Return
    EndSwitch

    ; Amend array
    ; Get data from dragged element(s)
    If $iMultipleItems Then
        ; Multiple dragged elements
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    $aInsertData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1 + $i]
                Next
            Case 2
                Local $aInsertData[$iMultipleItems + 1]
                For $i = 0 To $iMultipleItems
                    Local $aItemData[UBound($aGLVEx_Array, 2)]
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $aItemData[$j] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$j]
                    Next
                    $aInsertData[$i] = $aItemData
                Next
        EndSwitch
    Else
        ; Single dragged element
        Switch UBound($aGLVEx_Array, 0) ; Check array format
            Case 1
                Local $aInsertData[1]
                $aInsertData[0] = $aGLVEx_Array[$iGLVExDragged_Index + 1]
            Case 2
                Local $aInsertData[1]
                Local $aItemData[UBound($aGLVEx_Array, 2)]
                For $i = 0 To UBound($aGLVEx_Array, 2) - 1
                    $aItemData[$i] = $aGLVEx_Array[$iGLVExDragged_Index + 1][$i]
                Next
                $aInsertData[0] = $aItemData
        EndSwitch
    EndIf

    ; Copy checkbox data from dragged elements
    If IsArray($aGLVExDragCheck_Array) Then
        If $iMultipleItems Then
            Local $aDragged_Data[$iMultipleItems + 1]
            For $i = 0 To $iMultipleItems
                $aDragged_Data[$i] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iGLVExDragged_Index + $i)
            Next
        Else
            Local $aDragged_Data[1]
            $aDragged_Data[0] = _GUICtrlListView_GetItemChecked($hGLVEx_Handle, $iGLVExDragged_Index)
        EndIf
    EndIf

    ; Delete dragged element(s) from arrays
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_Array_Delete($aGLVEx_Array, $iGLVExDragged_Index + 1)
        If IsArray($aGLVExDragCheck_Array) Then
            _GUIListViewEx_Array_Delete($aGLVExDragCheck_Array, $iGLVExDragged_Index + 1)
        EndIf
    Next

    ; Amend insert positon for multiple items deleted above
    If $iGLVExDragged_Index < $iGLVExInsert_Index Then
        $iGLVExInsert_Index -= $iMultipleItems
    EndIf
    ; Re-insert dragged element(s) into array
    For $i = $iMultipleItems To 0 Step -1
        _GUIListViewEx_Array_Insert($aGLVEx_Array, $iGLVExInsert_Index + 1, $aInsertData[$i])
        If IsArray($aGLVExDragCheck_Array) Then
            _GUIListViewEx_Array_Insert($aGLVExDragCheck_Array, $iGLVExInsert_Index + 1, $aDragged_Data[$i])
        EndIf
    Next

    ; Amend ListView to match array
    If $iGLVExDragged_Index > $iGLVExInsert_Index Then
        _GUIListViewEx_Data_Change($iGLVExInsert_Index, $iGLVExDragged_Index + $iMultipleItems)
    Else
        _GUIListViewEx_Data_Change($iGLVExDragged_Index, $iGLVExInsert_Index + $iMultipleItems)
    EndIf

    ; Reset checkbox data
    If IsArray($aGLVExDragCheck_Array) Then
        For $i = 1 To UBound($aGLVExDragCheck_Array) - 1
            _GUICtrlListView_SetItemChecked($hGLVEx_Handle, $i - 1, $aGLVExDragCheck_Array[$i])
        Next
        ; Clear array
        $aGLVExDragCheck_Array = 0
    EndIf

    ; Set highlight to inserted item(s)
    For $i = 0 To $iMultipleItems
        _GUIListViewEx_HighLight($iGLVExInsert_Index + $i)
    Next

    ; Store amended array
    $aGLVEx_Data[$aGLVEx_Data[0][1]][2] = $aGLVEx_Array
    ; Delete copied array
    $aGLVEx_Array = 0

EndFunc   ;==>_GUIListViewEx_WM_LBUTTONUP_Handler

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_HighLight($iIndexA, $iIndexB)
; Description ...: Highlights first item and ensures visible while removing hightlight from second in multiple selection ListViews
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Highlight($iIndexA, $iIndexB = -1)

    ; Check if Native or UDF and set focus
    If $hGLVEx_CID Then
        GUICtrlSetState($hGLVEx_CID, 256) ; $GUI_FOCUS
    Else
        _WinAPI_SetFocus($hGLVEx_Handle)
    EndIf
    ; Cancel highlight on other item - needed for multisel listviews
    If $iIndexB <> -1 Then _GUICtrlListView_SetItemSelected($hGLVEx_Handle, $iIndexB, False)
    ; Set highlight to inserted item and ensure in view
    _GUICtrlListView_SetItemState($hGLVEx_Handle, $iIndexA, $LVIS_SELECTED, $LVIS_SELECTED)
    _GUICtrlListView_EnsureVisible($hGLVEx_Handle, $iIndexA)

EndFunc   ;==>_GUIListViewEx_HighLight

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _GUIListViewEx_Data_Change($iStart, $iEnd)
; Description ...: Resets ListView items within a defined range to the current values in the stored array
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _GUIListViewEx_Data_Change($iStart, $iEnd)

    Local $sInsert

    ; Check if Native or UDF
    If $hGLVEx_CID Then
        ; Native ListView
        For $i = $iStart To $iEnd
            ; Get CID of the item
            Local $iCID = _GUICtrlListView_GetItemParam($hGLVEx_Handle, $i)
            ; Check array type
            Switch UBound($aGLVEx_Array, 0)
                Case 1
                    $sInsert = $aGLVEx_Array[$i + 1]
                Case 2
                    $sInsert = ""
                    For $j = 0 To UBound($aGLVEx_Array, 2) - 1
                        $sInsert &= $aGLVEx_Array[$i + 1][$j] & "|"
                    Next
            EndSwitch
            ; Set data
            GUICtrlSetData($iCID, $sInsert)
        Next
    Else
        ; UDF ListView
        For $i = $iStart To $iEnd
            ; Check if multicolumn
            Local $iDim2 = UBound($aGLVEx_Array, 2)
            If @error Then
                _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1])
            Else
                ; For each column - or just once if not multicolumn
                For $j = 0 To $iDim2 - 1
                    ; Set data
                    _GUICtrlListView_SetItemText($hGLVEx_Handle, $i, $aGLVEx_Array[$i + 1][$j], $j)
                Next
            EndIf
        Next
    EndIf

EndFunc   ;==>_GUIListViewEx_Data_Change

; #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 = "", $iStart = 0)

    ; Get size of the Array to modify
    Local $iIndex_Max = UBound($avArray)

    ; Get type of array
    Switch UBound($avArray, 0)
        Case 1

            ReDim $avArray[$iIndex_Max + 1]
            $avArray[$iIndex_Max] = $vAdd

        Case 2

        ; Get size of second dimension
        Local $iDim2 = UBound($avArray, 2)

        ; Redim the Array
        ReDim $avArray[$iIndex_Max + 1][$iDim2]

        ; Add new elements
        If IsArray($vAdd) Then
            ; Get size of Insert array
            Local $vAdd_Max = UBound($vAdd)