| /* | |
| * Listview control | |
| * | |
| * Copyright 1998 Eric Kohl | |
| * Copyright 1999 Luc Tourangeau | |
| * | |
| * NOTES | |
| * Listview control implementation. | |
| * | |
| * TODO: | |
| * | |
| * 1. Multiple selections in icon or small icon display modes DO NOT | |
| * behave like the Microsoft control. | |
| * 2. No horizontal scrolling when header is larger than the client area. | |
| * 3. Implement LVM_FINDITEM for key selections. | |
| * 4. Drawing optimizations. | |
| * | |
| * Notifications: | |
| * LISTVIEW_Notify : most notifications from children (editbox and header) | |
| * | |
| * Data structure: | |
| * LISTVIEW_SortItems : empty stub | |
| * LISTVIEW_SetItemCount : empty stub | |
| * | |
| * Unicode: | |
| * LISTVIEW_SetItem32W : no unicode support | |
| * LISTVIEW_InsertItem32W : no unicode support | |
| * LISTVIEW_InsertColumn32W : no unicode support | |
| * LISTVIEW_GetColumnW : no unicode support | |
| * | |
| * Advanced functionality: | |
| * LISTVIEW_GetNumberOfWorkAreas : not implemented | |
| * LISTVIEW_GetNextItem : empty stub | |
| * LISTVIEW_GetHotCursor : not implemented | |
| * LISTVIEW_GetHotItem : not implemented | |
| * LISTVIEW_GetHoverTime : not implemented | |
| * LISTVIEW_GetISearchString : not implemented | |
| * LISTVIEW_GetBkImage : not implemented | |
| * LISTVIEW_EditLabel : REPORT (need to implement a timer) | |
| * LISTVIEW_GetColumnOrderArray : not implemented | |
| * LISTVIEW_Arrange : empty stub | |
| * LISTVIEW_FindItem : empty stub | |
| * LISTVIEW_ApproximateViewRect : incomplete | |
| * LISTVIEW_Scroll : not implemented | |
| * LISTVIEW_KeyDown : page up and page down + redo small icon and icon | |
| * LISTVIEW_RedrawItems : empty stub | |
| * LISTVIEW_Update : not completed | |
| */ | |
| #include <string.h> | |
| #include "winbase.h" | |
| #include "commctrl.h" | |
| #include "listview.h" | |
| #include "debug.h" | |
| DEFAULT_DEBUG_CHANNEL(listview) | |
| /* | |
| * constants | |
| */ | |
| /* maximum size of a label */ | |
| #define DISP_TEXT_SIZE 128 | |
| /* padding for items in list and small icon display modes */ | |
| #define WIDTH_PADDING 12 | |
| /* padding for items in list, report and small icon display modes */ | |
| #define HEIGHT_PADDING 1 | |
| /* offset of items in report display mode */ | |
| #define REPORT_MARGINX 2 | |
| /* padding for icon in large icon display mode */ | |
| #define ICON_TOP_PADDING 2 | |
| #define ICON_BOTTOM_PADDING 2 | |
| /* padding for label in large icon display mode */ | |
| #define LABEL_VERT_OFFSET 2 | |
| /* default label width for items in list and small icon display modes */ | |
| #define DEFAULT_LABEL_WIDTH 40 | |
| /* default column width for items in list display mode */ | |
| #define DEFAULT_COLUMN_WIDTH 96 | |
| /* | |
| * macros | |
| */ | |
| /* retrieve the number of items in the listview */ | |
| #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount) | |
| #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \ | |
| (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm)) | |
| #define ListView_Notify(hwnd,lCtrlId,pnmh) \ | |
| (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh)) | |
| /* | |
| * forward declarations | |
| */ | |
| static VOID LISTVIEW_AlignLeft(HWND); | |
| static VOID LISTVIEW_AlignTop(HWND); | |
| static VOID LISTVIEW_AddGroupSelection(HWND, INT); | |
| static VOID LISTVIEW_AddSelection(HWND, INT); | |
| static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA); | |
| static INT LISTVIEW_FindInsertPosition(HDPA, INT); | |
| static VOID LISTVIEW_GetItemDispInfo(HWND, INT, LISTVIEW_ITEM *lpItem, INT *, | |
| UINT *, CHAR **, INT); | |
| static INT LISTVIEW_GetItemHeight(HWND, LONG); | |
| static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT); | |
| static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT); | |
| static INT LISTVIEW_GetItemWidth(HWND, LONG); | |
| static INT LISTVIEW_GetLabelWidth(HWND, INT); | |
| static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT); | |
| static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT); | |
| static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT, LPARAM, | |
| LISTVIEW_SUBITEM *, INT, INT *, | |
| CHAR **, INT); | |
| static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT); | |
| static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA); | |
| static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA); | |
| static LRESULT LISTVIEW_MouseSelection(HWND, INT, INT); | |
| static BOOL LISTVIEW_RemoveColumn(HDPA, INT); | |
| static VOID LISTVIEW_RemoveSelections(HWND, INT, INT); | |
| static BOOL LISTVIEW_RemoveSubItem(HDPA, INT); | |
| static BOOL LISTVIEW_ScrollView(HWND, INT, INT); | |
| static VOID LISTVIEW_SetGroupSelection(HWND, INT); | |
| static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA); | |
| static VOID LISTVIEW_SetItemFocus(HWND, INT); | |
| static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT); | |
| static VOID LISTVIEW_SetScroll(HWND, LONG); | |
| static VOID LISTVIEW_SetSelection(HWND, INT); | |
| static VOID LISTVIEW_SetSize(HWND, LONG, LONG, LONG); | |
| static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA); | |
| static VOID LISTVIEW_SetViewInfo(HWND, LONG); | |
| static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT); | |
| static BOOL LISTVIEW_ToggleSelection(HWND, INT); | |
| static VOID LISTVIEW_UnsupportedStyles(LONG lStyle); | |
| /*** | |
| * DESCRIPTION: | |
| * Scrolls the content of the listview. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : number of horizontal scroll positions | |
| * (relative to the current scroll postioon) | |
| * [I] INT : number of vertical scroll positions | |
| * (relative to the current scroll postioon) | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_ScrollView(HWND hwnd, INT nHScroll, INT nVScroll) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| INT nHScrollPos = 0; | |
| INT nVScrollPos = 0; | |
| INT nHScrollInc = 0; | |
| INT nVScrollInc = 0; | |
| BOOL bResult = FALSE; | |
| if (((lStyle & WS_HSCROLL) != 0) && (nHScroll != 0)) | |
| { | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| nHScrollInc = nHScroll * infoPtr->nItemWidth; | |
| break; | |
| case LVS_REPORT: | |
| /* TO DO : not implemented at this point. I experiences some | |
| problems when performing child window scrolling. */ | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nHScrollInc = nHScroll * max(nListWidth, nListWidth / 10); | |
| break; | |
| } | |
| nHScrollPos = GetScrollPos(hwnd, SB_HORZ) + nHScroll; | |
| } | |
| if (((lStyle & WS_VSCROLL) != 0) & (nVScroll != 0)) | |
| { | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| nVScrollInc = nVScroll * infoPtr->nItemHeight; | |
| nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nVScrollInc = nVScroll * max(nListHeight, nListHeight / 10); | |
| nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll; | |
| break; | |
| } | |
| } | |
| /* perform scroll operation & set new scroll position */ | |
| if ((nHScrollInc != 0) || (nVScrollInc != 0)) | |
| { | |
| RECT rc; | |
| HDC hdc = GetDC(hwnd); | |
| ScrollDC(hdc, -nHScrollInc, -nVScrollInc, &infoPtr->rcList, NULL, | |
| (HRGN) NULL, &rc); | |
| InvalidateRect(hwnd, &rc, TRUE); | |
| SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE); | |
| SetScrollPos(hwnd, SB_VERT, nVScrollPos, TRUE); | |
| ReleaseDC(hwnd, hdc); | |
| bResult = TRUE; | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Prints a message for unsupported window styles. | |
| * A kind of TODO list for window styles. | |
| * | |
| * PARAMETER(S): | |
| * [I] LONG : window style | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_UnsupportedStyles(LONG lStyle) | |
| { | |
| if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS) | |
| { | |
| FIXME( listview, " LVS_EDITLABELS\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_NOCOLUMNHEADER) | |
| { | |
| FIXME( listview, " LVS_SORTDESCENDING\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP) | |
| { | |
| FIXME( listview, " LVS_NOLABELWRAP\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL) | |
| { | |
| FIXME( listview, " LVS_NOSCROLL\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER) | |
| { | |
| FIXME( listview, " LVS_NOSORTHEADER\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED) | |
| { | |
| FIXME( listview, " LVS_OWNERDRAWFIXED\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS) | |
| { | |
| FIXME( listview, " LVS_SHAREIMAGELISTS\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_SHOWSELALWAYS) | |
| { | |
| FIXME( listview, " LVS_SHOWSELALWAYS\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_SINGLESEL) | |
| { | |
| FIXME( listview, " LVS_SINGLESEL\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING) | |
| { | |
| FIXME( listview, " LVS_SORTASCENDING\n"); | |
| } | |
| if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING) | |
| { | |
| FIXME( listview, " LVS_SORTDESCENDING\n"); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Aligns the items with the top edge of the window. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_AlignTop(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| POINT ptItem; | |
| RECT rcView; | |
| INT i; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| ZeroMemory(&ptItem, sizeof(POINT)); | |
| ZeroMemory(&rcView, sizeof(RECT)); | |
| if (nListWidth > infoPtr->nItemWidth) | |
| { | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| if (ptItem.x + infoPtr->nItemWidth > nListWidth) | |
| { | |
| ptItem.x = 0; | |
| ptItem.y += infoPtr->nItemHeight; | |
| } | |
| LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y); | |
| ptItem.x += infoPtr->nItemWidth; | |
| rcView.right = max(rcView.right, ptItem.x); | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y); | |
| ptItem.x += infoPtr->nItemWidth; | |
| } | |
| rcView.right = ptItem.x; | |
| rcView.bottom = infoPtr->nItemHeight; | |
| } | |
| rcView.bottom = ptItem.y + infoPtr->nItemHeight; | |
| LISTVIEW_SetViewRect(hwnd, &rcView); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Aligns the items with the left edge of the window. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_AlignLeft(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| POINT ptItem; | |
| RECT rcView; | |
| INT i; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| ZeroMemory(&ptItem, sizeof(POINT)); | |
| ZeroMemory(&rcView, sizeof(RECT)); | |
| if (nListHeight > infoPtr->nItemHeight) | |
| { | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| if (ptItem.y + infoPtr->nItemHeight > nListHeight) | |
| { | |
| ptItem.y = 0; | |
| ptItem.x += infoPtr->nItemWidth; | |
| } | |
| LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y); | |
| ptItem.y += infoPtr->nItemHeight; | |
| rcView.bottom = max(rcView.bottom, ptItem.y); | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y); | |
| ptItem.y += infoPtr->nItemHeight; | |
| } | |
| rcView.bottom = ptItem.y; | |
| rcView.right = infoPtr->nItemWidth; | |
| } | |
| rcView.right = ptItem.x + infoPtr->nItemWidth; | |
| LISTVIEW_SetViewRect(hwnd, &rcView); | |
| break; | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves display information. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] LISTVIEW_ITEM* : listview control item | |
| * [O] INT : image index | |
| * [O] UINT : state value | |
| * [O] CHAR** : string | |
| * [I] INT : size of string | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_GetItemDispInfo(HWND hwnd, INT nItem, | |
| LISTVIEW_ITEM *lpItem, INT *pnDispImage, | |
| UINT *puState, CHAR **ppszDispText, | |
| INT nDispTextSize) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMLVDISPINFOA dispInfo; | |
| ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA)); | |
| if ((pnDispImage != NULL) && (lpItem->iImage == I_IMAGECALLBACK)) | |
| { | |
| dispInfo.item.mask |= LVIF_IMAGE; | |
| } | |
| if ((ppszDispText != NULL) && (lpItem->pszText == LPSTR_TEXTCALLBACKA)) | |
| { | |
| ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize); | |
| dispInfo.item.mask |= LVIF_TEXT; | |
| dispInfo.item.pszText = *ppszDispText; | |
| dispInfo.item.cchTextMax = nDispTextSize; | |
| } | |
| if ((puState != NULL) && (infoPtr->uCallbackMask != 0)) | |
| { | |
| dispInfo.item.mask |= LVIF_STATE; | |
| dispInfo.item.stateMask = infoPtr->uCallbackMask; | |
| } | |
| if (dispInfo.item.mask != 0) | |
| { | |
| dispInfo.hdr.hwndFrom = hwnd; | |
| dispInfo.hdr.idFrom = lCtrlId; | |
| dispInfo.hdr.code = LVN_GETDISPINFOA; | |
| dispInfo.item.iItem = nItem; | |
| dispInfo.item.iSubItem = 0; | |
| dispInfo.item.lParam = lpItem->lParam; | |
| ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo); | |
| } | |
| if (pnDispImage != NULL) | |
| { | |
| if (dispInfo.item.mask & LVIF_IMAGE) | |
| { | |
| *pnDispImage = dispInfo.item.iImage; | |
| } | |
| else | |
| { | |
| *pnDispImage = lpItem->iImage; | |
| } | |
| } | |
| if (ppszDispText != NULL) | |
| { | |
| if (dispInfo.item.mask & LVIF_TEXT) | |
| { | |
| if (dispInfo.item.mask & LVIF_DI_SETITEM) | |
| { | |
| Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText); | |
| } | |
| *ppszDispText = dispInfo.item.pszText; | |
| } | |
| else | |
| { | |
| *ppszDispText = lpItem->pszText; | |
| } | |
| } | |
| if (puState != NULL) | |
| { | |
| if (dispInfo.item.mask & LVIF_STATE) | |
| { | |
| *puState = lpItem->state; | |
| *puState &= ~dispInfo.item.stateMask; | |
| *puState |= (dispInfo.item.state & dispInfo.item.stateMask); | |
| } | |
| else | |
| { | |
| *puState = lpItem->state; | |
| } | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves subitem display information. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] LONG : LPARAM of item | |
| * [I] LISTVIEW_SUBITEM* : listview control subitem | |
| * [I] INT : subitem position/order | |
| * [O] INT : image index | |
| * [O] UINT : state value | |
| * [O] CHAR** : display string | |
| * [I] INT : size of string | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT nItem, LPARAM lParam, | |
| LISTVIEW_SUBITEM *lpSubItem, | |
| INT nSubItemPos, INT *pnDispImage, | |
| CHAR **ppszDispText, INT nDispTextSize) | |
| { | |
| LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMLVDISPINFOA dispInfo; | |
| ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA)); | |
| if (lpSubItem == NULL) | |
| { | |
| ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize); | |
| dispInfo.item.mask |= LVIF_TEXT; | |
| dispInfo.item.pszText = *ppszDispText; | |
| dispInfo.item.cchTextMax = nDispTextSize; | |
| dispInfo.hdr.hwndFrom = hwnd; | |
| dispInfo.hdr.idFrom = lCtrlId; | |
| dispInfo.hdr.code = LVN_GETDISPINFOA; | |
| dispInfo.item.iItem = nItem; | |
| dispInfo.item.iSubItem = nSubItemPos; | |
| dispInfo.item.lParam = lParam; | |
| ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo); | |
| if (dispInfo.item.mask & LVIF_DI_SETITEM) | |
| { | |
| Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText); | |
| } | |
| *ppszDispText = dispInfo.item.pszText; | |
| } | |
| else | |
| { | |
| if ((pnDispImage != NULL) && (lpSubItem->iImage == I_IMAGECALLBACK)) | |
| { | |
| dispInfo.item.mask |= LVIF_IMAGE; | |
| } | |
| if ((ppszDispText != NULL) && (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)) | |
| { | |
| ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize); | |
| dispInfo.item.mask |= LVIF_TEXT; | |
| dispInfo.item.pszText = *ppszDispText; | |
| dispInfo.item.cchTextMax = nDispTextSize; | |
| } | |
| if (dispInfo.item.mask != 0) | |
| { | |
| dispInfo.hdr.hwndFrom = hwnd; | |
| dispInfo.hdr.idFrom = lCtrlId; | |
| dispInfo.hdr.code = LVN_GETDISPINFOA; | |
| dispInfo.item.iItem = nItem; | |
| dispInfo.item.iSubItem = lpSubItem->iSubItem; | |
| dispInfo.item.lParam = lParam; | |
| ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo); | |
| } | |
| if (pnDispImage != NULL) | |
| { | |
| if (dispInfo.item.mask & LVIF_IMAGE) | |
| { | |
| *pnDispImage = dispInfo.item.iImage; | |
| } | |
| else | |
| { | |
| *pnDispImage = lpSubItem->iImage; | |
| } | |
| } | |
| if (ppszDispText != NULL) | |
| { | |
| if (dispInfo.item.mask & LVIF_TEXT) | |
| { | |
| if (dispInfo.item.mask & LVIF_DI_SETITEM) | |
| { | |
| Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText); | |
| } | |
| *ppszDispText = dispInfo.item.pszText; | |
| } | |
| else | |
| { | |
| *ppszDispText = lpSubItem->pszText; | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Calculates the width of an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LONG : window style | |
| * | |
| * RETURN: | |
| * Returns item width. | |
| */ | |
| static INT LISTVIEW_GetItemWidth(HWND hwnd, LONG lStyle) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nHeaderItemCount; | |
| RECT rcHeaderItem; | |
| INT nItemWidth = 0; | |
| INT nLabelWidth; | |
| INT i; | |
| TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle); | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| nItemWidth = infoPtr->iconSpacing.cx; | |
| break; | |
| case LVS_REPORT: | |
| /* calculate width of header */ | |
| nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader); | |
| for (i = 0; i < nHeaderItemCount; i++) | |
| { | |
| if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0) | |
| { | |
| nItemWidth += (rcHeaderItem.right - rcHeaderItem.left); | |
| } | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_LIST: | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i); | |
| nItemWidth = max(nItemWidth, nLabelWidth); | |
| } | |
| /* default label size */ | |
| if (GETITEMCOUNT(infoPtr) == 0) | |
| { | |
| nItemWidth = DEFAULT_COLUMN_WIDTH; | |
| } | |
| else | |
| { | |
| if (nItemWidth == 0) | |
| { | |
| nItemWidth = DEFAULT_LABEL_WIDTH; | |
| } | |
| else | |
| { | |
| /* add padding */ | |
| nItemWidth += WIDTH_PADDING; | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| nItemWidth += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlState != NULL) | |
| { | |
| nItemWidth += infoPtr->iconSize.cx; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| return nItemWidth; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Calculates the height of an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LONG : window style | |
| * | |
| * RETURN: | |
| * Returns item width. | |
| */ | |
| static INT LISTVIEW_GetItemHeight(HWND hwnd, LONG lStyle) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nItemHeight = 0; | |
| TEXTMETRICA tm; | |
| HFONT hOldFont; | |
| HDC hdc; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| nItemHeight = infoPtr->iconSpacing.cy; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_REPORT: | |
| case LVS_LIST: | |
| hdc = GetDC(hwnd); | |
| hOldFont = SelectObject(hdc, infoPtr->hFont); | |
| GetTextMetricsA(hdc, &tm); | |
| nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING; | |
| SelectObject(hdc, hOldFont); | |
| ReleaseDC(hwnd, hdc); | |
| break; | |
| } | |
| return nItemHeight; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets diplay information (needed for drawing operations). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetViewInfo(HWND hwnd, LONG lStyle) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| /* get number of fully visible items per column */ | |
| infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight); | |
| break; | |
| case LVS_LIST: | |
| /* get number of fully visible items per column */ | |
| infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight); | |
| /* get number of fully visible items per row */ | |
| infoPtr->nCountPerRow = max(1, nListWidth / infoPtr->nItemWidth); | |
| break; | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Adds a block of selections. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nFirst = min(infoPtr->nSelectionMark, nItem); | |
| INT nLast = max(infoPtr->nSelectionMark, nItem); | |
| LVITEMA lvItem; | |
| INT i; | |
| lvItem.state = LVIS_SELECTED; | |
| lvItem.stateMask= LVIS_SELECTED; | |
| for (i = nFirst; i <= nLast; i++) | |
| { | |
| ListView_SetItemState(hwnd, i, &lvItem); | |
| } | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| infoPtr->nSelectionMark = nItem; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Adds a single selection. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LVITEMA lvItem; | |
| lvItem.state = LVIS_SELECTED; | |
| lvItem.stateMask= LVIS_SELECTED; | |
| ListView_SetItemState(hwnd, nItem, &lvItem); | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| infoPtr->nSelectionMark = nItem; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Selects or unselects an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * SELECT: TRUE | |
| * UNSELECT : FALSE | |
| */ | |
| static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult; | |
| LVITEMA lvItem; | |
| lvItem.stateMask= LVIS_SELECTED; | |
| if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) | |
| { | |
| lvItem.state = 0; | |
| ListView_SetItemState(hwnd, nItem, &lvItem); | |
| bResult = FALSE; | |
| } | |
| else | |
| { | |
| lvItem.state = LVIS_SELECTED; | |
| ListView_SetItemState(hwnd, nItem, &lvItem); | |
| bResult = TRUE; | |
| } | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| infoPtr->nSelectionMark = nItem; | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets a single group selection. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nFirst = min(infoPtr->nSelectionMark, nItem); | |
| INT nLast = max(infoPtr->nSelectionMark, nItem); | |
| LVITEMA lvItem; | |
| INT i; | |
| if (nFirst > 0) | |
| { | |
| LISTVIEW_RemoveSelections(hwnd, 0, nFirst - 1); | |
| } | |
| if (nLast < GETITEMCOUNT(infoPtr)) | |
| { | |
| LISTVIEW_RemoveSelections(hwnd, nLast + 1, GETITEMCOUNT(infoPtr)); | |
| } | |
| lvItem.state = LVIS_SELECTED; | |
| lvItem.stateMask = LVIS_SELECTED; | |
| for (i = nFirst; i <= nLast; i++) | |
| { | |
| ListView_SetItemState(hwnd, i, &lvItem); | |
| } | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Manages the item focus. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LVITEMA lvItem; | |
| lvItem.state = 0; | |
| lvItem.stateMask = LVIS_FOCUSED; | |
| ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem); | |
| lvItem.state = LVIS_FOCUSED; | |
| lvItem.stateMask = LVIS_FOCUSED; | |
| ListView_SetItemState(hwnd, nItem, &lvItem); | |
| infoPtr->nFocusedItem = nItem; | |
| /* if multiple selection is allowed */ | |
| ListView_EnsureVisible(hwnd, nItem, FALSE); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets a single selection. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LVITEMA lvItem; | |
| if (nItem > 0) | |
| { | |
| LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1); | |
| } | |
| if (nItem < GETITEMCOUNT(infoPtr)) | |
| { | |
| LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr)); | |
| } | |
| lvItem.state = 0; | |
| lvItem.stateMask = LVIS_FOCUSED; | |
| ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem); | |
| lvItem.state = LVIS_SELECTED | LVIS_FOCUSED; | |
| lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; | |
| ListView_SetItemState(hwnd, nItem, &lvItem); | |
| infoPtr->nFocusedItem = nItem; | |
| infoPtr->nSelectionMark = nItem; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Set selection(s) with keyboard. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_KeySelection(HWND hwnd, INT nItem) | |
| { | |
| WORD wShift = HIWORD(GetKeyState(VK_SHIFT)); | |
| WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL)); | |
| if (wShift) | |
| { | |
| LISTVIEW_SetGroupSelection(hwnd, nItem); | |
| } | |
| else if (wCtrl) | |
| { | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| } | |
| else | |
| { | |
| LISTVIEW_SetSelection(hwnd, nItem); | |
| /* if multiple selection is allowed */ | |
| ListView_EnsureVisible(hwnd, nItem, FALSE); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Determines the selected item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : x ccordinate | |
| * [I] INT : y coordinate | |
| * | |
| * RETURN: | |
| * SUCCESS : item index | |
| * FAILURE : -1 | |
| */ | |
| static LRESULT LISTVIEW_MouseSelection(HWND hwnd, INT nPosX, INT nPosY) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| RECT rcItem; | |
| INT i; | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| rcItem.left = LVIR_SELECTBOUNDS; | |
| if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE) | |
| { | |
| if ((rcItem.left <= nPosX) && (nPosX <= rcItem.right) && | |
| (rcItem.top <= nPosY) && (nPosY <= rcItem.bottom)) | |
| { | |
| return i; | |
| } | |
| } | |
| } | |
| return -1; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Removes all selection states. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast) | |
| { | |
| LVITEMA lvItem; | |
| INT i; | |
| lvItem.state = 0; | |
| lvItem.stateMask = LVIS_SELECTED; | |
| for (i = nFirst; i <= nLast; i++) | |
| { | |
| ListView_SetItemState(hwnd, i, &lvItem); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Removes a column. | |
| * | |
| * PARAMETER(S): | |
| * [IO] HDPA : dynamic pointer array handle | |
| * [I] INT : column index (subitem index) | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem) | |
| { | |
| BOOL bResult = TRUE; | |
| HDPA hdpaSubItems; | |
| INT i; | |
| for (i = 0; i < hdpaItems->nItemCount; i++) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i); | |
| if (hdpaSubItems != NULL) | |
| { | |
| if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE) | |
| { | |
| bResult = FALSE; | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Removes a subitem at a given position. | |
| * | |
| * PARAMETER(S): | |
| * [IO] HDPA : dynamic pointer array handle | |
| * [I] INT : subitem index | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem) | |
| { | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| INT i; | |
| for (i = 1; i < hdpaSubItems->nItemCount; i++) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i); | |
| if (lpSubItem != NULL) | |
| { | |
| if (lpSubItem->iSubItem == nSubItem) | |
| { | |
| /* free string */ | |
| if ((lpSubItem->pszText != NULL) && | |
| (lpSubItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpSubItem->pszText); | |
| } | |
| /* free item */ | |
| COMCTL32_Free(lpSubItem); | |
| /* free dpa memory */ | |
| if (DPA_DeletePtr(hdpaSubItems, i) == NULL) | |
| { | |
| return FALSE; | |
| } | |
| } | |
| else if (lpSubItem->iSubItem > nSubItem) | |
| { | |
| return TRUE; | |
| } | |
| } | |
| } | |
| return TRUE; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Compares the item information. | |
| * | |
| * PARAMETER(S): | |
| * [I] LISTVIEW_ITEM *: destination item | |
| * [I] LPLVITEM : source item | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE (EQUAL) | |
| * FAILURE : FALSE (NOT EQUAL) | |
| */ | |
| static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem) | |
| { | |
| UINT uChanged = 0; | |
| if ((lpItem != NULL) && (lpLVItem != NULL)) | |
| { | |
| if (lpLVItem->mask & LVIF_STATE) | |
| { | |
| if ((lpItem->state & lpLVItem->stateMask) != | |
| (lpLVItem->state & lpLVItem->stateMask)) | |
| { | |
| uChanged |= LVIF_STATE; | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_IMAGE) | |
| { | |
| if (lpItem->iImage != lpLVItem->iImage) | |
| { | |
| uChanged |= LVIF_IMAGE; | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_PARAM) | |
| { | |
| if (lpItem->lParam != lpLVItem->lParam) | |
| { | |
| uChanged |= LVIF_PARAM; | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_INDENT) | |
| { | |
| if (lpItem->iIndent != lpLVItem->iIndent) | |
| { | |
| uChanged |= LVIF_INDENT; | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| if (lpItem->pszText != LPSTR_TEXTCALLBACKA) | |
| { | |
| uChanged |= LVIF_TEXT; | |
| } | |
| } | |
| else | |
| { | |
| if (lpItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| uChanged |= LVIF_TEXT; | |
| } | |
| else | |
| { | |
| if (lpLVItem->pszText) | |
| { | |
| if (lpItem->pszText) | |
| { | |
| if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0) | |
| { | |
| uChanged |= LVIF_TEXT; | |
| } | |
| } | |
| else | |
| { | |
| uChanged |= LVIF_TEXT; | |
| } | |
| } | |
| else | |
| { | |
| if (lpItem->pszText) | |
| { | |
| uChanged |= LVIF_TEXT; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return uChanged; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Initializes item attributes. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [O] LISTVIEW_ITEM *: destination item | |
| * [I] LPLVITEM : source item | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem, | |
| LPLVITEMA lpLVItem) | |
| { | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| if ((lpItem != NULL) && (lpLVItem != NULL)) | |
| { | |
| bResult = TRUE; | |
| if (lpLVItem->mask & LVIF_STATE) | |
| { | |
| lpItem->state &= ~lpLVItem->stateMask; | |
| lpItem->state |= (lpLVItem->state & lpLVItem->stateMask); | |
| } | |
| if (lpLVItem->mask & LVIF_IMAGE) | |
| { | |
| lpItem->iImage = lpLVItem->iImage; | |
| } | |
| if (lpLVItem->mask & LVIF_PARAM) | |
| { | |
| lpItem->lParam = lpLVItem->lParam; | |
| } | |
| if (lpLVItem->mask & LVIF_INDENT) | |
| { | |
| lpItem->iIndent = lpLVItem->iIndent; | |
| } | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING)) | |
| { | |
| return FALSE; | |
| } | |
| if ((lpItem->pszText != NULL) && | |
| (lpItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpItem->pszText); | |
| } | |
| lpItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| if (lpItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpItem->pszText = NULL; | |
| } | |
| bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText); | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Initializes subitem attributes. | |
| * | |
| * NOTE: the documentation specifies that the operation fails if the user | |
| * tries to set the indent of a subitem. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [O] LISTVIEW_SUBITEM *: destination subitem | |
| * [I] LPLVITEM : source subitem | |
| * | |
| * RETURN: | |
| * SUCCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem, | |
| LPLVITEMA lpLVItem) | |
| { | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| if ((lpSubItem != NULL) && (lpLVItem != NULL)) | |
| { | |
| if (!(lpLVItem->mask & LVIF_INDENT)) | |
| { | |
| bResult = TRUE; | |
| ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM)); | |
| lpSubItem->iSubItem = lpLVItem->iSubItem; | |
| if (lpLVItem->mask & LVIF_IMAGE) | |
| { | |
| lpSubItem->iImage = lpLVItem->iImage; | |
| } | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING)) | |
| { | |
| return FALSE; | |
| } | |
| if ((lpSubItem->pszText != NULL) && | |
| (lpSubItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpSubItem->pszText); | |
| } | |
| lpSubItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpSubItem->pszText = NULL; | |
| } | |
| bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText); | |
| } | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Adds a subitem at a given position (column index). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPLVITEM : new subitem atttributes | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_SUBITEM *lpSubItem = NULL; | |
| BOOL bResult = FALSE; | |
| HDPA hdpaSubItems; | |
| INT nPosition, nItem; | |
| if (lpLVItem != NULL) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM)); | |
| if (lpSubItem != NULL) | |
| { | |
| if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE) | |
| { | |
| nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems, | |
| lpSubItem->iSubItem); | |
| nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem); | |
| if (nItem != -1) | |
| { | |
| bResult = TRUE; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* cleanup if unsuccessful */ | |
| if ((bResult == FALSE) && (lpSubItem != NULL)) | |
| { | |
| COMCTL32_Free(lpSubItem); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Finds the dpa insert position (array index). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : subitem index | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem) | |
| { | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| INT i; | |
| for (i = 1; i < hdpaSubItems->nItemCount; i++) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i); | |
| if (lpSubItem != NULL) | |
| { | |
| if (lpSubItem->iSubItem > nSubItem) | |
| { | |
| return i; | |
| } | |
| } | |
| } | |
| return hdpaSubItems->nItemCount; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves a listview subitem at a given position (column index). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : subitem index | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem) | |
| { | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| INT i; | |
| for (i = 1; i < hdpaSubItems->nItemCount; i++) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i); | |
| if (lpSubItem != NULL) | |
| { | |
| if (lpSubItem->iSubItem == nSubItem) | |
| { | |
| return lpSubItem; | |
| } | |
| else if (lpSubItem->iSubItem > nSubItem) | |
| { | |
| return NULL; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets item attributes. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPLVITEM : new item atttributes | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| HDPA hdpaSubItems; | |
| LISTVIEW_ITEM *lpItem; | |
| NMLISTVIEW nmlv; | |
| UINT uChanged; | |
| LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| if (lpLVItem != NULL) | |
| { | |
| if (lpLVItem->iSubItem == 0) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem); | |
| if (lpItem != NULL) | |
| { | |
| ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); | |
| nmlv.hdr.hwndFrom = hwnd; | |
| nmlv.hdr.idFrom = lCtrlId; | |
| nmlv.hdr.code = LVN_ITEMCHANGING; | |
| nmlv.lParam = lpItem->lParam; | |
| uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem); | |
| if (uChanged != 0) | |
| { | |
| if (uChanged & LVIF_STATE) | |
| { | |
| nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask; | |
| nmlv.uOldState = lpItem->state & lpLVItem->stateMask; | |
| } | |
| nmlv.uChanged = uChanged; | |
| nmlv.iItem = lpLVItem->iItem; | |
| nmlv.lParam = lpItem->lParam; | |
| /* send LVN_ITEMCHANGING notification */ | |
| ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv); | |
| /* copy information */ | |
| bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem); | |
| /* send LVN_ITEMCHANGED notification */ | |
| nmlv.hdr.code = LVN_ITEMCHANGED; | |
| ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv); | |
| } | |
| else | |
| { | |
| bResult = TRUE; | |
| } | |
| InvalidateRect(hwnd, NULL, FALSE); | |
| } | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets subitem attributes. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPLVITEM : new subitem atttributes | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| HDPA hdpaSubItems; | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| if (lpLVItem != NULL) | |
| { | |
| if (lpLVItem->iSubItem > 0) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| /* set subitem only if column is present */ | |
| if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem) | |
| { | |
| lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem); | |
| if (lpSubItem != NULL) | |
| { | |
| bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem); | |
| } | |
| else | |
| { | |
| bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem); | |
| } | |
| InvalidateRect(hwnd, NULL, FALSE); | |
| } | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the index of the item at coordinate (0, 0) of the client area. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * item index | |
| */ | |
| static INT LISTVIEW_GetTopIndex(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *) GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nItem = 0; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (lStyle & WS_HSCROLL) | |
| { | |
| nItem = GetScrollPos(hwnd, SB_HORZ) * infoPtr->nCountPerColumn; | |
| } | |
| break; | |
| case LVS_REPORT: | |
| if (lStyle & WS_VSCROLL) | |
| { | |
| nItem = GetScrollPos(hwnd, SB_VERT); | |
| } | |
| break; | |
| } | |
| return nItem; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Evaluates if scrollbars are needed & sets the scroll range/position. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LONG : window style | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetScroll(HWND hwnd, LONG lStyle) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL); | |
| INT nVScrollWidth = GetSystemMetrics(SM_CXVSCROLL); | |
| INT nHiddenWidth; | |
| INT nHiddenHeight; | |
| INT nHiddenItemCount; | |
| INT nScrollPos; | |
| INT nMaxRange; | |
| INT nCountPerPage; | |
| INT nPixPerScrollPos; | |
| RECT rcView; | |
| TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle); | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| nCountPerPage = infoPtr->nCountPerRow * infoPtr->nCountPerColumn; | |
| if (nCountPerPage < GETITEMCOUNT(infoPtr)) | |
| { | |
| /* display horizontal scrollbar */ | |
| if ((lStyle & WS_HSCROLL) == 0) | |
| { | |
| ShowScrollBar(hwnd, SB_HORZ, TRUE); | |
| } | |
| /* calculate new scrollbar range */ | |
| nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage; | |
| if ((nHiddenItemCount % infoPtr->nCountPerColumn) == 0) | |
| { | |
| nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn; | |
| } | |
| else | |
| { | |
| nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn + 1; | |
| } | |
| SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); | |
| nScrollPos = ListView_GetTopIndex(hwnd) / infoPtr->nCountPerColumn; | |
| SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE); | |
| } | |
| else | |
| { | |
| /* hide scrollbar */ | |
| if ((lStyle & WS_HSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_HORZ, FALSE); | |
| } | |
| } | |
| break; | |
| case LVS_REPORT: | |
| /* | |
| * This section was commented out because I experienced some problems | |
| * with the scrolling of the header control. The idea was to add a | |
| * horizontal scrollbar when the width of the client area was smaller | |
| * than the width of the header control. | |
| */ | |
| /* if (infoPtr->nItemWidth > nListWidth) */ | |
| /* { */ | |
| /* if ((lStyle & WS_HSCROLL) == 0) */ | |
| /* { */ | |
| /* ShowScrollBar(hwnd, SB_HORZ, TRUE); */ | |
| /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */ | |
| /* LISTVIEW_SetViewInfo(hwnd, lStyle); */ | |
| /* } */ | |
| /* nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; */ | |
| /* nHiddenWidth = infoPtr->nItemWidth - nListWidth; */ | |
| /* nPixPerScrollPos = max(1, nListWidth / 10); */ | |
| /* if ((nHiddenWidth % nPixPerScrollPos) == 0) */ | |
| /* { */ | |
| /* nMaxRange = nHiddenWidth / nPixPerScrollPos; */ | |
| /* } */ | |
| /* else */ | |
| /* { */ | |
| /* nMaxRange = nHiddenWidth / nPixPerScrollPos + 1; */ | |
| /* } */ | |
| /* SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); */ | |
| /* SetScrollPos(hwnd, SB_HORZ, 0, TRUE); */ | |
| /* } */ | |
| /* else */ | |
| /* { */ | |
| /* if ((lStyle & WS_HSCROLL) != 0) */ | |
| /* { */ | |
| /* ShowScrollBar(hwnd, SB_HORZ, FASLE); */ | |
| /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */ | |
| /* LISTVIEW_SetViewInfo(hwnd, lStyle); */ | |
| /* } */ | |
| /* } */ | |
| if (infoPtr->nCountPerColumn < GETITEMCOUNT(infoPtr)) | |
| { | |
| if ((lStyle & WS_VSCROLL) == 0) | |
| { | |
| if (nListWidth > nVScrollWidth) | |
| { | |
| ShowScrollBar(hwnd, SB_VERT, TRUE); | |
| nListWidth -= nVScrollWidth; | |
| } | |
| } | |
| /* vertical range & position */ | |
| nMaxRange = GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn; | |
| SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE); | |
| SetScrollPos(hwnd, SB_VERT, ListView_GetTopIndex(hwnd), TRUE); | |
| } | |
| else | |
| { | |
| if ((lStyle & WS_VSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_VERT, FALSE); | |
| nListWidth += nVScrollWidth; | |
| } | |
| } | |
| break; | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE) | |
| { | |
| if (rcView.right - rcView.left > nListWidth) | |
| { | |
| if ((lStyle & WS_HSCROLL) == 0) | |
| { | |
| if (nListHeight > nHScrollHeight) | |
| { | |
| ShowScrollBar(hwnd, SB_HORZ, TRUE); | |
| nListHeight -= nHScrollHeight; | |
| } | |
| } | |
| /* calculate size of hidden items */ | |
| nHiddenWidth = rcView.right - rcView.left - nListWidth; | |
| nPixPerScrollPos = max(1, nListWidth / 10); | |
| /* vertical range & position */ | |
| if ((nHiddenWidth % nPixPerScrollPos) == 0) | |
| { | |
| nMaxRange = nHiddenWidth / nPixPerScrollPos; | |
| } | |
| else | |
| { | |
| nMaxRange = nHiddenWidth / nPixPerScrollPos + 1; | |
| } | |
| /* set range and position */ | |
| SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); | |
| SetScrollPos(hwnd, SB_HORZ, 0, TRUE); | |
| } | |
| else | |
| { | |
| if ((lStyle & WS_HSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_HORZ, FALSE); | |
| nListHeight += nHScrollHeight; | |
| } | |
| } | |
| if (rcView.bottom - rcView.top > nListHeight) | |
| { | |
| if ((lStyle & WS_VSCROLL) == 0) | |
| { | |
| if (nListWidth > nVScrollWidth) | |
| { | |
| ShowScrollBar(hwnd, SB_VERT, TRUE); | |
| nListWidth -= nVScrollWidth; | |
| } | |
| } | |
| /* calculate size of hidden items */ | |
| nHiddenHeight = rcView.bottom - rcView.top - nListHeight; | |
| nPixPerScrollPos = max(1, nListHeight / 10); | |
| /* set vertical range & position */ | |
| if ((nHiddenHeight % nPixPerScrollPos) == 0) | |
| { | |
| nMaxRange = nHiddenHeight / nPixPerScrollPos; | |
| } | |
| else | |
| { | |
| nMaxRange = nHiddenHeight / nPixPerScrollPos + 1; | |
| } | |
| /* set range and position */ | |
| SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE); | |
| SetScrollPos(hwnd, SB_VERT, 0, TRUE); | |
| } | |
| else | |
| { | |
| if ((lStyle & WS_VSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_VERT, FALSE); | |
| nListWidth += nVScrollWidth; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws a subitem. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * [I] INT : item index | |
| * [I] LPARAM : item lparam | |
| * [I] LISTVIEW_SUBITEM * : item | |
| * [I] INT : column index (header index) | |
| * [I] RECT * : clipping rectangle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, LPARAM lParam, | |
| LISTVIEW_SUBITEM *lpSubItem, INT nColumn, | |
| RECT *lprc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| CHAR szDispText[DISP_TEXT_SIZE]; | |
| LPSTR pszDispText = NULL; | |
| /* set item colors */ | |
| SetBkColor(hdc, infoPtr->clrTextBk); | |
| SetTextColor(hdc, infoPtr->clrText); | |
| pszDispText = szDispText; | |
| LISTVIEW_GetSubItemDispInfo(hwnd, nItem, lParam, lpSubItem, nColumn, NULL, | |
| &pszDispText, DISP_TEXT_SIZE); | |
| /* draw text : using arbitrary offset of 10 pixels */ | |
| ExtTextOutA(hdc, lprc->left, lprc->top, ETO_OPAQUE|ETO_CLIPPED, | |
| lprc, pszDispText, lstrlenA(pszDispText), NULL); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * [I] LISTVIEW_ITEM * : item | |
| * [I] INT : item index | |
| * [I] RECT * : clipping rectangle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem, | |
| INT nItem, RECT rc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| CHAR szDispText[DISP_TEXT_SIZE]; | |
| LPSTR pszDispText = NULL; | |
| BOOL bSelected; | |
| INT nLabelWidth; | |
| INT nImage; | |
| UINT uState; | |
| TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom); | |
| pszDispText = szDispText; | |
| LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText, | |
| DISP_TEXT_SIZE); | |
| if (uState & LVIS_SELECTED) | |
| { | |
| bSelected = TRUE; | |
| /* set item colors */ | |
| SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); | |
| SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); | |
| /* 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 icons */ | |
| if (infoPtr->himlState != NULL) | |
| { | |
| /* right shift 12 bits to obtain index in image list */ | |
| if (bSelected != FALSE) | |
| { | |
| ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left, | |
| rc.top, ILD_SELECTED); | |
| } | |
| else | |
| { | |
| ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left, | |
| rc.top, ILD_NORMAL); | |
| } | |
| rc.left += infoPtr->iconSize.cx; | |
| } | |
| /* small icons */ | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| if (bSelected != FALSE) | |
| { | |
| ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left, | |
| rc.top, ILD_SELECTED); | |
| } | |
| else | |
| { | |
| ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left, | |
| rc.top, ILD_NORMAL); | |
| } | |
| rc.left += infoPtr->iconSize.cx; | |
| } | |
| nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText); | |
| if (rc.left + nLabelWidth < rc.right) | |
| { | |
| rc.right = rc.left + nLabelWidth; | |
| } | |
| /* draw label */ | |
| ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED, | |
| &rc, pszDispText, lstrlenA(pszDispText), NULL); | |
| if (lpItem->state & LVIS_FOCUSED) | |
| { | |
| Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws an item when in large icon display mode. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * [I] LISTVIEW_ITEM * : item | |
| * [I] INT : item index | |
| * [I] RECT * : clipping rectangle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem, | |
| INT nItem, RECT rc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| CHAR szDispText[DISP_TEXT_SIZE]; | |
| LPSTR pszDispText = NULL; | |
| BOOL bSelected; | |
| INT nLabelWidth; | |
| INT nImage; | |
| UINT uState; | |
| INT nDrawPosX = 0; | |
| TEXTMETRICA tm; | |
| TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom); | |
| pszDispText = szDispText; | |
| LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText, | |
| DISP_TEXT_SIZE); | |
| if (uState & LVIS_SELECTED) | |
| { | |
| bSelected = TRUE; | |
| /* set item colors */ | |
| SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); | |
| SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); | |
| /* 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); | |
| } | |
| if (infoPtr->himlNormal != NULL) | |
| { | |
| rc.top += ICON_TOP_PADDING; | |
| nDrawPosX = rc.left + (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2; | |
| if (bSelected != FALSE) | |
| { | |
| ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top, | |
| ILD_SELECTED); | |
| } | |
| else | |
| { | |
| ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top, | |
| ILD_NORMAL); | |
| } | |
| } | |
| rc.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING; | |
| nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText); | |
| nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth; | |
| if (nDrawPosX > 1) | |
| { | |
| rc.left += nDrawPosX / 2; | |
| rc.right = rc.left + nLabelWidth; | |
| } | |
| else | |
| { | |
| rc.left += 1; | |
| rc.right = rc.left + infoPtr->iconSpacing.cx - 1; | |
| } | |
| /* draw label */ | |
| GetTextMetricsA(hdc, &tm); | |
| rc.bottom = rc.top + tm.tmHeight + HEIGHT_PADDING; | |
| ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED, | |
| &rc, pszDispText, lstrlenA(pszDispText), NULL); | |
| if (lpItem->state & LVIS_FOCUSED) | |
| { | |
| Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws listview items when in report display mode. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0); | |
| INT nDrawPosY = infoPtr->rcList.top; | |
| LISTVIEW_ITEM *lpItem; | |
| LISTVIEW_SUBITEM *lpSubItem = NULL; | |
| BOOL bNeedSubItem = TRUE; | |
| INT nColumnCount; | |
| HDPA hdpaSubItems; | |
| RECT rcItem; | |
| INT j, k; | |
| INT nItem; | |
| INT nLast; | |
| nItem = ListView_GetTopIndex(hwnd); | |
| nLast = nItem + infoPtr->nCountPerColumn; | |
| while (nItem <= nLast) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| /* the width of the header items will determine the size of the | |
| listview items */ | |
| Header_GetItemRect(infoPtr->hwndHeader, 0, &rcItem); | |
| rcItem.left += REPORT_MARGINX; | |
| rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX); | |
| rcItem.top = nDrawPosY; | |
| rcItem.bottom = rcItem.top + infoPtr->nItemHeight; | |
| LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rcItem); | |
| } | |
| nColumnCount = Header_GetItemCount(infoPtr->hwndHeader); | |
| for (k = 1, j = 1; j < nColumnCount; j++) | |
| { | |
| Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem); | |
| rcItem.left += REPORT_MARGINX; | |
| rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX); | |
| rcItem.top = nDrawPosY; | |
| rcItem.bottom = rcItem.top + infoPtr->nItemHeight; | |
| if (k < hdpaSubItems->nItemCount) | |
| { | |
| if (bNeedSubItem != FALSE) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, k); | |
| k++; | |
| } | |
| if (lpSubItem != NULL) | |
| { | |
| if (lpSubItem->iSubItem == j) | |
| { | |
| LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, lpSubItem, | |
| j, &rcItem); | |
| bNeedSubItem = TRUE; | |
| } | |
| else | |
| { | |
| LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, | |
| &rcItem); | |
| bNeedSubItem = FALSE; | |
| } | |
| } | |
| else | |
| { | |
| LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, | |
| &rcItem); | |
| bNeedSubItem = TRUE; | |
| } | |
| } | |
| else | |
| { | |
| LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, | |
| &rcItem); | |
| } | |
| } | |
| } | |
| nDrawPosY += infoPtr->nItemHeight; | |
| nItem++; | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws listview items when in list display mode. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_ITEM *lpItem; | |
| HDPA hdpaSubItems; | |
| RECT rc; | |
| INT i, j; | |
| INT nColumnCount; | |
| INT nItem = ListView_GetTopIndex(hwnd); | |
| if (infoPtr->rcList.right > 0) | |
| { | |
| /* get number of display columns */ | |
| if (infoPtr->rcList.right % infoPtr->nItemWidth == 0) | |
| { | |
| nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth; | |
| } | |
| else | |
| { | |
| nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1; | |
| } | |
| for (i = 0; i < nColumnCount; i++) | |
| { | |
| j = 0; | |
| while ((nItem < GETITEMCOUNT(infoPtr)) && | |
| (j<infoPtr->nCountPerColumn)) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| rc.top = j * infoPtr->nItemHeight; | |
| rc.left = i * infoPtr->nItemWidth; | |
| rc.bottom = rc.top + infoPtr->nItemHeight; | |
| rc.right = rc.left + infoPtr->nItemWidth; | |
| LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rc); | |
| } | |
| } | |
| nItem++; | |
| j++; | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws listview items when in icon or small icon display mode. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_ITEM *lpItem; | |
| HDPA hdpaSubItems; | |
| POINT ptPosition; | |
| POINT ptOrigin; | |
| RECT rc; | |
| INT i; | |
| LISTVIEW_GetOrigin(hwnd, &ptOrigin); | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| LISTVIEW_GetItemPosition(hwnd, i, &ptPosition); | |
| ptPosition.x += ptOrigin.x; | |
| ptPosition.y += ptOrigin.y; | |
| if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top) | |
| { | |
| if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left) | |
| { | |
| if (ptPosition.y < infoPtr->rcList.bottom) | |
| { | |
| if (ptPosition.x < infoPtr->rcList.right) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| rc.top = ptPosition.y; | |
| rc.left = ptPosition.x; | |
| rc.bottom = rc.top + infoPtr->nItemHeight; | |
| rc.right = rc.left + infoPtr->nItemWidth; | |
| if (bSmall == FALSE) | |
| { | |
| LISTVIEW_DrawLargeItem(hwnd, hdc, lpItem, i, rc); | |
| } | |
| else | |
| { | |
| LISTVIEW_DrawItem(hwnd, hdc, lpItem, i, rc); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Draws listview items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * | |
| * RETURN: | |
| * NoneX | |
| */ | |
| static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| HFONT hOldFont; | |
| HPEN hPen, hOldPen; | |
| /* select font */ | |
| hOldFont = SelectObject(hdc, infoPtr->hFont); | |
| /* select the doted pen (for drawing the focus box) */ | |
| hPen = CreatePen(PS_DOT, 1, 0); | |
| hOldPen = SelectObject(hdc, hPen); | |
| /* select transparent brush (for drawing the focus box) */ | |
| SelectObject(hdc, GetStockObject(NULL_BRUSH)); | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| LISTVIEW_RefreshList(hwnd, hdc); | |
| break; | |
| case LVS_REPORT: | |
| LISTVIEW_RefreshReport(hwnd, hdc); | |
| break; | |
| case LVS_SMALLICON: | |
| LISTVIEW_RefreshIcon(hwnd, hdc, TRUE); | |
| break; | |
| case LVS_ICON: | |
| LISTVIEW_RefreshIcon(hwnd, hdc, FALSE); | |
| } | |
| /* unselect objects */ | |
| SelectObject(hdc, hOldFont); | |
| SelectObject(hdc, hOldPen); | |
| /* delete pen */ | |
| DeleteObject(hPen); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Calculates the approximate width and height of a given number of items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : number of items | |
| * [I] INT : width | |
| * [I] INT : 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 = GETITEMCOUNT(infoPtr); | |
| if (lStyle & LVS_LIST) | |
| { | |
| if (wHeight == 0xFFFF) | |
| { | |
| /* use current height */ | |
| wHeight = infoPtr->rcList.bottom; | |
| } | |
| 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; | |
| } | |
| } | |
| /* Microsoft padding magic */ | |
| wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2; | |
| wWidth = nColumnCount * infoPtr->nItemWidth + 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] HWND : window handle | |
| * [I] INT : alignment code | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode) | |
| { | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| if (((LVS_TYPEMASK & lStyle) == LVS_ICON) || | |
| ((LVS_TYPEMASK & lStyle) == LVS_SMALLICON)) | |
| { | |
| 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 */ | |
| break; | |
| } | |
| } | |
| return bResult; | |
| } | |
| /* << LISTVIEW_CreateDragImage >> */ | |
| /*** | |
| * DESCRIPTION: | |
| * Removes all listview items and subitems. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| LISTVIEW_ITEM *lpItem; | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| NMLISTVIEW nmlv; | |
| BOOL bSuppress; | |
| BOOL bResult = FALSE; | |
| INT i; | |
| INT j; | |
| HDPA hdpaSubItems; | |
| TRACE(listview, "(hwnd=%x,)\n", hwnd); | |
| if (GETITEMCOUNT(infoPtr) > 0) | |
| { | |
| /* initialize memory */ | |
| ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); | |
| /* send LVN_DELETEALLITEMS notification */ | |
| nmlv.hdr.hwndFrom = hwnd; | |
| nmlv.hdr.idFrom = lCtrlId; | |
| nmlv.hdr.code = LVN_DELETEALLITEMS; | |
| nmlv.iItem = -1; | |
| /* verify if subsequent LVN_DELETEITEM notifications should be | |
| suppressed */ | |
| bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv); | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); | |
| if (hdpaSubItems != NULL) | |
| { | |
| for (j = 1; j < hdpaSubItems->nItemCount; j++) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j); | |
| if (lpSubItem != NULL) | |
| { | |
| /* free subitem string */ | |
| if ((lpSubItem->pszText != NULL) && | |
| (lpSubItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpSubItem->pszText); | |
| } | |
| /* free subitem */ | |
| COMCTL32_Free(lpSubItem); | |
| } | |
| } | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| if (bSuppress == FALSE) | |
| { | |
| /* send LVN_DELETEITEM notification */ | |
| nmlv.hdr.code = LVN_DELETEITEM; | |
| nmlv.iItem = i; | |
| nmlv.lParam = lpItem->lParam; | |
| ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv); | |
| } | |
| /* free item string */ | |
| if ((lpItem->pszText != NULL) && | |
| (lpItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpItem->pszText); | |
| } | |
| /* free item */ | |
| COMCTL32_Free(lpItem); | |
| } | |
| DPA_Destroy(hdpaSubItems); | |
| } | |
| } | |
| /* reinitialize listview memory */ | |
| bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems); | |
| /* align items (set position of each item) */ | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| } | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| /* invalidate client area (optimization needed) */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Removes a column from the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : column index | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE) | |
| { | |
| bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn); | |
| /* reset scroll parameters */ | |
| if ((lStyle & LVS_TYPEMASK) == LVS_REPORT) | |
| { | |
| LISTVIEW_SetViewInfo(hwnd, lStyle); | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| } | |
| /* refresh client area */ | |
| InvalidateRect(hwnd, NULL, FALSE); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Removes an item from the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMLISTVIEW nmlv; | |
| BOOL bResult = FALSE; | |
| HDPA hdpaSubItems; | |
| LISTVIEW_ITEM *lpItem; | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| INT i; | |
| TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem); | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| /* initialize memory */ | |
| ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); | |
| hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| for (i = 1; i < hdpaSubItems->nItemCount; i++) | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i); | |
| if (lpSubItem != NULL) | |
| { | |
| /* free item string */ | |
| if ((lpSubItem->pszText != NULL) && | |
| (lpSubItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpSubItem->pszText); | |
| } | |
| /* free item */ | |
| COMCTL32_Free(lpSubItem); | |
| } | |
| } | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| /* send LVN_DELETEITEM notification */ | |
| nmlv.hdr.hwndFrom = hwnd; | |
| nmlv.hdr.idFrom = lCtrlId; | |
| nmlv.hdr.code = LVN_DELETEITEM; | |
| nmlv.iItem = nItem; | |
| nmlv.lParam = lpItem->lParam; | |
| SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId, | |
| (LPARAM)&nmlv); | |
| /* free item string */ | |
| if ((lpItem->pszText != NULL) && | |
| (lpItem->pszText != LPSTR_TEXTCALLBACKA)) | |
| { | |
| COMCTL32_Free(lpItem->pszText); | |
| } | |
| /* free item */ | |
| COMCTL32_Free(lpItem); | |
| } | |
| bResult = DPA_Destroy(hdpaSubItems); | |
| } | |
| /* align items (set position of each item) */ | |
| switch(lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| } | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| /* refresh client area */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| } | |
| return bResult; | |
| } | |
| /* LISTVIEW_EditLabel */ | |
| /*** | |
| * DESCRIPTION: | |
| * Ensures the specified item is visible, scrolling into view if necessary. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] BOOL : partially or entirely visible | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| INT nHScrollPos = 0; | |
| INT nVScrollPos = 0; | |
| INT nScrollPosHeight = 0; | |
| INT nScrollPosWidth = 0; | |
| RECT rcItem; | |
| BOOL bResult = FALSE; | |
| /* ALWAYS bPartial == FALSE, FOR NOW! */ | |
| rcItem.left = LVIR_BOUNDS; | |
| if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE) | |
| { | |
| if (rcItem.left < infoPtr->rcList.left) | |
| { | |
| /* scroll left */ | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| rcItem.left += infoPtr->rcList.left; | |
| nScrollPosWidth = infoPtr->nItemWidth; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nScrollPosWidth = max(1, nListWidth / 10); | |
| rcItem.left += infoPtr->rcList.left; | |
| break; | |
| } | |
| if (rcItem.left % nScrollPosWidth == 0) | |
| { | |
| nHScrollPos = rcItem.left / nScrollPosWidth; | |
| } | |
| else | |
| { | |
| nHScrollPos = rcItem.left / nScrollPosWidth - 1; | |
| } | |
| } | |
| else if (rcItem.right > infoPtr->rcList.right) | |
| { | |
| /* scroll right */ | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| rcItem.right -= infoPtr->rcList.right; | |
| nScrollPosWidth = infoPtr->nItemWidth; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nScrollPosWidth = max(1, nListWidth / 10); | |
| rcItem.right -= infoPtr->rcList.right; | |
| break; | |
| } | |
| if (rcItem.right % nScrollPosWidth == 0) | |
| { | |
| nHScrollPos = rcItem.right / nScrollPosWidth; | |
| } | |
| else | |
| { | |
| nHScrollPos = rcItem.right / nScrollPosWidth + 1; | |
| } | |
| } | |
| if (rcItem.top < infoPtr->rcList.top) | |
| { | |
| /* scroll up */ | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| rcItem.top -= infoPtr->rcList.top; | |
| nScrollPosHeight = infoPtr->nItemHeight; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nScrollPosHeight = max(1, nListHeight / 10); | |
| rcItem.top += infoPtr->rcList.top; | |
| break; | |
| } | |
| if (rcItem.top % nScrollPosHeight == 0) | |
| { | |
| nVScrollPos = rcItem.top / nScrollPosHeight; | |
| } | |
| else | |
| { | |
| nVScrollPos = rcItem.top / nScrollPosHeight - 1; | |
| } | |
| } | |
| else if (rcItem.bottom > infoPtr->rcList.bottom) | |
| { | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| rcItem.bottom -= infoPtr->rcList.bottom; | |
| nScrollPosHeight = infoPtr->nItemHeight; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nScrollPosHeight = max(1, nListHeight / 10); | |
| rcItem.bottom -= infoPtr->rcList.bottom; | |
| break; | |
| } | |
| if (rcItem.bottom % nScrollPosHeight == 0) | |
| { | |
| nVScrollPos = rcItem.bottom / nScrollPosHeight; | |
| } | |
| else | |
| { | |
| nVScrollPos = rcItem.bottom / nScrollPosHeight + 1; | |
| } | |
| } | |
| bResult = LISTVIEW_ScrollView(hwnd, nHScrollPos, nVScrollPos); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Searches for an item with specific characteristics. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : 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) | |
| { | |
| FIXME (listview, "empty stub!\n"); | |
| return -1; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the background color of the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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] HWND : window handle | |
| * [O] LPLVMKBIMAGE : background image attributes | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE` | |
| */ | |
| /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */ | |
| /* { */ | |
| /* FIXME (listview, "empty stub!\n"); */ | |
| /* return FALSE; */ | |
| /* } */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the callback mask. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Value of mask | |
| */ | |
| static UINT LISTVIEW_GetCallbackMask(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| return infoPtr->uCallbackMask; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves column attributes. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : column index | |
| * [IO] LPLVCOLUMNA : column information | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, | |
| LPLVCOLUMNA lpColumn) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| HDITEMA hdi; | |
| BOOL bResult = FALSE; | |
| if (lpColumn != NULL) | |
| { | |
| /* initialize memory */ | |
| 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; | |
| } | |
| bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi); | |
| if (bResult != 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 bResult; | |
| } | |
| /* LISTVIEW_GetColumnW */ | |
| /* LISTVIEW_GetColumnOrderArray */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the column width. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] int : 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; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| nColumnWidth = infoPtr->nItemWidth; | |
| break; | |
| case LVS_REPORT: | |
| /* get column width from header */ | |
| ZeroMemory(&hdi, sizeof(HDITEMA)); | |
| hdi.mask = HDI_WIDTH; | |
| if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE) | |
| { | |
| nColumnWidth = hdi.cxy; | |
| } | |
| break; | |
| } | |
| 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] HWND : 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; | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (infoPtr->rcList.right / infoPtr->nItemWidth) | |
| { | |
| nItemCount = infoPtr->nCountPerRow * infoPtr->nCountPerColumn; | |
| } | |
| break; | |
| case LVS_REPORT: | |
| nItemCount = infoPtr->nCountPerColumn; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| nItemCount = GETITEMCOUNT(infoPtr); | |
| break; | |
| } | |
| return nItemCount; | |
| } | |
| /* LISTVIEW_GetEditControl */ | |
| /* LISTVIEW_GetExtendedListViewStyle */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the handle to the header control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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] HWND : window handle | |
| * [I] INT : 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; | |
| break; | |
| case LVSIL_SMALL: | |
| himl = infoPtr->himlSmall; | |
| break; | |
| case LVSIL_STATE: | |
| himl = infoPtr->himlState; | |
| break; | |
| } | |
| return (LRESULT)himl; | |
| } | |
| /* LISTVIEW_GetISearchString */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves item attributes. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [IO] LPLVITEMA : item info | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_ITEM *lpItem; | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| HDPA hdpaSubItems; | |
| BOOL bResult = FALSE; | |
| TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem); | |
| if (lpLVItem != NULL) | |
| { | |
| if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| if (lpLVItem->iSubItem == 0) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| bResult = TRUE; | |
| /* retrieve valid data */ | |
| if (lpLVItem->mask & LVIF_STATE) | |
| { | |
| lpLVItem->state = lpItem->state & lpLVItem->stateMask; | |
| } | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpLVItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| bResult = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText, | |
| lpLVItem->cchTextMax); | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_IMAGE) | |
| { | |
| lpLVItem->iImage = lpItem->iImage; | |
| } | |
| if (lpLVItem->mask & LVIF_PARAM) | |
| { | |
| lpLVItem->lParam = lpItem->lParam; | |
| } | |
| if (lpLVItem->mask & LVIF_INDENT) | |
| { | |
| lpLVItem->iIndent = lpItem->iIndent; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, | |
| lpLVItem->iSubItem); | |
| if (lpSubItem != NULL) | |
| { | |
| bResult = TRUE; | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpLVItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| bResult = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText, | |
| lpLVItem->cchTextMax); | |
| } | |
| } | |
| if (lpLVItem->mask & LVIF_IMAGE) | |
| { | |
| lpLVItem->iImage = lpSubItem->iImage; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /* LISTVIEW_GetItemW */ | |
| /* LISTVIEW_GetHotCursor */ | |
| /* LISTVIEW_GetHotItem */ | |
| /* LISTVIEW_GetHoverTime> */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the number of items in the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Number of items. | |
| */ | |
| static LRESULT LISTVIEW_GetItemCount(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| return GETITEMCOUNT(infoPtr); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the position (upper-left) of the listview control item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [O] LPPOINT : coordinate information | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, | |
| LPPOINT lpptPosition) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| HDPA hdpaSubItems; | |
| LISTVIEW_ITEM *lpItem; | |
| INT nRow; | |
| TRACE(listview, "(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem, | |
| lpptPosition); | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && | |
| (lpptPosition != NULL)) | |
| { | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| bResult = TRUE; | |
| nItem = nItem - ListView_GetTopIndex(hwnd); | |
| if (nItem < 0) | |
| { | |
| nRow = nItem % infoPtr->nCountPerColumn; | |
| if (nRow == 0) | |
| { | |
| lpptPosition->x = (nItem / infoPtr->nCountPerColumn * | |
| infoPtr->nItemWidth); | |
| lpptPosition->y = 0; | |
| } | |
| else | |
| { | |
| lpptPosition->x = ((nItem / infoPtr->nCountPerColumn - 1) * | |
| infoPtr->nItemWidth); | |
| lpptPosition->y = ((nRow + infoPtr->nCountPerColumn) * | |
| infoPtr->nItemHeight); | |
| } | |
| } | |
| else | |
| { | |
| lpptPosition->x = (nItem / infoPtr->nCountPerColumn * | |
| infoPtr->nItemWidth); | |
| lpptPosition->y = (nItem % infoPtr->nCountPerColumn * | |
| infoPtr->nItemHeight); | |
| } | |
| break; | |
| case LVS_REPORT: | |
| bResult = TRUE; | |
| lpptPosition->x = REPORT_MARGINX; | |
| lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) * | |
| infoPtr->nItemHeight) + infoPtr->rcList.top; | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| bResult = TRUE; | |
| lpptPosition->x = lpItem->ptPosition.x; | |
| lpptPosition->y = lpItem->ptPosition.y; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the bounding rectangle for a listview control item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [IO] LPRECT : bounding rectangle coordinates | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| POINT ptOrigin; | |
| POINT ptItem; | |
| HDC hdc; | |
| HFONT hOldFont; | |
| INT nMaxWidth; | |
| INT nLabelWidth; | |
| TEXTMETRICA tm; | |
| TRACE(listview, "(hwnd=%x,nItem=%d,lprc=%p)\n", hwnd, nItem, lprc); | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL)) | |
| { | |
| if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE) | |
| { | |
| switch(lprc->left) | |
| { | |
| case LVIR_ICON: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| if (infoPtr->himlNormal != NULL) | |
| { | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->right = lprc->left + infoPtr->iconSize.cx; | |
| lprc->bottom = (lprc->top + infoPtr->iconSize.cy + | |
| ICON_BOTTOM_PADDING + ICON_TOP_PADDING); | |
| } | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right = lprc->left + infoPtr->iconSize.cx; | |
| } | |
| else | |
| { | |
| lprc->right = lprc->left; | |
| } | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_LIST: | |
| bResult = TRUE; | |
| lprc->left = ptItem.x; | |
| lprc->top = ptItem.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right = lprc->left + infoPtr->iconSize.cx; | |
| } | |
| else | |
| { | |
| lprc->right = lprc->left; | |
| } | |
| break; | |
| } | |
| break; | |
| case LVIR_LABEL: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| if (infoPtr->himlNormal != NULL) | |
| { | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy + | |
| ICON_BOTTOM_PADDING + ICON_TOP_PADDING); | |
| nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| if (infoPtr->iconSpacing.cx - nLabelWidth > 1) | |
| { | |
| lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2; | |
| lprc->right = lprc->left + nLabelWidth; | |
| } | |
| else | |
| { | |
| lprc->left += 1; | |
| lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1; | |
| } | |
| hdc = GetDC(hwnd); | |
| hOldFont = SelectObject(hdc, infoPtr->hFont); | |
| GetTextMetricsA(hdc, &tm); | |
| lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING; | |
| SelectObject(hdc, hOldFont); | |
| ReleaseDC(hwnd, hdc); | |
| } | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| nMaxWidth = lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| if (lprc->left + nLabelWidth < nMaxWidth + infoPtr->nItemWidth) | |
| { | |
| lprc->right = lprc->left + nLabelWidth; | |
| } | |
| else | |
| { | |
| lprc->right = nMaxWidth + infoPtr->nItemWidth; | |
| } | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_LIST: | |
| bResult = TRUE; | |
| lprc->left = ptItem.x; | |
| lprc->top = ptItem.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| lprc->right = lprc->left + LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| break; | |
| } | |
| break; | |
| case LVIR_BOUNDS: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| if (infoPtr->himlNormal != NULL) | |
| { | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->right = lprc->left + infoPtr->iconSpacing.cx; | |
| lprc->bottom = lprc->top + infoPtr->iconSpacing.cy; | |
| } | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x +ptOrigin.x; | |
| lprc->right = lprc->left; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_LIST: | |
| bResult = TRUE; | |
| lprc->left = ptItem.x; | |
| lprc->right = lprc->left; | |
| lprc->top = ptItem.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| break; | |
| } | |
| break; | |
| case LVIR_SELECTBOUNDS: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| if (infoPtr->himlNormal != NULL) | |
| { | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->right = lprc->left + infoPtr->iconSpacing.cx; | |
| lprc->bottom = lprc->top + infoPtr->iconSpacing.cy; | |
| } | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) | |
| { | |
| bResult = TRUE; | |
| lprc->left = ptItem.x + ptOrigin.x; | |
| lprc->top = ptItem.y + ptOrigin.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| lprc->right = lprc->left; | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_LIST: | |
| bResult = TRUE; | |
| lprc->left = ptItem.x; | |
| lprc->top = ptItem.y; | |
| lprc->bottom = lprc->top + infoPtr->nItemHeight; | |
| if (infoPtr->himlState != NULL) | |
| { | |
| lprc->left += infoPtr->iconSize.cx; | |
| } | |
| lprc->right = lprc->left; | |
| if (infoPtr->himlSmall != NULL) | |
| { | |
| lprc->right += infoPtr->iconSize.cx; | |
| } | |
| lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem); | |
| break; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the width of a label. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * SUCCESS : string width (in pixels) | |
| * FAILURE : zero | |
| */ | |
| static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_ITEM *lpItem; | |
| HDPA hdpaSubItems; | |
| INT nLabelWidth = 0; | |
| TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem); | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| CHAR szDispText[DISP_TEXT_SIZE]; | |
| LPSTR pszDispText = NULL; | |
| pszDispText = szDispText; | |
| LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL, &pszDispText, | |
| DISP_TEXT_SIZE); | |
| nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText); | |
| } | |
| } | |
| return nLabelWidth; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the spacing between listview control items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] BOOL : flag for small or large icon | |
| * | |
| * RETURN: | |
| * Horizontal + vertical spacing | |
| */ | |
| static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lResult; | |
| if (bSmall == FALSE) | |
| { | |
| lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); | |
| } | |
| else | |
| { | |
| /* TODO: need to store width of smallicon item */ | |
| lResult = MAKELONG(0, infoPtr->nItemHeight); | |
| } | |
| return lResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the state of a listview control item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] UINT : 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); | |
| LVITEMA lvItem; | |
| UINT uState = 0; | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| ZeroMemory(&lvItem, sizeof(LVITEMA)); | |
| lvItem.iItem = nItem; | |
| lvItem.stateMask = uMask; | |
| lvItem.mask = LVIF_STATE; | |
| if (ListView_GetItemA(hwnd, &lvItem) != FALSE) | |
| { | |
| uState = lvItem.state; | |
| } | |
| } | |
| return uState; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the text of a listview control item or subitem. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [IO] LPLVITEMA : item information | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LISTVIEW_ITEM *lpItem; | |
| LISTVIEW_SUBITEM *lpSubItem; | |
| HDPA hdpaSubItems; | |
| INT nLength = 0; | |
| if (lpLVItem != NULL) | |
| { | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| if (lpLVItem->iSubItem == 0) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpLVItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| nLength = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText, | |
| lpLVItem->cchTextMax); | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, | |
| lpLVItem->iSubItem); | |
| if (lpSubItem != NULL) | |
| { | |
| if (lpLVItem->mask & LVIF_TEXT) | |
| { | |
| if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA) | |
| { | |
| lpLVItem->pszText = LPSTR_TEXTCALLBACKA; | |
| } | |
| else | |
| { | |
| nLength = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText, | |
| lpLVItem->cchTextMax); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return nLength; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Searches for an item based on properties + relationships. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] UINT : relationship flag | |
| * | |
| * RETURN: | |
| * SUCCESS : item index | |
| * FAILURE : -1 | |
| */ | |
| static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags) | |
| { | |
| FIXME (listview, "empty stub!\n"); | |
| return -1; | |
| } | |
| /* LISTVIEW_GetNumberOfWorkAreas */ | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the origin coordinates when in icon or small icon display mode. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [O] LPPOINT : coordinate information | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; | |
| INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; | |
| BOOL bResult = FALSE; | |
| TRACE(listview, "(hwnd=%x,lpptOrigin=%p)\n", hwnd, lpptOrigin); | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if ((lStyle & WS_HSCROLL) != 0) | |
| { | |
| lpptOrigin->x = -GetScrollPos(hwnd, SB_HORZ) * nListWidth / 10; | |
| } | |
| else | |
| { | |
| lpptOrigin->x = 0; | |
| } | |
| if ((lStyle & WS_VSCROLL) != 0) | |
| { | |
| lpptOrigin->y = -GetScrollPos(hwnd, SB_VERT) * nListHeight / 10; | |
| } | |
| else | |
| { | |
| lpptOrigin->y = 0; | |
| } | |
| bResult = TRUE; | |
| break; | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the number of items that are marked as selected. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Number of items selected. | |
| */ | |
| static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nSelectedCount = 0; | |
| INT i; | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED) | |
| { | |
| nSelectedCount++; | |
| } | |
| } | |
| return nSelectedCount; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves item index that marks the start of a multiple selection. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| return infoPtr->nSelectionMark; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the width of a string. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * SUCCESS : string width (in pixels) | |
| * FAILURE : zero | |
| */ | |
| static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| HFONT hFont, hOldFont; | |
| SIZE stringSize; | |
| HDC hdc; | |
| ZeroMemory(&stringSize, sizeof(SIZE)); | |
| if (lpszText != NULL) | |
| { | |
| hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; | |
| hdc = GetDC(hwnd); | |
| hOldFont = SelectObject(hdc, hFont); | |
| GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize); | |
| SelectObject(hdc, hOldFont); | |
| ReleaseDC(hwnd, hdc); | |
| } | |
| return stringSize.cx; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the text backgound color. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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] HWND : 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: | |
| * Set the bounding rectangle of all the items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPRECT : bounding rectangle | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| BOOL bResult = FALSE; | |
| TRACE(listview, "(hwnd=%x,lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", hwnd, lprcView->left, lprcView->top, lprcView->right, lprcView->bottom); | |
| if (lprcView != NULL) | |
| { | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| bResult = TRUE; | |
| infoPtr->rcView.left = lprcView->left; | |
| infoPtr->rcView.top = lprcView->top; | |
| infoPtr->rcView.right = lprcView->right; | |
| infoPtr->rcView.bottom = lprcView->bottom; | |
| break; | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the bounding rectangle of all the items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [O] LPRECT : bounding rectangle | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| POINT ptOrigin; | |
| TRACE(listview, "(hwnd=%x,lprcView=%p)\n", hwnd, lprcView); | |
| if (lprcView != NULL) | |
| { | |
| bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin); | |
| if (bResult != FALSE) | |
| { | |
| lprcView->left = infoPtr->rcView.left + ptOrigin.x; | |
| lprcView->top = infoPtr->rcView.top + ptOrigin.y; | |
| lprcView->right = infoPtr->rcView.right + ptOrigin.x; | |
| lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y; | |
| } | |
| TRACE(listview, "(lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", lprcView->left, lprcView->top, lprcView->right, lprcView->bottom); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Determines which section of the item was selected (if any). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [IO] LPLVHITTESTINFO : hit test information | |
| * | |
| * RETURN: | |
| * SUCCESS : item index | |
| * FAILURE : -1 | |
| */ | |
| static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| RECT rcItem; | |
| INT i; | |
| for (i = 0; i < GETITEMCOUNT(infoPtr); i++) | |
| { | |
| rcItem.left = LVIR_BOUNDS; | |
| if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE) | |
| { | |
| rcItem.left = LVIR_ICON; | |
| if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE) | |
| { | |
| if ((lpHitTestInfo->pt.x >= rcItem.left) && | |
| (lpHitTestInfo->pt.x <= rcItem.right) && | |
| (lpHitTestInfo->pt.y >= rcItem.top) && | |
| (lpHitTestInfo->pt.y <= rcItem.bottom)) | |
| { | |
| lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM; | |
| lpHitTestInfo->iItem = i; | |
| lpHitTestInfo->iSubItem = 0; | |
| return i; | |
| } | |
| } | |
| rcItem.left = LVIR_LABEL; | |
| if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE) | |
| { | |
| if ((lpHitTestInfo->pt.x >= rcItem.left) && | |
| (lpHitTestInfo->pt.x <= rcItem.right) && | |
| (lpHitTestInfo->pt.y >= rcItem.top) && | |
| (lpHitTestInfo->pt.y <= rcItem.bottom)) | |
| { | |
| lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM; | |
| lpHitTestInfo->iItem = i; | |
| lpHitTestInfo->iSubItem = 0; | |
| return i; | |
| } | |
| } | |
| lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM; | |
| lpHitTestInfo->iItem = i; | |
| lpHitTestInfo->iSubItem = 0; | |
| return i; | |
| } | |
| } | |
| lpHitTestInfo->flags = LVHT_NOWHERE; | |
| return -1; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Determines wich listview item is located at the specified position. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [IO} LPLVHITTESTINFO : hit test information | |
| * | |
| * RETURN: | |
| * SUCCESS : item index | |
| * FAILURE : -1 | |
| */ | |
| static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nItem = -1; | |
| lpHitTestInfo->flags = 0; | |
| if (infoPtr->rcList.left > lpHitTestInfo->pt.x) | |
| { | |
| lpHitTestInfo->flags = LVHT_TOLEFT; | |
| } | |
| else if (infoPtr->rcList.right < lpHitTestInfo->pt.x) | |
| { | |
| lpHitTestInfo->flags = LVHT_TORIGHT; | |
| } | |
| if (infoPtr->rcList.top > lpHitTestInfo->pt.y) | |
| { | |
| lpHitTestInfo->flags |= LVHT_ABOVE; | |
| } | |
| else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y) | |
| { | |
| lpHitTestInfo->flags |= LVHT_BELOW; | |
| } | |
| if (lpHitTestInfo->flags == 0) | |
| { | |
| nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo); | |
| } | |
| return nItem; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Inserts a new column. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : column index | |
| * [I] LPLVCOLUMNA : column information | |
| * | |
| * RETURN: | |
| * SUCCESS : new column index | |
| * FAILURE : -1 | |
| */ | |
| static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn, | |
| LPLVCOLUMNA lpColumn) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| HDITEMA hdi; | |
| INT nNewColumn = -1; | |
| TRACE(listview,"(hwnd=%x,nColumn=%d,lpColumn=%p)\n",hwnd, nColumn, lpColumn); | |
| if (lpColumn != NULL) | |
| { | |
| /* initialize memory */ | |
| ZeroMemory(&hdi, sizeof(HDITEMA)); | |
| if (lpColumn->mask & LVCF_FMT) | |
| { | |
| /* format member is valid */ | |
| hdi.mask |= HDI_FORMAT; | |
| /* set text alignment (leftmost column must be left-aligned) */ | |
| if (nColumn == 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_BITMAP_ON_RIGHT) | |
| { | |
| hdi.fmt |= HDF_BITMAP_ON_RIGHT; | |
| /* ??? */ | |
| } | |
| if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) | |
| { | |
| /* ??? */ | |
| } | |
| if (lpColumn->fmt & LVCFMT_IMAGE) | |
| { | |
| hdi.fmt |= HDF_IMAGE; | |
| hdi.iImage = I_IMAGECALLBACK; | |
| } | |
| } | |
| 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.cchTextMax = lstrlenA(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; | |
| } | |
| /* insert item in header control */ | |
| nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA, | |
| (WPARAM)nColumn, (LPARAM)&hdi); | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| InvalidateRect(hwnd, NULL, FALSE); | |
| } | |
| return nNewColumn; | |
| } | |
| /* LISTVIEW_InsertColumnW */ | |
| /*** | |
| * DESCRIPTION: | |
| * Inserts a new item in the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPLVITEMA : item information | |
| * | |
| * RETURN: | |
| * SUCCESS : new item index | |
| * FAILURE : -1 | |
| */ | |
| static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMLISTVIEW nmlv; | |
| INT nItem = -1; | |
| HDPA hdpaSubItems; | |
| LISTVIEW_ITEM *lpItem = NULL; | |
| TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem); | |
| if (lpLVItem != NULL) | |
| { | |
| /* make sure it's not a subitem; cannot insert a subitem */ | |
| if (lpLVItem->iSubItem == 0) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM)); | |
| if (lpItem != NULL) | |
| { | |
| ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM)); | |
| if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE) | |
| { | |
| /* insert item in listview control data structure */ | |
| hdpaSubItems = DPA_Create(8); | |
| if (hdpaSubItems != NULL) | |
| { | |
| nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem); | |
| if (nItem != -1) | |
| { | |
| nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem, | |
| hdpaSubItems); | |
| if (nItem != -1) | |
| { | |
| /* manage item focus */ | |
| if (lpLVItem->mask & LVIF_STATE) | |
| { | |
| if (lpLVItem->stateMask & LVIS_FOCUSED) | |
| { | |
| LISTVIEW_SetItemFocus(hwnd, nItem); | |
| } | |
| } | |
| /* send LVN_INSERTITEM notification */ | |
| ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); | |
| nmlv.hdr.hwndFrom = hwnd; | |
| nmlv.hdr.idFrom = lCtrlId; | |
| nmlv.hdr.code = LVN_INSERTITEM; | |
| nmlv.iItem = nItem; | |
| nmlv.lParam = lpItem->lParam;; | |
| ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv); | |
| /* align items (set position of each item) */ | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| } | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| /* refresh client area */ | |
| InvalidateRect(hwnd, NULL, FALSE); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* free memory if unsuccessful */ | |
| if ((nItem == -1) && (lpItem != NULL)) | |
| { | |
| COMCTL32_Free(lpItem); | |
| } | |
| return nItem; | |
| } | |
| /* LISTVIEW_InsertItemW */ | |
| /*** | |
| * DESCRIPTION: | |
| * Redraws a range of items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : first item | |
| * [I] INT : 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); | |
| BOOL bResult = FALSE; | |
| RECT rc; | |
| if (nFirst <= nLast) | |
| { | |
| if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr))) | |
| { | |
| if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr))) | |
| { | |
| /* bResult = */ | |
| InvalidateRect(hwnd, &rc, FALSE); | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /* LISTVIEW_Scroll */ | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the background color. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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 the callback mask. This mask will be used when the parent | |
| * window stores state information (some or all). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] UINT : state mask | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| infoPtr->uCallbackMask = uMask; | |
| return TRUE; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the attributes of a header item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : column index | |
| * [I] LPLVCOLUMNA : column attributes | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn, | |
| LPLVCOLUMNA lpColumn) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| HDITEMA hdi; | |
| if ((lpColumn != NULL) && (nColumn >= 0) && | |
| (nColumn < Header_GetItemCount(infoPtr->hwndHeader))) | |
| { | |
| /* initialize memory */ | |
| ZeroMemory(&hdi, sizeof(HDITEMA)); | |
| if (lpColumn->mask & LVCF_FMT) | |
| { | |
| /* format member is valid */ | |
| hdi.mask |= HDI_FORMAT; | |
| /* set text alignment (leftmost column must be left-aligned) */ | |
| if (nColumn == 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_BITMAP_ON_RIGHT) | |
| { | |
| hdi.fmt |= HDF_BITMAP_ON_RIGHT; | |
| } | |
| if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) | |
| { | |
| hdi.fmt |= HDF_IMAGE; | |
| } | |
| if (lpColumn->fmt & LVCFMT_IMAGE) | |
| { | |
| hdi.fmt |= HDF_IMAGE; | |
| hdi.iImage = I_IMAGECALLBACK; | |
| } | |
| } | |
| 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.cchTextMax = lstrlenA(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; | |
| } | |
| /* set header item attributes */ | |
| bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the width of a column | |
| * | |
| * PARAMETERS: | |
| * [I] HWND : window handle | |
| * [I] INT : column index | |
| * [I] INT : column width | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx) | |
| { | |
| LISTVIEW_INFO *infoPtr; | |
| HDITEMA hdi; | |
| LRESULT lret; | |
| LONG lStyle; | |
| /* set column width only if in report mode */ | |
| lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| if ((lStyle & LVS_TYPEMASK) != LVS_REPORT) | |
| return (FALSE); | |
| /* make sure we can get the listview info */ | |
| if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0))) | |
| return (FALSE); | |
| if (!infoPtr->hwndHeader) /* make sure we have a header */ | |
| return (FALSE); | |
| /* | |
| * FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and | |
| * LVSCV_AUTOSIZE_USEHEADER (-2) | |
| */ | |
| if (cx < 0) | |
| return (FALSE); | |
| hdi.mask = HDI_WIDTH; | |
| hdi.cxy = cx; | |
| /* call header to update the column change */ | |
| lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi); | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT); | |
| InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */ | |
| return lret; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets image lists. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : 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 the attributes of an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LPLVITEM : item information | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| if (lpLVItem != NULL) | |
| { | |
| if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| if (lpLVItem->iSubItem == 0) | |
| { | |
| bResult = LISTVIEW_SetItem(hwnd, lpLVItem); | |
| } | |
| else | |
| { | |
| bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem); | |
| } | |
| } | |
| } | |
| return bResult; | |
| } | |
| /* LISTVIEW_SetItemW */ | |
| /*** | |
| * DESCRIPTION: | |
| * Preallocates memory. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item count (prjected number of items) | |
| * | |
| * RETURN: | |
| * None | |
| */ | |
| static VOID LISTVIEW_SetItemCount(HWND hwnd, INT nItemCount) | |
| { | |
| FIXME (listview, "empty stub!\n"); | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the position of an item. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] INT : x coordinate | |
| * [I] INT : y coordinate | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem, | |
| INT nPosX, INT nPosY) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| LISTVIEW_ITEM *lpItem; | |
| HDPA hdpaSubItems; | |
| BOOL bResult = FALSE; | |
| TRACE(listview, "(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY); | |
| if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); | |
| if (hdpaSubItems != NULL) | |
| { | |
| lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0); | |
| if (lpItem != NULL) | |
| { | |
| bResult = TRUE; | |
| lpItem->ptPosition.x = nPosX; | |
| lpItem->ptPosition.y = nPosY; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the state of one or many items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I]INT : item index | |
| * [I] LPLVITEM : item or subitem info | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| LVITEMA lvItem; | |
| INT i; | |
| if (nItem == -1) | |
| { | |
| bResult = TRUE; | |
| ZeroMemory(&lvItem, sizeof(LVITEMA)); | |
| lvItem.mask = LVIF_STATE; | |
| lvItem.state = lpLVItem->state; | |
| lvItem.stateMask = lpLVItem->stateMask; | |
| /* apply to all items */ | |
| for (i = 0; i< GETITEMCOUNT(infoPtr); i++) | |
| { | |
| lvItem.iItem = i; | |
| if (ListView_SetItemA(hwnd, &lvItem) == FALSE) | |
| { | |
| bResult = FALSE; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| ZeroMemory(&lvItem, sizeof(LVITEMA)); | |
| lvItem.mask = LVIF_STATE; | |
| lvItem.state = lpLVItem->state; | |
| lvItem.stateMask = lpLVItem->stateMask; | |
| lvItem.iItem = nItem; | |
| bResult = ListView_SetItemA(hwnd, &lvItem); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the text of an item or subitem. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : item index | |
| * [I] LPLVITEMA : item or subitem info | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| BOOL bResult = FALSE; | |
| LVITEMA lvItem; | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| ZeroMemory(&lvItem, sizeof(LVITEMA)); | |
| lvItem.mask = LVIF_TEXT; | |
| lvItem.pszText = lpLVItem->pszText; | |
| lvItem.iItem = nItem; | |
| lvItem.iSubItem = lpLVItem->iSubItem; | |
| bResult = ListView_SetItemA(hwnd, &lvItem); | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the text background color. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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; | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| return TRUE; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the text foreground color. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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; | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| return TRUE; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sorts the listview items. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * SUCCESS : TRUE | |
| * FAILURE : FALSE | |
| */ | |
| static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam) | |
| { | |
| FIXME (listview, "empty stub!\n"); | |
| return TRUE; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Updates an items or rearranges the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : 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); | |
| BOOL bResult = FALSE; | |
| RECT rc; | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| bResult = TRUE; | |
| /* rearrange with default alignment style */ | |
| if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) || | |
| ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON))) | |
| { | |
| ListView_Arrange(hwnd, 0); | |
| } | |
| else | |
| { | |
| /* get item bounding rectangle */ | |
| rc.left = LVIR_BOUNDS; | |
| ListView_GetItemRect(hwnd, nItem, &rc); | |
| InvalidateRect(hwnd, &rc, FALSE); | |
| } | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Creates the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam; | |
| LOGFONTA logFont; | |
| /* initialize info pointer */ | |
| ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO)); | |
| /* determine the type of structures to use */ | |
| infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT, | |
| (WPARAM)hwnd, (LPARAM)NF_QUERY); | |
| if (infoPtr->notifyFormat != NFR_ANSI) | |
| { | |
| FIXME (listview, "ANSI notify format is NOT used\n"); | |
| } | |
| /* initialize color information */ | |
| infoPtr->clrBk = GetSysColor(COLOR_WINDOW); | |
| infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT); | |
| infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW); | |
| /* set default values */ | |
| infoPtr->uCallbackMask = 0; | |
| infoPtr->nFocusedItem = -1; | |
| infoPtr->nSelectionMark = -1; | |
| infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING); | |
| infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING); | |
| ZeroMemory(&infoPtr->rcList, sizeof(RECT)); | |
| /* get default font (icon title) */ | |
| SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0); | |
| infoPtr->hDefaultFont = CreateFontIndirectA(&logFont); | |
| infoPtr->hFont = infoPtr->hDefaultFont; | |
| /* create header */ | |
| infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL, | |
| WS_CHILD | HDS_HORZ | HDS_BUTTONS, | |
| 0, 0, 0, 0, hwnd, (HMENU)0, | |
| lpcs->hInstance, NULL); | |
| /* set header font */ | |
| SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, | |
| (LPARAM)TRUE); | |
| switch (lpcs->style & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON); | |
| break; | |
| case LVS_REPORT: | |
| ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL); | |
| case LVS_SMALLICON: | |
| case LVS_LIST: | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON); | |
| break; | |
| } | |
| /* display unsupported listview window styles */ | |
| LISTVIEW_UnsupportedStyles(lpcs->style); | |
| /* allocate memory for the data structure */ | |
| infoPtr->hdpaItems = DPA_Create(10); | |
| /* initialize size of items */ | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpcs->style); | |
| infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpcs->style); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Erases the background of the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] WPARAM : device context handle | |
| * [I] LPARAM : not used | |
| * | |
| * 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 | |
| { | |
| RECT rc; | |
| HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk); | |
| GetClientRect(hwnd, &rc); | |
| FillRect((HDC)wParam, &rc, hBrush); | |
| DeleteObject(hBrush); | |
| bResult = TRUE; | |
| } | |
| return bResult; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Retrieves the listview control font. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Font handle. | |
| */ | |
| static LRESULT LISTVIEW_GetFont(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| return infoPtr->hFont; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Performs vertical scrolling. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : scroll code | |
| * [I] INT : scroll position | |
| * [I] HWND : scrollbar control window handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, INT nScroll, | |
| HWND hScrollWnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nScrollPosInc = 0; | |
| INT nScrollPos; | |
| INT nMinRange; | |
| INT nMaxRange; | |
| GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange); | |
| nScrollPos = GetScrollPos(hwnd, SB_VERT); | |
| switch (nScrollCode) | |
| { | |
| case SB_LINEUP: | |
| if (nScrollPos > nMinRange) | |
| { | |
| nScrollPosInc = -1; | |
| } | |
| break; | |
| case SB_LINEDOWN: | |
| if (nScrollPos < nMaxRange) | |
| { | |
| nScrollPosInc = 1; | |
| } | |
| break; | |
| case SB_PAGEUP: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| if (nScrollPos > nMinRange + infoPtr->nCountPerColumn) | |
| { | |
| nScrollPosInc = -infoPtr->nCountPerColumn; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMinRange - nScrollPos; | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (nScrollPos > nMinRange + 10) | |
| { | |
| nScrollPosInc = -10; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMinRange - nScrollPos; | |
| } | |
| break; | |
| } | |
| break; | |
| case SB_PAGEDOWN: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_REPORT: | |
| if (nScrollPos < nMaxRange - infoPtr->nCountPerColumn) | |
| { | |
| nScrollPosInc = infoPtr->nCountPerColumn; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMaxRange - nScrollPos; | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (nScrollPos < nMaxRange - 10) | |
| { | |
| nScrollPosInc = 10; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMaxRange - nScrollPos; | |
| } | |
| break; | |
| } | |
| break; | |
| case SB_THUMBPOSITION: | |
| nScrollPosInc = nScroll - nScrollPos; | |
| break; | |
| } | |
| if (nScrollPosInc != 0) | |
| { | |
| LISTVIEW_ScrollView(hwnd, 0, nScrollPosInc); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Performs horizontal scrolling. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : scroll code | |
| * [I] INT : scroll position | |
| * [I] HWND : scrollbar control window handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, | |
| INT nScroll, HWND hScrollWnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| INT nScrollPosInc = 0; | |
| INT nScrollPos; | |
| INT nMinRange; | |
| INT nMaxRange; | |
| GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange); | |
| nScrollPos = GetScrollPos(hwnd, SB_HORZ); | |
| switch (nScrollCode) | |
| { | |
| case SB_LINELEFT: | |
| if (nScrollPos > nMinRange) | |
| { | |
| nScrollPosInc = -1; | |
| } | |
| break; | |
| case SB_LINERIGHT: | |
| if (nScrollPos < nMaxRange) | |
| { | |
| nScrollPosInc = 1; | |
| } | |
| break; | |
| case SB_PAGELEFT: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (nScrollPos > nMinRange + infoPtr->nCountPerRow) | |
| { | |
| nScrollPosInc = -infoPtr->nCountPerRow; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMinRange - nScrollPos; | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (nScrollPos > nMinRange + 10) | |
| { | |
| nScrollPosInc = -10; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMinRange - nScrollPos; | |
| } | |
| break; | |
| } | |
| break; | |
| case SB_PAGERIGHT: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (nScrollPos < nMaxRange - infoPtr->nCountPerRow) | |
| { | |
| nScrollPosInc = infoPtr->nCountPerRow; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMaxRange - nScrollPos; | |
| } | |
| break; | |
| case LVS_REPORT: | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (nScrollPos < nMaxRange - 10) | |
| { | |
| nScrollPosInc = 10; | |
| } | |
| else | |
| { | |
| nScrollPosInc = nMaxRange - nScrollPos; | |
| } | |
| break; | |
| } | |
| break; | |
| case SB_THUMBPOSITION: | |
| nScrollPosInc = nScroll - nScrollPos; | |
| break; | |
| } | |
| if (nScrollPosInc != 0) | |
| { | |
| LISTVIEW_ScrollView(hwnd, nScrollPosInc, 0); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * ??? | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : 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); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| INT nCountPerColumn; | |
| INT nCountPerRow; | |
| HWND hwndParent = GetParent(hwnd); | |
| NMLVKEYDOWN nmKeyDown; | |
| NMHDR nmh; | |
| /* send LVN_KEYDOWN notification */ | |
| ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN)); | |
| nmKeyDown.hdr.hwndFrom = hwnd; | |
| nmKeyDown.hdr.idFrom = nCtrlId; | |
| nmKeyDown.hdr.code = LVN_KEYDOWN; | |
| nmKeyDown.wVKey = nVirtualKey; | |
| nmKeyDown.flags = 0; | |
| SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown); | |
| /* initialize */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| switch (nVirtualKey) | |
| { | |
| case VK_RETURN: | |
| if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1)) | |
| { | |
| /* send NM_RETURN notification */ | |
| nmh.code = NM_RETURN; | |
| ListView_Notify(hwndParent, nCtrlId, &nmh); | |
| /* send LVN_ITEMACTIVATE notification */ | |
| nmh.code = LVN_ITEMACTIVATE; | |
| ListView_Notify(hwndParent, nCtrlId, &nmh); | |
| } | |
| break; | |
| case VK_HOME: | |
| if (GETITEMCOUNT(infoPtr) > 0) | |
| { | |
| LISTVIEW_KeySelection(hwnd, 0); | |
| } | |
| break; | |
| case VK_END: | |
| if (GETITEMCOUNT(infoPtr) > 0) | |
| { | |
| LISTVIEW_KeySelection(hwnd, GETITEMCOUNT(infoPtr) - 1); | |
| } | |
| break; | |
| case VK_LEFT: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (infoPtr->nFocusedItem >= infoPtr->nCountPerColumn) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - | |
| infoPtr->nCountPerColumn); | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / | |
| infoPtr->nItemHeight, 1); | |
| if (infoPtr->nFocusedItem >= nCountPerColumn) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerColumn); | |
| } | |
| } | |
| else | |
| { | |
| nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) / | |
| infoPtr->nItemWidth, 1); | |
| if (infoPtr->nFocusedItem % nCountPerRow != 0) | |
| { | |
| LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 1); | |
| } | |
| } | |
| break; | |
| } | |
| break; | |
| case VK_UP: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| case LVS_REPORT: | |
| if (infoPtr->nFocusedItem > 0) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1); | |
| } | |
| break; | |
| default: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / | |
| infoPtr->nItemHeight, 1); | |
| if (infoPtr->nFocusedItem % nCountPerColumn != 0) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1); | |
| } | |
| } | |
| else | |
| { | |
| nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) / | |
| infoPtr->nItemWidth, 1); | |
| if (infoPtr->nFocusedItem >= nCountPerRow) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerRow); | |
| } | |
| } | |
| } | |
| break; | |
| case VK_RIGHT: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - | |
| infoPtr->nCountPerColumn) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + | |
| infoPtr->nCountPerColumn); | |
| } | |
| break; | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / | |
| infoPtr->nItemHeight, 1); | |
| if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerColumn) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerColumn); | |
| } | |
| } | |
| else | |
| { | |
| nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) / | |
| infoPtr->nItemWidth, 1); | |
| if ((infoPtr->nFocusedItem % nCountPerRow != nCountPerRow - 1) && | |
| (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1)) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1); | |
| } | |
| } | |
| } | |
| break; | |
| case VK_DOWN: | |
| switch (LVS_TYPEMASK & lStyle) | |
| { | |
| case LVS_LIST: | |
| case LVS_REPORT: | |
| if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1); | |
| } | |
| break; | |
| case LVS_SMALLICON: | |
| case LVS_ICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / | |
| infoPtr->nItemHeight, 1); | |
| if (infoPtr->nFocusedItem % nCountPerColumn != nCountPerColumn - 1) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1); | |
| } | |
| } | |
| else | |
| { | |
| nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) / | |
| infoPtr->nItemWidth, 1); | |
| if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerRow) | |
| { | |
| LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerRow); | |
| } | |
| } | |
| } | |
| break; | |
| case VK_PRIOR: | |
| break; | |
| case VK_NEXT: | |
| break; | |
| } | |
| /* refresh client area */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Kills the focus. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_KillFocus(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| /* send NM_KILLFOCUS notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_KILLFOCUS; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* set window focus flag */ | |
| infoPtr->bFocus = FALSE; | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes double click messages (left mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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 nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| /* send NM_DBLCLK notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_DBLCLK; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* send LVN_ITEMACTIVATE notification */ | |
| nmh.code = LVN_ITEMACTIVATE; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes mouse down messages (left mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| static BOOL bGroupSelect = TRUE; | |
| NMHDR nmh; | |
| INT nItem; | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| /* send NM_RELEASEDCAPTURE notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_RELEASEDCAPTURE; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| if (infoPtr->bFocus == FALSE) | |
| { | |
| SetFocus(hwnd); | |
| } | |
| /* set left button down flag */ | |
| infoPtr->bLButtonDown = TRUE; | |
| nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY); | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT)) | |
| { | |
| if (bGroupSelect != FALSE) | |
| { | |
| LISTVIEW_AddGroupSelection(hwnd, nItem); | |
| } | |
| else | |
| { | |
| LISTVIEW_AddSelection(hwnd, nItem); | |
| } | |
| } | |
| else if (wKey & MK_CONTROL) | |
| { | |
| bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem); | |
| } | |
| else if (wKey & MK_SHIFT) | |
| { | |
| LISTVIEW_SetGroupSelection(hwnd, nItem); | |
| } | |
| else | |
| { | |
| LISTVIEW_SetSelection(hwnd, nItem); | |
| } | |
| } | |
| else | |
| { | |
| /* remove all selections */ | |
| LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr)); | |
| } | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes mouse up messages (left mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| if (infoPtr->bLButtonDown != FALSE) | |
| { | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| /* send NM_CLICK notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_CLICK; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* set left button flag */ | |
| infoPtr->bLButtonDown = FALSE; | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Creates the listview control (called before WM_CREATE). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] WPARAM : unhandled | |
| * [I] LPARAM : widow creation info | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam) | |
| { | |
| LISTVIEW_INFO *infoPtr; | |
| TRACE(listview, "(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam); | |
| /* 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] HWND : window handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_NCDestroy(HWND hwnd) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| TRACE(listview, "(hwnd=%x)\n", hwnd); | |
| /* delete all items */ | |
| LISTVIEW_DeleteAllItems(hwnd); | |
| /* destroy data structure */ | |
| DPA_Destroy(infoPtr->hdpaItems); | |
| /* destroy font */ | |
| infoPtr->hFont = (HFONT)0; | |
| if (infoPtr->hDefaultFont) | |
| { | |
| DeleteObject(infoPtr->hDefaultFont); | |
| } | |
| /* free listview info pointer*/ | |
| COMCTL32_Free(infoPtr); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Handles notifications from children. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] INT : 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 */ | |
| if (lpnmh->code == HDN_ENDTRACKA) | |
| { | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT); | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| } | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Determines the type of structure to use. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle of the sender | |
| * [I] HWND : listview window handle | |
| * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| if (nCommand == NF_REQUERY) | |
| { | |
| /* determine the type of structure to use */ | |
| infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT, | |
| (WPARAM)hwnd, (LPARAM)NF_QUERY); | |
| if (infoPtr->notifyFormat == NFR_UNICODE) | |
| { | |
| FIXME (listview, "NO support for unicode structures"); | |
| } | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Paints/Repaints the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HDC : device context handle | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc) | |
| { | |
| PAINTSTRUCT ps; | |
| TRACE(listview, "(hwnd=%x,hdc=%x)\n", hwnd, hdc); | |
| if (hdc == 0) | |
| { | |
| hdc = BeginPaint(hwnd, &ps); | |
| LISTVIEW_Refresh(hwnd, hdc); | |
| EndPaint(hwnd, &ps); | |
| } | |
| else | |
| { | |
| LISTVIEW_Refresh(hwnd, hdc); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes double click messages (right mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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) | |
| { | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| /* send NM_RELEASEDCAPTURE notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_RELEASEDCAPTURE; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* send NM_RDBLCLK notification */ | |
| nmh.code = NM_RDBLCLK; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes mouse down messages (right mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| INT nItem; | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| /* send NM_RELEASEDCAPTURE notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_RELEASEDCAPTURE; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* make sure the listview control window has the focus */ | |
| if (infoPtr->bFocus == FALSE) | |
| { | |
| SetFocus(hwnd); | |
| } | |
| /* set right button down flag */ | |
| infoPtr->bRButtonDown = TRUE; | |
| /* determine the index of the selected item */ | |
| nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY); | |
| if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr))) | |
| { | |
| if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL))) | |
| { | |
| LISTVIEW_SetSelection(hwnd, nItem); | |
| } | |
| } | |
| else | |
| { | |
| LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr)); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes mouse up messages (right mouse button). | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : 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); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY); | |
| if (infoPtr->bRButtonDown != FALSE) | |
| { | |
| /* send NM_RClICK notification */ | |
| ZeroMemory(&nmh, sizeof(NMHDR)); | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_RCLICK; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* set button flag */ | |
| infoPtr->bRButtonDown = FALSE; | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the focus. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HWND : window handle of previously focused window | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| INT nCtrlId = GetWindowLongA(hwnd, GWL_ID); | |
| NMHDR nmh; | |
| /* send NM_SETFOCUS notification */ | |
| nmh.hwndFrom = hwnd; | |
| nmh.idFrom = nCtrlId; | |
| nmh.code = NM_SETFOCUS; | |
| ListView_Notify(GetParent(hwnd), nCtrlId, &nmh); | |
| /* set window focus flag */ | |
| infoPtr->bFocus = TRUE; | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the font. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] HFONT : 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); | |
| TRACE(listview, "(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw); | |
| if (hFont == 0) | |
| { | |
| infoPtr->hFont = infoPtr->hDefaultFont; | |
| } | |
| else | |
| { | |
| infoPtr->hFont = hFont; | |
| } | |
| if ((LVS_TYPEMASK & lStyle ) == LVS_REPORT) | |
| { | |
| /* set header font */ | |
| SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, | |
| MAKELPARAM(fRedraw, 0)); | |
| } | |
| /* invalidate listview control client area */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| if (fRedraw != FALSE) | |
| { | |
| UpdateWindow(hwnd); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Resizes the listview control. This function processes WM_SIZE | |
| * messages. At this time, the width and height are not used. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] WORD : new width | |
| * [I] WORD : new height | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height) | |
| { | |
| LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); | |
| TRACE(listview, "(hwnd=%x,width=%d,height=%d)\n",hwnd, Width, Height); | |
| LISTVIEW_SetSize(hwnd, lStyle, -1, -1); | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_LIST: | |
| case LVS_REPORT: | |
| LISTVIEW_SetViewInfo(hwnd, lStyle); | |
| break; | |
| case LVS_ICON: | |
| case LVS_SMALLICON: | |
| if (lStyle & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| } | |
| LISTVIEW_SetScroll(hwnd, lStyle); | |
| /* invalidate + erase background */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Sets the size information for a given style. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] LONG : window style | |
| * [I] WORD : new width | |
| * [I] WORD : new height | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static VOID LISTVIEW_SetSize(HWND hwnd, LONG lStyle, LONG lWidth, LONG lHeight) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| HDLAYOUT hl; | |
| WINDOWPOS wp; | |
| RECT rcList; | |
| GetClientRect(hwnd, &rcList); | |
| if (lWidth == -1) | |
| { | |
| infoPtr->rcList.left = max(rcList.left, 0); | |
| infoPtr->rcList.right = max(rcList.right, 0); | |
| } | |
| else | |
| { | |
| infoPtr->rcList.left = max(rcList.left, 0); | |
| infoPtr->rcList.right = infoPtr->rcList.left + max(lWidth, 0); | |
| } | |
| if (lHeight == -1) | |
| { | |
| infoPtr->rcList.top = max(rcList.top, 0); | |
| infoPtr->rcList.bottom = max(rcList.bottom, 0); | |
| } | |
| else | |
| { | |
| infoPtr->rcList.top = max(rcList.top, 0); | |
| infoPtr->rcList.bottom = infoPtr->rcList.top + max(lHeight, 0); | |
| } | |
| switch (lStyle & LVS_TYPEMASK) | |
| { | |
| case LVS_LIST: | |
| if ((lStyle & WS_HSCROLL) == 0) | |
| { | |
| INT nHScrollHeight; | |
| nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL); | |
| if (infoPtr->rcList.bottom > nHScrollHeight) | |
| { | |
| infoPtr->rcList.bottom -= nHScrollHeight; | |
| } | |
| } | |
| break; | |
| case LVS_REPORT: | |
| hl.prc = &rcList; | |
| hl.pwpos = ℘ | |
| Header_Layout(infoPtr->hwndHeader, &hl); | |
| infoPtr->rcList.top = max(wp.cy, 0); | |
| break; | |
| } | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Processes WM_STYLECHANGED messages. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : window handle | |
| * [I] WPARAM : window style type (normal or extended) | |
| * [I] LPSTYLESTRUCT : window style information | |
| * | |
| * RETURN: | |
| * Zero | |
| */ | |
| static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType, | |
| LPSTYLESTRUCT lpss) | |
| { | |
| LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); | |
| RECT rcList = infoPtr->rcList; | |
| HDLAYOUT hl; | |
| WINDOWPOS wp; | |
| TRACE(listview, "(hwnd=%x,styletype=%x,stylestruct=%p)\n", | |
| hwnd, wStyleType, lpss); | |
| if (wStyleType == GWL_STYLE) | |
| { | |
| if ((lpss->styleOld & WS_HSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_HORZ, FALSE); | |
| } | |
| if ((lpss->styleOld & WS_VSCROLL) != 0) | |
| { | |
| ShowScrollBar(hwnd, SB_VERT, FALSE); | |
| } | |
| if ((LVS_TYPEMASK & lpss->styleOld) == LVS_REPORT) | |
| { | |
| /* remove header */ | |
| ShowWindow(infoPtr->hwndHeader, SW_HIDE); | |
| } | |
| switch (lpss->styleNew & LVS_TYPEMASK) | |
| { | |
| case LVS_ICON: | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON); | |
| LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1); | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew); | |
| infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew); | |
| if (lpss->styleNew & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| case LVS_REPORT: | |
| hl.prc = &rcList; | |
| hl.pwpos = ℘ | |
| Header_Layout(infoPtr->hwndHeader, &hl); | |
| SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, | |
| wp.cy, wp.flags); | |
| ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL); | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON); | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew); | |
| infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew); | |
| LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1); | |
| LISTVIEW_SetViewInfo(hwnd, lpss->styleNew); | |
| break; | |
| case LVS_LIST: | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON); | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew); | |
| infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew); | |
| LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1); | |
| LISTVIEW_SetViewInfo(hwnd, lpss->styleNew); | |
| break; | |
| case LVS_SMALLICON: | |
| infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON); | |
| infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON); | |
| LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1); | |
| infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew); | |
| infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew); | |
| if (lpss->styleNew & LVS_ALIGNLEFT) | |
| { | |
| LISTVIEW_AlignLeft(hwnd); | |
| } | |
| else | |
| { | |
| LISTVIEW_AlignTop(hwnd); | |
| } | |
| break; | |
| } | |
| LISTVIEW_SetScroll(hwnd, lpss->styleNew); | |
| /* print unsupported styles */ | |
| LISTVIEW_UnsupportedStyles(lpss->styleNew); | |
| /* invalidate client area */ | |
| InvalidateRect(hwnd, NULL, TRUE); | |
| } | |
| return 0; | |
| } | |
| /*** | |
| * DESCRIPTION: | |
| * Window procedure of the listview control. | |
| * | |
| * PARAMETER(S): | |
| * [I] HWND : | |
| * [I] UINT : | |
| * [I] WPARAM : | |
| * [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: | |
| return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam); | |
| case LVM_FINDITEMA: | |
| return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam); | |
| case LVM_GETBKCOLOR: | |
| return LISTVIEW_GetBkColor(hwnd); | |
| /* case LVM_GETBKIMAGE: */ | |
| case LVM_GETCALLBACKMASK: | |
| return LISTVIEW_GetCallbackMask(hwnd); | |
| case LVM_GETCOLUMNA: | |
| return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam); | |
| /* case LVM_GETCOLUMNW: */ | |
| /* 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_GETITEMW: */ | |
| 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_GETITEMTEXTW: */ | |
| 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_GETSTRINGWIDTHW: */ | |
| /* case LVM_GETSUBITEMRECT: */ | |
| case LVM_GETTEXTBKCOLOR: | |
| return LISTVIEW_GetTextBkColor(hwnd); | |
| case LVM_GETTEXTCOLOR: | |
| return LISTVIEW_GetTextColor(hwnd); | |
| /* case LVM_GETTOOLTIPS: */ | |
| case LVM_GETTOPINDEX: | |
| return LISTVIEW_GetTopIndex(hwnd); | |
| /* 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_INSERTCOLUMNW: */ | |
| case LVM_INSERTITEMA: | |
| return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam); | |
| /* case LVM_INSERTITEMW: */ | |
| 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: | |
| return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam); | |
| case LVM_SETCOLUMNA: | |
| return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam); | |
| /* case LVM_SETCOLUMNW: */ | |
| /* case LVM_SETCOLUMNORDERARRAY: */ | |
| case LVM_SETCOLUMNWIDTH: | |
| return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam); | |
| /* 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_SETITEMW: */ | |
| case LVM_SETITEMCOUNT: | |
| LISTVIEW_SetItemCount(hwnd, (INT)wParam); | |
| break; | |
| case LVM_SETITEMPOSITION: | |
| return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam), | |
| (INT)HIWORD(lParam)); | |
| /* case LVM_SETITEMPOSITION: */ | |
| case LVM_SETITEMSTATE: | |
| return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam); | |
| case LVM_SETITEMTEXTA: | |
| return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam); | |
| /* 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_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_NOTIFYFORMAT: | |
| return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)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, (int)SLOWORD(lParam), (int)SHIWORD(lParam)); | |
| case WM_STYLECHANGED: | |
| return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam); | |
| /* case WM_TIMER: */ | |
| case WM_VSCROLL: | |
| return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam), | |
| (INT)HIWORD(wParam), (HWND)lParam); | |
| /* 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); | |
| } | |
| } | |