List View with header tooltips

by Richard Russell, April 2011

The article List View with tooltips shows how to add tooltips to the main body of a List View control. Occasionally you may instead want to add tooltips to the column headers; the program listed below shows one way of achieving that. Basically it differs from the other program only in using the Header Control handle hwndHD% rather than the List View handle hwndLV%, and in substituting the LVM_SUBITEMHITTEST and LVM_GETITEMRECT messages with the equivalents for the Header Control: HDM_HITTEST and HDM_GETITEMRECT respectively.

It would be possible to combine the code from the two programs to provide tooltips for both the main body of the List View and the column headers. I will leave that as an exercise for the reader!

        REM. List View with header tooltips, Richard Russell, 05-Apr-2011
 
        REM. Install libraries:
        INSTALL @lib$+"WINLIB5"
 
        nColumns% = 5
 
        REM!WC Windows constants:
        GW_CHILD = 5
        HDM_GETITEMRECT = 4615
        HDM_HITTEST = 4614
        LVCF_FMT = 1
        LVCF_SUBITEM = 8
        LVCF_TEXT = 4
        LVCF_WIDTH = 2
        LVIF_PARAM = 4
        LVIF_STATE = 8
        LVIF_TEXT = 1
        LVM_GETTOOLTIPS = 4174
        LVM_INSERTCOLUMN = 4123
        LVM_INSERTITEM = 4103
        LVM_SETITEMTEXT = 4142
        LVS_REPORT = 1
        TTF_SUBCLASS = 16
        TTM_ADDTOOL = &404
        TTM_NEWTOOLRECT = &406
        TTM_UPDATETIPTEXT = &40C
 
        ON ERROR SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : PROCcleanup : QUIT
        ON CLOSE PROCcleanup : QUIT
 
        REM. Declare and initialise structures:
        DIM pt{x%,y%}, rc{l%,t%,r%,b%}
        DIM ti{cbSize%, uFlags%, hwnd%, uId%, rect{} = rc{}, hinst%, lpszText%}
        DIM hdh{pt{} = pt{}, flags%, iItem%}
        DIM lvc{mask%, fmt%, cx%, pszText%, cchTextMax%, iSubItem%}
        DIM lvi{mask%, iItem%, iSubItem%, state%, stateMask%, pszText%, \
        \       cchTextMax%, iImage%, lParam%}
        lvc.mask% = LVCF_WIDTH OR LVCF_SUBITEM OR LVCF_FMT OR LVCF_TEXT
        lvi.mask% = LVIF_TEXT OR LVIF_STATE OR LVIF_PARAM
 
        REM. Create list view control:
        SYS "InitCommonControls"
        dx% =  @vdu.tr%
        dy% =  @vdu.tb%
        hwndLV% = FN_createwindow("SysListView32", "", 0, 0, dx%, dy%, 0, LVS_REPORT, 0)
        SYS "GetWindow", hwndLV%, GW_CHILD TO hwndHD%
        FOR col% = 0 TO nColumns%-1
          title$ = "Column " + STR$col% + " header" + CHR$0
          lvc.cx%         = dx% DIV nColumns%
          lvc.pszText%    = !^title$
          lvc.cchTextMax% = LEN(title$)
          lvc.iSubItem%   = col%
          SYS "SendMessage", hwndLV%, LVM_INSERTCOLUMN, col%, lvc{}
        NEXT
        SYS "SendMessage", hwndLV%, LVM_GETTOOLTIPS, 0, 0 TO hwndTT%
        ti.cbSize% = DIM(ti{})
        ti.uFlags% = TTF_SUBCLASS
        ti.hwnd% = hwndHD%
        SYS "SendMessage", hwndTT%, TTM_ADDTOOL, 0, ti{}
 
        REM. Populate list view control:
        FOR item% = 0 TO 10
          FOR col% = 0 TO nColumns%
            text$ = "Item " + STR$item% + " column " + STR$col% + CHR$0
            lvi.iItem%      = item%
            lvi.iSubItem%   = col%
            lvi.pszText%    = !^text$
            lvi.cchTextMax% = LEN(text$)
            IF col% THEN
              SYS "SendMessage", hwndLV%, LVM_SETITEMTEXT, item%, lvi{}
            ELSE
              SYS "SendMessage", hwndLV%, LVM_INSERTITEM, item%, lvi{}
            ENDIF
          NEXT col%
        NEXT item%
 
        REM. Polling loop, monitoring mouse position:
        oldx% = -1
        oldy% = -1
        REPEAT
          WAIT 1
          SYS "GetCursorPos", pt{}
          SYS "ScreenToClient", hwndHD%, pt{}
          IF pt.x%<>oldx% OR pt.y%<>oldy% THEN
            oldx% = pt.x%
            oldy% = pt.y%
            PROCtooltip(pt.x%, pt.y%)
          ENDIF
        UNTIL FALSE
 
        DEF PROCtooltip(x%, y%)
        LOCAL tip$
        hdh.pt.x% = x%
        hdh.pt.y% = y%
        SYS "SendMessage", hwndHD%, HDM_HITTEST, 0, hdh{}
        IF hdh.iItem% >= 0 THEN
          SYS "SendMessage", hwndHD%, HDM_GETITEMRECT, hdh.iItem%, rc{}
          tip$ = "Tooltip for column " + STR$(hdh.iItem%) + CHR$0
          ti.lpszText% = !^tip$
          ti.rect.l% = rc.l%
          ti.rect.r% = rc.r%
          ti.rect.t% = rc.t%
          ti.rect.b% = rc.b%
          SYS "SendMessage", hwndTT%, TTM_UPDATETIPTEXT, 0, ti{}
          SYS "SendMessage", hwndTT%, TTM_NEWTOOLRECT, 0, ti{}
        ENDIF
        ENDPROC
 
        DEF PROCcleanup
        hwndLV% += 0 : IF hwndLV% PROC_closewindow(hwndLV%) : hwndLV% = 0
        ENDPROC