Jump to content
Sign in to follow this  
OldCodger

Drag/modify in listviews

Recommended Posts

OldCodger

Morning..

I have searched the forums high and low and can't find an answer to my issue.

I have two list views:

The source has 3 columns and the target has 5 columns.

I would like the capability to drag an item from source to target(which is easy) but modify the source item by adding a value to the start of the item and a value to the end of the item so it marries with the target listview columns...

..also the dropped modified item should be inserted at a row where the cursor is released in the target.

Any ideas?

Thanks.

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

My GUIListViewEx UDF will allow drag/drop action between ListViews, but I specifically limited it to ListViews with the same number of columns as it got all too difficult to manage otherwise. But feel free to plunder the existing code as much as you want - just do not expect me to amend the UDF! :D

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 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
OldCodger

OldCodger,

My GUIListViewEx UDF will allow drag/drop action between ListViews, but I specifically limited it to ListViews with the same number of columns as it got all too difficult to manage otherwise. But feel free to plunder the existing code as much as you want - just do not expect me to amend the UDF! :D

M23

 

I have had a play with that udf and although it's a peach, Melba(he he).. I can't suss how to use it for my issues.

I am learning AutoIT(slowly) but some things do me tree in.

Edited by Melba23
Fixed quote

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

Post what you have so far (at least a GUI with a couple of filled 3/5 column ListViews) and I will see what I can do. ;)

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 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
OldCodger

Ok.. this is the cut down version.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <StringConstants.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>

;Dim Globals
Global $blDragging = False, $hDragImage = 0, $hLwDragFrom = 0, $sInputSeason = "", $sInput17WS = ""

#region GUI
Global $hGUI = GUICreate("Test Listview drag", 900, 535)

;Input the target season code
GUICtrlCreateLabel("Season", 40, 430, 80, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iInputSeason = GUICtrlCreateInput("", 40, 450, 80, 20)

;Input Target item description
GUICtrlCreateLabel("Desc.", 130, 430, 80, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iInput17WS = GUICtrlCreateInput("", 130, 450, 80, 20)

;Define Source listview to recieve search results - 3 columns
GUICtrlCreateLabel("Source", 10, 105, 250, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iLwSource = GUICtrlCreateListView("Director|Manager|Buyer", 10, 125, 250, 300, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS))
Global $hLwSource = GUICtrlGetHandle($iLwSource)

For $i = 0 To 2
    _GUICtrlListView_SetColumnWidth($hLwSource, $i, 75)
Next

For $i = 0 To 16
    $item = _GUICtrlListView_AddItem($iLwSource, _makeJunkName())
    _GUICtrlListView_AddSubItem($iLwSource, $item, _makeJunkName(), 1)
    _GUICtrlListView_AddSubItem($iLwSource, $item, _makeJunkName(), 2)
Next

;Define Target listview to recieve segment selections - 5 columns
GUICtrlCreateLabel("Target", 400, 10, 300, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iLwTarget = GUICtrlCreateListView("Season|Director|Manager|Buyer|Description", 330, 30, 480, 395)
Global $hLwTarget = GUICtrlGetHandle($iLwTarget)
_GUICtrlListView_SetExtendedListViewStyle($hLwTarget, $LVS_EX_GRIDLINES)

For $i = 0 To 4
    _GUICtrlListView_SetColumnWidth($hLwTarget, $i, 92)
Next

For $i = 0 To 16
    $item = _GUICtrlListView_AddItem($iLwTarget, _makeJunkName())
    _GUICtrlListView_AddSubItem($iLwTarget, $item, _makeJunkName(), 1)
    _GUICtrlListView_AddSubItem($iLwTarget, $item, _makeJunkName(), 2)
    _GUICtrlListView_AddSubItem($iLwTarget, $item, _makeJunkName(), 3)
    _GUICtrlListView_AddSubItem($iLwTarget, $item, _makeJunkName(), 4)

Next

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUIRegisterMsg($WM_LBUTTONUP, "WM_LBUTTONUP")

GUISetState(@SW_SHOW, $hGUI)
#endregion GUI

;Main control loop
While 1
    Sleep(10)
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

GUIDelete($hGUI)

; Create a junk name for testing
Func _makeJunkName()
    Local $labelout = ''
    For $i = 1 To 10
        $labelout &= Chr(Random(65, 90, 1))
    Next
    Return $labelout
EndFunc   ;==>_makeJunkName

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam, $ilParam

    Local $tNMHDR = 0, $hWndFrom = 0, $iIDFrom = 0, $iCode = 0

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)

    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $iIDFrom
        Case $iLwSource
            Switch $iCode
                Case $LVN_BEGINDRAG

                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    Local $iItem = DllStructGetData($tInfo, "Item")

                    Local $aImageData = _GUICtrlListView_CreateDragImage($hWndFrom, $iItem)

                    $hDragImage = $aImageData[0]
                    _GUIImageList_BeginDrag($hDragImage, 0, -7, 3)

                    $hLwDragFrom = $hWndFrom

                    $blDragging = True

            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func WM_LBUTTONUP($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam, $ilParam

    If Not $blDragging Then Return $GUI_RUNDEFMSG


    _GUIImageList_DragLeave($hLwDragFrom)
    _GUIImageList_EndDrag()
    _GUIImageList_Destroy($hDragImage)

    Local $sInputSeason = GUICtrlRead($iInputSeason)
    Local $sInput17WS = GUICtrlRead($iInput17WS)
    Local $aNewCInfo = GUIGetCursorInfo($hGUI)

    ConsoleWrite("season = " & $sInputSeason & @CRLF)
    ConsoleWrite("desc = " & $sInput17WS & @CRLF)
    ConsoleWrite("dragging from " & $hLwDragFrom & @CRLF)
    ConsoleWrite("hwnd =  " & $hLwSource & @CRLF)
    ConsoleWrite("CInfo =  " & $aNewCInfo[4] & @CRLF)
    ConsoleWrite("Target =  " & $hLwTarget & @CRLF)

    ; If we are moving from source to target and we ARE in target box
    If $hLwDragFrom = $hLwSource And $aNewCInfo[4] = $iLwTarget AND($sInputSeason <> "" AND $sInput17WS <> "") Then

        ;#################################################################
        ;#Add season to the start and Description to end and then drag to cursor row on the target...
        ;################################################################
        _GUICtrlListView_CopyItems($hLwSource, $hLwTarget, 1)

    EndIf

    $blDragging = False

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_LBUTTONUP

Thanks..

Edit: Corrected error in code.

Edited by OldCodger

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

Got it - do not hold your breath! :D

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

OldCodger,

That was easier than I thought it might be. I have modifed the UDF so that will work for your specific case - you can drag/drop inside each ListView but you can only drag from the 3 column to the 5 column when it will add the contents of the 2 inputs fore and aft. :)

Here is your script as modified to initialise the ListViews and tell your UDF about the inputs:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <StringConstants.au3>
#include <GUIImageList.au3>

#include "OC.au3" ; <<<<<<<<<<<<<<<<<<<<<< Your UDF

;Dim Globals
Global $blDragging = False, $hDragImage = 0, $hLwDragFrom = 0, $sInputSeason = "", $sInput17WS = ""

#region GUI
Global $hGUI = GUICreate("Test Listview drag", 900, 535)

;Input the target season code
GUICtrlCreateLabel("Season", 40, 430, 80, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iInputSeason = GUICtrlCreateInput("Summer", 40, 450, 80, 20)

;Input Target item description
GUICtrlCreateLabel("Desc.", 130, 430, 80, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iInput17WS = GUICtrlCreateInput("Horrible", 130, 450, 80, 20)

; Tell the UDF about the inputs
_OC_Inputs($iInputSeason, $iInput17WS)

;Define Source listview to recieve search results - 3 columns
GUICtrlCreateLabel("Source", 10, 105, 250, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iLwSource = GUICtrlCreateListView("Director|Manager|Buyer", 10, 125, 250, 300, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS))
Global $hLwSource = GUICtrlGetHandle($iLwSource)

For $i = 0 To 2
    _GUICtrlListView_SetColumnWidth($hLwSource, $i, 75)
Next

For $i = 0 To 10
    GUICtrlCreateListViewItem(_makeJunkName($i) & "|" & _makeJunkName() & "|" & _makeJunkName(), $iLwSource)
Next

; Initialise this ListView
$aArray = _OC_ReadToArray($iLwSource)
$iSrc_Index = _OC_Init($iLwSource, $aArray)

;Define Target listview to recieve segment selections - 5 columns
GUICtrlCreateLabel("Target", 400, 10, 300, 20, $SS_CENTER)
GUICtrlSetFont(-1, 10, 800)
Global $iLwTarget = GUICtrlCreateListView("Season|Director|Manager|Buyer|Description", 330, 30, 480, 395)
Global $hLwTarget = GUICtrlGetHandle($iLwTarget)
_GUICtrlListView_SetExtendedListViewStyle($hLwTarget, $LVS_EX_GRIDLINES)

For $i = 0 To 4
    _GUICtrlListView_SetColumnWidth($hLwTarget, $i, 92)
Next

For $i = 0 To 10
    GUICtrlCreateListViewItem(_makeJunkName($i) & "|" & _makeJunkName() & "|" & _makeJunkName() & "|" & _makeJunkName() & "|" & _makeJunkName(), $iLwTarget)
Next

; Initialise this ListView
$aArray = _OC_ReadToArray($iLwTarget)
$iTgt_Index = _OC_Init($iLwTarget, $aArray)

; Register the various messages
_OC_MsgRegister()

GUISetState(@SW_SHOW, $hGUI)
#endregion GUI

;Main control loop
While 1
    Sleep(10)
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

GUIDelete($hGUI)

; Create a junk name for testing
Func _makeJunkName($sIndex = "")
    Local $labelout = $sIndex
    For $i = StringLen($sIndex) + 1 To 10
        $labelout &= Chr(Random(65, 90, 1))
    Next
    Return $labelout
EndFunc   ;==>_makeJunkName
And here is your UDF - save it as OC.au3: ;)

WARNING: Do not use this version of the UDF with any other script - it will crash for certain! :D

 

#include-once

; #INDEX# ============================================================================================================
; Title .........: GUIListViewEx
; AutoIt Version : 3.3 +
; Language ......: English
; Description ...: Permits insertion, deletion, moving, dragging, sorting and editing of items within activated ListViews
; Remarks .......: - It is important to use _OC_Close when a enabled ListView is deleted to free the memory used
;                    by the $aOC_Data array which shadows the ListView contents.
;                  - Windows message handlers required:
;                     - WM_NOTIFY: All UDF functions
;                     - WM_MOUSEMOVE and WM_LBUTTONUP: Dragging
;                  - If the script already has WM_NOTIFY, WM_MOUSEMOVE or WM_LBUTTONUPhandlers then only set unregistered
;                    messages in _OC_MsgRegister and call the relevant _OC_WM_#####_Handler
;                    from within the existing handler
;                  - Uses 2 undocumented functions within GUIListView UDF to set and colour insert mark (thanks rover)
;                  - If ListView editable, Opt("GUICloseOnESC") set to 0 as ESC = edit cancel.  Do not reset Opt in script
; Author ........: Melba23
; Credits .......: martin (basic drag code), Array.au3 authors (array functions), KaFu and ProgAndy (font function)
; ====================================================================================================================

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

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

; #GLOBAL VARIABLES# =================================================================================================
; Array to hold registered ListView data
Global $aOC_Data[1][12] = [[0, 0, -1]]
; [0][0] = Count            [n][0]  = ListView handle
; [0][1] = Active Index     [n][1]  = Native ListView ControlID / 0
; [0][2] = Active Column    [n][2]  = Shadow array
; [0][3] = Item Depth       [n][3]  = Shadow array count element (0/1) & 2D return (+ 2)
;                           [n][4]  = Sort status
;                           [n][5]  = Drag image flag
;                           [n][6]  = Checkbox array flag
;                           [n][7]  = Editable columns range
;                           [n][8]  = Editable header flag
;                           [n][9]  = Edit cursor active flag
;                           [n][10] = Item depth for scrolling
;                           [n][11] = Edit combo flag/data
; Variables for all UDF functions
Global $hOC_SrcHandle, $cOC_SrcID, $iOC_SrcIndex, $aOC_SrcArray
; Variables for UDF dragging handlers
Global $hOC_TgtHandle, $cOC_TgtID, $iOC_TgtIndex, $aOC_TgtArray
Global $iOC_Dragging = 0, $iOC_DraggedIndex, $hOC_DraggedImage = 0
Global $iOC_InsertIndex = -1, $iOC_LastY, $fOC_BarUnder
; Variables for UDF edit
Global $hOC_Editing, $cOC_EditID = 9999, $fOC_EditClickFlag = False, $fOC_HeaderEdit = False
; Variables for inputs
Global $aOC_Inputs[2]

; #CURRENT# ==========================================================================================================
; _OC_Init:                 Enables UDF functions for the ListView and sets various flags
; _OC_Close:                Disables all UDF functions for the specified ListView and clears all memory used
; _OC_SetActive:            Set specified ListView as active for UDF functions
; _OC_GetActive:            Get index number of ListView active for UDF functions
; _OC_ReadToArray:          Creates an array from the current ListView content to be loaded in _Init function
; _OC_ReturnArray:          Returns an array reflecting the current content of the ListView
; _OC_Insert:               Inserts data just below selected item in active ListView
; _OC_Delete:               Deletes selected item(s) in active ListView
; _OC_Up:                   Moves selected item(s) in active ListView up 1 row
; _OC_Down:                 Moves selected item(s) in active ListView down 1 row
; _OC_EditOnClick:          Edit ListView items in user-defined columns when doubleclicked
; _OC_EditItem:             Edit ListView items programatically
; _OC_EditHeader:           Edit ListView headers programatically
; _OC_ComboData:            Set data for edit combo
; _OC_MsgRegister:          Registers Windows messages required for the UDF
; _OC_WM_NOTIFY_Handler:    Windows message handler for WM_NOTIFY - needed for dall UDF functions
; _OC_WM_MOUSEMOVE_Handler: Windows message handler for WM_MOUSEMOVE - needed for drag
; _OC_WM_LBUTTONUP_Handler: Windows message handler for WM_LBUTTONUP - needed for drag
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _OC_ExpandCols:   Expands column ranges to list each column separately
; _OC_HighLight:    Highlights specified ListView item and ensures it is visible
; _OC_EditProcess:  Runs ListView editing process
; _OC_GetLVFont:    Gets font details for ListView to be edited
; _OC_EditCoords:   Ensures item in view then locates and sizes edit control
; _OC_ReWriteLV:    Deletes all ListView content and refills to match array
; _OC_GetLVCoords:  Gets screen coords for ListView
; _OC_GetCursorWnd: Gets handle of control under the mouse cursor
; _OC_Array_Add:    Adds a specified value at the end of an array
; _OC_Array_Insert: Adds a value at the specified index of an array
; _OC_Array_Delete: Deletes a specified index from an array
; _OC_Array_Swap:   Swaps specified elements within an array
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Init
; Description ...: Enables UDF functions for the ListView and sets various flags
; Syntax.........: _OC_Init($hLV, [$aArray = ""[, $iStart = 0[, $iColour[, $fImage[, $iAdded[, $sCols]]]]]])
; Parameters ....: $hLV     - Handle or ControlID of ListView
;                  $aArray  - Name of array used to fill ListView.  "" for empty ListView
;                  $iStart  - 0 = ListView data starts in [0] element of array (default)
;                             1 = Count in [0] element
;                  $iColour - RGB colour for insert mark (default = black)
;                  $fImage  - True  = Shadow image of dragged item when dragging
;                             False = No shadow image (default)
;                  $iAdded  - 0    - No added features (default).  To get added features add the following
;                             + 1  - Sortable by clicking on column headers
;                             + 2  - Edit control available when double clicking on a subitem in user-defined columns
;                             + 4  - Edit continues within same ListView by triple mouse-click (only if ListView editable)
;                             + 8  - Headers editable by Ctrl-click (only if ListView editable)
;                             + 16 - Left/right cursor active in edit - use Ctrl-arrow to move to next item (if set)
;                             + 32 - Combo control used for editing
;                  $sCols   - Editable columns - only used if Editable flag set in $iAdded
;                                 All columns: "*" (default)
;                                 Limit columns: example "1;2;5-6;8-9;10" - ranges expanded automatically
; 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
;                  - The $iStart parameter determines if a count element will be returned by other GUIListViewEx functions
;                  - The _OC_ReadToArray function will read an existing ListView into an array
;                  - Only first item of a multiple selection is shadow imaged when dragging (API limitation)
; Example........: Yes
;=====================================================================================================================
Func _OC_Init($hLV, $aArray = "", $iStart = 0, $iColour = 0, $fImage = False, $iAdded = 0, $sCols = "*")

    Local $iIndex = 0

    ; See if there is a blank line available in the array
    For $i = 1 To $aOC_Data[0][0]
        If $aOC_Data[$i][0] = 0 Then
            $iIndex = $i
            ExitLoop
        EndIf
    Next
    ; If no blank line found then increase array size
    If $iIndex = 0 Then
        $aOC_Data[0][0] += 1
        ReDim $aOC_Data[$aOC_Data[0][0] + 1][UBound($aOC_Data, 2)]
        $iIndex = $aOC_Data[0][0]
    EndIf

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

    ; Store ListView content in shadow array
    $aOC_Data[$iIndex][2] = _OC_ReadToArray($hLV, 1)

    ; Store array count flag
    $aOC_Data[$iIndex][3] = $iStart
    ; Store 1D/2D array return type flag
    If IsArray($aArray) Then
        If UBound($aArray, 0) = 2 Then $aOC_Data[$iIndex][3] += 2
    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 drag image required
    If $fImage Then
        $aOC_Data[$iIndex][5] = 1
    EndIf

    ; If sortable, store sort array
    If BitAND($iAdded, 1) Then
        Local $aLVSortState[_GUICtrlListView_GetColumnCount($hLV)]
        $aOC_Data[$iIndex][4] = $aLVSortState
    Else
        $aOC_Data[$iIndex][4] = 0
    EndIf
    ; If editable
    If BitAND($iAdded, 2) Then
        $aOC_Data[$iIndex][7] = _OC_ExpandCols($sCols)
        ; Limit ESC to edit cancel
        Opt("GUICloseOnESC", 0)
        ; If move edit by click add flag to valid col list
        If BitAND($iAdded, 4) Then
            $aOC_Data[$iIndex][7] &= ";#"
        EndIf
        ; If header editable on Ctrl-click set flag
        If BitAND($iAdded, 8) Then
            $aOC_Data[$iIndex][8] = 1
        EndIf
    Else
        $aOC_Data[$iIndex][7] = ""
    EndIf
    ; If Edit cursor
    If BitAND($iAdded, 16) Then
        $aOC_Data[$iIndex][9] = 1
    EndIf

    ; If Combo
    If BitAND($iAdded, 32) Then
        Local $aComboData_Array[_GUICtrlListView_GetColumnCount($hLV)]
        $aOC_Data[$iIndex][11] = $aComboData_Array
    EndIf

    ;  If checkbox extended style
    If BitAND(_GUICtrlListView_GetExtendedListViewStyle($hLV), 4) Then ; $LVS_EX_CHECKBOXES
        $aOC_Data[$iIndex][6] = 1
    EndIf

    ; Measure item depth for scroll - if empty reset when filled later
    Local $aRect = _GUICtrlListView_GetItemRect($aOC_Data[$iIndex][0], 0)
    $aOC_Data[$iIndex][10] =  $aRect[3] - $aRect[1]

    ; If only 1 current ListView then activate
    Local $iListView_Count = 0
    For $i = 1 To $iIndex
        If $aOC_Data[$i][0] Then $iListView_Count += 1
    Next
    If $iListView_Count = 1 Then _OC_SetActive($iIndex)

    ; Return ListView index
    Return $iIndex

EndFunc   ;==>_OC_Init

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Close
; Description ...: Disables all UDF functions for the specified ListView and clears all memory used
; Syntax.........: _OC_Close($iIndex)
; Parameters ....: $iIndex - Index number of ListView to close as returned by _OC_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 _OC_Close($iIndex = 0)

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

    If $iIndex = 0 Then
        ; Remove all ListView data
        Global $aOC_Data[1][UBound($aOC_Data, 2)] = [[0, 0]]
    Else
        ; Reset all data for ListView
        For $i = 0 To UBound($aOC_Data, 2) - 1
            $aOC_Data[$iIndex][$i] = 0
        Next

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

    Return 1

EndFunc   ;==>_OC_Close

Func _OC_Inputs($cCID_1, $cCID_2)
    $aOC_Inputs[0] = $cCID_1
    $aOC_Inputs[1] = $cCID_2
EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _OC_SetActive
; Description ...: Set specified ListView as active for UDF functions
; Syntax.........: _OC_SetActive($iIndex)
; Parameters ....: $iIndex - Index number of ListView as returned by _OC_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 _OC_SetActive($iIndex)

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

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

    If $iIndex Then
        ; Store index of specified ListView
        $aOC_Data[0][1] = $iIndex
        ; Set values for specified ListView
        $hOC_SrcHandle = $aOC_Data[$iIndex][0]
        $cOC_SrcID = $aOC_Data[$iIndex][1]
    Else
        ; Clear active index
        $aOC_Data[0][1] = 0
        $hOC_SrcHandle = 0
        $cOC_SrcID = 0
    EndIf

    Return $iCurr_Index

EndFunc   ;==>_OC_SetActive

; #FUNCTION# =========================================================================================================
; Name...........: _OC_GetActive
; Description ...: Get index number of ListView active for UDF functions
; Syntax.........: _OC_GetActive()
; Parameters ....: None
; Requirement(s).: v3.3 +
; Return values .: Success: Index number as returned by _OC_Init, 0 = no active ListView
; Author ........: Melba23
; Modified ......:
; Remarks .......:
; Example........: Yes
;=====================================================================================================================
Func _OC_GetActive()

    Return $aOC_Data[0][1]

EndFunc   ;==>_OC_GetActive

; #FUNCTION# =========================================================================================================
; Name...........: _OC_ReadToArray
; Description ...: Creates an array from the current ListView content to be loaded in _Init function
; Syntax.........: _OC_ReadToArray($hLV[, $iCount = 0])
; Parameters ....: $hLV    - ControlID or handle of ListView
;                  $iCount - 0 (default) = ListView data starts in [0] element of array, 1 = Count in [0] element
; Requirement(s).: v3.3 +
; Return values .: Success: 2D array of current ListView content
;                           Empty string if ListView empty and no count element
;                  Failure: Returns null string and sets @error as follows:
;                           1 = Invalid ListView ControlID or handle
; Author ........: Melba23
; Modified ......:
; Remarks .......: If returned array is used in _OC_Init the $iStart parameters must match in the 2 functions
; Example........: Yes
;=====================================================================================================================
Func _OC_ReadToArray($hLV, $iStart = 0)

    Local $aLVArray = "", $aRow

    ; Use the ListView handle
    If Not IsHWnd($hLV) Then
        $hLV = GUICtrlGetHandle($hLV)
        If Not IsHWnd($hLV) Then
            Return SetError(1, 0, "")
        EndIf
    EndIf
    ; Get ListView row count
    Local $iRows = _GUICtrlListView_GetItemCount($hLV)
    ; Check for empty ListView with no count
    If $iRows + $iStart <> 0 Then
        ; Get ListView column count
        Local $iCols = _GUICtrlListView_GetColumnCount($hLV)
        ; Create 2D array to hold ListView content and add count - count overwritten if not needed
        Local $aLVArray[$iRows + $iStart][$iCols] = [[$iRows]]
        ; Read ListView content into array
        For $i = 0 To $iRows - 1
            ; Read the row content
            $aRow = _GUICtrlListView_GetItemTextArray($hLV, $i)
            For $j = 1 To $aRow[0]
                ; Add to the ListView content array
                $aLVArray[$i + $iStart][$j - 1] = $aRow[$j]
            Next
        Next
    EndIf
    ; Return array or empty string
    Return $aLVArray

EndFunc   ;==>_OC_ReadToArray

; #FUNCTION# =========================================================================================================
; Name...........: _OC_ReturnArray
; Description ...: Returns an array reflecting the current content of an activated ListView
; Syntax.........: _OC_ReturnArray($iIndex[, $iCheck])
; Parameters ....: $iIndex - Index number of ListView as returned by _OC_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 content - _OC_Init parameters determine:
;                               Whether count in top element - $iStart = 0/1
;                               1D/2D array type - same as $aArray
;                                   If no array passed then single col => 1D; multiple column => 2D
;                  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 .......:
; Example........: Yes
;=====================================================================================================================
Func _OC_ReturnArray($iIndex, $iCheck = 0)

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

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

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

    ; Remove count element of array if required
    Local $iCount = 1
    If BitAND($aOC_Data[$iIndex][3], 1) = 0 Then
        $iCount = 0
        ; Check at least one entry in array
        If $aRetArray[0][0] = 0 Then Return SetError(2, 0, "")
        ; Delete count element
        _OC_Array_Delete($aRetArray, 0)
    EndIf

    ; Now check if 1D array to be returned
    If BitAND($aOC_Data[$iIndex][3], 2) = 0 Then
        ; Get number of 2D elements
        Local $iCols = UBound($aRetArray, 2)
        ; Create 1D array - count will be overwritten if not needed
        Local $aTempArray[UBound($aRetArray)] = [$aRetArray[0][0]]
        ; Fill with concatenated lines
        For $i = $iCount To UBound($aTempArray) - 1
            Local $aLine = ""
            For $j = 0 To $iCols - 1
                $aLine &= $aRetArray[$i][$j] & "|"
            Next
            $aTempArray[$i] = StringTrimRight($aLine, 1)
        Next
        $aRetArray = $aTempArray
    EndIf

    ; Return array
    Return $aRetArray

EndFunc   ;==>_OC_ReturnArray

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Insert
; Description ...: Inserts data just below selected item in active ListView - if no selection, data added at end
; Syntax.........: _OC_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 data is added at
;                  the end of the ListView.  If multiple items are selected, the data is inserted after the first
;                  - $vData can be passed in string or array format - it is automatically transformed if required
; Example........: Yes
;=====================================================================================================================
Func _OC_Insert($vData)

    Local $vInsert

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

    ; Load active ListView details
    $hOC_SrcHandle = $aOC_Data[$iArray_Index][0]
    $cOC_SrcID = $aOC_Data[$iArray_Index][1]

    ; Copy array for manipulation
    $aOC_SrcArray = $aOC_Data[$iArray_Index][2]

    ; Create Local array for checkboxes (if no checkboxes makes no difference)
    Local $aCheck_Array[UBound($aOC_SrcArray)]
    For $i = 1 To UBound($aCheck_Array) - 1
        $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
    Next

    ; Get selected item in ListView
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hOC_SrcHandle)

    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($hOC_SrcHandle, $aIndex[$i], False)
        Next
    EndIf

    ; If empty array insert at 0
    If $aOC_SrcArray[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 + 1]
                Next
        EndSwitch
    EndIf
    ; Increase count
    $aOC_SrcArray[0][0] += 1

    ; Insert data into arrays
    If $iIndex = "" Then
        _OC_Array_Add($aOC_SrcArray, $vInsert)
        _OC_Array_Add($aCheck_Array, False)
    Else
        _OC_Array_Insert($aOC_SrcArray, $iInsert_Index + 2, $vInsert)
        _OC_Array_Insert($aCheck_Array, $iInsert_Index + 2, False)
    EndIf

    ; Rewrite ListView
    _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aCheck_Array, $iArray_Index)

    ; Set highlight
    If $iIndex = "" Then
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, _GUICtrlListView_GetItemCount($hOC_SrcHandle) - 1)
    Else
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iInsert_Index + 1)
    EndIf

    ; Store amended array
    $aOC_Data[$iArray_Index][2] = $aOC_SrcArray
    ; Delete copied array
    $aOC_SrcArray = 0
    ; Return amended array
    Return _OC_ReturnArray($iArray_Index)

EndFunc   ;==>_OC_Insert

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Delete
; Description ...: Deletes selected item(s) in active ListView
; Syntax.........: _OC_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 _OC_Delete()

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

    ; Load active ListView details
    $hOC_SrcHandle = $aOC_Data[$iArray_Index][0]
    $cOC_SrcID = $aOC_Data[$iArray_Index][1]

    ; Copy array for manipulation
    $aOC_SrcArray = $aOC_Data[$iArray_Index][2]

    ; Create Local array for checkboxes (if no checkboxes makes no difference)
    Local $aCheck_Array[UBound($aOC_SrcArray)]
    For $i = 1 To UBound($aCheck_Array) - 1
        $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
    Next

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

    ; Extract all selected items
    Local $aIndex = StringSplit($iIndex, "|")
    For $i = 1 To $aIndex[0]
        ; Remove highlighting from items
        _GUICtrlListView_SetItemSelected($hOC_SrcHandle, $i, False)
    Next

    ; Decrease count
    $aOC_SrcArray[0][0] -= $aIndex[0]

    Local $aCheck_Array[UBound($aOC_SrcArray)]
    For $i = 1 To UBound($aCheck_Array) - 1
        $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
    Next

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

    ; Rewrite ListView
    _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aCheck_Array, $iArray_Index)

    ; Set highlight
    If $aIndex[1] = 0 Then
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, 0)
    Else
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $aIndex[1] - 1)
    EndIf

    ; Store amended array
    $aOC_Data[$iArray_Index][2] = $aOC_SrcArray
    ; Delete copied array
    $aOC_SrcArray = 0
    ; Return amended array
    Return _OC_ReturnArray($iArray_Index)

EndFunc   ;==>_OC_Delete

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Up
; Description ...: Moves selected item(s) in active ListView up 1 row
; Syntax.........: _OC_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 top consecutive block is moved
; Example........: Yes
;=====================================================================================================================
Func _OC_Up()

    Local $iGLVExMove_Index, $iOC_Moving = 0

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

    ; Load active ListView details
    $hOC_SrcHandle = $aOC_Data[$iArray_Index][0]
    $cOC_SrcID = $aOC_Data[$iArray_Index][1]

    ; Copy array for manipulation
    $aOC_SrcArray = $aOC_Data[$iArray_Index][2]

    ; Create Local array for checkboxes (if no checkboxes makes no difference)
    Local $aCheck_Array[UBound($aOC_SrcArray)]
    For $i = 1 To UBound($aCheck_Array) - 1
        $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
    Next

    ; Check for selected items
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hOC_SrcHandle)
    If $iIndex = "" Then
        Return SetError(2, 0, "")
    EndIf
    Local $aIndex = StringSplit($iIndex, "|")
    $iGLVExMove_Index = $aIndex[1]
    ; Check if item is part of a multiple selection
    If $aIndex[0] > 1 Then
        ; Check for consecutive items
        For $i = 1 To $aIndex[0] - 1
            If $aIndex[$i + 1] = $aIndex[1] + $i Then
                $iOC_Moving += 1
            Else
                ExitLoop
            EndIf
        Next
    Else
        $iGLVExMove_Index = $aIndex[1]
    EndIf

    ; Check not top item
    If $iGLVExMove_Index < 1 Then
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, 0)
        Return SetError(3, 0, "")
    EndIf

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

    ; Move consecutive items
    For $iIndex = $iGLVExMove_Index To $iGLVExMove_Index + $iOC_Moving
        ; Swap array elements
        _OC_Array_Swap($aOC_SrcArray, $iIndex, $iIndex + 1)
        _OC_Array_Swap($aCheck_Array, $iIndex, $iIndex + 1)
    Next

    ; Rewrite ListView
    _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aCheck_Array, $iArray_Index)

    ; Set highlight
    For $i = 0 To $iOC_Moving
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iGLVExMove_Index + $i - 1)
    Next

    ; Store amended array
    $aOC_Data[$iArray_Index][2] = $aOC_SrcArray
    ; Delete copied array
    $aOC_SrcArray = 0
    ; Return amended array
    Return _OC_ReturnArray($iArray_Index)

EndFunc   ;==>_OC_Up

; #FUNCTION# =========================================================================================================
; Name...........: _OC_Down
; Description ...: Moves selected item(s) in active ListView down 1 row
; Syntax.........: _OC_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 bottom consecutive block is moved
; Example........: Yes
;=====================================================================================================================
Func _OC_Down()

    Local $iGLVExMove_Index, $iOC_Moving = 0

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

    ; Load active ListView details
    $hOC_SrcHandle = $aOC_Data[$iArray_Index][0]
    $cOC_SrcID = $aOC_Data[$iArray_Index][1]

    ; Copy array for manipulation
    $aOC_SrcArray = $aOC_Data[$iArray_Index][2]

    ; Create Local array for checkboxes (if no checkboxes makes no difference)
    Local $aCheck_Array[UBound($aOC_SrcArray)]
    For $i = 1 To UBound($aCheck_Array) - 1
        $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
    Next

    ; Check for selected items
    Local $iIndex = _GUICtrlListView_GetSelectedIndices($hOC_SrcHandle)
    If $iIndex = "" Then
        Return SetError(2, 0, "")
    EndIf
    Local $aIndex = StringSplit($iIndex, "|")
    ; Check if item is part of a multiple selection
    If $aIndex[0] > 1 Then
        $iGLVExMove_Index = $aIndex[$aIndex[0]]
        ; Check for consecutive items
        For $i = 1 To $aIndex[0] - 1
            If $aIndex[$aIndex[0] - $i] = $aIndex[$aIndex[0]] - $i Then
                $iOC_Moving += 1
            Else
                ExitLoop
            EndIf
        Next
    Else
        $iGLVExMove_Index = $aIndex[1]
    EndIf

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

    ; Check not last item
    If $iGLVExMove_Index = _GUICtrlListView_GetItemCount($hOC_SrcHandle) - 1 Then
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iIndex)
        Return SetError(3, 0, "")
    EndIf

    ; Move consecutive items
    For $iIndex = $iGLVExMove_Index To $iGLVExMove_Index - $iOC_Moving Step -1
        ; Swap array elements
        _OC_Array_Swap($aOC_SrcArray, $iIndex + 1, $iIndex + 2)
        _OC_Array_Swap($aCheck_Array, $iIndex + 1, $iIndex + 2)
    Next

    ; Rewrite ListView
    _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aCheck_Array, $iArray_Index)

    ; Set highlight
    For $i = 0 To $iOC_Moving
        _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iGLVExMove_Index - $iOC_Moving + $i + 1)
    Next

    ; Store amended array
    $aOC_Data[$iArray_Index][2] = $aOC_SrcArray
    ; Delete copied array
    $aOC_SrcArray = 0
    ; Return amended array
    Return _OC_ReturnArray($iArray_Index)

EndFunc   ;==>_OC_Down

; #FUNCTION# =========================================================================================================
; Name...........: _OC_EditOnClick
; Description ...: Edit ListView items and headers in user-defined columns when doubleclicked
; Syntax.........: _OC_EditOnClick([$iEditMode = 0[, $iDelta_X = 0[, $iDelta_Y = 0]]])
; Parameters ....: $iEditMode - Only used if using Edit control:
;                                    Return after single edit - 0 (default)
;                                    {TAB} and arrow keys move to next item - 2-digit code (row mode/column mode)
;                                        1 = Reaching edge terminates edit process
;                                        2 = Reaching edge remains in place
;                                        3 = Reaching edge loops to opposite edge
;                                        Positive value = ESC abandons current edit only, previous edits remain
;                                        Negative value = ESC resets all edits in current session
;                               Ignored if using Combo control - return after single edit
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3 +
; Return values .: If no double-click: Empty string
;                  After double-click on ListView item:
;                      2D array of [row][column] items edited (both zero-based) - total edits in [0][0]
;                  After double-click just above ListView header:
;                      2D array  [column edited][new header text]
;                  Failure: Sets @error as follows:
;                      1 - ListView not editable
;                      2 - Empty ListView
;                      3 - Column not editable
; Author ........: Melba23
; Modified ......:
; Remarks .......: This function must be placed within the script idle loop.
;                  Edit control depends on _OC_Init $iAdded parameter:
;                      + 2  = Element editable - default edit control
;                      + 32 = Combo control used for editing
;                  Once item edit process started, all other script activity is suspended until following occurs:
;                      {ENTER}  = Current edit confirmed and editing process ended
;                      {ESCAPE} = Current or all edits cancelled and editing process ended
;                      If using Edit control:
;                          If $iEditMode non-zero then {TAB} and arrow keys = Current edit confirmed & continue editing
;                          Click outside edit = Editing process ends and
;                              If $iAdded + 4 : Current edit accepted
;                              Else :           Current edit cancelled
;                      If using Combo control:
;                          Combo actioned     = Combo selection accepted and editing process ended
;                          Click outside edit = Edit process ended and editing process ended
;                  For header edit only {ENTER}, {ESCAPE} and mouse click are actioned - single edit only
;                  The function only returns an array after an edit process launched by a double-click.  If no
;                  double-click has occurred, the function returns an empty string.  The user should check that a
;                  valid array is present before attempting to access it.
;                  If header edited [0][1] element of returned array exists - if items edited this element is empty
; Example........: Yes
;=====================================================================================================================
Func _OC_EditOnClick($iEditMode = 0, $iDelta_X = 0, $iDelta_Y = 0)

    Local $aEdited, $iError

    ; If an item was double clicked
    If $fOC_EditClickFlag Then

        ; Clear flag
        $fOC_EditClickFlag = False

        ; Check Type parameter
        Switch Abs($iEditMode)
            Case 0, 11, 12, 13, 21, 22, 23, 31, 32, 33 ; Single edit or both axes set to valid parameter
                ; Allow
            Case Else
                Return SetError(1, 0, "")
        EndSwitch

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

        ; Get clicked item info
        Local $aLocation = _GUICtrlListView_SubItemHitTest($hOC_SrcHandle)
        ; Check valid row
        If $aLocation[0] = -1 Then
            Return SetError(3, 0, "")
        EndIf

        ; Get valid column string
        Local $sCols = $aOC_Data[$iLV_Index][7]
        ; And validate selected column
        If Not StringInStr($sCols, "*") Then
            If Not StringInStr(";" & $sCols, ";" & $aLocation[1]) Then
                Return SetError(1, 0, "")
            EndIf
        EndIf

        ; Start edit
        $aEdited = _OC_EditProcess($iLV_Index, $aLocation, $sCols, $iDelta_X, $iDelta_Y, $iEditMode)
        $iError = @error
        ; Return result array
        Return SetError($iError, 0, $aEdited)

    EndIf

    ; If a header was double clicked
    If $fOC_HeaderEdit Then

        ; Clear the flag
        $fOC_HeaderEdit = False

        ; Wait until mouse button released as click occurs outside the control
        While _WinAPI_GetAsyncKeyState(0x01)
            Sleep(10)
        WEnd

        ; Edit header using the default values set by the handler
        $aEdited = _OC_EditHeader()
        $iError = @error
        ; Return result
        Return SetError($iError, 0, $aEdited)

    EndIf

    ; If nothing was clicked
    Return ""

EndFunc   ;==>_OC_EditOnClick

; #FUNCTION# =========================================================================================================
; Name...........: _OC_EditItem
; Description ...: Edit ListView items programatically
; Syntax.........: _OC_EditItem($iLV_Index, $iRow, $iCol[, $iEditMode = 0[, $iDelta_X = 0[, $iDelta_Y = 0]]])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _OC_Init
;                  $iRow      - Zero-based row of item to edit
;                  $iCol      - Zero-based column of item to edit
;                  $iEditMode - Only used if using Edit control:
;                                    Return after single edit - 0 (default)
;                                    {TAB} and arrow keys move to next item - 2-digit code (row mode/column mode)
;                                        1 = Reaching edge terminates edit process
;                                        2 = Reaching edge remains in place
;                                        3 = Reaching edge loops to opposite edge
;                                        Positive value = ESC abandons current edit only, previous edits remain
;                                        Negative value = ESC resets all edits in current session
;                               Ignored if using Combo control - return after single edit
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3 +
; Return values .: Success: 2D array of zero-based [row][column] items edited - total number of edits in [0][0] element
;                  Failure: Sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - ListView not editable
;                           3 - Invalid row
;                           4 - Invalid column
;                           5 - Invalid edit mode
; Author ........: Melba23
; Modified ......:
; Remarks .......: Once edit started, all other script activity is suspended until following occurs:
;                      {ENTER}  = Current edit confirmed and editing ended
;                      {ESCAPE} = Current edit cancelled and editing ended
;                      If $iEditMode non-zero then {TAB} and arrow keys = Current edit confirmed continue editing
;                      Click outside edit = Editing process ends and
;                          If $iAdded + 4 : Current edit accepted
;                          Else :           Current edit cancelled
; Example........: Yes
;=====================================================================================================================
Func _OC_EditItem($iLV_Index, $iRow, $iCol, $iEditMode = 0, $iDelta_X = 0, $iDelta_Y = 0)

    ; Activate the ListView
    _OC_SetActive($iLV_Index)
    If @error Then
        Return SetError(1, 0, "")
    EndIf
    ; Check ListView is editable
    If $aOC_Data[$iLV_Index][7] = "" Then
        Return SetError(2, 0, "")
    EndIf
    ; Check row and col values
    Local $iMax = _GUICtrlListView_GetItemCount($hOC_SrcHandle)
    If $iRow < 0 Or $iRow > $iMax - 1 Then
        Return SetError(3, 0, "")
    EndIf
    $iMax = _GUICtrlListView_GetColumnCount($hOC_SrcHandle)
    If $iCol < 0 Or $iCol > $iMax - 1 Then
        Return SetError(4, 0, "")
    EndIf
    ; Check edit mode parameter
    Switch Abs($iEditMode)
        Case 0, 11, 12, 13, 21, 22, 23, 31, 32, 33 ; Single edit or both axes set to valid parameter
            ; Allow
        Case Else
            Return SetError(5, 0, "")
    EndSwitch

    ; Declare location array
    Local $aLocation[2] = [$iRow, $iCol]
    ; Load valid column string
    Local $sValidCols = $aOC_Data[$iLV_Index][7]
    ; Start edit
    Local $aEdited = _OC_EditProcess($iLV_Index, $aLocation, $sValidCols, $iDelta_X, $iDelta_Y, $iEditMode)
    ; Return result array
    Return $aEdited

EndFunc   ;==>_OC_EditItem

; #FUNCTION# =========================================================================================================
; Name...........: _OC_EditHeader($iLV_Index = Default, $iCol = Default, $iDelta_X = 0, $iDelta_Y = 0)
; Description ...: Edit ListView headers programatically
; Syntax.........: _OC_EditHeader([$iLV_Index = Default[, $iCol = Default[, $iDelta_X = 0[, $iDelta_Y = 0]]]])
; Parameters ....: $iLV_Index - Index number of ListView as returned by _OC_Init - default active ListView
;                  $iCol      - Zero-based column of header to edit
;                  $iDelta_X  - Permits fine adjustment of edit control in X axis if needed
;                  $iDelta_Y  - Permits fine adjustment of edit control in Y axis if needed
; Requirement(s).: v3.3 +
; Return values .: Success: Array: 2D array [column][new text]
;                  Failure: Empty string and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - ListView not editable
;                           3 - Invalid column
; Author ........: Melba23
; Modified ......:
; Remarks .......: Once edit started, all other script activity is suspended until following occurs:
;                      {ENTER}  = Current edit confirmed and editing ended
;                      {ESCAPE} or click on other control = Current edit cancelled and editing ended
; Example........: Yes
;=====================================================================================================================
Func _OC_EditHeader($iLV_Index = Default, $iCol = Default, $iDelta_X = 0, $iDelta_Y = 0)

    Local $aRet = ""

    If $iLV_Index = Default Then
        $iLV_Index = $aOC_Data[0][1]
    EndIf

    ; Activate the ListView
    _OC_SetActive($iLV_Index)
    If @error Then
        Return SetError(1, 0, $aRet)
    EndIf

    Local $hLV_Handle = $aOC_Data[$iLV_Index][0]
    Local $cLV_CID = $aOC_Data[$iLV_Index][1]

    ; Check ListView is editable
    If $aOC_Data[$iLV_Index][7] = "" Then
        Return SetError(2, 0, $aRet)
    EndIf
    ; Check col value
    If $iCol = Default Then
        $iCol = $aOC_Data[0][2]
    EndIf
    Local $iMax = _GUICtrlListView_GetColumnCount($hLV_Handle)
    If $iCol < 0 Or $iCol > $iMax - 1 Then
        Return SetError(3, 0, $aRet)
    EndIf

    Local $tPoint = DllStructCreate("struct;long X;long Y;endstruct")
    ; Get position of ListView within GUI client area
    _OC_GetLVCoords($hLV_Handle, $tPoint)
    ; Get ListView client area to allow for scrollbars
    Local $aLVClient = WinGetClientSize($hLV_Handle)
    ; Get ListView font details
    Local $aLV_FontDetails = _OC_GetLVFont($hLV_Handle)
    ; Disable ListView
    WinSetState($hLV_Handle, "", @SW_DISABLE)
    ; Read current text of header
    Local $aHeader_Data = _GUICtrlListView_GetColumn($hLV_Handle, $iCol)
    Local $sHeaderOrgText = $aHeader_Data[5]
    ; Get required edit coords for 0 item
    Local $aLocation[2] = [0, $iCol]
    Local $aEdit_Coords = _OC_EditCoords($hLV_Handle, $cLV_CID, $aLocation, $tPoint, $aLVClient[0] - 5, $iDelta_X, $iDelta_Y)
    ; Now get header size and adjust coords for header
    Local $hHeader = _GUICtrlListView_GetHeader($hLV_Handle)
    Local $aHeader_Pos = WinGetPos($hHeader)
    $aEdit_Coords[0] -= 2
    $aEdit_Coords[1] -= $aHeader_Pos[3]
    $aEdit_Coords[3] = $aHeader_Pos[3]
    ; Create temporary edit - get handle, set font size, give keyboard focus and select all text
    $cOC_EditID = GUICtrlCreateEdit($sHeaderOrgText, $aEdit_Coords[0], $aEdit_Coords[1], $aEdit_Coords[2], $aEdit_Coords[3], 0)
    Local $hTemp_Edit = GUICtrlGetHandle($cOC_EditID)
    GUICtrlSetFont($cOC_EditID, $aLV_FontDetails[0], Default, Default, $aLV_FontDetails[1])
    GUICtrlSetState($cOC_EditID, 256) ; $GUI_FOCUS
    GUICtrlSendMsg($cOC_EditID, 0xB1, 0, -1) ; $EM_SETSEL
    ; Valid keys to action (ENTER, ESC)
    Local $aKeys[2] = [0x0D, 0x1B]
    ; Clear key code flag
    Local $iKey_Code = 0
    ; Wait for a key press
    While 1
        ; Check for valid key or mouse button pressed
        For $i = 0 To 1
            If _WinAPI_GetAsyncKeyState($aKeys[$i]) Then
                ; Set key pressed flag
                $iKey_Code = $aKeys[$i]
                ExitLoop 2
            EndIf
        Next
        ; Temp input loses focus
        If _WinAPI_GetFocus() <> $hTemp_Edit Then
            ExitLoop
        EndIf
        ; If edit moveable by click then check for mouse pressed outside edit
        If _WinAPI_GetAsyncKeyState(0x01) Then
            Local $aCInfo = GUIGetCursorInfo()
            If $aCInfo[4] <> $cOC_EditID Then
                $iKey_Code = 0x01
                ExitLoop
            EndIf
        EndIf
        ; Save CPU
        Sleep(10)
    WEnd
    ; Action keypress
    Switch $iKey_Code
        Case 0x0D
            ; Change column header text
            Local $sHeaderNewText = GUICtrlRead($cOC_EditID)
            If $sHeaderNewText <> $sHeaderOrgText Then
                _GUICtrlListView_SetColumn($hLV_Handle, $iCol, $sHeaderNewText)
                Local $aRet[1][2] = [[$iCol, $sHeaderNewText]]
            EndIf
    EndSwitch
    ; Delete Edit
    GUICtrlDelete($cOC_EditID)
    ; Reenable ListView
    WinSetState($hLV_Handle, "", @SW_ENABLE)

    Return $aRet

EndFunc   ;==>_OC_EditHeader

; #FUNCTION# =========================================================================================================
; Name...........: _OC_ComboData
; Description ...: Set data for edit combo
; Syntax.........: _OC_ComboData($iLV_Index, $iCol, $vData, $fRead_Only = False)
; Parameters ....: $iLV_Index  - Index number of ListView as returned by _OC_Init - default active ListView
;                  $iCol       - Column of ListView to show this data.  Use -1 for all columns
;                  $vData      - Content of combo - either delimited string or 0-based array
;                  $fRead_Only - Whether combo is readonly - default editable
; Requirement(s).: v3.3 +
; Return values .: Success: 1
;                  Failure: 0 and sets @error as follows:
;                           1 - Invalid ListView Index
;                           2 - Combo not enabled
;                           3 - Invalid column parameter
; Author ........: Melba23
; Modified ......:
; Remarks .......: Once edit started, all other script activity is suspended until following occurs:
;                      Combo selection made or {ENTER} = Current edit confirmed and editing ended
;                      {ESCAPE} or click on other control = Current edit cancelled and editing ended
; Example........: Yes
;=====================================================================================================================
Func _OC_ComboData($iIndex, $iCol, $vData, $fRead_Only = False)

    ; Check valid index
    If $iIndex < 1 Or $iIndex > $aOC_Data[0][0] Then
        Return SetError(1, 0, 0)
    EndIf
    ; Check if combo enabled
    If Not IsArray($aOC_Data[$iIndex][11]) Then
        Return SetError(2, 0, 0)
    EndIf
    ; Check if valid col
    If $iCol < -1 Or $iCol > _GUICtrlListView_GetColumnCount($aOC_Data[$iIndex][0]) - 1 Then
        Return SetError(3, 0, 0)
    EndIf
    ; Extract array
    Local $aComboData_Array = $aOC_Data[$iIndex][11]
    ; Clear current combo data
    If $iCol = -1 Then
        For $i = 0 To UBound($aComboData_Array) - 1
            $aComboData_Array[$i] = ""
        Next
    Else
        $aComboData_Array[$iCol] = ""
    EndIf
    Local $sCombo_Data = ""
    ; If array passed
    If IsArray($vData) Then
        ; Loop through at create delimited string
        For $i = 0 To UBound($vData) - 1
            $sCombo_Data &= "|" & $vData[$i]
        Next
    Else
        ; Check for leading |
        If StringLeft($vData, 1) <> "|" Then
            $sCombo_Data = "|" & $vData
        EndIf
    EndIf
    ; Set readonly flag if required
    If $fRead_Only Then
        $sCombo_Data = "#" & $sCombo_Data
    EndIf
    ; Set new value into array
    If $iCol = -1 Then
        For $i = 0 To UBound($aComboData_Array) - 1
            $aComboData_Array[$i] = $sCombo_Data
        Next
    Else
        $aComboData_Array[$iCol] = $sCombo_Data
    EndIf
    ; Store array
    $aOC_Data[$iIndex][11] = $aComboData_Array
    ; Show success
    Return 1

EndFunc

; #FUNCTION# =========================================================================================================
; Name...........: _OC_MsgRegister
; Description ...: Registers Windows messages required for the UDF
; Syntax.........: _OC_MsgRegister([$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 message handlers already registered, then call the relevant handler function from within that handler
;                  WM_NOTIFY handler required for all UDF functions
;                  WM_MOUSEMOVE and WM_LBUTTONUP handlers required for drag
; Example........: Yes
;=====================================================================================================================
Func _OC_MsgRegister($fNOTIFY = True, $fMOUSEMOVE = True, $fLBUTTONUP = True)

    ; Register required messages
    If $fNOTIFY    Then GUIRegisterMsg(0x004E, "_OC_WM_NOTIFY_Handler")    ; $WM_NOTIFY
    If $fMOUSEMOVE Then GUIRegisterMsg(0x0200, "_OC_WM_MOUSEMOVE_Handler") ; $WM_MOUSEMOVE
    If $fLBUTTONUP Then GUIRegisterMsg(0x0202, "_OC_WM_LBUTTONUP_Handler") ; $WM_LBUTTONUP

EndFunc   ;==>_OC_MsgRegister

; #FUNCTION# =========================================================================================================
; Name...........: _OC_WM_NOTIFY_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _OC_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 _OC_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

    ; Check if enabled ListView
    For $iLV_Index = 1 To $aOC_Data[0][0]
        If DllStructGetData($tStruct, 1) = $aOC_Data[$iLV_Index][0] Then
            ExitLoop
        EndIf
    Next
    If $iLV_Index > $aOC_Data[0][0] Then Return ; Not enabled

    Local $iCode = BitAND(DllStructGetData($tStruct, 3), 0xFFFFFFFF)
    Switch $iCode

        Case $LVN_BEGINSCROLL
            ; if editing then abandon
            If $cOC_EditID <> 9999 Then
                ; Delete temp edit control and set placeholder
                GUICtrlDelete($cOC_EditID)
                $cOC_EditID = 9999
                ; Reactivate ListView
                WinSetState($hOC_Editing, "", @SW_ENABLE)
            EndIf

        Case $LVN_COLUMNCLICK, -2 ; $NM_CLICK

            ; Set values for active ListView
            $aOC_Data[0][1] = $iLV_Index
            $hOC_SrcHandle = $aOC_Data[$iLV_Index][0]
            $cOC_SrcID = $aOC_Data[$iLV_Index][1]
            ; Get column index
            Local $iCol = DllStructGetData($tStruct, 5)
            ; Store it
            $aOC_Data[0][2] = $iCol

            ; If a column was clicked
            If $iCode = $LVN_COLUMNCLICK Then
                ; Scroll column into view
                ; Get X coord of first item in column
                Local $aRect = _GUICtrlListView_GetSubItemRect($hOC_SrcHandle, 0, $iCol)
                ; Get col width
                Local $aLV_Pos = WinGetPos($hOC_SrcHandle)
                ; Scroll to left edge if all column not in view
                If $aRect[0] < 0 Or $aRect[2] > $aLV_Pos[2] - 17 Then
                    _GUICtrlListView_Scroll($hOC_SrcHandle, $aRect[0], 0)
                EndIf

                ; Look for Ctrl key pressed
                _WinAPI_GetAsyncKeyState(0x11) ; Needed to avoid double setting
                If _WinAPI_GetAsyncKeyState(0x11) Then
                    ; Load valid column string
                    Local $sValidCols = $aOC_Data[$iLV_Index][7]
                    ; Check column is editable
                    If StringInStr($sValidCols, "*") Or StringInStr(";" & $sValidCols, ";" & $iCol) Then
                        ; Set header edit flag
                        $fOC_HeaderEdit = True
                    EndIf

                Else
                    ; If ListView sortable
                    If IsArray($aOC_Data[$iLV_Index][4]) Then
                        ; Load array
                        $aOC_SrcArray = $aOC_Data[$iLV_Index][2]
                        ; Load current ListView sort state array
                        Local $aLVSortState = $aOC_Data[$aOC_Data[0][0]][4]
                        ; Sort column - get column from from struct
                        _GUICtrlListView_SimpleSort($hOC_SrcHandle, $aLVSortState, $iCol)
                        ; Store new ListView sort state array
                        $aOC_Data[$aOC_Data[0][0]][4] = $aLVSortState
                        ; Reread listview items into array
                        Local $iDim2 = UBound($aOC_SrcArray, 2) - 1
                        For $j = 1 To $aOC_SrcArray[0][0]
                            For $k = 0 To $iDim2
                                $aOC_SrcArray[$j][$k] = _GUICtrlListView_GetItemText($hOC_SrcHandle, $j - 1, $k)
                            Next
                        Next
                        ; Store amended array
                        $aOC_Data[$iLV_Index][2] = $aOC_SrcArray
                        ; Delete array
                        $aOC_SrcArray = 0
                    EndIf
                EndIf
            EndIf

        Case $LVN_BEGINDRAG

            ; Set values for this ListView
            $aOC_Data[0][1] = $iLV_Index

            ; Store source & target ListView data for eventual inter-LV drag
            $hOC_SrcHandle = $aOC_Data[$iLV_Index][0]
            $cOC_SrcID = $aOC_Data[$iLV_Index][1]
            $iOC_SrcIndex = $iLV_Index
            $aOC_SrcArray = $aOC_Data[$iLV_Index][2]
            $hOC_TgtHandle = $hOC_SrcHandle
            $cOC_TgtID = $cOC_SrcID
            $iOC_TgtIndex = $iOC_SrcIndex
            $aOC_TgtArray = $aOC_SrcArray

            ; Copy array for manipulation
            $aOC_SrcArray = $aOC_Data[$iLV_Index][2]

            ; Set drag image flag
            Local $fImage = $aOC_Data[$iLV_Index][5]

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

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

            ; Check for selected items
            Local $iIndex = _GUICtrlListView_GetSelectedIndices($hOC_SrcHandle)
            ; Check if item is part of a multiple selection
            If StringInStr($iIndex, $iOC_DraggedIndex) And StringInStr($iIndex, "|") Then
                ; Extract all selected items
                Local $aIndex = StringSplit($iIndex, "|")
                For $i = 1 To $aIndex[0]
                    If $aIndex[$i] = $iOC_DraggedIndex Then ExitLoop
                Next
                ; Now check for consecutive items
                If $i <> 1 Then ; Up
                    For $j = $i - 1 To 1 Step -1
                        ; Consecutive?
                        If $aIndex[$j] <> $aIndex[$j + 1] - 1 Then ExitLoop
                        ; Adjust dragged index to this item
                        $iOC_DraggedIndex -= 1
                        ; Increase number to drag
                        $iOC_Dragging += 1
                    Next
                EndIf
                If $i <> $aIndex[0] Then ; Down
                    For $j = $i + 1 To $aIndex[0]
                        ; Consecutive
                        If $aIndex[$j] <> $aIndex[$j - 1] + 1 Then ExitLoop
                        ; Increase number to drag
                        $iOC_Dragging += 1
                    Next
                EndIf
            Else ; Either no selection or only a single
                ; Set flag
                $iOC_Dragging = 1
            EndIf

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

            ; Create drag image
            If $fImage Then
                Local $aImageData = _GUICtrlListView_CreateDragImage($hOC_SrcHandle, $iOC_DraggedIndex)
                $hOC_DraggedImage = $aImageData[0]
                _GUIImageList_BeginDrag($hOC_DraggedImage, 0, 0, 0)
            EndIf

        Case -3 ; $NM_DBLCLK
            ; Only if editable
            If $aOC_Data[$iLV_Index][7] <> "" Then
                ; Set values for active ListView
                $aOC_Data[0][1] = $iLV_Index;
                $hOC_SrcHandle = $aOC_Data[$iLV_Index][0]
                ; Copy array for manipulation
                $aOC_SrcArray = $aOC_Data[$iLV_Index][2]
                ; Set editing flag
                $fOC_EditClickFlag = True
            EndIf

    EndSwitch

EndFunc   ;==>_OC_WM_NOTIFY_Handler

; #FUNCTION# =========================================================================================================
; Name...........: _OC_WM_MOUSEMOVE_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _OC_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 _OC_WM_MOUSEMOVE_Handler($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam

    Local $iVertScroll

    ; If dragging
    If $iOC_Dragging Then

        ; Get item depth to make sure scroll is enough to get next item into view
        If $aOC_Data[$aOC_Data[0][1]][10] Then
            $iVertScroll = $aOC_Data[$aOC_Data[0][1]][10]
        Else
            Local $aRect = _GUICtrlListView_GetItemRect($hOC_SrcHandle, 0)
            $iVertScroll = $aRect[3] - $aRect[1]
        EndIf

        ; Get window under mouse cursor
        Local $hCurrent_Wnd = _OC_GetCursorWnd()

        ; If not over the current tgt ListView
        If $hCurrent_Wnd <> $hOC_TgtHandle Then
            ; Is it another initiated ListView
            For $i = 1 To $aOC_Data[0][0]
                If $aOC_Data[$i][0] = $hCurrent_Wnd Then
                    ; Clear insert mark in current tgt ListView
                    _GUICtrlListView_SetInsertMark($hOC_TgtHandle, -1, True)
                    ; Set data for new tgt ListView
                    $hOC_TgtHandle = $hCurrent_Wnd
                    $cOC_TgtID = $aOC_Data[$i][1]
                    $iOC_TgtIndex = $i
                    $aOC_TgtArray = $aOC_Data[$i][2]
                    $aOC_Data[0][3] = $aOC_Data[$i][10] ; Set item depth
                    ; No point in looping further
                    ExitLoop
                EndIf
            Next
        EndIf

        ; Get current mouse Y coord
        Local $iCurr_Y = BitShift($lParam, 16)

        ; Set insert mark to correct side of items depending on sense of movement when cursor within range
        If $iOC_InsertIndex <> -1 Then
            If $iOC_LastY = $iCurr_Y Then
                Return "GUI_RUNDEFMSG"
            ElseIf $iOC_LastY > $iCurr_Y Then
                $fOC_BarUnder = False
                _GUICtrlListView_SetInsertMark($hOC_TgtHandle, $iOC_InsertIndex, False)
            Else
                $fOC_BarUnder = True
                _GUICtrlListView_SetInsertMark($hOC_TgtHandle, $iOC_InsertIndex, True)
            EndIf
        EndIf
        ; Store current Y coord
        $iOC_LastY = $iCurr_Y

        ; Get ListView item under mouse
        Local $aLVHit = _GUICtrlListView_HitTest($hOC_TgtHandle)
        Local $iCurr_Index = $aLVHit[0]

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

        ; Check if over same item
        If $iOC_InsertIndex <> $iCurr_Index Then
            ; Show insert mark on current item
            _GUICtrlListView_SetInsertMark($hOC_TgtHandle, $iCurr_Index, $fOC_BarUnder)
            ; Store current item
            $iOC_InsertIndex = $iCurr_Index
        EndIf

    EndIf

    Return "GUI_RUNDEFMSG"

EndFunc   ;==>_OC_WM_MOUSEMOVE_Handler

; #FUNCTION# =========================================================================================================
; Name...........: _OC_WM_LBUTTONUP_Handler
; Description ...: Windows message handler for WM_NOTIFY
; Syntax.........: _OC_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 _OC_WM_LBUTTONUP_Handler($hWnd, $iMsg, $wParam, $lParam)

    #forceref $hWnd, $iMsg, $wParam, $lParam

    If Not $iOC_Dragging Then
        Return "GUI_RUNDEFMSG"
    EndIf

    ; Only allow dropping internally and from 3 to 5
    If _GUICtrlListView_GetColumnCount($hOC_SrcHandle) = 5 And _GUICtrlListView_GetColumnCount($hOC_TgtHandle) <> 5 Then
        Return "GUI_RUNDEFMSG"
    EndIf

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

    ; Reset flag
    $iOC_Dragging = 0

    ; Get window under mouse cursor
    Local $hCurrent_Wnd = _OC_GetCursorWnd()

    ; Abandon if mouse not within tgt ListView
    If $hCurrent_Wnd <> $hOC_TgtHandle Then
        ; Clear insert mark
        _GUICtrlListView_SetInsertMark($hOC_TgtHandle, -1, True)
        ; Reset highlight to original items in Src ListView
        For $i = 0 To $iMultipleItems
            _OC_Highlight($hOC_TgtHandle, $cOC_TgtID, $iOC_DraggedIndex + $i)
        Next
        ; Delete copied arrays
        $aOC_SrcArray = 0
        $aOC_TgtArray = 0
        Return
    EndIf

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

    ; Clear drag image
    If $hOC_DraggedImage Then
        _GUIImageList_DragLeave($hOC_SrcHandle)
        _GUIImageList_EndDrag()
        _GUIImageList_Destroy($hOC_DraggedImage)
        $hOC_DraggedImage = 0
    EndIf

    ; Dropping within same ListView
    If $hOC_SrcHandle = $hOC_TgtHandle Then
        ; Determine position to insert
        If $fOC_BarUnder Then
            If $iOC_DraggedIndex > $iOC_InsertIndex Then $iOC_InsertIndex += 1
        Else
            If $iOC_DraggedIndex < $iOC_InsertIndex Then $iOC_InsertIndex -= 1
        EndIf

        ; Check not dropping on dragged item(s)
        Switch $iOC_InsertIndex
            Case $iOC_DraggedIndex To $iOC_DraggedIndex + $iMultipleItems
                ; Reset highlight to original items
                For $i = 0 To $iMultipleItems
                    _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iOC_DraggedIndex + $i)
                Next
                ; Delete copied arrays
                $aOC_SrcArray = 0
                $aOC_TgtArray = 0
                Return
        EndSwitch

        ; Create Local array for checkboxes (if no checkboxes makes no difference)
        Local $aCheck_Array[UBound($aOC_SrcArray)]
        For $i = 1 To UBound($aCheck_Array) - 1
            $aCheck_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $i - 1)
        Next

        ; Create Local array for dragged items checkbox state
        Local $aCheckDrag_Array[$iMultipleItems + 1]

        ; Amend arrays
        ; Get data from dragged element(s)
        If $iMultipleItems Then
            ; Multiple dragged elements
            Local $aInsertData[$iMultipleItems + 1]
            For $i = 0 To $iMultipleItems
                Local $aItemData[UBound($aOC_SrcArray, 2)]
                For $j = 0 To UBound($aOC_SrcArray, 2) - 1
                    $aItemData[$j] = $aOC_SrcArray[$iOC_DraggedIndex + 1 + $i][$j]
                Next
                $aInsertData[$i] = $aItemData
                $aCheckDrag_Array[$i] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $iOC_DraggedIndex + $i)
            Next
        Else
            ; Single dragged element
            Local $aInsertData[1]
            Local $aItemData[UBound($aOC_SrcArray, 2)]
            For $i = 0 To UBound($aOC_SrcArray, 2) - 1
                $aItemData[$i] = $aOC_SrcArray[$iOC_DraggedIndex + 1][$i]
            Next
            $aInsertData[0] = $aItemData
            $aCheckDrag_Array[0] = _GUICtrlListView_GetItemChecked($hOC_SrcHandle, $iOC_DraggedIndex)
        EndIf

        ; Delete dragged element(s) from arrays
        For $i = 0 To $iMultipleItems
            _OC_Array_Delete($aOC_SrcArray, $iOC_DraggedIndex + 1)
            _OC_Array_Delete($aCheck_Array, $iOC_DraggedIndex + 1)
        Next

        ; Amend insert positon for multiple items deleted above
        If $iOC_DraggedIndex < $iOC_InsertIndex Then
            $iOC_InsertIndex -= $iMultipleItems
        EndIf

        ; Re-insert dragged element(s) into array
        For $i = $iMultipleItems To 0 Step -1
            _OC_Array_Insert($aOC_SrcArray, $iOC_InsertIndex + 1, $aInsertData[$i])
            _OC_Array_Insert($aCheck_Array, $iOC_InsertIndex + 1, $aCheckDrag_Array[$i])
        Next

        ; Rewrite ListView to match array
        _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aCheck_Array, $iOC_SrcIndex)

        ; Set highlight to inserted item(s)
        For $i = 0 To $iMultipleItems
            _OC_Highlight($hOC_SrcHandle, $cOC_SrcID, $iOC_InsertIndex + $i)
        Next

        ; Store amended array
        $aOC_Data[$aOC_Data[0][1]][2] = $aOC_SrcArray
        ; Delete copied arrays
        $aOC_SrcArray = 0
        $aOC_TgtArray = 0

    Else ; Dropping in another ListView

        ; This can only be 3 to 5

        ; Get additional items
        Local $sPrefix = GUICtrlRead($aOC_Inputs[0])
        Local $sSuffix = GUICtrlRead($aOC_Inputs[1])

        ; Determine position to insert
        If $fOC_BarUnder Then
            $iOC_InsertIndex += 1
        EndIf

        ; Amend array
        ; Get data from dragged element(s)
        If $iMultipleItems Then
            ; Multiple dragged elements
            Local $aInsertData[$iMultipleItems + 1]
            For $i = 0 To $iMultipleItems
                Local $aItemData[UBound($aOC_SrcArray, 2) + 2]
                $aItemData[0] = $sPrefix
                For $j = 0 To UBound($aOC_SrcArray, 2) - 1
                    $aItemData[$j + 1] = $aOC_SrcArray[$iOC_DraggedIndex + 1 + $i][$j]
                Next
                $aItemData[$j + 1] = $sSuffix
                $aInsertData[$i] = $aItemData
            Next
        Else
            ; Single dragged element
            Local $aInsertData[1]
            Local $aItemData[UBound($aOC_SrcArray, 2) + 2]
            $aItemData[0] = $sPrefix
            For $i = 0 To UBound($aOC_SrcArray, 2) - 1
                $aItemData[$i + 1] = $aOC_SrcArray[$iOC_DraggedIndex + 1][$i]
            Next
            $aItemData[$i + 1] = $sSuffix
            $aInsertData[0] = $aItemData
        EndIf

        ; Delete dragged element(s) from source array
        For $i = 0 To $iMultipleItems
            _OC_Array_Delete($aOC_SrcArray, $iOC_DraggedIndex + 1)
            $aOC_SrcArray[0][0] -= 1
        Next

        ; Insert dragged element(s) into target array
        For $i = $iMultipleItems To 0 Step -1
            _OC_Array_Insert($aOC_TgtArray, $iOC_InsertIndex + 1, $aInsertData[$i])
            $aOC_TgtArray[0][0] += 1
        Next

        ; Rewrite ListViews to match arrays
        _OC_ReWriteLV($hOC_SrcHandle, $cOC_SrcID, $aOC_SrcArray, $aOC_SrcArray, $iOC_SrcIndex, False)
        _OC_ReWriteLV($hOC_TgtHandle, $cOC_TgtID, $aOC_TgtArray, $aOC_TgtArray, $iOC_TgtIndex, False)
        ; Note no checkbox array needed ListViews with them are not interdraggable, so repass normal array and set final parameter

        ; Set highlight to inserted item(s)
        _OC_SetActive($iOC_TgtIndex)
        For $i = 0 To $iMultipleItems
            _OC_Highlight($hOC_TgtHandle, $cOC_TgtID, $iOC_InsertIndex + $i)
        Next

        ; Store amended arrays
        $aOC_Data[$iOC_SrcIndex][2] = $aOC_SrcArray
        $aOC_Data[$iOC_TgtIndex][2] = $aOC_TgtArray

    EndIf

    ; Delete copied arrays
    $aOC_SrcArray = 0
    $aOC_TgtArray = 0

EndFunc   ;==>_OC_WM_LBUTTONUP_Handler

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_ExpandCols
; Description ...: Expands column ranges to list each column separately
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_ExpandCols($sCols)

    Local $iNumber

    ; Strip any whitespace
    $sCols = StringStripWS($sCols, 8)
    ; Check if "all cols"
    If $sCols <> "*" Then
        ; Check if ranges to be expanded
        If StringInStr($sCols, "-") Then
            ; Parse string
            Local $aSplit_1, $aSplit_2
            ; Split on ";"
            $aSplit_1 = StringSplit($sCols, ";")
            $sCols = ""
            ; Check each element
            For $i = 1 To $aSplit_1[0]
                ; Try and split on "-"
                $aSplit_2 = StringSplit($aSplit_1[$i], "-")
                ; Add first value in all cases
                $sCols &= $aSplit_2[1] & ";"
                ; If a valid range and limit values are in ascending order
                If ($aSplit_2[0]) > 1 And (Number($aSplit_2[2]) > Number($aSplit_2[1])) Then
                    ; Add the full range
                    $iNumber = $aSplit_2[1]
                    Do
                        $iNumber += 1
                        $sCols &= $iNumber & ";"
                    Until $iNumber = $aSplit_2[2]
                EndIf
            Next
        EndIf
    EndIf
    ; Return expanded string
    Return $sCols

EndFunc   ;==>_OC_ExpandCols

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_HighLight
; Description ...: Highlights first item and ensures visible, second item has highlight removed
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _OC_Highlight($hLVHandle, $cLV_CID, $iIndexA, $iIndexB = -1)

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

EndFunc   ;==>_OC_Highlight

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_GetLVFont
; Description ...: Gets font details for ListView to be edited
; Author ........: Based on _GUICtrlGetFont by KaFu & Prog@ndy
; Modified ......: Melba23
; ===============================================================================================================================
Func _OC_GetLVFont($hLVHandle)

    Local $iError = 0, $aFontDetails[2] = [Default, Default]

    ; Check handle
    If Not IsHWnd($hLVHandle) Then
        $hLVHandle = GUICtrlGetHandle($hLVHandle)
    EndIf
    If Not IsHWnd($hLVHandle) Then
        $iError = 1
    Else
        Local $hFONT = _SendMessage($hLVHandle, 0x0031) ; WM_GETFONT
        If Not $hFONT Then
            $iError = 2
        Else
            Local $hDC = _WinAPI_GetDC($hLVHandle)
            Local $hObjOrg = _WinAPI_SelectObject($hDC, $hFONT)
            Local $tFONT = DllStructCreate($tagLOGFONT)
            Local $aRet = DllCall('gdi32.dll', 'int', 'GetObjectW', 'ptr', $hFONT, 'int', DllStructGetSize($tFONT), 'ptr', DllStructGetPtr($tFONT))
            If @error Or $aRet[0] = 0 Then
                $iError = 3
            Else
                ; Get font size
                $aFontDetails[0] = Round((-1 * DllStructGetData($tFONT, 'Height')) * 72 / _WinAPI_GetDeviceCaps($hDC, 90), 1) ; $LOGPIXELSY = 90 => DPI aware
                ; Now look for font name
                $aRet = DllCall("gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", 0, "ptr", 0)
                Local $iCount = $aRet[0]
                Local $tBuffer = DllStructCreate("wchar[" & $iCount & "]")
                Local $pBuffer = DllStructGetPtr($tBuffer)
                $aRet = DllCall("Gdi32.dll", "int", "GetTextFaceW", "handle", $hDC, "int", $iCount, "ptr", $pBuffer)
                If @error Then
                    $iError = 4
                Else
                    $aFontDetails[1] = DllStructGetData($tBuffer, 1) ; FontFacename
                EndIf
            EndIf
            _WinAPI_SelectObject($hDC, $hObjOrg)
            _WinAPI_ReleaseDC($hLVHandle, $hDC)
        EndIf
    EndIf

    Return SetError($iError, 0, $aFontDetails)

EndFunc   ;==>_OC_GetLVFont

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_EditProcess
; Description ...: Runs ListView editing process
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_EditProcess($iLV_Index, $aLocation, $sCols, $iDelta_X, $iDelta_Y, $iEditMode)

    Local $hTemp_Edit, $iKey_Code, $iCombo_State, $aSplit, $sInsert, $fClick_Move = False, $fCursor_Move = True

    ; Unselect item
    _GUICtrlListView_SetItemSelected($hOC_SrcHandle, $aLocation[0], False)

    ; Declare return array - note second dimension [3] but only [2] returned if successful
    Local $aEdited[1][3] = [[0]] ; [Number of edited items][blank][blank]

    ; Load active ListView details
    $hOC_SrcHandle = $aOC_Data[$iLV_Index][0]
    $cOC_SrcID = $aOC_Data[$iLV_Index][1]

    ; Store handle of ListView concerned
    $hOC_Editing = $hOC_SrcHandle
    Local $cEditingID = $cOC_SrcID

    ; Valid keys to action
    ; ENTER, ESC
    Local $aKeys_Combo[2] = [0x0D, 0x1B]
    ; TAB, ENTER, ESC, up/down arrows
    Local $aKeys_Edit[5] = [0x09, 0x0D, 0x1B, 0x26, 0x28]
    ; Left/right arrows
    Local $aKeys_LR[2] = [0x25, 0x27]

    ; Set Reset-on-ESC mode
    Local $fReset_Edits = False
    If $iEditMode < 0 Then
        $fReset_Edits = True
        $iEditMode = Abs($iEditMode)
    EndIf

    ; Set row/col edit mode - default single edit
    Local $iEditRow = 0, $iEditCol = 0
    If $iEditMode Then
        ; Separate axis settings
        $aSplit = StringSplit($iEditMode, "")
        $iEditRow = $aSplit[1]
        $iEditCol = $aSplit[2]
    EndIf

    ; Check if edit to move on click
    If StringInStr($aOC_Data[$iLV_Index][7], ";#") Then
        $fClick_Move = True
    EndIf

    ; Check if cursor to move in edit
    If $aOC_Data[$iLV_Index][9] Then
        $fCursor_Move = False
    EndIf

    ; Check if combo
    Local $fCombo = False
    Local $fRead_Only = False
    If IsArray($aOC_Data[$iLV_Index][11]) Then
        ; Extract combo data for ListView
        Local $aComboData_Array = $aOC_Data[$iLV_Index][11]
        ; And then for this column
        Local $sCombo_Data = $aComboData_Array[$aLocation[1]]
        If $sCombo_Data Then
            $fCombo = True
            If StringLeft($sCombo_Data, 1) = "#" Then
                $fRead_Only = True
                $sCombo_Data = StringTrimLeft($sCombo_Data, 1)
            EndIf
        Else
            ; No combo data available
            Return
        EndIf
    EndIf

    Local $tPoint = DllStructCreate("struct;long X;long Y;endstruct")
    ; Get position of ListView within GUI client area
    _OC_GetLVCoords($hOC_Editing, $tPoint)
    ; Get ListView client area to allow for scrollbars
    Local $aLVClient = WinGetClientSize($hOC_Editing)
    ; Get ListView font details
    Local $aLV_FontDetails = _OC_GetLVFont($hOC_Editing)
    ; Disable ListView
    WinSetState($hOC_Editing, "", @SW_DISABLE)

    ; Start the edit loop
    While 1
        ; Read current text of clicked item
        Local $sItemOrgText = _GUICtrlListView_GetItemText($hOC_Editing, $aLocation[0], $aLocation[1])
        ; Ensure item is visible and get required edit coords
        Local $aEdit_Pos = _OC_EditCoords($hOC_Editing, $cEditingID, $aLocation, $tPoint, $aLVClient[0] - 5, $iDelta_X, $iDelta_Y)

        If $fCombo Then
            ; Create temporary combo - get handle, set font size, give keyboard focus
            If $fRead_Only Then
                $cOC_EditID = GUICtrlCreateCombo("", $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 0x03) ; $CBS_DROPDOWNLIST
            Else
                $cOC_EditID = GUICtrlCreateCombo("", $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 0x02) ; $CBS_DROPDOWN
            EndIf
            GUICtrlSetFont($cOC_EditID, $aLV_FontDetails[0], Default, Default, $aLV_FontDetails[1])
            GUICtrlSetData($cOC_EditID, $sCombo_Data, $sItemOrgText)
            Local $tInfo = DllStructCreate("dword Size;struct;long EditLeft;long EditTop;long EditRight;long EditBottom;endstruct;" & _
            "struct;long BtnLeft;long BtnTop;long BtnRight;long BtnBottom;endstruct;dword BtnState;hwnd hCombo;hwnd hEdit;hwnd hList")
            Local $iInfo = DllStructGetSize($tInfo)
            DllStructSetData($tInfo, "Size", $iInfo)
            Local $hCombo = GUICtrlGetHandle($cOC_EditID)
            _SendMessage($hCombo, 0x164, 0, $tInfo, 0, "wparam", "struct*") ; $CB_GETCOMBOBOXINFO
            $hTemp_Edit = DllStructGetData($tInfo, "hEdit")
            Local $aMPos = MouseGetPos()
            MouseMove($aMPos[0], $aMPos[1] + 20, 0)
            Sleep(10)
            MouseMove($aMPos[0], $aMPos[1], 0)
            _WinAPI_SetFocus($hTemp_Edit)

        Else
            ; Create temporary edit - get handle, set font size, give keyboard focus and select all text
            $cOC_EditID = GUICtrlCreateEdit($sItemOrgText, $aEdit_Pos[0], $aEdit_Pos[1], $aEdit_Pos[2], $aEdit_Pos[3], 0)
            $hTemp_Edit = GUICtrlGetHandle($cOC_EditID)
            GUICtrlSetFont($cOC_EditID, $aLV_FontDetails[0], Default, Default, $aLV_FontDetails[1])
            GUICtrlSetState($cOC_EditID, 256) ; $GUI_FOCUS
            GUICtrlSendMsg($cOC_EditID, 0xB1, 0, -1) ; $EM_SETSEL
        EndIf

        ; Copy array for manipulation
        $aOC_SrcArray = $aOC_Data[$iLV_Index][2]
        ; Clear key code flag
        $iKey_Code = 0
        ; Clear combo down/up flag
        $iCombo_State = False
        ; Wait for a key press or combo down/up
        While 1
            If $fCombo Then
                ; Check for dropdown opena and close
                Switch _SendMessage($hCombo, 0x157) ; $CB_GETDROPPEDSTATE
                    Case 0
                        ; If opened and closed act as if Enter pressed
                        If $iCombo_State = True Then
                            $iKey_Code = 0x0D
                            ExitLoop
                        EndIf
                    Case 1
                        ; Set flag if opened
                        If Not $iCombo_State Then
                            $iCombo_State = True
                        EndIf
                EndSwitch
                ; Check for valid key pressed
                For $i = 0 To 1
                    If _WinAPI_GetAsyncKeyState($aKeys_Combo[$i]) Then
                        ; Set key pressed flag
                        $iKey_Code = $aKeys_Combo[$i]
                        ExitLoop 2
                    EndIf
                Next
            Else
                ; If edit moveable by click then check for mouse pressed outside edit
                If _WinAPI_GetAsyncKeyState(0x01) Then
                    Local $aCInfo = GUIGetCursorInfo()
                    If $aCInfo[4] <> $cOC_EditID Then
                        If $fClick_Move Then
                            $iKey_Code = 0x02 ; Confirm edit and end process
                        Else
                            $iKey_Code = 0x01 ; Abandon editing
                        EndIf
                        ExitLoop
                    EndIf
                EndIf
                ; Check for valid key pressed
                For $i = 0 To 4
                    If _WinAPI_GetAsyncKeyState($aKeys_Edit[$i]) Then
                        ; Set key pressed flag
                        $iKey_Code = $aKeys_Edit[$i]
                        ExitLoop 2
                    EndIf
                Next
                ; Check for left/right keys
                For $i = 0 To 1
                    If _WinAPI_GetAsyncKeyState($aKeys_LR[$i]) Then
                        ; Check if left/right move edit
                        If $fCursor_Move Then
                            ; Set key pressed flag
                            $iKey_Code = $aKeys_LR[$i]
                            ExitLoop 2
                        Else
                            ; See if Ctrl pressed
                            If _WinAPI_GetAsyncKeyState(0x11) Then
                                ; Set key pressed flag
                                $iKey_Code = $aKeys_LR[$i]
                                ExitLoop 2
                            EndIf
                        EndIf
                    EndIf
                Next
            EndIf
            ; Temp input loses focus
            If _WinAPI_GetFocus() <> $hTemp_Edit Then
                ExitLoop
            EndIf
            ; Save CPU
            Sleep(10)
        WEnd
        ; Check if edit to be confirmed
        Switch $iKey_Code
            Case 0x02, 0x09, 0x0D, 0x25, 0x26, 0x27, 0x28 ; Mouse (with Click=Move), TAB, ENTER, arrow keys
                ; Read edit content
                Local $sItemNewText = GUICtrlRead($cOC_EditID)

                ; Check replacement required
                If $sItemNewText <> $sItemOrgText Then
                    ; Amend item text
                    _GUICtrlListView_SetItemText($hOC_Editing, $aLocation[0], $sItemNewText, $aLocation[1])
                    ; Amend array element
                    $aOC_SrcArray[$aLocation[0] + 1][$aLocation[1]] = $sItemNewText
                    ; Store amended array
                    $aOC_Data[$iLV_Index][2] = $aOC_SrcArray
                    ; Add item data to return array
                    $aEdited[0][0] += 1
                    ReDim $aEdited[$aEdited[0][0] + 1][3]
                    ; Save location & original content
                    $aEdited[$aEdited[0][0]][0] = $aLocation[0]
                    $aEdited[$aEdited[0][0]][1] = $aLocation[1]
                    $aEdited[$aEdited[0][0]][2] = $sItemOrgText
                EndIf
        EndSwitch
        ; Delete temporary edit and set place holder
        GUICtrlDelete($cOC_EditID)
        $cOC_EditID = 9999
        ; Check edit mode
        If $iEditMode = 0 Then ; Single edit
            ; Exit edit process
            ExitLoop
        Else
            Switch $iKey_Code
                Case 0x00, 0x01, 0x02, 0x0D ; Edit lost focus, mouse button outside edit, ENTER pressed
                    ; Wait until key/button no longer pressed
                    While _WinAPI_GetAsyncKeyState($iKey_Code)
                        Sleep(10)
                    WEnd
                    ; Exit Edit process
                    ExitLoop
                Case 0x1B ; ESC pressed
                    ; Check Reset-on-ESC mode
                    If $fReset_Edits Then
                        ; Reset previous confirmed edits starting with most recent
                        For $i = $aEdited[0][0] To 1 Step -1
                            _GUICtrlListView_SetItemText($hOC_Editing, $aEdited[$i][0], $aEdited[$i][2], $aEdited[$i][1])
                            Switch UBound($aOC_SrcArray, 0)
                                Case 1
                                    $aSplit = StringSplit($aOC_SrcArray[$aEdited[$i][0] + 1], "|")
                                    $aSplit[$aEdited[$i][1] + 1] = $aEdited[$i][2]
                                    $sInsert = ""
                                    For $j = 1 To $aSplit[0]
                                        $sInsert &= $aSplit[$j] & "|"
                                    Next
                                    $aOC_SrcArray[$aEdited[$i][0] + 1] = StringTrimRight($sInsert, 1)
                                Case 2
                                    $aOC_SrcArray[$aEdited[$i][0] + 1][$aEdited[$i][1]] = $aEdited[$i][2]
                            EndSwitch
                        Next
                        ; Store amended array
                        $aOC_Data[$iLV_Index][2] = $aOC_SrcArray
                        ; Empty return array as no edits made
                        ReDim $aEdited[1][2]
                        $aEdited[0][0] = 0
                    EndIf
                    ; Wait until key no longer pressed
                    While _WinAPI_GetAsyncKeyState(0x1B)
                        Sleep(10)
                    WEnd
                    ; Exit Edit process
                    ExitLoop
                Case 0x09, 0x27 ; TAB or right arrow
                    While 1
                        ; Set next column
                        $aLocation[1] += 1
                        ; Check column exists
                        If $aLocation[1] = _GUICtrlListView_GetColumnCount($hOC_Editing) Then
                            ; Does not exist so check required action
                            Switch $iEditCol
                                Case 1
                                    ; Exit edit process
                                    ExitLoop 2
                                Case 2
                                    ; Stay on same location
                                    $aLocation[1] -= 1
                                    ExitLoop
                                Case 3
                                    ; Loop
                                    $aLocation[1] = 0
                            EndSwitch
                        EndIf
                        ; Check this column is editable
                        If Not StringInStr($sCols, "*") Then
                            If StringInStr(";" & $sCols, ";" & $aLocation[1]) Then
                                ; Editable column
                                ExitLoop
                            EndIf
                        Else
                            ; Editable column
                            ExitLoop
                        EndIf
                    WEnd
                Case 0x25 ; Left arrow
                    While 1
                        $aLocation[1] -= 1
                        If $aLocation[1] < 0 Then
                            Switch $iEditCol
                                Case 1
                                    ExitLoop 2
                                Case 2
                                    $aLocation[1] += 1
                                    ExitLoop
                                Case 3
                                    $aLocation[1] = _GUICtrlListView_GetColumnCount($hOC_Editing) - 1
                            EndSwitch
                        EndIf
                        If Not StringInStr($sCols, "*") Then
                            If StringInStr(";" & $sCols, ";" & $aLocation[1]) Then
                                ExitLoop
                            EndIf
                        Else
                            ExitLoop
                        EndIf
                    WEnd
                Case 0x28 ; Down key
                    While 1
                        ; Set next row
                        $aLocation[0] += 1
                        ; Check column exists
                        If $aLocation[0] = _GUICtrlListView_GetItemCount($hOC_Editing) Then
                            ; Does not exist so check required action
                            Switch $iEditRow
                                Case 1
                                    ; Exit edit process
                                    ExitLoop 2
                                Case 2
                                    ; Stay on same location
                                    $aLocation[0] -= 1
                                    ExitLoop
                                Case 3
                                    ; Loop
                                    $aLocation[0] = -1
                            EndSwitch
                        Else
                            ; All rows editable
                            ExitLoop
                        EndIf
                    WEnd
                Case 0x26 ; Up key
                    While 1
                        $aLocation[0] -= 1
                        If $aLocation[0] < 0 Then
                            Switch $iEditRow
                                Case 1
                                    ExitLoop 2
                                Case 2
                                    $aLocation[0] += 1
                                    ExitLoop
                                Case 3
                                    $aLocation[0] = _GUICtrlListView_GetItemCount($hOC_Editing)
                            EndSwitch
                        Else
                            ExitLoop
                        EndIf
                    WEnd
            EndSwitch
            ; Wait until key no longer pressed
            While _WinAPI_GetAsyncKeyState($iKey_Code)
                Sleep(10)
            WEnd
            ; Continue edit loop on next item
        EndIf
    WEnd
    ; Delete copied array
    $aOC_SrcArray = 0
    ; Remove original text column from return array
    ReDim $aEdited[$aEdited[0][0] + 1][2]
    ; Reenable ListView
    WinSetState($hOC_Editing, "", @SW_ENABLE)
    ; Reselect item
    _GUICtrlListView_SetItemState($hOC_SrcHandle, $aLocation[0], $LVIS_SELECTED, $LVIS_SELECTED)

    Return $aEdited

EndFunc   ;==>_OC_EditProcess

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_EditCoords
; Description ...: Ensures item in view then locates and sizes edit control
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_EditCoords($hLV_Handle, $cLV_CID, $aLocation, $tPoint, $iLVWidth, $iDelta_X, $iDelta_Y)

    ; Declare array to hold return data
    Local $aEdit_Data[4]
    ; Ensure row visible
    _GUICtrlListView_EnsureVisible($hLV_Handle, $aLocation[0])
    ; Get size of item
    Local $aRect = _GUICtrlListView_GetSubItemRect($hLV_Handle, $aLocation[0], $aLocation[1])
    ; Set required edit height
    $aEdit_Data[3] = $aRect[3] - $aRect[1] + 1
    ; Set required edit width
    $aEdit_Data[2] = _GUICtrlListView_GetColumnWidth($hLV_Handle, $aLocation[1])
    ; Ensure column visible - scroll to left edge if all column not in view
    If $aRect[0] < 0 Or $aRect[2] > $iLVWidth Then
        _GUICtrlListView_Scroll($hLV_Handle, $aRect[0], 0)
        ; Redetermine item coords
        $aRect = _GUICtrlListView_GetSubItemRect($hLV_Handle, $aLocation[0], $aLocation[1])
        ; Check available column width and limit if required
        If $aRect[0] + $aEdit_Data[2] > $iLVWidth Then
            $aEdit_Data[2] = $iLVWidth - $aRect[0]
        EndIf
    EndIf
    ; Adjust Y coord if Native ListView
    If $cLV_CID Then
        $iDelta_Y += 1
    EndIf
    ; Determine screen coords for edit control
    $aEdit_Data[0] = DllStructGetData($tPoint, "X") + $aRect[0] + $iDelta_X + 2
    $aEdit_Data[1] = DllStructGetData($tPoint, "Y") + $aRect[1] + $iDelta_Y

    ; Return edit data
    Return $aEdit_Data

EndFunc   ;==>_OC_EditCoords

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_ReWriteLV
; Description ...: Deletes all ListView content and refills to match array
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_ReWriteLV($hLVHandle, $cLV_CID, ByRef $aLV_Array, ByRef $aCheck_Array, $iLV_Index, $fCheckBox = True)

    Local $iVertScroll, $sLine, $iNewItem

    ; Get item depth
    If $aOC_Data[$iLV_Index][10] Then
        $iVertScroll = $aOC_Data[$iLV_Index][10]
    Else
        ; If not already set then ListView was empty so determine
        Local $aRect = _GUICtrlListView_GetItemRect($hLVHandle, 0)
        $aOC_Data[$iLV_Index][10] = $aRect[3] - $aRect[1]
        ; If still empty set a placeholder for this instance
        If $iVertScroll = 0 Then
            ; And make sure scroll is likely to be enough to get next item into view
            $iVertScroll = 20
        EndIf
    EndIf

    ; Get top item
    Local $iTopIndex_Org = _GUICtrlListView_GetTopIndex($hLVHandle)

    ; Check if native or UDF ListView
    If $cLV_CID Then
        ; Delete native created items
        For $i = _GUICtrlListView_GetItemCount($hLVHandle) - 1 To 0 Step -1
            GUICtrlDelete(_GUICtrlListView_GetItemParam($hLVHandle, $i))
        Next
        ; Refill items from array
        For $i = 1 To $aLV_Array[0][0]
            ; Create item text
            $sLine = ""
            For $j = 0 To UBound($aLV_Array, 2) - 1
                $sLine &= $aLV_Array[$i][$j] & "|"
            Next
            ; Create item
            GUICtrlCreateListViewItem(StringTrimRight($sLine, 1), $cLV_CID)
            ; Reset checkbox if they exist
            If $fCheckBox And $aCheck_Array[$i] Then
                _GUICtrlListView_SetItemChecked($hLVHandle, $i - 1)
            EndIf
        Next
    Else
        ; Delete UDF created items
        DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hLVHandle, "uint", $LVM_DELETEALLITEMS, "wparam", 0, "lparam", 0)
        ; Refill items from array
        For $i = 1 To $aLV_Array[0][0]
            ; Add Item
            $iNewItem = _GUICtrlListView_AddItem($hLVHandle, $aLV_Array[$i][0])
            ; Add new subitems
            For $j = 1 To UBound($aLV_Array, 2) - 1
                _GUICtrlListView_AddSubItem($hLVHandle, $iNewItem, $aLV_Array[$i][$j], $j)
            Next
            ; Reset checkbox if required
            If $fCheckBox And $aCheck_Array[$i] Then
                _GUICtrlListView_SetItemChecked($hLVHandle, $i - 1)
            EndIf
        Next
    EndIf

    ; Now scroll to same place or max possible
    Local $iTopIndex_Curr = _GUICtrlListView_GetTopIndex($hLVHandle)
    While $iTopIndex_Curr < $iTopIndex_Org
        _GUICtrlListView_Scroll($hLVHandle, 0, $iVertScroll)
        ; If scroll had no effect then max scroll up
        If _GUICtrlListView_GetTopIndex($hLVHandle) = $iTopIndex_Curr Then
            ExitLoop
        Else
            ; Reset current top index
            $iTopIndex_Curr = _GUICtrlListView_GetTopIndex($hLVHandle)
        EndIf
    WEnd

    _GUICtrlListView_EndUpdate($hLVHandle)

EndFunc   ;==>_OC_ReWriteLV

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_GetLVCoords
; Description ...: Gets screen coords for ListView
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_GetLVCoords($hLV_Handle, ByRef $tPoint)

    ; Get handle of ListView parent
    Local $aWnd = DllCall("user32.dll", "hwnd", "GetParent", "hwnd", $hLV_Handle)
    Local $hWnd = $aWnd[0]
    ; Get position of ListView within GUI client area
    Local $aLVPos = WinGetPos($hLV_Handle)
    DllStructSetData($tPoint, "X", $aLVPos[0])
    DllStructSetData($tPoint, "Y", $aLVPos[1])
    _WinAPI_ScreenToClient($hWnd, $tPoint)

EndFunc

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_GetCursorWnd
; Description ...: Gets handle of control under the mouse cursor
; Author ........: Melba23
; Modified ......:
; ===============================================================================================================================
Func _OC_GetCursorWnd()

    Local $tPoint = DllStructCreate("struct;long X;long Y;endstruct")
    DllStructSetData($tPoint, "X", MouseGetPos(0))
    DllStructSetData($tPoint, "Y", MouseGetPos(1))
    Local $aHwnd = DllCall("user32.dll", "hwnd", "WindowFromPoint", "struct", $tPoint)
    Return $aHwnd[0]

EndFunc

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_Array_Add
; Description ...: Adds a specified value at the end of an existing 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _OC_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   ;==>_OC_Array_Add

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_Array_Insert
; Description ...: Adds a value at the specified index of a 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _OC_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 = _OC_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   ;==>_OC_Array_Insert

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_Array_Delete
; Description ...: Deletes a specified index from an existing 1D or 2D array.
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _OC_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   ;==>_OC_Array_Delete

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: _OC_Array_Swap
; Description ...: Swaps specified elements within a 1D or 2D array
; Author ........: Melba23
; Remarks .......:
; ===============================================================================================================================
Func _OC_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   ;==>_OC_Array_Swap
Everything else in your UDF still works, so you should be able to do anythind else you need with the ListViews. Let me know how it works for you - it works fine for me. :)

WARNING: Do not use this version of the UDF with any other script - it will crash for certain! :D

And before anyone asks: No, I am not going to add a feature like this to the normal UDF - it is far too specific a case to be generalised. ;)

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 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
OldCodger

.....Let me know how it works for you - it works fine for me. :)

Thanks M23..

 

It works(mostly)..

 

Intermittently, it removes all target items and puts a numeric in row1-column1 eg '13'

Edited by Melba23
Fixed quote

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

I need a bit more to go on than that! :D

Any particular lines in either ListView? Multiple or single drags? :huh:

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 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
OldCodger

OldCodger,

I need a bit more to go on than that! :D

Any particular lines in either ListView? Multiple or single drags? :huh:

M23

 

I've only tried single drag so far.. it's random.. no patterns to the error at all.

Also, the drop is sometimes above, sometimes below the cursor item.

I have to go now, so I'll let your genius flow. ;)

See you tomorrow.

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

Are you using the scripts I posted or have you modified your original? If so, can I see it because there might be something else affecting the drag/drop. :)

 

Also, the drop is sometimes above, sometimes below the cursor item

Some people are fussy! You can always drag it to the correct place afterwards you know! :P

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 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
OldCodger

OldCodger,

Are you using the scripts I posted or have you modified your original? If so, can I see it because there might be something else affecting the drag/drop. :)

 

 

No, it's the sample code you delivered, I haven't changed anything yet and wouldn't modify my application until the code was ratified.

 

Some people are fussy! You can always drag it to the correct place afterwards you know! :P

 

Yeah I know, it's a nice to have, not imperative. ;)

Cheers..

Glenn.

Share this post


Link to post
Share on other sites
OldCodger

I have created a snapshot of the issue.

Should you want to view it...

  • Save the attached files to a  folder
  •  
  • Rename the .doc file to .swf
  •  
  • Rename the .docx file to .js
  •  
  • run the .htm for the snapshot

I can't attach swf or js files, I understand why.. but if you know what you are doing as far as protection is concerned you can see what happens sometimes.

ListviewDrag.htm

ListviewDrag.doc

ListviewDrag.docx

Share this post


Link to post
Share on other sites
Melba23

OldCodger,

Apologies - I forgot all about this. :>

I could reproduce the problem when the cursor had not actually moved over the existing items in the target ListView. In that case the UDF has not had a chance to recognise where it is on the target ListView and so it tries to insert the dragged item at position -1, with the reults that you see. I have added some code to prevent this happening - the dragged item should now be added at the end of the list if no specific position has been set. At worst it will be inserted at the top. See if it works for you: :)

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • Broihon
      By Broihon
      Hey guys,

      I ran into a problem when I wanted to delete items of a listview using the delete key. My approach is to register my own WndProc for the listview and then filter the $WM_GETDLGCODE msg and then call the original WndProc.
      That works like a charm. The problem is that when the listview gets redrawn it somehow ends up in an infinite loop. The listview is suddenly emtpy and I can't interact with any controls of the GUI at all. Here's the code:
       
      #include <GUIConstantsEx.au3> #include <GUIListView.au3> #include <WinAPI.au3> $h_GUI = GUICreate("Test", 200, 200, 350, 350) $h_LV = GUICtrlCreateListView("Col 1|Col 2|Col 3", 0, 0, 200, 200) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 0) _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 1) _GUICtrlListView_AddSubItem($h_LV, 0, "bla0", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 0) _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 1) _GUICtrlListView_AddSubItem($h_LV, 1, "bla1", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 0) _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 1) _GUICtrlListView_AddSubItem($h_LV, 2, "bla2", 2) _GUICtrlListView_AddItem($h_LV, "") _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 0) _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 1) _GUICtrlListView_AddSubItem($h_LV, 3, "bla3", 2) $h_LV_NewWndProc = DllCallbackRegister("WndProc_LV", "int", "hwnd;uint;wparam;lparam") $g_LV_OldWndProc = _WinAPI_SetWindowLong(GUICtrlGetHandle($h_LV), $GWL_WNDPROC, DllCallbackGetPtr($h_LV_NewWndProc)) GUISetState(@SW_SHOW) Func WndProc_LV($hWnd, $uMsg, $wParam, $lParam) Return _WinAPI_CallWindowProc($g_LV_OldWndProc, $hWnd, $uMsg, $wParam, $lParam) EndFunc ;==>WndProc_GUI Do Until GUIGetMsg() = $GUI_EVENT_CLOSE DllCallbackFree($h_LV_NewWndProc) As you can see I'm doing nothing in the WndProc of the listview. I'm simply calling the original WndProc. This still "freezes" when I mess with the width of the columns or in the original project when I add more items that they don't fit in the listview and I have to scroll. If I don't do that it's working fine.
    • c.haslam
      By c.haslam
      I have
      Local $idListview = GUICtrlCreateListView("",8,8,@DesktopWidth/2-16,@DesktopHeight-150,$LVS_SHOWSELALWAYS, _ $LVS_EX_INFOTIP) Local $hListView = GUICtrlGetHandle($idListview) _GUICtrlListView_InsertColumn($hListview, 0, "Filename", 400) _GUICtrlListView_InsertColumn($hListview, 1, "Ext", 50) _GUICtrlListView_InsertColumn($hListview, 2, "Size",70) _GUICtrlListView_InsertColumn($hListview, 3, 'Date time',100) _GUICtrlListView_InsertColumn($hListview, 4, "Path", 385) _GUICtrlListView_InsertColumn($hListview, 5, "sizeInt", 0) _GUICtrlListView_JustifyColumn($hListview, $kSize,1) ; right align then further on
      While True $sFnamExt = FileFindNextFile($iSrch) If @error Then ExitLoop EndIf $sAtts = FileGetAttrib($sPath&'\'&$sFnamExt) If StringInStr($sAtts,'D') Then If $sFnamExt<>'$RECYCLE.BIN' Then $sDirs &= '?'&$sPath&'\'&$sFnamExt EndIf Else $p = StringInStr($sFnamExt,'.',0,-1) ; last If $p=0 Then $sFnam = $sFnamExt $sExt = '' Else $sFnam = StringLeft($sFnamExt,$p-1) $sExt = StringTrimLeft($sFnamExt,$p) EndIf _GUICtrlListView_AddItem($hListview,$sFnam,-1,_GUICtrlListView_GetItemCount($hListview)+1000) _GUICtrlListView_AddSubItem($hListview,$nItem,$sExt,$kExt) $nSize = FileGetSize($sPath&'\'&$sFnamExt) $sSize = AddThousandsSeparator($nsize) _GUICtrlListView_AddSubItem($hListview,$nItem,$sSize,$kSize) _GUICtrlListView_AddSubItem($hListview,$nItem,$nsize,$kSizeInt) $nTotBytes += $nSize $a1 = FileGetTime($sPath&'\'&$sFnamExt,$FT_MODIFIED,$FT_ARRAY) $t = $a1[0]&'-'&$a1[1]&'-'&$a1[2]&' '&$a1[3]&':'&$a1[4] _GUICtrlListView_AddSubItem($hListview,$nItem,$t,$kDateTime) _GUICtrlListView_AddSubItem($hListview,$nItem,$sPath,$kPath) If $gSQL Then $s = "Insert into tbl values ("&_SQLite_Escape($sFnam)&","&_SQLite_Escape($sExt)&",'"& _ $sSize&"','"& _ $t&"',"&_SQLite_Escape($sPath)&","&$nSize&")" _SQLite_Exec(-1,$s) If @error Then MsgBox(0,@ScriptLineNumber,_SQLite_ErrMsg()) EndIf EndIf EndIf WEnd FileClose($iSrch) You will see that I heeded the advice in Help > _GUICtrlListView_AddItem: "As AutoIt uses the $iParam parameter to store the controlID of native-created ListView items, this value should be set sufficiently high for UDF-created items to avoid possible conflict with any existing controls - a starting value of 1000 is recommended."
      (It's unfortunate that the Example does not heed this advice. OK, it doesn't need to because there are no other controls, but still --- it would help neophytes if it did. Also to me _GUICtrlListView_AddItem is not native because it is a UDF. Confused?)
      My script then does a sort using SQLite, and updates the ListView:
      Local $hQuery Local $colNames = ['fnam','ext','nsize','dateTime','path','SizeInt'] Local $s = "Select * FROM tbl ORDER BY "&$colNames[$ncol]&';' _SQLite_Query(-1,$s, $hQuery) If @error Then MsgBox(0,@ScriptLineNumber,_SQLite_ErrMsg()) EndIf Local $aRow[$kSizeInt+1] Local $iItem=-1 While _SQLite_FetchData($hQuery, $aRow, False, False) = $SQLITE_OK ; Read Out the next Row If @error Then MsgBox(0,@ScriptLineNumber,_SQLite_ErrMsg()) EndIf $iItem += 1 For $i = $kFnam To $kSizeInt _GUICtrlListView_SetItem($hListview,$aRow[$i],$iItem,$i,Default) Next WEnd This works, but I had earlier coded
      _GUICtrlListView_SetItem($hListview,$aRow[$i],$iItem,$i,Default,$iItem+1000) because the same advice is in the Help for this function.
      So my care in specifying $param back-fired! What am I not understanding?
      The only difference in what works is that the $param parameter is defaulted.
    • FrancescoDiMuro
      By FrancescoDiMuro
      Good evening everyone
      I am building a management for the company I work with, and I just imported a real amount of rows ( about 29000 ), in my SQLite DB.
      The thing I am not understanding, is the time that the script takes to build this amount of rows in the ListView.
      I didn't measure it, but I think it took 2 minutes or so to create each ListView item...
      It is normal that it takes so much time?
      What can I do to improve the creation of the items?

      Here's the code I am using to query and to create ListView items...
      ; Articles ListView: Global $lvwArticles = GUICtrlCreateListView("ID|Fornitore|Codice|Descrizione|EU|Prezzo|Sconto Applicato|Note", 14, 87, 1507, 660, BitOR($GUI_SS_DEFAULT_LISTVIEW,$LVS_SORTASCENDING,$LVS_SORTDESCENDING), BitOR($WS_EX_CLIENTEDGE,$LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT)) ; Query $strQuery = "SELECT * FROM ARTICOLI;" ; Query Execution _SQLite_GetTable2d($objDatabase, $strQuery, $arrResult, $intRows, $intColumns) If @error Then ; Error Handling Else ; Cleaning the ListView _GUICtrlListView_DeleteAllItems($lvwArticles) If @error Then ; Error Handling Else ; No records in the Table If UBound($arrResult) < 2 Then ; Error Handling Else _GUICtrlListView_BeginUpdate($lvwArticles) For $intCounter = 1 To UBound($arrResult) - 1 $strListViewItem = $arrResult[$intCounter][0] & "|" & _ $arrResult[$intCounter][1] & "|" & _ $arrResult[$intCounter][2] & "|" & _ $arrResult[$intCounter][3] & "|" & _ $arrResult[$intCounter][4] & "|" & _ $arrResult[$intCounter][5] & "|" & _ $arrResult[$intCounter][6] & "|" & _ $arrResult[$intCounter][7] $objListViewItem = GUICtrlCreateListViewItem($strListViewItem, $lvwArticles) Next _GUICtrlListView_EndUpdate($lvwArticles) EndIf EndIf EndIf Thanks in advance


      Best Regards.
    • Skysnake
      By Skysnake
      I am tracking this topic by @LarsJ.  It is very advanced and overkill for what I am currently trying to do.
       
      Problem is this.
      Listview contains columns, one of which is right aligned and gets populated by float values, such as 123.99.  Some do not have decimals ie 124.00 and on sort gets truncated to 124.  Its obviously still the same value, but the display has reset.
      ; line below is for list VIEW ;..................................0.........1......2............ $cListView = GUICtrlCreateListView("CUSTOMER|AMOUNT|DESCRIPTION", 8, 152, 764, 279) GUICtrlSetBkColor($cListView, $GUI_BKCOLOR_LV_ALTERNATE) ; alternate between the listview background color and the listview item background color GUICtrlSetBkColor($cListView, $LVStdClr) ; Set the background color for the listview _GUICtrlListView_SetColumnWidth($cListView, 0, 120) ; -- the client name _GUICtrlListView_SetColumnWidth($cListView, 1, 90) ;-- the amount _GUICtrlListView_JustifyColumn($cListView, 1, 1) ; 1 - Text is right aligned _GUICtrlListView_SetColumnWidth($cListView, 2, 200) ; the description What I am looking for is something native and simple like a 
          _GUICtrlListView_SetColumnFormat($cListView, 1, "%.2f") ;  1 - column is stringformatted to "%.2f"
      So that after each sort it will appear as it was in the original rendering.
      Is there something like this? I have not been able to find a simple solution.

      Thanks.
      Skysnake
    • Ambient
      By Ambient
      I have tried several way sto get this to work to no avail. Any help would be appreciated. #include <ListViewConstants.au3> #include <GuiListView.au3> #include "GuiListViewEx.au3" $idItem = GUICtrlCreateListViewItem($r & " | " & $c & $adoRs.Fields("TransactionAmount").value & " | " & $Timestamp & " | " & _StringProper($adoRs.Fields("Tillid").value) & @CRLF & @CRLF & "Card Number : " & $cardnum & " " , $idListView) ConsoleWrite( "IDITEM" & $idItem) If STRINGLEFT($adoRs.Fields("TransactionAmount").value,1)= "-" Then Consolewrite(" String is Negative" & @CRLF) ;Drops in Here as expected ;GUICtrlSetColor(-1, $COLOR_RED) ; Colour line if item is negative this didn' work $TxC= _GUICtrlListView_SetTextColor($hListView, $CLR_RED) ; I also tried $TxC= _GUICtrlListView_SetTextColor(-1, 0xFF0000) CONSOLEWRITE("TEXTCOLOUR RETURNED " & $TxC & @crlf) ; This is returning True ELSE Consolewrite(" String is NOT Negative" & @CRLF) EndIf  
×