/*
**********************************
以下为LISTVIEW编辑类控件
**********************************
*/

; ==================================================================================================================================
; Namespace:      LV_InCellEdit
; Function:       Support for in-cell ListView editing.
; Tested with:    AHK 1.1.24.00 (1.1.20+ required)
; Tested on:      Win 10 Pro (x64)
; Change History: 1.3.00.00/2016-07-21/just me - Code revision + new options.
;                 1.2.02.00/2015-12-14/just me - Bug fix and support for centered columns.
;                 1.2.01.00/2015-09-08/just me - Added EditUserFunc option.
;                 1.2.00.00/2015-03-29/just me - New version based on AHK 1.1.20+ features.
;                 1.1.04.00/2014-03-22/just me - Added method EditCell
;                 1.1.03.00/2012-05-05/just me - Added back option BlankSubItem for method Attach
;                 1.1.02.00/2012-05-01/just me - Added method SetColumns
;                 1.1.01.00/2012-03-18/just me
; ==================================================================================================================================
; CLASS LV_InCellEdit
;
; Unlike other in-cell editing scripts, this class is using the ListViews built-in edit control.
; Advantage:
;     You don't have to care about the font and the GUI, and most of the job can be done by handling common ListView
;     notifications.
; Disadvantage:
;     I've still found no way to prevent the ListView from blanking out the first subitem of the row while editing another
;     subitem. The only known workaround is to add a hidden first column.
;
; The class provides methods to restrict editing to certain columns, to directly start editing of a specified cell, and to
; deactivate/activate the built-in message handler for WM_NOTIFY messages (see below).
;
; The message handler for WM_NOTIFY messages will be activated for the specified ListView whenever a new instance is created.
; As long as the message handler is activated a double-click on any cell will show an Edit control within this cell allowing to
; edit the current content. The default behavior for editing the first column by two subsequent single clicks is disabled.
; You have to press "Esc" to cancel editing, otherwise the content of the Edit will be stored in the current cell.
; ListViews must have the -ReadOnly option to be editable.
;
; While editing, "Esc", "Tab", "Shift+Tab", "Down", and "Up" keys are registered as hotkeys. "Esc" will cancel editing without
; changing the value of the current cell. All other hotkeys will store the content of the edit in the current cell and continue
; editing for the next (Tab), previous (Shift+Tab), upper (Up), or lower (Down) cell. You cannot use the keys for other purposes
; while editing.
;
; All changes are stored in MyInstance.Changed. You may track the changes by triggering (A_GuiEvent == "F") in the ListView's
; g-Label and checking MyInstance["Changed"] as shown in the sample scipt. If "True", MyInstance.Changed contains an array of
; objects with keys "Row" (row number), "Col" (column number), and "Txt" (new content).
; Changed may be deleted by the script whenever it is needed.
;
; If you want to temporarily disable in-cell editing call MyInstance.OnMessage(False). To enable it again, call
; MyInstance.OnMessage().
;
; To avoid the loss of Gui events and messages the message handler might need to be 'critical'. This can be achieved by setting
; the instance property 'Critical' to the required value (e.g. MyInstance.Critical := 100).
; New instances default to 'Critical, Off'. Though sometimes needed, ListViews or the whole Gui may become unresponsive under
; certain circumstances if Critical is set and the ListView has a g-label.
;类LV_InCellEdit
;与其他单元内编辑脚本不同,这个类使用的是ListViews内置的编辑控件。
;优势:
;你不需要关心字体和GUI,大部分工作可以通过处理common ListView来完成
;通知。
;劣势:
;我仍然发现没有办法防止ListView从空白的第一个子项的行,而编辑另一个
;子项。
;已知的唯一解决方案是添加一个隐藏的第一列。
;类提供了一些方法,以限制对某些列的编辑,直接开始编辑指定的单元格,以及
;取消激活/激活WM_NOTIFY消息的内置消息处理程序(见下文)。
;;WM_NOTIFY消息的消息处理程序将在创建新实例时为指定的ListView激活。
;只要消息处理程序被激活,双击任何单元格都会显示该单元格内的编辑控件
;编辑当前内容。禁用后续两次单击编辑第一列的默认行为。
;您必须按“Esc”来取消编辑,否则编辑的内容将存储在当前单元格中。
;ListViews必须具有-ReadOnly选项才能编辑。
;;编辑时,“Esc”、“Tab”、“Shift+Tab”、“Down”和“Up”键注册为热键。“Esc”将取消编辑
;更改当前单元格的值。所有其他热键将在当前单元格中存储编辑的内容并继续
;编辑下一个(标签),上一个(Shift+标签),上(上),或下(下)单元格。您不能将密钥用于其他目的;当编辑。
;;所有更改都存储在MyInstance.Changed中。你可以通过在ListView中触发(A_GuiEvent == "F")来跟踪变化
;g-Label并检查MyInstance["Changed"],如示例脚本所示。如果“True”,MyInstance。changes包含一个数组
;对象的键“Row”(行号)、“Col”(列号)和“Txt”(新内容)。;更改后的可以在需要时被脚本删除。
;;如果您想临时禁用单元内编辑,请调用MyInstance.OnMessage(False)。要再次启用它,请调用
;MyInstance.OnMessage()。
;;为了避免Gui事件和消息的丢失,消息处理程序可能需要是“关键的”。这可以通过设置来实现
;实例属性“Critical”到所需的值(例如MyInstance。关键:= 100)。
;新实例默认为'Critical, Off'。虽然有时需要,ListViews或整个Gui可能会变得无响应;在某些情况下,如果设置了Critical并且ListView有g-label。
; ==================================================================================================================================
Class LV_InCellEdit {
   ; ===============================================================================================================================
   ; Constructor     Creates a new LV_InCellEdit instance for the specified ListView.
   ; Parameters:     HWND           -  The ListView's HWND.
   ;                 Optional ------------------------------------------------------------------------------------------------------
   ;                 BlankSubItem   -  Blank out subitems text while editing.
   ;                                   Values:  True / False
   ;                                   Default: False
   ;                 ScrollToLeft   -  Per default, edited columns are scrolled only until they are fully visible.
   ;                                   Set this parameter to True to scroll the columns to the left edge of the ListView.
   ;                                   Values:  True / False
   ;                                   Default: False (use default scrolling).
   ;                 UseColumnWidth -  Per default, the width of the edit control is determined by the width of its text.
   ;                                   Set this parameter to true to let the edit fill the whole column.
   ;                                   Values:  True / False
   ;                                   Default: False (use default scrolling).
   ;                 EditUserFunc   -  The name of a user-defined funtion to be called from
   ;                                   LVN_BEGINEDITLABEL and LVN_ENDEDITLABEL.
   ;                                   The function must accept at least 6 Parameters:
   ;                                      State -  The state of the edit operation: BEGIN / END
   ;                                      HLV   -  The handle to the ListView.
   ;                                      HED   -  The handle to the edit control.
   ;                                      Row   -  The row number of the edited item.
   ;                                      Col   -  The column number of the edited item.
   ;                                      Text  -  The edited item's text before / after editing.
   ;                                   To avoid the loss of messages the function should return as soon as possible.
   ; Note:           The BlankSubItem, ScrollToLeft, and UseColumnWidth properties may be changed dynamically after the instance
   ;                 has been created.
   ; ===============================================================================================================================
	__New(HWND, BlankSubItem := False, ScrollToLeft := False, UseColumnWidth := False, EditUserFunc := "") {
		If (This.Base.Base.__Class) ; do not instantiate instances
			Return False
		If LV_InCellEdit.Attached[HWND] ; HWND is already attached
			Return False
		If !DllCall("IsWindow", "Ptr", HWND) ; invalid HWND
			Return False
		VarSetCapacity(Class, 512, 0)
		DllCall("GetClassName", "Ptr", HWND, "Str", Class, "Int", 256)
		If (Class <> "SysListView32") ; HWND doesn't belong to a ListView
			Return False
		If (EditUserFunc <> "") && (Func(EditUserFunc).MaxParams < 6)
			Return False
      ; ----------------------------------------------------------------------------------------------------------------------------
		ControlGet, Styles, Style, , , ahk_id %HWND%
		If !(Styles & 0x0200) ; LVS_EDITLABELS
			GuiControl, +0x0200, %HWND%
		This.Styles := Styles
      ; Set LVS_EX_DOUBLEBUFFER (0x010000) style to avoid drawing issues.
		DllCall("SendMessage", "Ptr", HWND, "UInt", 0x1036, "Ptr", 0x010000, "Ptr", 0x010000) ; LVM_SETEXTENDEDLISTVIEWSTYLE
		This.HWND := HWND
		This.HEDT := 0
		This.HHDR := DllCall("SendMessage", "Ptr", HWND, "UInt", 0x101F, "Ptr", 0, "Ptr", 0, "UPtr") ; LVM_GETHEADER
		This.Item := -1
		This.Subitem := -1
		This.ItemText := ""
		This.MaxItem := 0
		This.MaxSubitem := 0
		This.Cancelled := False
		This.Next := False
		This.BlankSubitem := !!BlankSubItem
		This.ScrollToLeft := !!ScrollToLeft
		This.UseColumnWidth := !!UseColumnWidth
		This.Critical := "Off"
		This.Col1W := 0
		This.MinW := 0
		This.ExtW := 0
		If (EditUserFunc <> "")
			This.EditUserFunc := Func(EditUserFunc)
		This.OnMessage()
		LV_InCellEdit.Attached[HWND] := True
	}
   ; ===============================================================================================================================
   ; Destructor
   ; ===============================================================================================================================
	__Delete() {
		LV_InCellEdit.Attached.Delete(This.HWND)
		If !(This.Styles & 0x0200)
			GuiControl, -0x0200, % This.HWND
		This.OnMessage(False)
	}
   ; ===============================================================================================================================
   ; EditCell        Edit the specified cell, if possible.
   ; Parameters:     Row   -  1-based row number
   ;                 Col   -  1-based column number
   ;                          Default: 0 - edit the first editable column
   ; Return values:  True on success; otherwise False
   ; ===============================================================================================================================
	EditCell(Row, Col := 0) {
		If !(H := This.HWND)
			Return False
		Rows := DllCall("SendMessage", "Ptr", H, "UInt", 0x1004, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETITEMCOUNT
		If (Row < 1) || (Row > Rows)
			Return False
		This.MaxItem := Rows - 1
		Cols := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
		This.MaxSubitem := Cols - 1
		If (Col = 0)
			If This["Columns"]
				Col := This.Columns.MinIndex() + 1
		Else
			Loop, %Cols%
				Col := A_Index
		Until (DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
		If (Col < 1) || (Col > Cols)
			Return False
		If (This["Columns"]) && (!This.Columns[Col - 1])
			Return False
		If !(DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0)
			Return False
		This.DoubleClick(--Row, --Col)
		Return True
	}
   ; ===============================================================================================================================
   ; SetColumns      Sets the columns you want to edit
   ; Parameters:     ColNumbers* -  zero or more numbers of columns which shall be editable. If entirely omitted,
   ;                                the ListView will be reset to enable editing of all columns.
   ; Return values:  True on success; otherwise False
   ; Note:           All passed editable columns must be visible!
   ; ===============================================================================================================================
	SetColumns(ColNumbers*) {
		If !(H := This.HWND)
			Return False
		This.Delete("Columns")
		If (ColNumbers.MinIndex() = "")
			Return True
		ColCount := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
		Cols := []
		For Each, Col In ColNumbers {
			If Col Is Not Integer
				Return False
			If (Col < 1) || (Col > ColCount)
				Return False
			If !(DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
				Return False
			Cols[Col - 1] := True
		}
		This["Columns"] := Cols
		Return True
	}
   ; ===============================================================================================================================
   ; OnMessage       Activate / deactivate the message handler for WM_NOTIFY messages for this ListView
   ; Parameters:     Apply    -  True / False
   ;                             Default: True
   ; Return Value:   Always True
   ; ===============================================================================================================================
	OnMessage(Apply := True) {
		If !This.HWND
			Return False
		If (Apply) && !This["NotifyFunc"] {
			This.NotifyFunc := ObjBindMethod(This, "On_WM_NOTIFY")
			OnMessage(0x004E, This.NotifyFunc, -1) ; add the WM_NOTIFY message handler
		}
		Else If !(Apply) && This["NotifyFunc"] {
			OnMessage(0x004E, This.NotifyFunc, 0) ; remove the WM_NOTIFY message handler
			This.NotifyFunc := ""
		}
		WinSet, Redraw, , % "ahk_id " . This.HWND
		Return True
	}
   ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   ; PRIVATE PROPERTIES AND METHODS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	Static Attached := {}
	Static OSVersion := DllCall("GetVersion", "UChar")
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; WM_COMMAND message handler for edit notifications
   ; -------------------------------------------------------------------------------------------------------------------------------
	On_WM_COMMAND(W, L, M, H) {
      ; LVM_GETSTRINGWIDTHW = 0x1057, LVM_GETSTRINGWIDTHA = 0x1011
		Critical, % This.Critical
		If (L = This.HEDT) {
			N := (W >> 16)
			If (N = 0x0400) || (N = 0x0300) || (N = 0x0100) { ; EN_UPDATE | EN_CHANGE | EN_SETFOCUS
				If (N = 0x0400) && !This.UseColumnWidth {
					ControlGetText, EditText, , % "ahk_id " . L
					EW := DllCall("SendMessage", "Ptr", This.HWND, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Ptr", &EditText, "Int") ; LVM_GETSTRINGWIDTH
					, EW += This.ExtW
					If (EW < This.MinW)
						EW := This.MinW
					If (This.EX + EW) > This.ClientW
						EW := This.ClientW - This.EX
					This.EW := EW
				}
				DllCall("SetWindowPos", "Ptr", L, "Ptr", 0, "Int", This.EX, "Int", This.EY, "Int", This.EW, "Int", This.EH, "UInt", 0x04)
			}
		}
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; WM_HOTKEY message handler
   ; -------------------------------------------------------------------------------------------------------------------------------
	On_WM_HOTKEY(W, L, M, H) {
      ; LVM_CANCELEDITLABEL = 0x10B3, Hotkeys: 0x801B  (Esc -> cancel)
		Critical, % This.Critical
		If (H = This.HWND) {
			If (W = 0x801B) { ; Esc
				This.Cancelled := True
            , DllCall("PostMessage", "Ptr", H, "UInt", 0x10B3, "Ptr", 0, "Ptr", 0)
			}
			Else {
				This.Next := True
			  , DllCall("SendMessage", "Ptr", H, "UInt", 0x10B3, "Ptr", 0, "Ptr", 0)
			  , This.Next := True
			  , This.NextSubitem(W)
			}
			Return False
		}
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; WM_NOTIFY message handler for ListView notifications
   ; -------------------------------------------------------------------------------------------------------------------------------
	On_WM_NOTIFY(W, L) {
		Critical, % This.Critical
		If (H := NumGet(L + 0, 0, "UPtr") = This.HWND) {
			M := NumGet(L + (A_PtrSize * 2), 0, "Int")
         ; BeginLabelEdit -------------------------------------------------------
			If (M = -175) || (M = -105) ; LVN_BEGINLABELEDITW || LVN_BEGINLABELEDITA
				Return This.LVN_BEGINLABELEDIT(L)
         ; EndLabelEdit ---------------------------------------------------------
			If (M = -176) || (M = -106) ; LVN_ENDLABELEDITW || LVN_ENDLABELEDITA
				Return This.LVN_ENDLABELEDIT(L)
         ; Double click ---------------------------------------------------------
			If (M = -3) ; NM_DBLCLICK
				This.NM_DBLCLICK(L)
		}
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; LVN_BEGINLABELEDIT notification
   ; -------------------------------------------------------------------------------------------------------------------------------
	LVN_BEGINLABELEDIT(L) {
		If (This.Item = -1) || (This.Subitem = -1)
			Return True
		SetControlDelay, -1
		H := This.HWND, Item := This.Item, SubItem := This.Subitem
		This.HEDT := HEDT := DllCall("SendMessage", "Ptr", H, "UInt", 0x1018, "Ptr", 0, "Ptr", 0, "UPtr")
		 , DllCall("SendMessage", "Ptr", HEDT, "UInt", 0x00D3, "Ptr", 0x01, "Ptr", 0) ; EM_SETMARGINS, EC_LEFTMARGIN
		 , VarSetCapacity(ItemText, 2048, 0) ; text buffer
		 , VarSetCapacity(LVITEM, 40 + (A_PtrSize * 5), 0) ; LVITEM structure
		 , NumPut(Item, LVITEM, 4, "Int"), NumPut(Subitem, LVITEM, 8, "Int")
		 , NumPut(&ItemText, LVITEM, 16 + A_PtrSize, "Ptr") , NumPut(1024 + 1, LVITEM, 16 + (A_PtrSize * 2), "Int") ; pszText, cchTextMax
		 , DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1073 : 0x102D, "Ptr", Item, "Ptr", &LVITEM) ; LVM_GETITEMTEXT
		 , This.ItemText := StrGet(&ItemText)
		 ; Call the user function, if any
		If (This.EditUserFunc)
			This.EditUserFunc.Call("BEGIN", H, HEDT, Item + 1, Subitem + 1, This.ItemText)
		DllCall("SendMessage", "Ptr", This.HEDT, "UInt", 0x000C, "Ptr", 0, "Ptr", &ItemText) ; WM_SETTEXT
		If (Subitem > 0) && (This.BlankSubitem) {
			Empty := ""
		    , NumPut(&Empty, LVITEM, 16 + A_PtrSize, "Ptr") ; pszText in LVITEM
		    , NumPut(0, LVITEM, 16 + (A_PtrSize * 2), "Int") ; cchTextMax in LVITEM
		    , DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1074 : 0x102E, "Ptr", Item, "Ptr", &LVITEM) ; LVM_SETITEMTEXT
		}
		; Set the edit's position and size
		EX := This.CX + This.Indent
		, EY := This.CY - (This.OSVersion < 6 ? 1 : 0) ; subtract 1 for WinXP
		If (This.UseColumnWidth)
			EW := This.CR - EX
		Else
			EW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Ptr", &ItemText, "Int") ; LVM_GETSTRINGWIDTH
		    , EW += This.ExtW
		    , EW := EW < This.MinW ? This.MinW : EW
		EH := This.CH + (This.OSVersion < 6 ? 3 : 0) ; add 3 for WinXP
		; Check the column alignment
		If (Subitem > 0) {
			VarSetCapacity(LVCOL, 56, 0)
		    , NumPut(1, LVCOL, "UInt") ; LVCF_FMT
		    , DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x105F : 0x1019, "Ptr", Subitem, "Ptr", &LVCOL) ; LVM_GETCOLUMN
			If (This.Center := NumGet(LVCOL, 4, "UInt") & 0x0002) ; LVCFMT_CENTER
				If (This.UseColumnWidth)
					Control, Style, +0x0001, , % "ahk_id " . This.HEDT
			Else If (ER := EX + EW) < (CR := This.CX + This.CW)
				EX += ((CR - ER) // 2) + This.Indent
		}
		EW := (EX + EW) > This.ClientW ? This.ClientW - EX : EW
		This.EX := EX, This.EY := EY, This.EW := EW, This.EH := EH
		; Register WM_COMMAND handler
		This.CommandFunc := ObjBindMethod(This, "On_WM_COMMAND")
		 , OnMessage(0x0111, This.CommandFunc)
		 ; Register hotkeys
		If !(This.Next)
			This.RegisterHotkeys()
		This.Cancelled := False
		This.Next := False
		Return False
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; LVN_ENDLABELEDIT notification
   ; -------------------------------------------------------------------------------------------------------------------------------
	LVN_ENDLABELEDIT(L) {
		H := This.HWND, Item := This.Item, Subitem := This.Subitem, ItemText := This.ItemText
		; Unregister WM_COMMAND handler
		OnMessage(0x0111, This.CommandFunc, 0)
		This.CommandFunc := ""
		; Unregister hotkeys
		If !(This.Next)
			This.RegisterHotkeys(False)
		If !(This.Cancelled)
			ControlGetText, ItemText, , % "ahk_id " . This.HEDT
		If (ItemText <> This.ItemText) {
			If !(This["Changed"])
				This.Changed := []
			This.Changed.Push({Row: Item + 1, Col: Subitem + 1, Txt: ItemText})
		}
		; Restore subitem's text if changed or blanked out
		If (ItemText <> This.ItemText) || ((Subitem > 0) && (This.BlankSubitem)) {
			VarSetCapacity(LVITEM, 40 + (A_PtrSize * 5), 0) ; LVITEM structure
		    , NumPut(Item, LVITEM, 4, "Int")
		    , NumPut(Subitem, LVITEM, 8, "Int")
		    , NumPut(&ItemText, LVITEM, 16 + A_PtrSize, "Ptr") ; pszText in LVITEM
		    , DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1074 : 0x102E, "Ptr", Item, "Ptr", &LVITEM) ; LVM_SETITEMTEXT
		}
		If !(This.Next)
			This.Item := This.Subitem := -1
		This.Cancelled := False
		This.Next := False
		; Call the user function, if any
		If (This.EditUserFunc)
			This.EditUserFunc.Call("END", H, This.HEDT, Item + 1, Subitem + 1, ItemText)
		Return False
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; NM_DBLCLICK notification
   ; -------------------------------------------------------------------------------------------------------------------------------
	NM_DBLCLICK(L) {
		Static CBW := DllCall("GetSystemMetrics", "Int", 49, "Int")
		H := This.HWND
		 , This.Item := This.Subitem := -1
		 , Item := NumGet(L + (A_PtrSize * 3), 0, "Int")
		 , Subitem := NumGet(L + (A_PtrSize * 3), 4, "Int")
		If (This["Columns"]) && (!This["Columns", Subitem])
			Return False
		VarSetCapacity(RC, 16, 0)
		If (Item >= 0) && (Subitem >= 0) {
			This.Item := Item, This.Subitem := Subitem
			If !(This.Next) {
				Rows := DllCall("SendMessage", "Ptr", H, "UInt", 0x1004, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETITEMCOUNT
			  , This.MaxItem := Rows - 1
			  , Cols := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
			  , This.MaxSubitem := Cols - 1
			  , DllCall("GetClientRect", "Ptr", H, "Ptr", &RC)
			  , This.ClientW := NumGet(RC, 8, "Int")
			  , This.MinW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Str", "WWW", "Int") ; LVM_GETSTRINGWIDTH
			  , This.ExtW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Str", "III", "Int") ; LVM_GETSTRINGWIDTH
			  , This.Col1W := DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETCOLUMNWIDTH
			  , This.Checked := DllCall("SendMessage", "Ptr", H, "UInt", 0x1037, "Ptr", 0, "Ptr", 0, "UInt") & 0x00000004 ; LVM_GETEXTENDEDLISTVIEWSTYLE
			}
			Numput(0, RC, "Int")
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x100E, "Ptr", 0, "Ptr", &RC) ; LVM_GETITEMRECT
		    , CX := NumGet(RC, "Int")
		    , NumPut(Subitem = 0 ? 2 : 1, RC, "Int")
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x100E, "Ptr", 0, "Ptr", &RC) ; LVM_GETITEMRECT
		    , This.Indent := NumGet(RC, "Int") - CX - ((Subitem > 0) && This.Checked ? CBW : 0)
		    , NumPut(0, RC, "Int")
		    , NumPut(Subitem, RC, 4, "Int")
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x1038, "Ptr", Item, "Ptr", &RC) ; LVM_GETSUBITEMRECT
		    , CX := NumGet(RC, 0, "Int"), CY := NumGet(RC, 4, "Int")
		    , CR := (Subitem = 0 ? CX + This.Col1W : NumGet(RC, 8, "Int"))
		    , CW := (Subitem = 0 ? This.Col1W : CR - CX), CH := NumGet(RC, 12, "Int") - CY
			ScrollH := 0
			If (CX < 0) || This.ScrollToLeft
				ScrollH := CX
			Else If ((CX + CW) > This.ClientW) {
				ScrollH := CX + CW - This.ClientW
				If (ScrollH > CX)
					ScrollH := CX
			}
			If (ScrollH)
				DllCall("SendMessage", "Ptr", H, "UInt", 0x1014, "Ptr", ScrollH, "Ptr", 0) ; LVM_SCROLL
			This.CX := CX - ScrollH, This.CY := CY, This.CW := CW, This.CH := CH, This.CR := CR - ScrollH
			DllCall("PostMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1076 : 0x1017, "Ptr", Item, "Ptr", 0) ; LVM_EDITLABEL
		}
		Return False
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; Next subitem
   ; -------------------------------------------------------------------------------------------------------------------------------
	NextSubitem(K) {
      ; Hotkeys: 0x8009 (Tab -> right), 0x8409 (Shift+Tab -> left), 0x8028  (Down -> down), 0x8026 (Up -> up)
      ; Find the next subitem
		H := This.HWND
		Item := This.Item
		Subitem := This.Subitem
		If (K = 0x8028) || (K = 0x8026) ; down || up
			Item += (K = 0x8028) ? 1 : -1
		Else { ; left || right
			Next := (K = 0x8409) ? -1 : 1
			Loop {
				Subitem += Next
				If (This["Columns"]) {
					If (Subitem < This.Columns.MinIndex())
						Subitem := This.Columns.MaxIndex(), Item--
					Else If (Subitem > This.Columns.MaxIndex())
						Subitem := This.Columns.MinIndex(), Item++
					Else
						While (This["Columns", Subitem] = "")
							Subitem += Next
				}
				Else If (Subitem < 0)
					SubItem := This.MaxSubitem, Item--
				Else If (Subitem > This.MaxSubitem)
					Subitem := 0, Item++
				If (DllCall("SendMessage", "Ptr", This.HWND, "UInt", 0x101D, "Ptr", SubItem, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
					Break
			}
		}
		Item := (Item > This.MaxItem) ? 0 : (Item < 0) ? This.MaxItem : Item
		If (Item <> This.Item)
			DllCall("SendMessage", "Ptr", H, "UInt", 0x1013, "Ptr", Item, "Ptr", 0) ; LVM_ENSUREVISIBLE
		This.DoubleClick(Item, Subitem)
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; Double Click
   ; -------------------------------------------------------------------------------------------------------------------------------
	DoubleClick(Item, Subitem) {
		If (H := This.HWND) {
			VarSetCapacity(RC, 16, 0), NumPut(Subitem, RC, 4, "Int")
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x1038, "Ptr", Item, "Ptr", &RC) ; LVM_GETSUBITEMRECT
		    , Point := NumGet(RC, 0, "UShort") | (NumGet(RC, 4, "UShort") << 16)
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x0201, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONDOWN
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x0202, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONUP
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x0203, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONDBLCLK
		    , DllCall("SendMessage", "Ptr", H, "UInt", 0x0202, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONUP
		}
	}
   ; -------------------------------------------------------------------------------------------------------------------------------
   ; Register/UnRegister hotkeys
   ; -------------------------------------------------------------------------------------------------------------------------------
	RegisterHotkeys(Register = True) {
      ; WM_HOTKEY := 0x0312, MOD_SHIFT := 0x0004
      ; Hotkeys: 0x801B  (Esc -> cancel, 0x8009 (Tab -> right), 0x8409 (Shift+Tab -> left)
      ;          0x8028  (Down -> down), 0x8026 (Up -> up)
		H := This.HWND
		If (Register) { ; Register
			DllCall("RegisterHotKey", "Ptr", H, "Int", 0x801B, "UInt", 0, "UInt", 0x1B)
		    , DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8009, "UInt", 0, "UInt", 0x09)
		    , DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8409, "UInt", 4, "UInt", 0x09)
		    , DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8028, "UInt", 0, "UInt", 0x28)
		    , DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8026, "UInt", 0, "UInt", 0x26)
		    , This.HotkeyFunc := ObjBindMethod(This, "On_WM_HOTKEY")
		    , OnMessage(0x0312, This.HotkeyFunc) ; WM_HOTKEY
		}
		Else { ; Unregister
			DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x801B)
		    , DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8009)
		    , DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8409)
		    , DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8028)
		    , DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8026)
		    , OnMessage(0x0312, This.HotkeyFunc, 0) ; WM_HOTKEY
		    , This.HotkeyFunc := ""
		}
	}
}	

代码使用就是:ICELV2 := New LV_InCellEdit(listviewID, True)