/* * Listview control * * Copyright 1998 Eric Kohl * Copyright 1999 Luc Tourangeau * * NOTES * Listview control implementation. The behavior conforms to version 4.70 * and earlier of the listview contol. * * TODO: * Most messages and notifications * Report, small icon and icon display modes */ #include #include "commctrl.h" #include "listview.h" #include "win.h" #include "debug.h" #include "winuser.h" /* prototypes */ static INT LISTVIEW_GetItemCountPerColumn(HWND hwnd); static INT LISTVIEW_GetItemCountPerRow(HWND hwnd); static INT LISTVIEW_GetFirstVisibleItem(HWND hwnd); static VOID LISTVIEW_SetVisible(HWND hwnd, INT nItem); /*** * DESCRIPTION: * Scrolls the specified item into the visible area. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * * RETURN: * None */ static VOID LISTVIEW_SetVisible(HWND hwnd, INT nItem) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCountPerRow; INT nItemCountPerColumn; INT nLastItem; INT nFirstItem; INT nHScrollPos; INT nVScrollPos; /* retrieve the index of the first visible fully item */ nFirstItem = LISTVIEW_GetFirstVisibleItem(hwnd); /* nunber of fully visible items per row */ nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); /* nunber of fully visible items per column */ nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0)) { if (lStyle & LVS_LIST) { if (lStyle & WS_HSCROLL) { /* last visible item index */ nLastItem = nItemCountPerColumn * nItemCountPerRow + nFirstItem - 1; if (nItem > nLastItem) { /* calculate new scroll position based on item index */ if (((nItem - nLastItem) % nItemCountPerColumn) == 0) nHScrollPos = (nItem - nLastItem) / nItemCountPerColumn; else nHScrollPos = (nItem - nLastItem) / nItemCountPerColumn + 1; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)nHScrollPos, (LPARAM)0); } else if (nItem < nFirstItem) { /* calculate new scroll position based on item index */ if (((nItem - nFirstItem) % nItemCountPerColumn) == 0) nHScrollPos = (nItem - nFirstItem) / nItemCountPerColumn; else nHScrollPos = (nItem - nFirstItem) / nItemCountPerColumn - 1; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)nHScrollPos, (LPARAM)0); } } } else if (lStyle & LVS_REPORT) { if (lStyle & WS_VSCROLL) { if (nFirstItem > 0) { nLastItem = nItemCountPerColumn + nFirstItem; } else { nLastItem = nItemCountPerColumn + nFirstItem - 1; } if (nItem > nLastItem) { /* calculate new scroll position based on item index */ nVScrollPos = nItem - nLastItem; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)0, (LPARAM)nVScrollPos); } else if (nItem < nFirstItem) { /* calculate new scroll position based on item index */ nVScrollPos = nItem - nFirstItem; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)0, (LPARAM)nVScrollPos); } } } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { if (lStyle & WS_VSCROLL) { /* last visible item index */ nLastItem = nItemCountPerColumn * nItemCountPerRow + nFirstItem - 1; if (nItem > nLastItem) { /* calculate new scroll position based on item index */ nVScrollPos = (nItem - nLastItem) / nItemCountPerRow + 1; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)0, (LPARAM)nVScrollPos); } else if (nItem < nFirstItem) { /* calculate new scroll position based on item index */ nHScrollPos = (nItem - nFirstItem) / nItemCountPerRow - 1; SendMessageA(hwnd, LVM_SCROLL, (WPARAM)0, (LPARAM)nHScrollPos); } } } /* refresh display */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } } /*** * DESCRIPTION: * Retrieves the index of the item at coordinate (0, 0) of the client area. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * item index */ static INT LISTVIEW_GetFirstVisibleItem(HWND hwnd) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCountPerRow; INT nItemCountPerColumn; INT nMinRange; INT nMaxRange; INT nHScrollPos; /* INT32 nVScrollPos; */ INT nItem = 0; /* get number of items per column */ nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); /* get number of fully visble items per row */ nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0)) { if (lStyle & LVS_LIST) { if (lStyle & WS_HSCROLL) { GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange); nHScrollPos = GetScrollPos(hwnd, SB_HORZ); if (nMinRange < nHScrollPos) { nItem = ((nHScrollPos - nMinRange) * nItemCountPerColumn * nItemCountPerRow); } } } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } return nItem; } /*** * DESCRIPTION: * Retrieves the number of items per row. In other words, the number * visible display columns. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of items per row. */ static INT LISTVIEW_GetItemCountPerRow(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCountPerRow = 0; if (infoPtr->nWidth > 0) { if (lStyle & LVS_LIST) { if (infoPtr->nColumnWidth > 0) { nItemCountPerRow = infoPtr->nWidth / infoPtr->nColumnWidth; if (nItemCountPerRow == 0) nItemCountPerRow = 1; } } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } return nItemCountPerRow; } /*** * DESCRIPTION: * Retrieves the number of items that can be displayed vertically in * the listview. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of items per column. */ static INT LISTVIEW_GetItemCountPerColumn(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCountPerColumn = 0; if (infoPtr->nHeight > 0) { if (lStyle & LVS_LIST) { if (infoPtr->nItemHeight > 0) nItemCountPerColumn = infoPtr->nHeight / infoPtr->nItemHeight; } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } return nItemCountPerColumn; } /*** * DESCRIPTION: * Retrieves the number of columns needed to display * all the items in listview. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of columns. */ static INT LISTVIEW_GetColumnCount(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nColumnCount = 0; INT nItemCountPerColumn; nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); if ((infoPtr->nItemCount > 0) && (nItemCountPerColumn > 0)) { if (lStyle & LVS_LIST) { if ((infoPtr->nItemCount % nItemCountPerColumn) == 0) { nColumnCount = infoPtr->nItemCount / nItemCountPerColumn ; } else { nColumnCount = infoPtr->nItemCount / nItemCountPerColumn + 1; } } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } return nColumnCount; } /*** * DESCRIPTION: * Sets the scrolling parameters. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * None */ static VOID LISTVIEW_SetScroll(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nColumnCount; INT nItemCountPerRow; INT nItemCountPerColumn; INT nMinRange, nMaxRange; INT nHScrollPos; /* INT32 nVScrollPos; */ nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0)) { if (lStyle & LVS_LIST) { /* get number of columns needed to display all the listview items */ nColumnCount = LISTVIEW_GetColumnCount(hwnd); if (nColumnCount > 0) { if (nColumnCount > nItemCountPerRow) { /* add scrollbar if not already present */ if (!(lStyle & WS_HSCROLL)) { /* display scrollbar */ ShowScrollBar(hwnd, SB_HORZ, TRUE); /* set scrollbar range and position */ nMaxRange = nColumnCount - nItemCountPerRow; SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); SetScrollPos(hwnd, SB_HORZ, 0, TRUE); } else { nHScrollPos = GetScrollPos(hwnd, SB_HORZ); GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange); if (nMaxRange != nColumnCount - nItemCountPerRow) { nMaxRange = nColumnCount - nItemCountPerRow; SetScrollRange(hwnd, SB_HORZ, nMinRange, nMaxRange, FALSE); if (nHScrollPos > nMaxRange) nHScrollPos = nMaxRange; SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE); } } /* refresh the client area */ InvalidateRect(hwnd,NULL, TRUE); UpdateWindow(hwnd); } else { /* remove scrollbar if present */ if (lStyle & WS_HSCROLL) { /* hide scrollbar */ ShowScrollBar(hwnd, SB_HORZ, FALSE); /* refresh the client area */ InvalidateRect(hwnd,NULL, TRUE); UpdateWindow(hwnd); } } } } else if (lStyle & LVS_REPORT) { HDLAYOUT hl; WINDOWPOS wp; RECT rc; rc.top = 0; rc.left = 0; rc.right = infoPtr->nWidth; rc.bottom = infoPtr->nHeight; hl.prc = &rc; hl.pwpos = ℘ SendMessageA(infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl); SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy, wp.flags); /* infoPtr->rcList.top += wp.cy; */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } } /*** * DESCRIPTION: * Modifies the state (selected and focused) of the listview items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : focused item index * [I] BOOL32 : flag for determining weither the control keys are used or not * [I] BOOL32 : flag for determining the input type (mouse or keyboard) * * RETURN: * None */ static VOID LISTVIEW_SetItemStates(HWND hwnd, INT nFocusedItem, BOOL bVirtualKeys, BOOL bMouseInput) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); WORD wShift = HIWORD(GetKeyState(VK_SHIFT)); WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL)); INT i; LVITEMA lvItem; /* initialize memory */ ZeroMemory(&lvItem, sizeof(LVITEMA)); if (wShift && (bVirtualKeys == TRUE)) { /* reset the selected and focused states of all the items */ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); if (infoPtr->nSelectionMark > nFocusedItem) { for (i = infoPtr->nSelectionMark; i > nFocusedItem; i--) { /* select items */ lvItem.stateMask = LVIS_SELECTED; lvItem.state = LVIS_SELECTED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)i, (LPARAM)&lvItem); } } else { for (i = infoPtr->nSelectionMark; i < nFocusedItem; i++) { /* select items */ lvItem.stateMask = LVIS_SELECTED; lvItem.state = LVIS_SELECTED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)i, (LPARAM)&lvItem); } } /* select anf focus item */ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = LVIS_SELECTED | LVIS_FOCUSED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)i, (LPARAM)&lvItem); } else { if (wCtrl && (bVirtualKeys == TRUE)) { /* make sure the focus is lost */ lvItem.stateMask = LVIS_FOCUSED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); if (bMouseInput == TRUE) { if (SendMessageA(hwnd, LVM_GETITEMSTATE, (WPARAM)nFocusedItem, (LPARAM)LVIS_SELECTED) & LVIS_SELECTED) { /* focus and unselect (toggle selection) */ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = LVIS_FOCUSED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)nFocusedItem, (LPARAM)&lvItem); } else { /* select and focus */ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = LVIS_SELECTED | LVIS_FOCUSED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)nFocusedItem, (LPARAM)&lvItem); } /* set the group selection start position */ infoPtr->nSelectionMark = nFocusedItem; } else { /* focus */ lvItem.stateMask = LVIS_FOCUSED; lvItem.state = LVIS_FOCUSED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)nFocusedItem, (LPARAM)&lvItem); } } else { /* clear selection and focus for all the items */ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); /* set select and focus for this particular item */ lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)nFocusedItem, (LPARAM)&lvItem); /* set the new group selection start position */ infoPtr->nSelectionMark = nFocusedItem; } } } /*** * DESCRIPTION: * Draws listview items when in list display maode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * None */ static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; HFONT hOldFont; HPEN hPen, hOldPen; INT nItemCountPerColumn; INT nItemCountPerRow; INT nSmallIconWidth; SIZE labelSize; INT nDrawPosX = 0; INT nDrawPosY = 0; BOOL bSelected; RECT rcBoundingBox; COLORREF clrHighlight; COLORREF clrHighlightText; INT i; INT nColumn = 0; INT nRow; INT j; /* get number of items per column */ nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); /* get number of items per row */ nItemCountPerRow = LISTVIEW_GetItemCountPerColumn(hwnd); if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0)) { /* select font */ hOldFont = SelectObject(hdc, infoPtr->hFont); /* inititialize system dependent information */ clrHighlight = GetSysColor(COLOR_HIGHLIGHT); clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT); nSmallIconWidth = GetSystemMetrics(SM_CXSMICON); /* select transparent brush (for drawing the focus box) */ SelectObject(hdc, GetStockObject(NULL_BRUSH)); /* select the doted pen (for drawing the focus box) */ hPen = CreatePen(PS_DOT, 1, 0); hOldPen = SelectObject(hdc, hPen); /* get starting index */ i = LISTVIEW_GetFirstVisibleItem(hwnd); /* DRAW ITEMS */ for (j = 0; i < infoPtr->nItemCount; i++, j++) { /* set draw position for current item */ nRow = j % nItemCountPerColumn; nColumn = j / nItemCountPerColumn; if (nRow == 0) nDrawPosY = 0; else nDrawPosY += infoPtr->nItemHeight; nDrawPosX = nColumn * infoPtr->nColumnWidth; /* get item */ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i); if (lpItem != NULL) { if (lpItem->state & LVIS_SELECTED) { bSelected = TRUE; /* set item colors */ SetBkColor(hdc, clrHighlight); SetTextColor(hdc, clrHighlightText); /* set raster mode */ SetROP2(hdc, R2_XORPEN); } else { bSelected = FALSE; /* set item colors */ SetBkColor(hdc, infoPtr->clrTextBk); SetTextColor(hdc, infoPtr->clrText); /* set raster mode */ SetROP2(hdc, R2_COPYPEN); } /* state images */ if (infoPtr->himlState != NULL) { /* right shift 12 bits to obtain index in image list */ if (bSelected == TRUE) ImageList_Draw(infoPtr->himlState, lpItem->state >> 12, hdc, nDrawPosX, nDrawPosY, ILD_SELECTED); else ImageList_Draw(infoPtr->himlState, lpItem->state >> 12, hdc, nDrawPosX, nDrawPosY, ILD_NORMAL); nDrawPosX += nSmallIconWidth; } /* small icons */ if (infoPtr->himlSmall != NULL) { if (bSelected == TRUE) ImageList_Draw(infoPtr->himlSmall, lpItem->iImage, hdc, nDrawPosX, nDrawPosY, ILD_SELECTED); else ImageList_Draw(infoPtr->himlSmall, lpItem->iImage, hdc, nDrawPosX, nDrawPosY, ILD_NORMAL); nDrawPosX += nSmallIconWidth; } /* get string size (in pixels) */ GetTextExtentPoint32A(hdc, lpItem->pszText, lstrlenA(lpItem->pszText), &labelSize); /* define a bounding box */ rcBoundingBox.left = nDrawPosX; rcBoundingBox.top = nDrawPosY; /* 2 pixels for padding purposes */ rcBoundingBox.right = nDrawPosX + labelSize.cx + 2; /* padding already included in infoPtr->nItemHeight */ rcBoundingBox.bottom = nDrawPosY + infoPtr->nItemHeight; /* draw text */ ExtTextOutA(hdc, nDrawPosX + 1, nDrawPosY+ 1, ETO_OPAQUE|ETO_CLIPPED, &rcBoundingBox, lpItem->pszText, lstrlenA(lpItem->pszText), NULL); if (lpItem->state & LVIS_FOCUSED) Rectangle(hdc, rcBoundingBox.left, rcBoundingBox.top, rcBoundingBox.right, rcBoundingBox.bottom); } } /* unselect objects */ SelectObject(hdc, hOldFont); SelectObject(hdc, hOldPen); /* delete pen */ DeleteObject(hPen); } } /*** * DESCRIPTION: * Draws listview items when in report display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * None */ static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc) { /* TO DO */ } /*** * DESCRIPTION: * Draws listview items when in small icon display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * None */ static VOID LISTVIEW_RefreshSmallIcon(HWND hwnd, HDC hdc) { /* TO DO */ } /*** * DESCRIPTION: * Draws listview items when in icon display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * None */ static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc) { /* TO DO */ } /*** * DESCRIPTION: * Draws listview items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * None */ static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); if (lStyle & LVS_LIST) { LISTVIEW_RefreshList(hwnd, hdc); } else if (lStyle & LVS_REPORT) { LISTVIEW_RefreshReport(hwnd, hdc); } else if (lStyle & LVS_SMALLICON) { LISTVIEW_RefreshSmallIcon(hwnd, hdc); } else if (lStyle & LVS_ICON) { LISTVIEW_RefreshIcon(hwnd, hdc); } } /*** * DESCRIPTION: * Calculates the approximate width and height of a given number of items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : number of items * [I] INT32 : width * [I] INT32 : height * * RETURN: * Returns a DWORD. The width in the low word and the height in high word. */ static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount, WORD wWidth, WORD wHeight) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCountPerColumn = 1; INT nColumnCount = 0; DWORD dwViewRect = 0; if (nItemCount == -1) nItemCount = infoPtr->nItemCount; if (lStyle & LVS_LIST) { if (wHeight == 0xFFFF) { /* use current height */ wHeight = infoPtr->nHeight; } if (wHeight < infoPtr->nItemHeight) { wHeight = infoPtr->nItemHeight; } if (nItemCount > 0) { if (infoPtr->nItemHeight > 0) { nItemCountPerColumn = wHeight / infoPtr->nItemHeight; if (nItemCountPerColumn == 0) nItemCountPerColumn = 1; if (nItemCount % nItemCountPerColumn != 0) nColumnCount = nItemCount / nItemCountPerColumn; else nColumnCount = nItemCount / nItemCountPerColumn + 1; } } wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2; wWidth = nColumnCount * infoPtr->nColumnWidth + 2; dwViewRect = MAKELONG(wWidth, wHeight); } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } return dwViewRect; } /*** * DESCRIPTION: * Arranges listview items in icon display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : alignment code * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode) { /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); BOOL bResult = FALSE; if (lStyle & LVS_ICON) { switch (nAlignCode) { case LVA_ALIGNLEFT: /* TO DO */ break; case LVA_ALIGNTOP: /* TO DO */ break; case LVA_DEFAULT: /* TO DO */ break; case LVA_SNAPTOGRID: /* TO DO */ } } return bResult; } /* << LISTVIEW_CreateDragImage >> */ /*** * DESCRIPTION: * Removes all listview items. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LISTVIEW_ITEM *lpItem; NMLISTVIEW nmlv; BOOL bNotify; INT i; BOOL bResult = TRUE; if (infoPtr->nItemCount > 0) { /* send LVN_DELETEALLITEMS notification */ ZeroMemory (&nmlv, sizeof (NMLISTVIEW)); nmlv.hdr.hwndFrom = hwnd; nmlv.hdr.idFrom = lCtrlId; nmlv.hdr.code = LVN_DELETEALLITEMS; nmlv.iItem = -1; bNotify = !(BOOL)SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv); nmlv.hdr.code = LVN_DELETEITEM; for (i = 0; i < infoPtr->nItemCount; i++) { if (bNotify == TRUE) { /* send LVN_DELETEITEM notification */ nmlv.iItem = i; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv); } /* get item */ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i); if (lpItem != NULL) { /* free item string */ if ((lpItem->pszText != NULL) && (lpItem->pszText != LPSTR_TEXTCALLBACKA)) COMCTL32_Free (lpItem->pszText); /* free item */ COMCTL32_Free (lpItem); } } /* ???? needs follow up */ DPA_DeleteAllPtrs (infoPtr->hdpaItems); /* reset item counter */ infoPtr->nItemCount = 0; /* reset scrollbar */ LISTVIEW_SetScroll(hwnd); } return bResult; } /*** * DESCRIPTION: * Removes a column from the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : column index * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn) { /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */ /* FIXME ??? */ /* if (infoPtr->nItemCount > 0) */ /* return FALSE; */ /* if (!SendMessage32A(infoPtr->hwndHeader, HDM_DELETEITEM, wParam, 0)) */ /* return FALSE; */ /* infoPtr->nColumnCount--; */ /* FIXME (listview, "semi stub!\n"); */ return TRUE; } /*** * DESCRIPTION: * Removes an item from the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LISTVIEW_ITEM *lpItem; NMLISTVIEW nmlv; BOOL bResult = FALSE; if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { /* send LVN_DELETEITEM notification */ ZeroMemory (&nmlv, sizeof (NMLISTVIEW)); nmlv.hdr.hwndFrom = hwnd; nmlv.hdr.idFrom = lCtrlId; nmlv.hdr.code = LVN_DELETEITEM; nmlv.iItem = nItem; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv); /* remove item */ lpItem = (LISTVIEW_ITEM*)DPA_DeletePtr (infoPtr->hdpaItems, nItem); if (lpItem != NULL) { /* free item string */ if ((lpItem->pszText != NULL) && (lpItem->pszText != LPSTR_TEXTCALLBACKA)) COMCTL32_Free (lpItem->pszText); /* free item */ COMCTL32_Free (lpItem); } /* decrement item counter */ infoPtr->nItemCount--; /* reset some of the draw data */ LISTVIEW_SetScroll(hwnd); bResult = TRUE; } return bResult; } /* << LISTVIEW_EditLabel >> */ /* << LISTVIEW_EnsureVisible >> */ /*** * DESCRIPTION: * Searches for an item with specific characteristics. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : base item index * [I] LPLVFINDINFO : item information to look for * * RETURN: * SUCCESS : index of item * FAILURE : -1 */ static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart, LPLVFINDINFO lpFindInfo) { /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */ /* LISTVIEW_ITEM *lpItem; */ /* INT32 nItem; */ /* INT32 nEnd = infoPtr->nItemCount; */ /* BOOL32 bWrap = FALSE; */ /* if (nStart == -1) */ /* nStart = 0; */ /* else */ /* nStart++ ; */ /* if (lpFindInfo->flags & LVFI_PARAM) */ /* { */ /* for (nItem = nStart; nItem < nEnd; nItem++) */ /* { */ /* get item pointer */ /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */ /* if (lpItem != NULL) */ /* { */ /* if (lpFindInfo->lParam == lpItem->lParam) */ /* return nItem; */ /* } */ /* } */ /* } */ /* else */ /* { */ /* if (lpFindInfo->flags & LVFI_PARTIAL) */ /* { */ /* for (nItem = nStart; nItem < nEnd; nItem++) */ /* { */ /* get item pointer */ /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */ /* if (lpItem) */ /* { */ /* if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz)) */ /* == 0) */ /* return nItem; */ /* } */ /* } */ /* } */ /* if (lpFindInfo->flags & LVFI_STRING) */ /* { */ /* for (nItem = nStart; nItem < nEnd; nItem++) */ /* { */ /* get item pointer */ /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */ /* if (lpItem != NULL) */ /* { */ /* if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */ /* return nItem; */ /* } */ /* } */ /* } */ /* if ((lpFindInfo->flags & LVFI_WRAP) && nStart) */ /* { */ /* nEnd = nStart; */ /* nStart = 0; */ /* bWrap = TRUE; */ /* } */ /* else */ /* bWrap = FALSE; */ return -1; } /*** * DESCRIPTION: * Retrieves the background color of the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * COLORREF associated with the background. */ static LRESULT LISTVIEW_GetBkColor(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); return infoPtr->clrBk; } /*** * DESCRIPTION: * Retrieves the background image of the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [O] LPLVMKBIMAGE : background image information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ /* static LRESULT LISTVIEW_GetBkImage(HWND32 hwnd, LPLVBKIMAGE lpBkImage) */ /* { */ /* return FALSE; */ /* } */ /* << LISTVIEW_GetCallbackMask >> */ /*** * DESCRIPTION: * Retrieves column attributes. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : column index * [IO] LPLVCOLUMN32A : column information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nIndex, LPLVCOLUMNA lpColumn) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); HDITEMA hdi; if (lpColumn == NULL) return FALSE; ZeroMemory (&hdi, sizeof(HDITEMA)); if (lpColumn->mask & LVCF_FMT) hdi.mask |= HDI_FORMAT; if (lpColumn->mask & LVCF_WIDTH) hdi.mask |= HDI_WIDTH; if (lpColumn->mask & LVCF_TEXT) hdi.mask |= (HDI_TEXT | HDI_FORMAT); if (lpColumn->mask & LVCF_IMAGE) hdi.mask |= HDI_IMAGE; if (lpColumn->mask & LVCF_ORDER) hdi.mask |= HDI_ORDER; if (!SendMessageA (infoPtr->hwndHeader, HDM_GETITEMA, (WPARAM)nIndex, (LPARAM)&hdi)) return FALSE; if (lpColumn->mask & LVCF_FMT) { lpColumn->fmt = 0; if (hdi.fmt & HDF_LEFT) lpColumn->fmt |= LVCFMT_LEFT; else if (hdi.fmt & HDF_RIGHT) lpColumn->fmt |= LVCFMT_RIGHT; else if (hdi.fmt & HDF_CENTER) lpColumn->fmt |= LVCFMT_CENTER; if (hdi.fmt & HDF_IMAGE) lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES; } if (lpColumn->mask & LVCF_WIDTH) lpColumn->cx = hdi.cxy; if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText)) lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax); if (lpColumn->mask & LVCF_IMAGE) lpColumn->iImage = hdi.iImage; if (lpColumn->mask & LVCF_ORDER) lpColumn->iOrder = hdi.iOrder; return TRUE; } /* << LISTVIEW_GetColumn32W >> */ /* << LISTVIEW_GetColumnOrderArray >> */ /*** * DESCRIPTION: * Retrieves the column width when list or report display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [I] int32 : column index * * RETURN: * SUCCESS : column width * FAILURE : zero */ static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); HDITEMA hdi; INT nColumnWidth = 0; if ((lStyle & LVS_LIST) || (lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nColumnWidth = infoPtr->nColumnWidth; } else if (lStyle & LVS_REPORT) { /* verify validity of index */ if ((nColumn >= 0) && (nColumn < infoPtr->nColumnCount)) { /* get column width from header */ hdi.mask = HDI_WIDTH; if (SendMessageA (infoPtr->hwndHeader, HDM_GETITEMA, (WPARAM)nColumn, (LPARAM)&hdi)) nColumnWidth = hdi.cxy; } } return nColumnWidth; } /*** * DESCRIPTION: * In list or report display mode, retrieves the number of items that can fit * vertically in the visible area. In icon or small icon display mode, * retrieves the total number of visible items. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of fully visible items. */ static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nItemCount = 0; INT nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); INT nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); if (lStyle & LVS_LIST) { if ((nItemCountPerRow > 0) && (nItemCountPerColumn > 0)) { nItemCount = nItemCountPerRow * nItemCountPerColumn; } } else if (lStyle & LVS_REPORT) { nItemCount = nItemCountPerColumn; } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nItemCount = infoPtr->nItemCount; } return nItemCount; } /* << LISTVIEW_GetEditControl >> */ /* << LISTVIEW_GetExtendedListViewStyle >> */ /*** * DESCRIPTION: * Retrieves a header handle. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Header handle. */ static LRESULT LISTVIEW_GetHeader(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); return infoPtr->hwndHeader; } /* << LISTVIEW_GetHotCursor >> */ /* << LISTVIEW_GetHotItem >> */ /* << LISTVIEW_GetHoverTime >> */ /*** * DESCRIPTION: * Retrieves an image list handle. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : image list identifier * * RETURN: * SUCCESS : image list handle * FAILURE : NULL */ static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); HIMAGELIST himl = NULL; switch (nImageList) { case LVSIL_NORMAL: himl = infoPtr->himlNormal; case LVSIL_SMALL: himl = infoPtr->himlSmall; case LVSIL_STATE: himl = infoPtr->himlState; } return (LRESULT)himl; } /* << LISTVIEW_GetISearchString >> */ /*** * DESCRIPTION: * Retrieves item attributes. * * PARAMETER(S): * [I] HWND32 : window handle * [IO] LPLVITEM32A : item info * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpListItem; BOOL bResult = FALSE; if (lpItem != NULL) { if ((lpItem->iItem >= 0) && (lpItem->iItem < infoPtr->nItemCount)) { /* get item */ lpListItem = DPA_GetPtr(infoPtr->hdpaItems, lpItem->iItem); if (lpListItem != NULL) { /* not tested for subitem > 0 */ lpListItem += lpItem->iSubItem; if (lpListItem != NULL) { /* retrieve valid data */ if (lpItem->mask & LVIF_STATE) lpItem->state = lpListItem->state & lpItem->stateMask; if (lpItem->mask & LVIF_TEXT) { if (lpListItem->pszText == LPSTR_TEXTCALLBACKA) lpItem->pszText = LPSTR_TEXTCALLBACKA; else Str_GetPtrA(lpListItem->pszText, lpItem->pszText, lpItem->cchTextMax); } if (lpItem->mask & LVIF_IMAGE) lpItem->iImage = lpListItem->iImage; if (lpItem->mask & LVIF_PARAM) lpItem->lParam = lpListItem->lParam; if (lpItem->mask & LVIF_INDENT) lpItem->iIndent = lpListItem->iIndent; bResult = TRUE; } } } } return bResult; } /* << LISTVIEW_GetItem32W >> */ /* << LISTVIEW_GetHotCursor >> */ /* << LISTVIEW_GetHotItem >> */ /* << LISTVIEW_GetHoverTime >> */ /*** * DESCRIPTION: * Retrieves the number of items in the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of items. */ static LRESULT LISTVIEW_GetItemCount(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); return infoPtr->nItemCount; } /*** * DESCRIPTION: * Retrieves the position (upper-left) of the listview control item. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [O] LPPOINT32 : coordinate information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, LPPOINT lpPt) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nColumn; INT nRow; BOOL bResult = FALSE; INT nItemCountPerColumn; INT nItemCountPerRow; INT nFirstItem; INT nLastItem; if ((nItem >= 0) && (nItem < infoPtr->nItemCount) && (lpPt != NULL)) { if (lStyle & LVS_LIST) { nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); if ((nItemCountPerColumn > 0) && (nItemCountPerRow > 0)) { nFirstItem = LISTVIEW_GetFirstVisibleItem(hwnd); nLastItem = nFirstItem + nItemCountPerRow * nItemCountPerRow - 1; if ((nItem >= nFirstItem) || (nItem <= nLastItem)) { nItem -= nFirstItem; /* get column */ nColumn = nItem / nItemCountPerColumn; /* get row */ nRow = nItem % nItemCountPerColumn; /* X coordinate of the column */ lpPt->x = nColumn * infoPtr->nColumnWidth; /* Y coordinate of the item */ lpPt->y = nRow * infoPtr->nItemHeight; bResult = TRUE; } } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } } } return bResult; } /*** * DESCRIPTION: * Retrieves the bounding rectangle for a listview control item. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [IO] LPRECT32 : bounding rectangle coordinates * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lpRect) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; POINT pt; INT nLabelWidth; BOOL bResult = FALSE; INT nSmallIconWidth; nSmallIconWidth = GetSystemMetrics(SM_CXSMICON); if ((nItem < 0) || (nItem >= infoPtr->nItemCount) || (lpRect == NULL)) return FALSE; /* get item */ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpItem == NULL) return FALSE; if (!SendMessageA(hwnd, LVM_GETITEMPOSITION, (WPARAM)nItem, (LPARAM)&pt)) return FALSE; nLabelWidth = SendMessageA(hwnd, LVM_GETSTRINGWIDTHA, (WPARAM)0, (LPARAM)lpItem->pszText); switch(lpRect->left) { case LVIR_BOUNDS: lpRect->left = pt.x; lpRect->top = pt.y; lpRect->right = lpRect->left + nSmallIconWidth + nLabelWidth; lpRect->bottom = lpRect->top + infoPtr->nItemHeight; bResult = TRUE; break; case LVIR_ICON: lpRect->left = pt.x; lpRect->top = pt.y; lpRect->right = lpRect->left + nSmallIconWidth; lpRect->bottom = lpRect->top + infoPtr->nItemHeight; bResult = TRUE; break; case LVIR_LABEL: lpRect->left = pt.x + nSmallIconWidth; lpRect->top = pt.y; lpRect->right = lpRect->left + nLabelWidth; lpRect->bottom = infoPtr->nItemHeight; bResult = TRUE; break; case LVIR_SELECTBOUNDS: /* TO DO */ break; } return bResult; } /*** * DESCRIPTION: * Retrieves the spacing between listview control items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] BOOL32 : small icon (TRUE) or large icon (FALSE) * * RETURN: * Horizontal + vertical spacing */ static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall) { INT nSmallIconHSpacing; INT nSmallIconVSpacing; INT nIconHSpacing; INT nIconVSpacing; LONG lResult = 0; if (bSmall == TRUE) { /* ??? */ nSmallIconHSpacing = 0; nSmallIconVSpacing = 0; lResult = MAKELONG(nSmallIconHSpacing, nSmallIconVSpacing); } else { nIconHSpacing = GetSystemMetrics(SM_CXICONSPACING); nIconVSpacing = GetSystemMetrics(SM_CYICONSPACING); lResult = MAKELONG(nIconHSpacing, nIconVSpacing); } return lResult; } /*** * DESCRIPTION: * Retrieves the state of a listview control item. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [I] UINT32 : state mask * * RETURN: * State specified by the mask. */ static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; INT nState = 0; if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpItem != NULL) nState = lpItem->state & uMask; } return nState; } /*** * DESCRIPTION: * Retrieves the text of a listview control item or subitem. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [IO] LPLVITEM32A : item information * * RETURN: * None */ static VOID LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpListItem; if ((nItem < 0) || (nItem >= infoPtr->nItemCount) || (lpItem == NULL)) return; lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpListItem == NULL) return; lpListItem += lpItem->iSubItem; if (lpListItem == NULL) return; if (lpListItem->pszText == LPSTR_TEXTCALLBACKA) lpItem->pszText = LPSTR_TEXTCALLBACKA; else Str_GetPtrA(lpListItem->pszText, lpItem->pszText, lpItem->cchTextMax); } /*** * DESCRIPTION: * Searches for an item based on properties + relationships. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [I] UINT32 : relationship flag * * RETURN: * SUCCESS : item index * FAILURE : -1 */ static LRESULT LISTVIEW_GetNextItem (HWND hwnd, INT nItem, UINT uFlags) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); INT nResult = -1; /* start at begin */ if (nItem == -1) nItem = 0; if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { /* TO DO */ } return nResult; } /* << LISTVIEW_GetNumberOfWorkAreas >> */ /*** * DESCRIPTION: * Retrieves the current origin when in icon or small icon display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [O] LPPOINT32 : coordinate information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpOrigin) { LONG lStyle = GetWindowLongA(hwnd, GWL_ID); BOOL bResult = FALSE; if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } return bResult; } /*** * DESCRIPTION: * Retrieves the number of items that are marked as selected. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Number of items selected. */ static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; INT nSelectedCount = 0; INT i; for (i = 0; i < infoPtr->nItemCount; i++) { lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i); if (lpItem != NULL) { if (lpItem->state & LVIS_SELECTED) nSelectedCount++; } } return nSelectedCount; } /*** * DESCRIPTION: * Retrieves item index that marks the start of a multiple selection. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Index number or -1 if there is no selection mark. */ static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); INT nResult = -1; if (SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, (WPARAM)0, (LPARAM)0) != 0) nResult = infoPtr->nSelectionMark; return nResult; } /*** * DESCRIPTION: * Retrieves the width of a string. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * SUCCESS : string width (in pixels) * FAILURE : zero */ static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpsz) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); HFONT hFont, hOldFont; HDC hdc; SIZE textSize; INT nResult = 0; if (lpsz != NULL) { hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); hdc = GetDC(hwnd); hOldFont = SelectObject (hdc, hFont); GetTextExtentPoint32A(hdc, lpsz, lstrlenA(lpsz), &textSize); SelectObject (hdc, hOldFont); ReleaseDC(hwnd, hdc); nResult = textSize.cx; } return nResult; } /*** * DESCRIPTION: * Retrieves the text backgound color. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * COLORREF associated with the the background. */ static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); return infoPtr->clrTextBk; } /*** * DESCRIPTION: * Retrieves the text color. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * COLORREF associated with the text. */ static LRESULT LISTVIEW_GetTextColor(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); return infoPtr->clrText; } /*** * DESCRIPTION: * Retrieves the bounding rectangle of all the items. * * PARAMETER(S): * [I] HWND32 : window handle * [O] LPRECT32 : bounding rectangle * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lpBoundingRect) { /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); BOOL bResult = FALSE; if (lpBoundingRect != NULL) { if ((lStyle & LVS_ICON) || (lStyle & LVS_SMALLICON)) { /* TO DO */ } } return bResult; } /*** * DESCRIPTION: * Determines item index when in small icon view. * * PARAMETER(S): * [I] HWND32 : window handle * [IO] LPLVHITTESTINFO : hit test information * * RETURN: * SUCCESS : item index * FAILURE : -1 */ static LRESULT HitTestSmallIconView(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; INT nColumn; INT nRow; INT nItem = 0; INT nLabelWidth; INT nOffset; INT nPosX = 0; INT nSmallIconWidth; INT nItemCountPerRow; /* get column */ nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth; /* get row */ nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight; /* calculate offset from start of column (in pixels) */ nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth; /* get recommended width of a small icon */ nSmallIconWidth = GetSystemMetrics(SM_CXSMICON); /* calculate index */ nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); nItem = nRow * nItemCountPerRow + LISTVIEW_GetFirstVisibleItem(hwnd) + nColumn; /* verify existance of item */ if (nItem < infoPtr->nItemCount) { /* get item */ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpItem != NULL) { if (infoPtr->himlState != NULL) { nPosX += nSmallIconWidth; if (nOffset <= nPosX) { lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } if (infoPtr->himlSmall != NULL) { nPosX += nSmallIconWidth; if (nOffset <= nPosX) { lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } /* get width of label in pixels */ nLabelWidth = SendMessageA(hwnd, LVM_GETSTRINGWIDTHA, (WPARAM)0, (LPARAM)lpItem->pszText); nLabelWidth += nPosX; if (nOffset <= nLabelWidth) { lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } } /* hit is not on an item */ lpHitTestInfo->flags = LVHT_NOWHERE; return -1; } /*** * DESCRIPTION: * Determines item index when in list display mode. * * PARAMETER(S): * [I] HWND32 : window handle * [IO] LPLVHITTESTINFO : hit test information * * RETURN: * SUCCESS : item index * FAILURE : -1 */ static LRESULT HitTestListView(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpItem; INT nColumn; INT nRow; INT nItem = 0; INT nLabelWidth; INT nOffset; INT nPosX = 0; INT nSmallIconWidth; INT nItemCountPerColumn; /* get column */ nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth; /* get row */ nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight; /* calculate offset from start of column (in pixels) */ nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth; /* get recommended width of a small icon */ nSmallIconWidth = GetSystemMetrics(SM_CXSMICON); /* calculate index */ nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); nItem = (nColumn * nItemCountPerColumn + LISTVIEW_GetFirstVisibleItem(hwnd) + nRow); /* verify existance of item */ if (nItem < infoPtr->nItemCount) { /* get item */ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpItem != NULL) { if (infoPtr->himlState != NULL) { nPosX += nSmallIconWidth; if (nOffset <= nPosX) { lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } if (infoPtr->himlSmall != NULL) { nPosX += nSmallIconWidth; if (nOffset <= nPosX) { lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } /* get width of label in pixels */ nLabelWidth = SendMessageA(hwnd, LVM_GETSTRINGWIDTHA, (WPARAM)0, (LPARAM)lpItem->pszText); nLabelWidth += nPosX; if (nOffset <= nLabelWidth) { lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM; lpHitTestInfo->iItem = nItem; lpHitTestInfo->iSubItem = 0; return nItem; } } } /* hit is not on an item */ lpHitTestInfo->flags = LVHT_NOWHERE; return -1; } /*** * DESCRIPTION: * Determines wich listview item is located at the specified position. * * PARAMETER(S): * [I] HWND32 : window handle * [IO} LPLVHITTESTINFO : hit test information * * RETURN: * SUCCESS : item index * FAILURE : -1 */ static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); if (lStyle & LVS_LIST) return HitTestListView(hwnd, lpHitTestInfo); else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { return HitTestSmallIconView(hwnd, lpHitTestInfo); } else if (lStyle & LVS_ICON) { /* TO DO */ } return -1; } /*** * DESCRIPTION: * Inserts a new column. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : column index * [I] LPLVCOLUMN32A : column information * * RETURN: * SUCCESS : new column index * FAILURE : -1 */ static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nIndex, LPLVCOLUMNA lpColumn) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); HDITEMA hdi; INT nResult; if ((lpColumn == NULL) || (infoPtr->nItemCount > 0)) return -1; FIXME (listview, "(%d %p): semi stub!\n", nIndex, lpColumn); /* initialize memory */ ZeroMemory (&hdi, sizeof(HDITEMA)); if (lpColumn->mask & LVCF_FMT) { if (nIndex == 0) hdi.fmt |= HDF_LEFT; else if (lpColumn->fmt & LVCFMT_LEFT) hdi.fmt |= HDF_LEFT; else if (lpColumn->fmt & LVCFMT_RIGHT) hdi.fmt |= HDF_RIGHT; else if (lpColumn->fmt & LVCFMT_CENTER) hdi.fmt |= HDF_CENTER; if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) hdi.fmt |= HDF_IMAGE; hdi.mask |= HDI_FORMAT; } if (lpColumn->mask & LVCF_WIDTH) { hdi.mask |= HDI_WIDTH; hdi.cxy = lpColumn->cx; } if (lpColumn->mask & LVCF_TEXT) { hdi.mask |= (HDI_TEXT | HDI_FORMAT); hdi.pszText = lpColumn->pszText; hdi.fmt |= HDF_STRING; } if (lpColumn->mask & LVCF_IMAGE) { hdi.mask |= HDI_IMAGE; hdi.iImage = lpColumn->iImage; } if (lpColumn->mask & LVCF_ORDER) { hdi.mask |= HDI_ORDER; hdi.iOrder = lpColumn->iOrder; } nResult = SendMessageA (infoPtr->hwndHeader, HDM_INSERTITEMA, (WPARAM)nIndex, (LPARAM)&hdi); if (nResult == -1) return -1; /* increment column counter */ infoPtr->nColumnCount++; return nResult; } /* << LISTVIEW_InsertColumn32W >> */ /*** * DESCRIPTION: * Inserts a new item in the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [I] LPLVITEM32A : item information * * RETURN: * SUCCESS : new item index * FAILURE : -1 */ static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LISTVIEW_ITEM *lpListItem; INT nItem; NMLISTVIEW nmlv; LVITEMA lvItem; INT nColumnWidth = 0; INT nSmallIconWidth; if (lpItem == NULL) return -1; if (lpItem->iSubItem != 0) return -1; /* allocate memory */ lpListItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM)); if (lpListItem == NULL) return -1; nSmallIconWidth = GetSystemMetrics(SM_CXSMICON); /* initialize listview control item */ ZeroMemory(lpListItem, sizeof(LISTVIEW_ITEM)); /* copy only valid data */ if (lpItem->mask & LVIF_TEXT) { if (lpItem->pszText == LPSTR_TEXTCALLBACKA) { if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING)) return -1; lpListItem->pszText = LPSTR_TEXTCALLBACKA; } else { nColumnWidth = SendMessageA(hwnd, LVM_GETSTRINGWIDTHA, (WPARAM)0, (LPARAM)lpItem->pszText); /* add padding for separating columns */ nColumnWidth += 10; /* calculate column width; make sure it's at least 96 pixels */ if (nColumnWidth < 96) nColumnWidth = 96; Str_SetPtrA(&lpListItem->pszText, lpItem->pszText); } } if (lpItem->mask & LVIF_STATE) { if (lpItem->stateMask & LVIS_FOCUSED) { /* clear LVIS_FOCUSED states */ ZeroMemory(&lvItem, sizeof(LVITEMA)); lvItem.stateMask = LVIS_FOCUSED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); /* set focused item index */ infoPtr->nFocusedItem = lpItem->iItem; } lpListItem->state = lpItem->state & lpItem->stateMask; } if (lpItem->mask & LVIF_IMAGE) lpListItem->iImage = lpItem->iImage; if (lpItem->mask & LVIF_PARAM) lpListItem->lParam = lpItem->lParam; if (lpItem->mask & LVIF_INDENT) lpListItem->iIndent = lpItem->iIndent; /* insert item in listview control data structure */ nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpItem->iItem, lpListItem); if (nItem == -1) return -1; /* increment item counter */ infoPtr->nItemCount++; /* calculate column width */ if (infoPtr->himlSmall != NULL) nColumnWidth += nSmallIconWidth; /* calculate column width */ if (infoPtr->himlState != NULL) nColumnWidth += nSmallIconWidth; /* set column width */ if (nColumnWidth > infoPtr->nColumnWidth) infoPtr->nColumnWidth = nColumnWidth; /* set drawing data */ LISTVIEW_SetScroll(hwnd); /* send LVN_INSERTITEM notification */ ZeroMemory (&nmlv, sizeof (NMLISTVIEW)); nmlv.hdr.hwndFrom = hwnd; nmlv.hdr.idFrom = lCtrlId; nmlv.hdr.code = LVN_INSERTITEM; nmlv.iItem = nItem; SendMessageA(GetParent (hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv); InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); return nItem; } /* << LISTVIEW_InsertItem32W >> */ /*** * DESCRIPTION: * Redraws a range of items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : first item * [I] INT32 : last item * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); if (nFirst > nLast) return FALSE; if ((nFirst < 0) || (nFirst >= infoPtr->nItemCount)) return FALSE; if ((nLast < 0) || (nLast >= infoPtr->nItemCount)) return FALSE; /* TO DO */ return TRUE; } /*** * DESCRIPTION: * Scrolls the content of a listview. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : amount of horizontal scrolling * [I] INT32 : amount of vertical scrolling * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_Scroll(HWND hwnd, INT nHScroll, INT nVScroll) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); BOOL bResult = FALSE; INT nHScrollPos; INT nMinRange; INT nMaxRange; if (lStyle & LVS_LIST) { nHScrollPos = GetScrollPos(hwnd, SB_HORZ); GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange); if ((nMinRange <= nHScrollPos + nHScroll) && (nHScrollPos + nHScroll <= nMaxRange)) { bResult = TRUE; nHScrollPos += nHScroll; SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE); /* refresh client area */ InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } } else if (lStyle & LVS_REPORT) { /* TO DO */ } else if (lStyle & LVS_SMALLICON) { /* TO DO */ } else if (lStyle & LVS_ICON) { /* TO DO */ } return bResult; } /*** * DESCRIPTION: * Sets the background color. * * PARAMETER(S): * [I] HWND32 : window handle * [I] COLORREF : background color * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); infoPtr->clrBk = clrBk; InvalidateRect(hwnd, NULL, TRUE); return TRUE; } /*** * DESCRIPTION: * Sets column attributes. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : column index * [I] LPLVCOLUMN32A : column information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nIndex, LPLVCOLUMNA lpColumn) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); HDITEMA hdi; if (lpColumn == NULL) return -1; /* initialize memory */ ZeroMemory (&hdi, sizeof(HDITEMA)); if (lpColumn->mask & LVCF_FMT) { if (nIndex == 0) hdi.fmt |= HDF_LEFT; else if (lpColumn->fmt & LVCFMT_LEFT) hdi.fmt |= HDF_LEFT; else if (lpColumn->fmt & LVCFMT_RIGHT) hdi.fmt |= HDF_RIGHT; else if (lpColumn->fmt & LVCFMT_CENTER) hdi.fmt |= HDF_CENTER; if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) hdi.fmt |= HDF_IMAGE; hdi.mask |= HDI_FORMAT; } if (lpColumn->mask & LVCF_WIDTH) { hdi.mask |= HDI_WIDTH; hdi.cxy = lpColumn->cx; } if (lpColumn->mask & LVCF_TEXT) { hdi.mask |= (HDI_TEXT | HDI_FORMAT); hdi.pszText = lpColumn->pszText; hdi.fmt |= HDF_STRING; } if (lpColumn->mask & LVCF_IMAGE) { hdi.mask |= HDI_IMAGE; hdi.iImage = lpColumn->iImage; } if (lpColumn->mask & LVCF_ORDER) { hdi.mask |= HDI_ORDER; hdi.iOrder = lpColumn->iOrder; } return (LRESULT)SendMessageA (infoPtr->hwndHeader, HDM_SETITEMA, (WPARAM)nIndex, (LPARAM)&hdi); } /*** * DESCRIPTION: * Sets image list. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : image list type * [I] HIMAGELIST : image list handle * * RETURN: * SUCCESS : old image list * FAILURE : NULL */ static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); HIMAGELIST himlTemp = 0; switch (nType) { case LVSIL_NORMAL: himlTemp = infoPtr->himlNormal; infoPtr->himlNormal = himl; return (LRESULT)himlTemp; case LVSIL_SMALL: himlTemp = infoPtr->himlSmall; infoPtr->himlSmall = himl; return (LRESULT)himlTemp; case LVSIL_STATE: himlTemp = infoPtr->himlState; infoPtr->himlState = himl; return (LRESULT)himlTemp; } return (LRESULT)NULL; } /*** * DESCRIPTION: * Sets item attributes. * * PARAMETER(S): * [I] HWND32 : window handle * [I] LPLVITEM32 : item information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LISTVIEW_ITEM *lpListItem; NMLISTVIEW nmlv; if (lpItem == NULL) return FALSE; if ((lpItem->iItem < 0) || (lpItem->iItem >= infoPtr->nItemCount)) return FALSE; /* send LVN_ITEMCHANGING notification */ ZeroMemory (&nmlv, sizeof (NMLISTVIEW)); nmlv.hdr.hwndFrom = hwnd; nmlv.hdr.idFrom = lCtrlId; nmlv.hdr.code = LVN_ITEMCHANGING; nmlv.iItem = lpItem->iItem; nmlv.iSubItem = lpItem->iSubItem; nmlv.uChanged = lpItem->mask; if (SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv) == FALSE) return FALSE; /* get item */ lpListItem = DPA_GetPtr(infoPtr->hdpaItems, lpItem->iItem); if (lpListItem == NULL) return FALSE; /* copy valid data */ if (lpItem->iSubItem > 0) { /* verify existance of sub-item */ lpListItem += lpItem->iSubItem; if (lpListItem == NULL) return FALSE; /* exit if indent attribute is valid */ if (lpItem->mask & LVIF_INDENT) return FALSE; if (lpItem->mask & LVIF_IMAGE) { /* set sub-item attribute */ } } else { if (lpItem->mask & LVIF_STATE) { lpListItem->state &= ~lpItem->stateMask; lpListItem->state |= (lpItem->state & lpItem->stateMask); } if (lpItem->mask & LVIF_IMAGE) lpListItem->iImage = lpItem->iImage; if (lpItem->mask & LVIF_PARAM) lpListItem->lParam = lpItem->lParam; if (lpItem->mask & LVIF_INDENT) lpListItem->iIndent = lpItem->iIndent; } if (lpItem->mask & LVIF_TEXT) { if (lpItem->pszText == LPSTR_TEXTCALLBACKA) { if ((lpListItem->pszText != NULL) && (lpListItem->pszText != LPSTR_TEXTCALLBACKA)) COMCTL32_Free (lpListItem->pszText); lpListItem->pszText = LPSTR_TEXTCALLBACKA; } else { if (lpListItem->pszText == LPSTR_TEXTCALLBACKA) lpListItem->pszText = NULL; if (Str_SetPtrA(&lpListItem->pszText, lpItem->pszText) == FALSE) return FALSE; } } /* send LVN_ITEMCHANGED notification */ nmlv.hdr.code = LVN_ITEMCHANGED; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmlv); return TRUE; } /* << LISTVIEW_SetItem32W >> */ /* LISTVIEW_SetItemCount*/ /*** * DESCRIPTION: * Sets item position. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * [I] INT32 : x coordinate * [I] INT32 : y coordinate * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetItemPosition(HWND hwnd, INT nItem, INT nPosX, INT nPosY) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); if ((nItem < 0) || (nItem >= infoPtr->nItemCount)) return FALSE; if ((lStyle & LVS_ICON) && (lStyle & LVS_SMALLICON)) { /* get item */ /* set position of item */ /* refresh */ if (lStyle & LVS_AUTOARRANGE) { InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } return TRUE; } return FALSE; } /*** * DESCRIPTION: * Sets the state of one or many items. * * PARAMETER(S): * [I] HWND32 : window handle * [I]INT32 : item index * [I] LPLVITEM32 : item information * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LISTVIEW_ITEM *lpListItem; INT i; if (nItem == -1) { /* apply to all the items */ for (i = 0; i< infoPtr->nItemCount; i++) { lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, i); if (lpListItem == NULL) return FALSE; lpListItem->state &= ~lpItem->stateMask; lpListItem->state |= (lpItem->state & lpItem->stateMask); } } else if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { lpListItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); if (lpListItem == NULL) return FALSE; /* set state */ lpListItem->state &= ~lpItem->stateMask; lpListItem->state |= (lpItem->state & lpItem->stateMask); } else return FALSE; return TRUE; } /*** * DESCRIPTION: * Sets the text background color. * * PARAMETER(S): * [I] HWND32 : window handle * [I] COLORREF : text background color * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); infoPtr->clrTextBk = clrTextBk; return TRUE; } /*** * DESCRIPTION: * Sets the text background color. * * PARAMETER(S): * [I] HWND32 : window handle * [I] COLORREF : text color * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); infoPtr->clrText = clrText; return TRUE; } /*** * DESCRIPTION: * ?? * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam) { /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0); */ FIXME (listview, "empty stub!\n"); return TRUE; } /*** * DESCRIPTION: * Updates an items. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : item index * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); RECT rcItemRect; BOOL bResult = FALSE; if ((nItem >= 0) || (nItem < infoPtr->nItemCount)) { /* get item bounding rectangle */ rcItemRect.left = LVIR_BOUNDS; SendMessageA(hwnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)&rcItemRect); InvalidateRect(hwnd, &rcItemRect, FALSE); /* rearrange with default alignment style */ if ((lStyle & LVS_AUTOARRANGE) && ((lStyle & LVS_ICON) || (lStyle & LVS_SMALLICON))) SendMessageA(hwnd, LVM_ARRANGE, (WPARAM)LVA_DEFAULT, (LPARAM)0); } return bResult; } /*** * DESCRIPTION: * Creates a listview control. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Zero */ static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); LOGFONTA logFont; HFONT hOldFont; HDC hdc; TEXTMETRICA tm; INT nSmallIconHeight; /* initialize color information */ infoPtr->clrBk = GetSysColor(COLOR_WINDOW); infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT); infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW); /* get default font (icon title) */ SystemParametersInfoA (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); infoPtr->hDefaultFont = CreateFontIndirectA (&logFont); infoPtr->hFont = infoPtr->hDefaultFont; /* initialize column width */ infoPtr->nColumnWidth = 96; /* get text height */ hdc = GetDC(hwnd); hOldFont = SelectObject(hdc, infoPtr->hFont); GetTextMetricsA(hdc, &tm); /* initialize item height with padding */ if (!(lStyle & LVS_ICON)) { nSmallIconHeight = GetSystemMetrics(SM_CYSMICON); infoPtr->nItemHeight = max(tm.tmHeight, nSmallIconHeight) + 2; } SelectObject(hdc, hOldFont); ReleaseDC(hwnd, hdc); /* create header */ infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, "", lStyle, 0, 0, 0, 0, hwnd, (HMENU)0, GetWindowLongA(hwnd, GWL_HINSTANCE), NULL); /* set header font */ SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, (LPARAM)TRUE); /* allocate memory */ infoPtr->hdpaItems = DPA_Create (10); return 0; } static LRESULT LISTVIEW_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); /* delete all items */ LISTVIEW_DeleteAllItems(hwnd); /* destroy dpa */ DPA_Destroy (infoPtr->hdpaItems); /* destroy header */ if (infoPtr->hwndHeader) DestroyWindow (infoPtr->hwndHeader); /* destroy font */ infoPtr->hFont = (HFONT)0; if (infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont); infoPtr->nColumnWidth = 96; return 0; } /*** * DESCRIPTION: * Erases the background of the listview control * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * SUCCESS : TRUE * FAILURE : FALSE */ static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam, LPARAM lParam) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); BOOL bResult; if (infoPtr->clrBk == CLR_NONE) bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam); else { HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk); RECT clientRect; GetClientRect(hwnd, &clientRect); FillRect((HDC)wParam, &clientRect, hBrush); DeleteObject(hBrush); bResult = TRUE; } return bResult; } /*** * DESCRIPTION: * Gets the listview control font. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Font handle. */ static LRESULT LISTVIEW_GetFont(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); return infoPtr->hFont; } /*** * DESCRIPTION: * Performs horizontal scrolling. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : scroll code * [I] INT32 : scroll position * [I] HWND32 : scrollbar control window handle * * RETURN: * Zero */ static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, INT nScrollPos, HWND hScrollWnd) { LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nHScrollPos; INT nMinRange; INT nMaxRange; GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange); nHScrollPos = GetScrollPos(hwnd, SB_HORZ); if (lStyle & LVS_LIST) { switch (nScrollCode) { case SB_LINELEFT: if (nHScrollPos > nMinRange) nHScrollPos--; break; case SB_LINERIGHT: if (nHScrollPos < nMaxRange) nHScrollPos++; break; case SB_PAGELEFT: if (nHScrollPos > nMinRange) nHScrollPos--; break; case SB_PAGERIGHT: if (nHScrollPos < nMaxRange) nHScrollPos++; break; case SB_THUMBPOSITION: nHScrollPos = nScrollPos; break; } SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE); /* refresh client area */ InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } return 0; } /*** * DESCRIPTION: * ????? * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : virtual key * [I] LONG : key data * * RETURN: * Zero */ static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); HWND hwndParent = GetParent(hwnd); INT nItemCountPerColumn; INT nItemCountPerRow; NMHDR nmh; INT nColumn; /* NMLVKEYDOWN nmKeyDown; */ /* send LVN_KEYDOWN notification */ /* nmh.hwndFrom = hwnd; */ /* nmh.idFrom = lCtrlId; */ /* nmh.code = LVN_KEYDOWN; */ /* nmKeyDown.hdr = nmh; */ /* nmKeyDown..wVKey = nVirtualKey; */ /* nmKeyCode.flags = 0; */ /* SendMessage32A(hwndParent, WM_NOTIFY, (WPARAM32)lCtrlId, (LPARAM)&nmKeyDown); */ switch (nVirtualKey) { case VK_RETURN: if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1)) { /* send NM_RETURN notification */ nmh.code = NM_RETURN; SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* send LVN_ITEMACTIVATE notification */ nmh.code = LVN_ITEMACTIVATE; SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); } break; case VK_HOME: if (infoPtr->nItemCount > 0) { /* set item state(s) */ infoPtr->nFocusedItem = 0; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); /* make item visible */ LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } break; case VK_END: if (infoPtr->nItemCount > 0) { /* set item state(s) */ infoPtr->nFocusedItem = infoPtr->nItemCount - 1; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); /* make item visible */ LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } break; case VK_LEFT: if (lStyle & LVS_LIST) { nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); if (infoPtr->nFocusedItem >= nItemCountPerColumn) { /* set item state(s) */ infoPtr->nFocusedItem -= nItemCountPerColumn; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); /* make item visible */ LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } else if (lStyle & LVS_REPORT) { /* TO DO ; does not affect the focused item, it only scrolls */ } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); nColumn = infoPtr->nFocusedItem % nItemCountPerRow; if (nColumn != 0) { infoPtr->nFocusedItem -= 1; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); /* refresh display */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } } break; case VK_UP: if ((lStyle & LVS_LIST) || (lStyle & LVS_REPORT)) { if (infoPtr->nFocusedItem > 0) { infoPtr->nFocusedItem -= 1; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); if (infoPtr->nFocusedItem >= nItemCountPerRow) { infoPtr->nFocusedItem -= nItemCountPerRow; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } break; case VK_RIGHT: if (lStyle & LVS_LIST) { nItemCountPerColumn = LISTVIEW_GetItemCountPerColumn(hwnd); if (infoPtr->nFocusedItem < infoPtr->nItemCount - nItemCountPerColumn) { infoPtr->nFocusedItem += nItemCountPerColumn; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } else if (lStyle & LVS_REPORT) { } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); nColumn = infoPtr->nFocusedItem % nItemCountPerRow; if (nColumn != nItemCountPerRow - 1) { infoPtr->nFocusedItem += 1; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); /* refresh display */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } } break; case VK_DOWN: if ((lStyle & LVS_LIST) || (lStyle & LVS_REPORT)) { if (infoPtr->nFocusedItem < infoPtr->nItemCount - 1) { infoPtr->nFocusedItem += 1; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } else if ((lStyle & LVS_SMALLICON) || (lStyle & LVS_ICON)) { nItemCountPerRow = LISTVIEW_GetItemCountPerRow(hwnd); if (infoPtr->nFocusedItem < infoPtr->nItemCount - nItemCountPerRow) { infoPtr->nFocusedItem += nItemCountPerRow; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, FALSE); LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } } break; case VK_PRIOR: break; case VK_NEXT: break; } return 0; } /*** * DESCRIPTION: * Kills the focus. * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Zero */ static LRESULT LISTVIEW_KillFocus(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_KILLFOCUS; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* set window focus flag */ infoPtr->bFocus = FALSE; return 0; } /*** * DESCRIPTION: * Left mouse button double click. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; /* send NM_DBLCLK notification */ nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_DBLCLK; SendMessageA(GetParent (hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* send LVN_ITEMACTIVATE notification */ nmh.code = LVN_ITEMACTIVATE; SendMessageA(GetParent (hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); return 0; } /*** * DESCRIPTION: * Left mouse button down. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LVHITTESTINFO hitTestInfo; LVITEMA lvItem; NMHDR nmh; INT nItem; /* send NM_RELEASEDCAPTURE notification */ nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_RELEASEDCAPTURE; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); if (infoPtr->bFocus == FALSE) SetFocus(hwnd); /* set left button down flag */ infoPtr->bLButtonDown = TRUE; /* set left button hit coordinates */ hitTestInfo.pt.x = wPosX; hitTestInfo.pt.y = wPosY; /* perform hit test */ nItem = SendMessageA(hwnd, LVM_HITTEST, (WPARAM)0, (LPARAM)&hitTestInfo); if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { /* perform state changes (selection and focus) */ infoPtr->nFocusedItem = nItem; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, TRUE, TRUE); /* scroll intem into view if doing a multiple selection */ if ((wKey & MK_CONTROL) || (wKey & MK_SHIFT)) { LISTVIEW_SetVisible(hwnd, infoPtr->nFocusedItem); } else { /* refresh display */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } } else { /* clear selection(s) */ ZeroMemory(&lvItem, sizeof(LVITEMA)); lvItem.stateMask = LVIS_SELECTED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); /* repaint everything */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); } return 0; } /*** * DESCRIPTION: * Left mouse button up. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; if (infoPtr->bLButtonDown == TRUE) { /* send NM_CLICK notification */ nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_CLICK; SendMessageA(GetParent (hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); } /* set left button flag */ infoPtr->bLButtonDown = FALSE; return 0; } /*** * DESCRIPTION: * Creates the listview control (called before WM_CREATE). * * PARAMETER(S): * [I] HWND32 : window handle * [I] WPARAM32 : unhandled * [I] LPARAM : widow creation info * * RETURN: * Zero */ static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam) { LISTVIEW_INFO *infoPtr; /* allocate memory for info structure */ infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc (sizeof(LISTVIEW_INFO)); SetWindowLongA(hwnd, 0, (LONG)infoPtr); if (infoPtr == NULL) { ERR (listview, "could not allocate info memory!\n"); return 0; } if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr) { ERR (listview, "pointer assignment error!\n"); return 0; } return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam); } /*** * DESCRIPTION: * Destroys the listview control (called after WM_DESTROY). * * PARAMETER(S): * [I] HWND32 : window handle * * RETURN: * Zero */ static LRESULT LISTVIEW_NCDestroy(HWND hwnd) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); /* free list view info data */ COMCTL32_Free (infoPtr); return 0; } /*** * DESCRIPTION: * Handles notification from children. * * PARAMETER(S): * [I] HWND32 : window handle * [I] INT32 : control identifier * [I] LPNMHDR : notification information * * RETURN: * Zero */ static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); if (lpnmh->hwndFrom == infoPtr->hwndHeader) { /* handle notification from header control */ FIXME (listview, "WM_NOTIFY from header!\n"); } else { /* handle notification from unknown source */ FIXME (listview, "WM_NOTIFY from unknown source!\n"); } return 0; } /*** * DESCRIPTION: * Draws the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HDC32 : device context handle * * RETURN: * Zero */ static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc) { PAINTSTRUCT ps; if (hdc == 0) { hdc = BeginPaint(hwnd, &ps); LISTVIEW_Refresh(hwnd, hdc); EndPaint(hwnd, &ps); } else LISTVIEW_Refresh(hwnd, hdc); return 0; } /*** * DESCRIPTION: * Right mouse button double clisk. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; /* send NM_RELEASEDCAPTURE notification */ nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_RELEASEDCAPTURE; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* send NM_RDBLCLK notification */ nmh.code = NM_RDBLCLK; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); return 0; } /*** * DESCRIPTION: * Right mouse button input. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); LVHITTESTINFO hitTestInfo; NMHDR nmh; LVITEMA lvItem; INT nItem; /* The syslistview32 control sends a NM_RELEASEDCAPTURE notification. I do not know why, but I decided to send it as well for compatibility purposes. */ ZeroMemory(&nmh, sizeof(NMHDR)); nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_RELEASEDCAPTURE; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* make sure listview control has focus */ if (infoPtr->bFocus == FALSE) SetFocus(hwnd); /* set left button down flag */ infoPtr->bRButtonDown = TRUE; /* set hit coordinates */ hitTestInfo.pt.x = wPosX; hitTestInfo.pt.y = wPosY; /* perform hit test */ nItem = SendMessageA(hwnd, LVM_HITTEST, (WPARAM)0, (LPARAM)&hitTestInfo); if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) { /* perform state changes (selection and focus) */ infoPtr->nFocusedItem = nItem; LISTVIEW_SetItemStates(hwnd, infoPtr->nFocusedItem, FALSE, TRUE); } else { /* clear selection(s) */ ZeroMemory(&lvItem, sizeof(LVITEMA)); lvItem.stateMask = LVIS_SELECTED; lvItem.state = 0; SendMessageA(hwnd, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&lvItem); } /* repaint everything */ InvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); return 0; } /*** * DESCRIPTION: * Right mouse button up. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : key flag * [I] WORD : x coordinate * [I] WORD : y coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX, WORD wPosY) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; if (infoPtr->bRButtonDown == TRUE) { /* initialize notification information */ ZeroMemory(&nmh, sizeof(NMHDR)); nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_RCLICK; SendMessageA(GetParent (hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); } /* set button flag */ infoPtr->bRButtonDown = FALSE; return 0; } /*** * DESCRIPTION: * Sets the focus. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HWND32 : window handle of previously focused window * * RETURN: * Zero */ static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); NMHDR nmh; /* send NM_SETFOCUS notification */ nmh.hwndFrom = hwnd; nmh.idFrom = lCtrlId; nmh.code = NM_SETFOCUS; SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, (LPARAM)&nmh); /* set window focus flag */ infoPtr->bFocus = TRUE; return 0; } /*** * DESCRIPTION: * Sets the font. * * PARAMETER(S): * [I] HWND32 : window handle * [I] HFONT32 : font handle * [I] WORD : redraw flag * * RETURN: * Zero */ static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); if (hFont == 0) { infoPtr->hFont = infoPtr->hDefaultFont; } else { infoPtr->hFont = hFont; } if (lStyle & LVS_REPORT) { /* set font of header */ SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0)); } /* invalidate listview control client area */ InvalidateRect(hwnd, NULL, FALSE); if (fRedraw == TRUE) UpdateWindow(hwnd); return 0; } /*** * DESCRIPTION: * Resizes the listview control. * * PARAMETER(S): * [I] HWND32 : window handle * [I] WORD : new width * [I] WORD : new height * * RETURN: * Zero */ static LRESULT LISTVIEW_Size(HWND hwnd, WORD wWidth, WORD wHeight) { LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); INT nHScrollHeight; if (lStyle & LVS_LIST) { if (!(lStyle & WS_HSCROLL)) { nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL); if (wHeight > nHScrollHeight) wHeight -= nHScrollHeight; } infoPtr->nHeight = (INT)wHeight; infoPtr->nWidth = (INT)wWidth; } /* set scrollbar(s) if needed */ LISTVIEW_SetScroll(hwnd); /* refresh client area */ InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); return 0; } /*** * DESCRIPTION: * Window procedure of the listview control. * * PARAMETER(S): * [I] HWND32 : * [I] UINT32 : * [I] WPARAM32 : * [I] LPARAM : * * RETURN: * */ LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case LVM_APPROXIMATEVIEWRECT: return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); case LVM_ARRANGE: return LISTVIEW_Arrange(hwnd, (INT)wParam); /* case LVM_CREATEDRAGIMAGE: */ case LVM_DELETEALLITEMS: return LISTVIEW_DeleteAllItems(hwnd); case LVM_DELETECOLUMN: return LISTVIEW_DeleteColumn(hwnd, (INT)wParam); case LVM_DELETEITEM: return LISTVIEW_DeleteItem(hwnd, (INT)wParam); /* case LVM_EDITLABEL: */ /* case LVM_ENSUREVISIBLE: */ case LVM_FINDITEMA: return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam); case LVM_GETBKCOLOR: return LISTVIEW_GetBkColor(hwnd); /* case LVM_GETBKIMAGE: */ /* case LVM_GETCALLBACKMASK: */ case LVM_GETCOLUMNA: return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam); /* case LVM_GETCOLUMN32W: */ /* case LVM_GETCOLUMNORDERARRAY: */ case LVM_GETCOLUMNWIDTH: return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam); case LVM_GETCOUNTPERPAGE: return LISTVIEW_GetCountPerPage(hwnd); /* case LVM_GETEDITCONTROL: */ /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */ case LVM_GETHEADER: return LISTVIEW_GetHeader(hwnd); /* case LVM_GETHOTCURSOR: */ /* case LVM_GETHOTITEM: */ /* case LVM_GETHOVERTIME: */ case LVM_GETIMAGELIST: return LISTVIEW_GetImageList(hwnd, (INT)wParam); /* case LVM_GETISEARCHSTRING: */ case LVM_GETITEMA: return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam); /* case LVM_GETITEM32W: */ case LVM_GETITEMCOUNT: return LISTVIEW_GetItemCount(hwnd); case LVM_GETITEMPOSITION: return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam); case LVM_GETITEMRECT: return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam); case LVM_GETITEMSPACING: return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam); case LVM_GETITEMSTATE: return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam); case LVM_GETITEMTEXTA: LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam); break; /* case LVM_GETITEMTEXT32W: */ case LVM_GETNEXTITEM: return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam)); /* case LVM_GETNUMBEROFWORKAREAS: */ case LVM_GETORIGIN: return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam); case LVM_GETSELECTEDCOUNT: return LISTVIEW_GetSelectedCount(hwnd); case LVM_GETSELECTIONMARK: return LISTVIEW_GetSelectionMark(hwnd); case LVM_GETSTRINGWIDTHA: return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam); /* case LVM_GETSTRINGWIDTH32W: */ /* case LVM_GETSUBITEMRECT: */ case LVM_GETTEXTBKCOLOR: return LISTVIEW_GetTextBkColor(hwnd); case LVM_GETTEXTCOLOR: return LISTVIEW_GetTextColor(hwnd); /* case LVM_GETTOOLTIPS: */ /* case LVM_GETTOPINDEX: */ /* case LVM_GETUNICODEFORMAT: */ case LVM_GETVIEWRECT: return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam); /* case LVM_GETWORKAREAS: */ case LVM_HITTEST: return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam); case LVM_INSERTCOLUMNA: return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam); /* case LVM_INSERTCOLUMN32W: */ case LVM_INSERTITEMA: return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam); /* case LVM_INSERTITEM32W: */ case LVM_REDRAWITEMS: return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam); case LVM_SCROLL: return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); case LVM_SETBKCOLOR: return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam); /* case LVM_SETBKIMAGE: */ /* case LVM_SETCALLBACKMASK: */ case LVM_SETCOLUMNA: return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam); /* case LVM_SETCOLUMN32W: */ /* case LVM_SETCOLUMNORDERARRAY: */ /* case LVM_SETCOLUMNWIDTH: */ /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */ /* case LVM_SETHOTCURSOR: */ /* case LVM_SETHOTITEM: */ /* case LVM_SETHOVERTIME: */ /* case LVM_SETICONSPACING: */ case LVM_SETIMAGELIST: return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam); case LVM_SETITEMA: return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam); /* case LVM_SETITEM32W: */ /* case LVM_SETITEMCOUNT: */ case LVM_SETITEMPOSITION16: return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam), (INT) HIWORD(lParam)); /* case LVM_SETITEMPOSITION32: */ case LVM_SETITEMSTATE: return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam); /* case LVM_SETITEMTEXT: */ /* case LVM_SETSELECTIONMARK: */ case LVM_SETTEXTBKCOLOR: return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam); case LVM_SETTEXTCOLOR: return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam); /* case LVM_SETTOOLTIPS: */ /* case LVM_SETUNICODEFORMAT: */ /* case LVM_SETWORKAREAS: */ case LVM_SORTITEMS: return LISTVIEW_SortItems(hwnd, wParam, lParam); /* case LVM_SUBITEMHITTEST: */ case LVM_UPDATE: return LISTVIEW_Update(hwnd, (INT)wParam); /* case WM_CHAR: */ /* case WM_COMMAND: */ case WM_CREATE: return LISTVIEW_Create(hwnd, wParam, lParam); case WM_DESTROY: return LISTVIEW_Destroy(hwnd, wParam, lParam); case WM_ERASEBKGND: return LISTVIEW_EraseBackground (hwnd, wParam, lParam); case WM_GETDLGCODE: return DLGC_WANTTAB | DLGC_WANTARROWS; case WM_GETFONT: return LISTVIEW_GetFont(hwnd); case WM_HSCROLL: return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam), (INT)HIWORD(wParam), (HWND)lParam); case WM_KEYDOWN: return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam); case WM_KILLFOCUS: return LISTVIEW_KillFocus(hwnd); case WM_LBUTTONDBLCLK: return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_LBUTTONDOWN: return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_LBUTTONUP: return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); /* case WM_MOUSEMOVE: */ /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */ case WM_NCCREATE: return LISTVIEW_NCCreate(hwnd, wParam, lParam); case WM_NCDESTROY: return LISTVIEW_NCDestroy(hwnd); case WM_NOTIFY: return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam); case WM_PAINT: return LISTVIEW_Paint(hwnd, (HDC)wParam); case WM_RBUTTONDBLCLK: return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_RBUTTONDOWN: return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_RBUTTONUP: return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_SETFOCUS: return LISTVIEW_SetFocus(hwnd, (HWND)wParam); case WM_SETFONT: return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam); /* case WM_SETREDRAW: */ case WM_SIZE: return LISTVIEW_Size(hwnd, LOWORD(lParam), HIWORD(lParam)); /* case WM_TIMER: */ /* case WM_VSCROLL: */ /* case WM_WINDOWPOSCHANGED: */ /* case WM_WININICHANGE: */ default: if (uMsg >= WM_USER) ERR (listview, "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); /* call default window procedure */ return DefWindowProcA (hwnd, uMsg, wParam, lParam); } return 0; } /*** * DESCRIPTION:` * Registers the window class. * * PARAMETER(S): * None * * RETURN: * None */ VOID LISTVIEW_Register(VOID) { WNDCLASSA wndClass; if (!GlobalFindAtomA(WC_LISTVIEWA)) { ZeroMemory (&wndClass, sizeof(WNDCLASSA)); wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *); wndClass.hCursor = LoadCursorA (0, IDC_ARROWA); wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndClass.lpszClassName = WC_LISTVIEWA; RegisterClassA (&wndClass); } } /*** * DESCRIPTION: * Unregisters the window class. * * PARAMETER(S): * None * * RETURN: * None */ VOID LISTVIEW_Unregister(VOID) { if (GlobalFindAtomA (WC_LISTVIEWA)) UnregisterClassA (WC_LISTVIEWA, (HINSTANCE)NULL); }