#include #include #include #include #include #include #include "RandomArray.au3" ; LarsJ #include "DrawItem.au3" ; " Opt("MustDeclareVars", 1) Global $g_iRows = 1000, $g_iCols = 6, $g_hGui, $g_hListView, $g_hHeader, $g_hEdit Global $g_aCols = ["Strings", "Integers", "Floats", "Dates", "Times", "R/C"], $g_aWidths = [230, 61, 124, 70, 60, 60] Global $g_aColAligns[$g_iCols] = [2, 1, 1, 0, 1, 1] ; $HDF_LEFT = 0, $HDF_RIGHT = 1, $HDF_CENTER = 2 Global $g_idListView, $g_idMarker, $g_idComboCol, $g_idComboColDummy, $g_idEditDummy, $g_idEndDragDummy Global $g_sSearch, $g_iSearchCol, $g_iSortDir, $g_iSearch = $g_iRows, $g_iLvItem = -1, $g_i2Borders_Height Global $g_aArray, $g_aSubArray, $g_aSubArray2, $g_tDefaultIndex, $g_tIndex = DllStructCreate("uint arr[" & $g_iRows & "]") Global $g_aIndex[$g_iCols], $g_aIndexTemp[$g_iCols] ; VarGetType's : $g_aIndex => "Array", $g_aIndex[0] => "String" Global $g_idContextDummy, $g_hContextmenu, $g_iItem = -1, $g_iSubItem = -1, $g_bShowAllRows = False, $g_bRightClickHeaders = True Global $fListViewHasFocus = 1 ; trying this for now, we'll see... Example() Func Example() ; Generate array & one index _Generate_All($g_aArray) $g_aSubArray = $g_aArray $g_aSubArray2 = $g_aArray $g_tDefaultIndex = $g_tIndex ; Compute LV_Height based on 40 full visible rows, no additional vertical pixel. Local $iLV_Height = _ComputeLV_Height(40) ; only 1 param => LV got headers & border ConsoleWrite("Computed LV height = " & $iLV_Height & " pixels" & @crlf & @crlf) ; Create GUI $g_hGui = GUICreate("Virtual ListView + Incr. Search + no overlap (2y)", 630 + 20, $iLV_Height + 30 + 20) ; Create Edit control (search) + dummy control Local $idEdit = GUICtrlCreateEdit("", 120, 10, 182, 20, BitXOR($GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle($idEdit) $g_idEditDummy = GUICtrlCreateDummy() ; Create 2 Search Buttons (Prev / Next) & 2 Accelerator Keys (F3 / Shift+F3) Local $idPrev = GUICtrlCreateButton("Prev", 312, 10, 50, 20) Local $idNext = GUICtrlCreateButton("Next", 370, 10, 50, 20) GUICtrlSetState($idPrev, $GUI_DISABLE) GUICtrlSetState($idNext, $GUI_DISABLE) Local $aAccelKeys[2][2] = [ [ "{F3}", $idNext ], [ "+{F3}", $idPrev ] ] GUISetAccelerators($aAccelKeys) ; Create ComboBox control (how to search : RegEx or Normal ?) Local $idSearchHow = GUICtrlCreateCombo("RegEx search", 11, 9, 100, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) Local $sSearchHow = "RegEx search", $sSearchHowPrev = $sSearchHow ; default way of searching (changeable) GUICtrlSetData($idSearchHow, "Normal search", $sSearchHow) ; Create ComboBox control (column where to search) + dummy control GUICtrlCreateLabel("Col", 429, 10, 20, 20, BitOR($SS_CENTERIMAGE, $SS_CENTER)) $g_idComboCol = GUICtrlCreateCombo("0", 452, 9, 41, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) $g_iSearchCol = 0 ; default column where to search (changeable) Local $iSearchColPrev = $g_iSearchCol For $i = 1 To $g_iCols - 1 GUICtrlSetData($g_idComboCol, $i & "|", $g_iSearchCol) Next $g_idComboColDummy = GUICtrlCreateDummy() ; Create Label control (number of matching results) Local $idResult = GUICtrlCreateLabel(" " & $g_iRows & " rows (no pattern)", 501, 10, 135, 20, BitOR($SS_CENTERIMAGE, $SS_SUNKEN)) ; Create ListView $g_idListView = GUICtrlCreateListView("", 10, 40, 630, $iLV_Height, BitOr($GUI_SS_DEFAULT_LISTVIEW, $LVS_OWNERDATA, $LVS_OWNERDRAWFIXED), $WS_EX_CLIENTEDGE) _GUICtrlListView_SetExtendedListViewStyle($g_idListView, BitOr($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT, $LVS_EX_HEADERDRAGDROP)) $g_hListView = GUICtrlGetHandle($g_idListView) $g_hHeader = _GUICtrlListView_GetHeader($g_idListView) For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn($g_idListView, $g_aCols[$i], $g_aWidths[$i]) _GUICtrlHeader_SetItemFormat($g_hHeader, $i, $HDF_STRING + $g_aColAligns[$i]) Next Local $iGetItemSpacingY = _GUICtrlListView_GetItemSpacingY($g_idListView, True) ;~ ; No ListView column resizing by dragging header dividers (LarsJ) ;~ ;_WinAPI_SetWindowLong( $hHeader, $GWL_STYLE, _WinAPI_GetWindowLong( $hHeader, $GWL_STYLE ) + $HDS_NOSIZING ) ; AutoIt 3.3.14.5 issue ;~ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "SetWindowLongPtrW" : "SetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE, "long_ptr", _ ;~ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING ) ; Create Marker (an orange line placed above the header of the column being searched) $g_idMarker = GUICtrlCreateLabel("", 0, 0) GUICtrlSetBkColor(-1, 0xFFA060) ; orange _MoveMarker($g_iSearchCol) _GUICtrlListView_SetSelectedColumn($g_idListView, $g_iSearchCol) ; Create dummy control to catch header end drag notification (HDN_ENDDRAG) $g_idEndDragDummy = GUICtrlCreateDummy() ; Create Context menu $g_idContextDummy = GUICtrlCreateDummy() Local $idContextMenu = GUICtrlCreateContextMenu($g_idContextDummy) Local $idContext_GetText = GUICtrlCreateMenuItem("Get text", $idContextMenu) GUICtrlCreateMenuItem("", $idContextMenu) Local $idContext_ShowAll = GUICtrlCreateMenuItem("Show all rows", $idContextMenu) Local $idContext_RightClickHeaders = GUICtrlCreateMenuItem("Right-click Headers", $idContextMenu) GUICtrlSetState(-1, 1) ; $GUI_CHECKED = 1 $g_hContextMenu = GuiCtrlGetHandle($idContextMenu) ; Sorting information $g_iSortDir = 0x0400 ; $HDF_SORTUP = 0x0400 Local $iSortCol = -1, $iSortColPrev = -1 ; Register message handlers GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; Sets the virtual number of items in a virtual list-view control GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iRows, 0) GUISetState(@SW_SHOW) ; Message loop Local $aSearch[$g_iRows], $iStart While 1 Switch GUIGetMsg() Case $g_idComboCol, $g_idComboColDummy, $idSearchHow $g_iSearchCol = GUICtrlRead($g_idComboCol) $sSearchHow = GUICtrlRead($idSearchHow) Select Case $g_iSearchCol <> $iSearchColPrev _MoveMarker($g_iSearchCol) ; Search column will be selected below, after ContinueCase $iSearchColPrev = $g_iSearchCol Case $sSearchHow <> $sSearchHowPrev $sSearchHowPrev = $sSearchHow Case Else ; no change in both Combo controls (same search column, same search way) ContinueLoop EndSelect ContinueCase Case $g_idEditDummy _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING + ($iSortCol > -1 ? $g_aColAligns[$iSortCol] : 0)) $g_sSearch = GUICtrlRead($idEdit) $g_tIndex = $g_tDefaultIndex ; Sorting information (same as 1st launch, to avoid descending displays when all unsorted rows are shown) $g_iSortDir = 0x0400 ; $HDF_SORTUP = 0x0400 $iSortCol = -1 $iSortColPrev = -1 If $g_sSearch = "" Then ; Empty search string, display all rows $g_aSubArray = $g_aArray $g_aSubArray2 = $g_aArray $g_iSearch = $g_iRows GUICtrlSetState($idPrev, $GUI_DISABLE) GUICtrlSetState($idNext, $GUI_DISABLE) Else ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "Normal search" Then ; all searches use RegEx => escape 12 + 1 metacharacters $g_sSearch = StringRegExpReplace($g_sSearch, "(\\|\.|\^|\$|\||\[|\(|\{|\*|\+|\?|\#|\))" , "\\$1") EndIf ; ConsoleWrite("$sSearchHow = " & $sSearchHow & @TAB & "$g_sSearch = " & $g_sSearch & @lf) Dim $aSearch[$g_iRows] For $i = 0 To $g_iRows - 1 If StringRegExp($g_aArray[$i][$g_iSearchCol], "(?i)" & $g_sSearch) Then For $j = 0 To $g_iCols - 1 $g_aSubArray2[$g_iSearch][$j] = $g_aArray[$i][$j] Next $aSearch[$i] = 1 ; include row ($aSearch will serve if user wants to show all rows and click Next / Prec) $g_iSearch += 1 EndIf Next ; Delete eventual temporary subindexes For $i = 0 To $g_iCols - 1 If VarGetType($g_aIndexTemp[$i]) = "DLLStruct" Then $g_aIndexTemp[$i] = "" ; "String" Next $g_aSubArray = $g_bShowAllRows ? $g_aArray : $g_aSubArray2 GUICtrlSetState($idPrev, ($g_bShowAllRows And $g_iSearch And $g_iSearch < $g_iRows) ? $GUI_ENABLE : $GUI_DISABLE) GUICtrlSetState($idNext, ($g_bShowAllRows And $g_iSearch And $g_iSearch < $g_iRows) ? $GUI_ENABLE : $GUI_DISABLE) EndIf GUICtrlSetData($idResult, " " & $g_iSearch & ($g_sSearch = "" ? " rows (no pattern)" : " matching rows")) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_bShowAllRows ? $g_iRows : $g_iSearch, 0) _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSearchCol) ; seems ok here (after $LVM_SETITEMCOUNT) Case $g_idListView ; Sort $iSortCol = GUICtrlGetState($g_idListView) If $iSortCol <> $iSortColPrev Then _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortColPrev, $HDF_STRING + ($iSortColPrev > -1 ? $g_aColAligns[$iSortColPrev] : 0)) EndIf ; Set $g_tIndex + eventual update of $g_aIndex[$iSortCol] OR $g_aIndexTemp[$iSortCol] If $g_bShowAllRows Or $g_sSearch = "" Or $g_iSearch = $g_iRows Then _UpdateIndex($g_aIndex, $iSortCol) Else _UpdateIndex($g_aIndexTemp, $iSortCol) EndIf $g_iSortDir = (($iSortCol = $iSortColPrev) ? ($g_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING + $g_aColAligns[$iSortCol] + $g_iSortDir) GUICtrlSendMsg($g_idListView, $LVM_SETSELECTEDCOLUMN, $iSortCol, 0) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_bShowAllRows ? $g_iRows : $g_iSearch, 0) $iSortColPrev = $iSortCol ; Update $aSearch (eventually) + automatic display of 1st match (eventually too) If $g_bShowAllRows And $g_sSearch And $g_iSearch And $g_iSearch < $g_iRows Then _Update_aSearch($aSearch, $iSortCol, $idPrev, $idNext) EndIf Case $idNext $iStart = $g_iLvItem = - 1 ? 0 : $g_iLvItem < $g_iRows - 1 ? $g_iLvItem + 1 : 0 While 1 ; The while loop is used to start all over when last row in the listview is reached For $i = $iStart To $g_iRows - 1 If $aSearch[$i] And $i > $g_iLvItem Then ExitLoop Next If $i < $g_iRows Then ExitLoop $g_iLvItem = -1 $iStart = 0 Wend If $g_iLvItem > - 1 Then _GUICtrlListView_SetItemSelected($g_idListView, $g_iLvItem, False, False) _GUICtrlListView_EnsureVisible($g_idListView, $i) _GUICtrlListView_SetItemSelected($g_idListView, $i, True, True) Case $idPrev $iStart = $g_iLvItem = - 1 ? $g_iRows - 1 : $g_iLvItem > 0 ? $g_iLvItem - 1 : $g_iRows - 1 While 1 ; The while loop is used to start all over when first row in the listview is reached For $i = $iStart To 0 Step -1 If $aSearch[$i] And $i < $g_iLvItem Then ExitLoop Next If $i > -1 Then ExitLoop $g_iLvItem = $g_iRows $iStart = $g_iRows - 1 Wend If $g_iLvItem > - 1 Then _GUICtrlListView_SetItemSelected($g_idListView, $g_iLvItem, False, False) _GUICtrlListView_EnsureVisible($g_idListView, $i) _GUICtrlListView_SetItemSelected($g_idListView, $i, True, True) Case $g_idContextDummy If $g_iItem > - 1 Then _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSubItem) GUICtrlSetState($idContext_GetText, $g_iItem = - 1 ? $GUI_DISABLE : $GUI_ENABLE) Local $iMenu_Choice = _TrackPopupMenu($g_hContextMenu, $g_hGui, MouseGetPos(0), MouseGetPos(1)) If $iMenu_Choice Then Switch $iMenu_Choice Case $idContext_GetText ; Get text Local $sGetText = _GetText($g_iItem, $g_iSubItem) MsgBox($MB_TOPMOST, "Context menu", "Row = " & $g_iItem & " Column = " & $g_iSubItem & " Text = " & $sGetText & @lf) Case $idContext_ShowAll ; Show all rows ? If BitAND(GUICtrlRead($idContext_ShowAll), 4) = 4 Then ; $GUI_UNCHECKED = 4 GUICtrlSetState($idContext_ShowAll, 1) ; $GUI_CHECKED = 1 $g_bShowAllRows = True $g_aSubArray = $g_aArray ; Set $g_tIndex + eventual update $g_aIndex[$iSortCol] If $iSortCol > - 1 Then _UpdateIndex($g_aIndex, $iSortCol) ; Update $aSearch (eventually) + automatic display of 1st match (eventually too) If $g_sSearch And $g_iSearch And $g_iSearch < $g_iRows Then _Update_aSearch($aSearch, $iSortCol, $idPrev, $idNext) Else GUICtrlSetState($idContext_ShowAll, 4) ; $GUI_UNCHECKED = 4 $g_bShowAllRows = False $g_aSubArray = $g_aSubArray2 ; Set $g_tIndex + eventual update of $g_aIndexTemp[$iSortCol] If $iSortCol > - 1 Then _UpdateIndex($g_aIndexTemp, $iSortCol) ; No eventual update of $aSearch because $g_bShowAllRows = False (2 buttons Prev & Next are disable in this case) EndIf GUICtrlSetState($idPrev, ($g_bShowAllRows And $g_sSearch And $g_iSearch And $g_iSearch < $g_iRows) ? $GUI_ENABLE : $GUI_DISABLE) GUICtrlSetState($idNext, ($g_bShowAllRows And $g_sSearch And $g_iSearch And $g_iSearch < $g_iRows) ? $GUI_ENABLE : $GUI_DISABLE) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_bShowAllRows ? $g_iRows : $g_iSearch, 0) Case $idContext_RightClickHeaders ; Activate headers right-click ? If BitAND(GUICtrlRead($idContext_RightClickHeaders), 4) = 4 Then ; $GUI_UNCHECKED = 4 GUICtrlSetState($idContext_RightClickHeaders, 1) ; $GUI_CHECKED = 1 $g_bRightClickHeaders = True Else GUICtrlSetState($idContext_RightClickHeaders, 4) ; $GUI_UNCHECKED = 4 $g_bRightClickHeaders = False EndIf EndSwitch Endif Case $g_idEndDragDummy _MoveMarker(GUICtrlRead($g_idComboCol)) Case $GUI_EVENT_RESTORE ; needed, or Marker goes back in 0, 0 after Restore (why ?) _MoveMarker($g_iSearchCol) Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete($g_hGui) EndFunc ;==>Example ;======================================================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Display items in an owner drawn ListView (called once per item : no separate messages for each subitem +++) Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ), $tSize = DllStructCreate( $tagSIZE ) Local Static $hBrushYellow = _WinAPI_CreateSolidBrush( 0xFFFF00 ), $hBrushCyan = _WinAPI_CreateSolidBrush( 0x00FFFF ) ; Yellow and cyan, BGR Local Static $hBrushHighLight = _WinAPI_GetSysColorBrush( $COLOR_HIGHLIGHT ), $hBrushButtonFace = _WinAPI_GetSysColorBrush( $COLOR_BTNFACE ) Local $tDrawItem = DllStructCreate( $tagDRAWITEM, $lParam ), $itemID = DllStructGetData( $tDrawItem, "itemID" ), _ $iState = DllStructGetData( $tDrawItem, "itemState" ), $hDC = DllStructGetData( $tDrawItem, "hDC" ), $sItemText, $iKeep_Left, $iKeep_Right ; LV client area width is useful to prevent drawing actual non-visible column(s). This width changes when a vertical scrollbar appears/disappears. Local $aLVCli_Width = WinGetClientSize($g_hListView)[0] ; Loop through all columns For $iCol = 0 To $g_iCols - 1 ; Subitem rectangle DllStructSetData( $tRect, 2, $iCol ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $g_idListView, $LVM_GETSUBITEMRECT, $itemID, $pRect ) ; If $iCol = 0 (first column), the rectangle is calculated for the entire listview item. ; Compensate for this by setting the width of the rectangle to the width of the first column. ; Before that, if the item is selected, fill the entire listview item with the highlight background color. If $iCol = 0 Then If BitAND( $iState, $ODS_SELECTED ) Then DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $fListViewHasFocus = 1 ? $hBrushHighLight : $hBrushButtonFace ) ; _WinAPI_FillRect Local $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, 0) DllStructSetData( $tRect, 1, $tRect.Left + $aRect[0] ) ; left position of column 0 (relative to LV client area) DllStructSetData( $tRect, 3, $tRect.Left + $aRect[2] - $aRect[0] ) ; right position of column 0 EndIf ; Don't redraw an actual non-visible column (it makes a big difference for a fluent scrolling when there are many columns, tested) If $tRect.Right < 0 Or $tRect.Left > $aLVCli_Width Then ContinueLoop ; Retrieve subitem text If $g_iSortDir = 0x0400 Then ; $HDF_SORTUP = 0x0400 $sItemText = $g_aSubArray[$g_tIndex.arr($itemID + 1)][$iCol] Else $sItemText = $g_aSubArray[$g_tIndex.arr(($g_bShowAllRows ? $g_iRows : $g_iSearch) - $itemID)][$iCol] EndIf ; Keep left coord of subitem before it's lost $iKeep_Left = $tRect.Left If $g_aColAligns[$iCol] Then ; $HDF_RIGHT = 1, $HDF_CENTER = 2 DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 Switch $g_aColAligns[$iCol] Case 1 ; $HDF_RIGHT DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tSize, "X" ) - 6 ) Case 2 ; $HDF_CENTER DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + ( DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tRect, "Left" ) - DllStructGetData( $tSize, "X" ) ) / 2 - 3 ) EndSwitch Else ; $HDF_LEFT = 0 DllStructSetData( $tRect, "Left", $tRect.Left + 6) ; if left-aligned column, add some space between it and the column at its left EndIf ; Subitem text color DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", BitAND( $iState, $ODS_SELECTED ) ? $fListViewHasFocus = 1 ? 0xFFFFFF : 0x000000 : 0x000000 ) ; _WinAPI_SetTextColor ; Prevent overlapping of any text on column placed at the left of processed column If $tRect.Left < $iKeep_Left Then $tRect.Left = $iKeep_Left ; Draw subitem text DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText ; Mark matching substring only if column index = search column If $iCol <> $g_iSearchCol Then ContinueLoop ; Matching substring? If $g_sSearch Then Local $sMatch = StringRegExp( $sItemText, "(?i)" & $g_sSearch, 1 ) If Not @error Then ; match found Local $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; Keep right coord of subitem before it's lost $iKeep_Right = $tRect.Right ; Rectangle for matching substring DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sItemText, "int", $extended - $iLen - 1, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) ; Prevent overlapping of matching substring on column placed at the right of searched column If $tRect.Right > $iKeep_Right Then ContinueLoop ; Fill rectangle with yellow or cyan (selected) background color DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 1 ) ; Top margin DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", BitAND( $iState, $ODS_SELECTED ) ? $hBrushCyan : $hBrushYellow ) ; _WinAPI_FillRect ; Draw matching substring in rectangle DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) - 1 ) ; Top margin DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000 ) ; _WinAPI_SetTextColor DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText EndIf EndIf Next Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ;======================================================================== Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Switch HWnd(DllStructGetData($tNMHDR, "hWndFrom")) Case $g_hListView Switch DllStructGetData($tNMHDR, "Code") Case $LVN_ITEMCHANGED Local $tNMListView = DllStructCreate($tagNMLISTVIEW, $lParam) Local $iNewState = DllStructGetData($tNMListView, "NewState") If BitAND($iNewState, $LVIS_FOCUSED) Then $g_iLvItem = DllStructGetData($tNMListView, "Item") Case $NM_RCLICK Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam) $g_iItem = DllStructGetData($tInfo, "Index") ;~ If $g_iItem > -1 Then ; valid row $g_iSubItem = DllStructGetData($tInfo, "SubItem") GUICtrlSendToDummy($g_idContextDummy) ;~ EndIf Case $LVN_ENDSCROLL Local $tNMLVSCROLL = DllStructCreate($tagNMLVSCROLL, $lParam) If $tNMLVSCROLL.DX <> 0 Then _MoveMarker(GUICtrlRead($g_idComboCol)) ; move marker only when horizontal scroll EndSwitch Case $g_hHeader Switch DllStructGetData($tNMHDR, "Code") Case $NM_RCLICK If $g_bRightClickHeaders Then Local $aHit = _GUICtrlListView_SubItemHitTest($g_hListView) ; $aHit[1] : 0-based index of the LV subitem... i.e. the column in our case (may be -1 if right click on empty part of header) If $aHit[1] > - 1 Then ; valid column GUICtrlSetData($g_idComboCol, $aHit[1]) GUICtrlSendToDummy($g_idComboColDummy) EndIf EndIf Case $HDN_ENDTRACKW _MoveMarker(GUICtrlRead($g_idComboCol)) Case $HDN_ENDDRAG GUICtrlSendToDummy($g_idEndDragDummy) Return False ; allow changes Case $HDN_DIVIDERDBLCLICKW Local $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam) Local $iCol = DllStructGetData($tNMHEADER, "Item") _GUICtrlListView_SetColumnWidth($g_idListView, $iCol, $g_aWidths[$iCol]) ; initial size _MoveMarker(GUICtrlRead($g_idComboCol)) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ;======================================================================== Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) Local $hWndFrom = $lParam Local $iCode = BitShift($wParam, 16) ; High word Switch $hWndFrom Case $g_hEdit Switch $iCode Case $EN_CHANGE GUICtrlSendToDummy($g_idEditDummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;======================================================================== Func _Generate_All(ByRef $g_aArray) ConsoleWrite("$g_iRows = " & $g_iRows & " $g_iCols = " & $g_iCols & @CRLF) $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz") ; $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" & "\.^$|[({*+?#)") ; 12 + 1 RegEx metacharacters For $i = 0 To $g_iRows - 1 $g_tIndex.arr($i + 1) = $i Next EndFunc ;==>_Generate_All ;======================================================================== Func _SortArrayStruct(Const ByRef $aArray, $iCol, $iRows) Local $tIndex = DllStructCreate("uint arr[" & $iRows & "]") Local $pIndex = DllStructGetPtr($tIndex) Local Static $hDll = DllOpen("kernel32.dll") Local Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])[0] Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>_SortArrayStruct ;======================================================================== Func _UpdateIndex(ByRef $aIndex, $iCol) If VarGetType($aIndex[$iCol]) = "DLLStruct" Then $g_tIndex = $aIndex[$iCol] Else $g_tIndex = _SortArrayStruct($g_aSubArray, $iCol, $g_bShowAllRows ? $g_iRows : $g_iSearch) $aIndex[$iCol] = $g_tIndex ; "DLLStruct" (or "Int32" when no match found +++) EndIf EndFunc ;==>_UpdateIndex ;======================================================================== Func _Update_aSearch(ByRef $aSearch, $iSortCol, $idPrev, $idNext) $g_iSearch = 0 Dim $aSearch[$g_iRows] For $i = 0 To $g_iRows - 1 If StringRegExp($g_aArray[$g_tIndex.arr($g_iSortDir = 0x0400 ? $i + 1 : $g_iRows - $i)][$g_iSearchCol], "(?i)" & $g_sSearch) Then $aSearch[$i] = 1 ; include row $g_iSearch += 1 EndIf Next If $g_iSearch And $iSortCol = $g_iSearchCol Then GUICtrlSetState($idPrev, $GUI_ENABLE) GUICtrlSetState($idNext, $GUI_ENABLE) ControlClick($g_hGui, "", $idNext) EndIf EndFunc ;==>_Update_aSearch ;======================================================================== Func _MoveMarker($iCol) ; Below, there is probably an easier code to compute the "left header coord (relative to LV)" when horizontal scrolling is involved. ; The simpler code in Func WM_DRAWITEM (used for column 0) is easier as message LVM_GETSUBITEMRECT can be used in Func WM_DRAWITEM but ; not here (the listview may be empty if a search didn't match => no listview item 0 is present => LVM_GETSUBITEMRECT not usable here) Local $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, $iCol) ; ConsoleWrite("Header coords (relative to LV) : $aRect[0] = " & $aRect[0] & " $aRect[2] = " & $aRect[2] & @crlf) Local Static $tPoint = DllStructCreate("int X;int Y") DllStructSetData($tPoint, "X", $aRect[0]) DllStructSetData($tPoint, "Y", $aRect[1]) ; unused DllCall("user32.dll", "bool", "ClientToScreen", "hwnd", $g_hHeader, "struct*", $tPoint) ; _WinAPI_ClientToScreen ; ConsoleWrite("A : left header coord (screen) : $tPoint.X = " & $tPoint.X & @crlf) Local $aLVPos = WinGetPos($g_hListView) ; coords LV window . Left & Top will change when user moves the GUI ; ConsoleWrite("B : left LV client area coord : " & $aLVPos[0] + $g_i2Borders_Height / 2 & @crlf) ControlMove($g_hGui, "", $g_idMarker, $tPoint.X - ($aLVPos[0] + $g_i2Borders_Height / 2) + 10 , 40 - 3, $aRect[2] - $aRect[0] + 1, 3) ; 10 / 40 are LV coords ; ConsoleWrite("C : left header coord (rel LV) : " & $tPoint.X - ($aLVPos[0] + $g_i2Borders_Height / 2) & " (A - B)" & @crlf & @crlf) EndFunc ;==>_MoveMarker ;======================================================================== Func _TrackPopupMenu($hMenu, $hWnd, $iX, $iY) ; $TPM_RETURNCMD (0x0100) returns the menu item identifier of the user's selection in the return value. Return DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0x0100, "int", $iX, "int", $iY, "hwnd", $hWnd, "ptr", 0)[0] EndFunc ;==>_TrackPopupMenu ;======================================================================== Func _GetText($iItem, $iSubItem) Local $sGetText If $g_iSortDir = 0x0400 Then ; $HDF_SORTUP = 0x0400 $sGetText = $g_aSubArray[$g_tIndex.arr($iItem + 1)][$iSubItem] Else $sGetText = $g_aSubArray[$g_tIndex.arr(($g_bShowAllRows ? $g_iRows : $g_iSearch) - $iItem)][$iSubItem] EndIf Return $sGetText EndFunc ;==>_GetText ;======================================================================== Func _ComputeLV_Height($iNb_Rows, $bHeader = True, $bBorder = True) Local $hGui = GUICreate("", 170, 200) ; test values not to be changed Local $idListView = GUICtrlCreateListView("Col 0", 10, 10, 150, 180) ; border $WS_EX_CLIENTEDGE Local $iClient_Height = WinGetClientSize(GUICtrlGetHandle($idListView))[1] $g_i2Borders_Height = 180 - $iClient_Height Local $hHeader = GUICtrlSendMsg($idListView, $LVM_GETHEADER, 0, 0) Local $iHeader_Height = _WinAPI_GetWindowHeight($hHeader) Local $iGetItemSpacingY = _GUICtrlListView_GetItemSpacingY($idListView, True) GUIDelete($hGui) Return ($iNb_Rows * $iGetItemSpacingY) + ($bHeader ? $iHeader_Height : 0) + ($bBorder ? $g_i2Borders_Height : 0) EndFunc ;==>_ComputeLV_Height