Sweden-Number/dlls/comctl32/listview.c

5909 lines
133 KiB
C

/*
* Listview control
*
* Copyright 1998 Eric Kohl
* Copyright 1999 Luc Tourangeau
*
* NOTES
* Listview control implementation.
*
* TODO:
* LISTVIEW_GetMaxItemWidth : large icon view
* LISTVIEW_Notify : notification from children
* LISTVIEW_KeyDown : key press messages
* LISTVIEW_HScroll : small icon and icon
* LISTVIEW_VScroll : small icon and icon
* LISTVIEW_SortItems : empty stub
* LISTVIEW_SetItemPosition : small icon and icon
* LISTVIEW_SetItemCount : empty stub
* LISTVIEW_SetItem32W : no unicode yet!
* LISTVIEW_SetColumn32A : DOUBLE CHECK
* LISTVIEW_Scroll : scrolling in pixels
* LISTVIEW_RedrawItems : define bounding rect
* LISTVIEW_InsertItem32W : no unicode yet!
* LISTVIEW_InsertColumn32W : no unicode yet!
* LISTVIEW_GetViewRect : small icon and icon
* LISTVIEW_GetOrigin : small icon and icon
* LISTVIEW_GetNumberOfWorkAreas : small icon and icon
* LISTVIEW_GetNextItem : all
* LISTVIEW_SetScroll : scrolling in pixels
* LISTVIEW_GetItemRect : all
* LISTVIEW_GetHotCursor : all
* LISTVIEW_GetHotItem : all
* LISTVIEW_GetHoverTime : all
* LISTVIEW_GetISearchString : all
* LISTVIEW_GetBkImage : all
* LISTVIEW_FindItem : all
* LISTVIEW_EnsureVisible : some
* LISTVIEW_EditLabel : REPORT (need to implement a timer)
* LISTVIEW_GetItemPosition : small icon and icon
* LISTVIEW_GetItemRect : some
* LISTVIEW_Arrange : small icon and icon
* LISTVIEW_ApproximateViewRect : report, small icon and icon
* LISTVIEW_RefreshIcon : large icon draw function
*/
#include <string.h>
#include "winbase.h"
#include "commctrl.h"
#include "listview.h"
#include "debug.h"
/* constants */
#define DISP_TEXT_SIZE 128
#define WIDTH_PADDING 12
#define HEIGHT_PADDING 2
#define MIN_COLUMN_WIDTH 96
/* macro section */
#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_SetSize(HWND hwnd, LONG lStyle, LONG lWidth,
LONG lHeight);
static VOID LISTVIEW_SetViewInfo(HWND hwnd);
static VOID LISTVIEW_SetScroll(HWND hwnd);
static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem);
static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem);
static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem);
static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem);
static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem);
static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast);
static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem);
static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem);
static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nColumn);
static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
LPLVITEMA lpLVItem);
static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
LPLVITEMA lpLVItem);
static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem);
static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem);
static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem);
static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem);
static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem);
/***
* DESCRIPTION:
* Prints a message for unsupported window styles.
*
* PARAMETER(S):
* [I] LONG : window style
*
* RETURN:
* None
*/
static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
{
if ((LVS_TYPEMASK & lStyle) == LVS_ALIGNLEFT)
{
FIXME(listview, " LVS_ALIGNLEFT\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_ALIGNTOP)
{
FIXME(listview, " LVS_ALIGNTOP\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_AUTOARRANGE)
{
FIXME(listview, " LVS_AUTOARRANGE\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
{
FIXME(listview, " LVS_EDITLABELS\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
{
FIXME(listview, " LVS_ICON\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_SMALLICON)
{
FIXME(listview, " LVS_SMALLICON\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
{
FIXME(listview, " LVS_SORTDESCENDING\n");
}
if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
{
FIXME(listview, " LVS_SORTDESCENDING\n");
}
}
/***
* DESCRIPTION:
* Retrieves display information.
*
* PARAMETER(S):
* [I] HWND : window handle
* [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 display information.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] LISTVIEW_SUBITEM* : listview control subitem
* [O] INT : image index
* [O] UINT : state value
* [O] CHAR** : string
* [I] INT : size of string
*
* RETURN:
* None
*/
static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT nItem, LPARAM lParam,
LISTVIEW_SUBITEM *lpSubItem,
INT nColumn, 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 = nColumn;
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 a new column width.
*
* PARAMETER(S):
* [I] HWND : window handle
*
* RETURN:
* Returns item width.
*/
static INT LISTVIEW_GetMaxItemWidth(HWND hwnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
LISTVIEW_ITEM *lpItem;
HDPA hdpaSubItems;
INT nStringWidth;
INT nMaxItemWidth = 0;
INT i;
if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
{
/* TO DO */
}
else
{
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
if (hdpaSubItems != NULL)
{
lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
if (lpItem != NULL)
{
CHAR szDispText[DISP_TEXT_SIZE];
LPSTR pszDispText;
pszDispText = szDispText;
LISTVIEW_GetItemDispInfo(hwnd, i, lpItem, NULL, NULL, &pszDispText,
DISP_TEXT_SIZE);
nStringWidth = ListView_GetStringWidthA(hwnd, pszDispText);
nMaxItemWidth = max(nMaxItemWidth, nStringWidth);
}
}
}
/* add arbitrary padding for separating columns */
nMaxItemWidth += WIDTH_PADDING;
if (infoPtr->himlSmall != NULL)
{
nMaxItemWidth += infoPtr->iconSize.cx;
}
if (infoPtr->himlState != NULL)
{
nMaxItemWidth += infoPtr->iconSize.cx;
}
}
nMaxItemWidth = max(MIN_COLUMN_WIDTH, nMaxItemWidth);
return nMaxItemWidth;
}
/***
* DESCRIPTION:
* Sets diplay information (needed for drawing and calculations).
*
* PARAMETER(S):
* [I] HWND : window handle
*
* RETURN:
* None
*/
static VOID LISTVIEW_SetViewInfo(HWND hwnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nHeight;
INT nWidth;
HDC hdc;
HFONT hOldFont;
TEXTMETRICA tm;
/* get text height */
hdc = GetDC(hwnd);
hOldFont = SelectObject(hdc, infoPtr->hFont);
GetTextMetricsA(hdc, &tm);
nHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
nWidth = infoPtr->rcList.right - infoPtr->rcList.left;
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
infoPtr->nColumnWidth = LISTVIEW_GetMaxItemWidth(hwnd);
infoPtr->nItemHeight = (max(tm.tmHeight, infoPtr->iconSize.cy) +
HEIGHT_PADDING);
infoPtr->nCountPerColumn = nHeight / infoPtr->nItemHeight;
if (infoPtr->nCountPerColumn == 0)
{
infoPtr->nCountPerColumn = 1;
}
infoPtr->nCountPerRow = nWidth / infoPtr->nColumnWidth;
if (infoPtr->nCountPerRow == 0)
{
infoPtr->nCountPerRow = 1;
}
break;
case LVS_REPORT:
infoPtr->nItemHeight = (max(tm.tmHeight, infoPtr->iconSize.cy) +
HEIGHT_PADDING);
infoPtr->nCountPerRow = 1;
infoPtr->nCountPerColumn = nHeight / infoPtr->nItemHeight;
if (infoPtr->nCountPerColumn == 0)
{
infoPtr->nCountPerColumn = 1;
}
break;
}
SelectObject(hdc, hOldFont);
ReleaseDC(hwnd, hdc);
}
/***
* 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:
* Reinitilizes the listview items.
*
* 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:
* Reinitilizes the listview items.
*
* 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:
* Reinitilizes the listview items.
*
* 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:
* 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;
}
}
}
}
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);
BOOL bResult = FALSE;
HDPA hdpaSubItems;
LISTVIEW_SUBITEM *lpSubItem = NULL;
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) == TRUE)
{
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:
* Sets scrollbar(s).
*
* PARAMETER(S):
* [I] HWND : window handle
*
* RETURN:
* TRUE if scrollbars were added, modified or removed.
*/
static VOID LISTVIEW_SetVScroll(HWND hwnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nScrollPos;
INT nMaxRange;
switch (LVS_TYPEMASK & lStyle)
{
case LVS_REPORT:
nMaxRange = GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn;
SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
nScrollPos = ListView_GetTopIndex(hwnd);
SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
break;
default:
/* TO DO */
}
}
static VOID LISTVIEW_SetHScroll(HWND hwnd)
{
/* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
/* INT nScrollPos; */
/* INT nMaxRange; */
switch (LVS_TYPEMASK & lStyle)
{
case LVS_REPORT:
/* TO DO */
break;
default:
/* TO DO */
}
}
static VOID LISTVIEW_SetScroll(HWND hwnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nHiddenItemCount;
INT nScrollPos;
INT nMaxRange;
INT nCountPerPage;
RECT rc;
BOOL bHScroll = FALSE;
BOOL bVScroll = FALSE;
INT nHeaderWidth = 0;
INT nItemCount;
INT i;
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
nCountPerPage = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
if (nCountPerPage < GETITEMCOUNT(infoPtr))
{
/* add scrollbar if not already present */
if (!(lStyle & WS_HSCROLL))
{
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
{
/* remove scrollbar if present */
if (lStyle & WS_HSCROLL)
{
/* hide scrollbar */
ShowScrollBar(hwnd, SB_HORZ, FALSE);
}
}
break;
case LVS_REPORT:
nItemCount = Header_GetItemCount(infoPtr->hwndHeader);
for (i = 0; i < nItemCount; i++)
{
if (Header_GetItemRect(infoPtr->hwndHeader, i, &rc) != 0)
{
nHeaderWidth += (rc.right - rc.left);
}
}
if (nHeaderWidth > (infoPtr->rcList.right - infoPtr->rcList.left))
{
bHScroll = TRUE;
/* add horizontal scrollbar if not present */
if (!(lStyle & WS_HSCROLL))
{
/* display scrollbar */
ShowScrollBar(hwnd, SB_HORZ, TRUE);
}
}
else
{
/* remove scrollbar if present */
if (lStyle & WS_HSCROLL)
{
/* hide scrollbar */
ShowScrollBar(hwnd, SB_HORZ, FALSE);
}
}
if (infoPtr->nCountPerColumn < GETITEMCOUNT(infoPtr))
{
bVScroll = TRUE;
/* add scrollbar if not already present */
if (!(lStyle & WS_VSCROLL))
{
/* display scrollbar */
ShowScrollBar(hwnd, SB_VERT, TRUE);
}
}
else
{
/* remove scrollbar if present */
if (lStyle & WS_VSCROLL)
{
/* hide scrollbar */
ShowScrollBar(hwnd, SB_VERT, FALSE);
}
}
break;
default:
/* TO DO */
}
/* set range and position */
GetClientRect(hwnd, &rc);
if ((bHScroll == TRUE) || (bVScroll == TRUE))
{
LISTVIEW_SetSize(hwnd, lStyle, rc.right, rc.bottom);
LISTVIEW_SetViewInfo(hwnd);
if (bHScroll == TRUE)
{
LISTVIEW_SetHScroll(hwnd);
}
if (bVScroll == TRUE)
{
LISTVIEW_SetVScroll(hwnd);
}
}
}
/***
* DESCRIPTION:
* Draws a subitem.
*
* PARAMETER(S):
* [I] HDC : device context handle
* [I] LISTVIEW_INFO * : listview information
* [I] LISTVIEW_SUBITEM * : subitem
* [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 + 10, lprc->top, ETO_OPAQUE|ETO_CLIPPED,
lprc, pszDispText, lstrlenA(pszDispText), NULL);
}
/***
* DESCRIPTION:
* Draws an item.
*
* PARAMETER(S):
* [I] HDC : device context handle
* [I] LISTVIEW_INFO * : listview information
* [I] LISTVIEW_ITEM * : item
* [I] RECT * : clipping rectangle
*
* RETURN:
* None
*/
static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem,
INT nItem, RECT *lprc)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
BOOL bSelected;
INT nLabelWidth;
INT nImage;
CHAR szDispText[DISP_TEXT_SIZE];
LPSTR pszDispText = NULL;
UINT uState;
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 == TRUE)
{
ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, lprc->left,
lprc->top, ILD_SELECTED);
}
else
{
ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, lprc->left,
lprc->top, ILD_NORMAL);
}
lprc->left += infoPtr->iconSize.cx;
}
/* small icons */
if (infoPtr->himlSmall != NULL)
{
if (bSelected == TRUE)
{
ImageList_Draw(infoPtr->himlSmall, nImage, hdc, lprc->left,
lprc->top, ILD_SELECTED);
}
else
{
ImageList_Draw(infoPtr->himlSmall, nImage, hdc, lprc->left,
lprc->top, ILD_NORMAL);
}
lprc->left += infoPtr->iconSize.cx;
}
nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
if (lprc->left + nLabelWidth < lprc->right)
{
lprc->right = lprc->left + nLabelWidth;
}
/* draw text */
ExtTextOutA(hdc, lprc->left + 1, lprc->top + 1, ETO_OPAQUE|ETO_CLIPPED,
lprc, pszDispText, lstrlenA(pszDispText), NULL);
if (lpItem->state & LVIS_FOCUSED)
{
Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->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;
INT nColumnCount;
HDPA hdpaSubItems;
RECT rc;
INT j, k;
INT nItem;
INT nLast;
BOOL bNeedSubItem = TRUE;
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)
{
Header_GetItemRect(infoPtr->hwndHeader, 0, &rc);
rc.top = nDrawPosY;
rc.bottom = rc.top + infoPtr->nItemHeight;
/* draw state icon + icon + text */
LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, &rc);
}
nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
for (k = 1, j = 1; j < nColumnCount; j++)
{
Header_GetItemRect(infoPtr->hwndHeader, j, &rc);
rc.top = nDrawPosY;
rc.bottom = rc.top + infoPtr->nItemHeight;
if (k < hdpaSubItems->nItemCount)
{
if (bNeedSubItem == TRUE)
{
lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, k);
k++;
}
if (lpSubItem != NULL)
{
if (lpSubItem->iSubItem == j)
{
LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, lpSubItem,
j, &rc);
bNeedSubItem = TRUE;
}
else
{
LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
&rc);
bNeedSubItem = FALSE;
}
}
else
{
LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
&rc);
bNeedSubItem = TRUE;
}
}
else
{
LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j, &rc);
}
}
}
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->nColumnWidth == 0)
{
nColumnCount = infoPtr->rcList.right / infoPtr->nColumnWidth;
}
else
{
nColumnCount = infoPtr->rcList.right / infoPtr->nColumnWidth + 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->nColumnWidth;
rc.bottom = rc.top + infoPtr->nItemHeight;
rc.right = rc.left + infoPtr->nColumnWidth;
/* draw state icon + icon + text */
LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, &rc);
}
}
nItem++;
j++;
}
}
}
}
/***
* DESCRIPTION:
* Draws listview items when in small icon display mode.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] HDC : device context handle
*
* RETURN:
* None
*/
static VOID LISTVIEW_RefreshSmallIcon(HWND hwnd, HDC hdc)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LISTVIEW_ITEM *lpItem;
HDPA hdpaSubItems;
RECT rc;
INT i, j;
INT nItem = ListView_GetTopIndex(hwnd);
for (i = 0; i < infoPtr->nCountPerColumn; i++)
{
j = 0;
while ((nItem < GETITEMCOUNT(infoPtr)) && (j < infoPtr->nCountPerRow))
{
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
if (hdpaSubItems != NULL)
{
lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
if (lpItem != NULL)
{
rc.top = i * infoPtr->nItemHeight;
rc.left = j * infoPtr->nColumnWidth;
rc.bottom = rc.top + infoPtr->nItemHeight;
rc.right = rc.left + infoPtr->nColumnWidth;
/* draw state icon + icon + text */
LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, &rc);
}
}
nItem++;
j++;
}
}
}
/***
* DESCRIPTION:
* Draws listview items when in icon display mode.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] HDC : device context handle
*
* RETURN:
* None
*/
static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc)
{
/* TO DO */
}
/***
* 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_RefreshSmallIcon(hwnd, hdc);
break;
case LVS_ICON:
LISTVIEW_RefreshIcon(hwnd, hdc);
}
/* 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->nColumnWidth + 2;
dwViewRect = MAKELONG(wWidth, wHeight);
}
else if (lStyle & LVS_REPORT)
{
/* TO DO */
}
else if (lStyle & LVS_SMALLICON)
{
/* TO DO */
}
else if (lStyle & LVS_ICON)
{
/* TO DO */
}
return dwViewRect;
}
/***
* DESCRIPTION:
* Arranges listview items in icon display mode.
*
* PARAMETER(S):
* [I] 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 */
}
}
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);
LISTVIEW_ITEM *lpItem;
LISTVIEW_SUBITEM *lpSubItem;
NMLISTVIEW nmlv;
BOOL bSuppress;
BOOL bResult = FALSE;
INT i;
INT j;
HDPA hdpaSubItems;
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);
/* reset scroll parameters */
LISTVIEW_SetScroll(hwnd);
/* invalidate client area (optimization needed) */
InvalidateRect(hwnd, NULL, FALSE);
}
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);
BOOL bResult = FALSE;
if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) == TRUE)
{
bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
}
/* reset scroll parameters */
LISTVIEW_SetScroll(hwnd);
/* 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 lCtrlId = GetWindowLongA(hwnd, GWL_ID);
NMLISTVIEW nmlv;
BOOL bResult = FALSE;
HDPA hdpaSubItems;
LISTVIEW_ITEM *lpItem;
LISTVIEW_SUBITEM *lpSubItem;
INT i;
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);
}
/* refresh client area */
InvalidateRect(hwnd, NULL, FALSE);
}
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 nLast;
INT nFirst;
INT nScrollPos;
BOOL bResult = TRUE;
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
if (lStyle & WS_HSCROLL)
{
nFirst = ListView_GetTopIndex(hwnd);
/* calculate last fully visible item index */
nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
if (nItem > nLast)
{
/* calculate new scroll position based on item index */
if (((nItem - nLast) % infoPtr->nCountPerColumn) == 0)
{
nScrollPos = (nItem - nLast) / infoPtr->nCountPerColumn;
}
else
{
nScrollPos = (nItem - nLast) / infoPtr->nCountPerColumn + 1;
}
bResult = ListView_Scroll(hwnd, nScrollPos, 0);
}
else if (nItem < nFirst)
{
/* calculate new scroll position based on item index */
if (((nItem - nFirst) % infoPtr->nCountPerColumn) == 0)
{
nScrollPos = (nItem - nFirst) / infoPtr->nCountPerColumn;
}
else
{
nScrollPos = (nItem - nFirst) / infoPtr->nCountPerColumn -1;
}
bResult = ListView_Scroll(hwnd, nScrollPos, 0);
}
}
break;
case LVS_REPORT:
if (lStyle & WS_VSCROLL)
{
nFirst = ListView_GetTopIndex(hwnd);
/* calculate last fully visible item index */
nLast = infoPtr->nCountPerColumn + nFirst - 1;
if (nItem > nLast)
{
nScrollPos = nItem - nLast;
bResult = ListView_Scroll(hwnd, 0, nScrollPos);
}
else if (nItem < nFirst)
{
nScrollPos = nItem - nFirst;
bResult = ListView_Scroll(hwnd, 0, nScrollPos);
}
}
break;
case LVS_SMALLICON:
/* TO DO */
break;
case LVS_ICON:
/* TO DO */
break;
}
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)
{
/* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
/* LISTVIEW_ITEM *lpItem; */
/* INT nItem; */
/* INT nEnd = GETITEMCOUNT(infoPtr); */
/* BOOL bWrap = FALSE; */
/* if (nStart == -1) */
/* nStart = 0; */
/* else */
/* nStart++ ; */
/* if (lpFindInfo->flags & LVFI_PARAM) */
/* { */
/* for (nItem = nStart; nItem < nEnd; nItem++) */
/* { */
/* get item pointer */
/* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
/* if (lpItem != NULL) */
/* { */
/* if (lpFindInfo->lParam == lpItem->lParam) */
/* return nItem; */
/* } */
/* } */
/* } */
/* else */
/* { */
/* if (lpFindInfo->flags & LVFI_PARTIAL) */
/* { */
/* for (nItem = nStart; nItem < nEnd; nItem++) */
/* { */
/* get item pointer */
/* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
/* if (lpItem) */
/* { */
/* if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz)) */
/* == 0) */
/* return nItem; */
/* } */
/* } */
/* } */
/* if (lpFindInfo->flags & LVFI_STRING) */
/* { */
/* for (nItem = nStart; nItem < nEnd; nItem++) */
/* { */
/* get item pointer */
/* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
/* if (lpItem != NULL) */
/* { */
/* if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */
/* return nItem; */
/* } */
/* } */
/* } */
/* if ((lpFindInfo->flags & LVFI_WRAP) && nStart) */
/* { */
/* nEnd = nStart; */
/* nStart = 0; */
/* bWrap = TRUE; */
/* } */
/* else */
/* bWrap = FALSE; */
return -1;
}
/***
* DESCRIPTION:
* Retrieves the background color of the listview control.
*
* PARAMETER(S):
* [I] 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) */
/* { */
/* 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 == TRUE)
{
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;
if ((LVS_TYPEMASK & lStyle) == LVS_LIST)
{
nColumnWidth = infoPtr->nColumnWidth;
}
else if ((LVS_TYPEMASK & lStyle) == LVS_REPORT)
{
/* get column width from header */
ZeroMemory(&hdi, sizeof(HDITEMA));
hdi.mask = HDI_WIDTH;
if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) == TRUE)
{
nColumnWidth = hdi.cxy;
}
}
return nColumnWidth;
}
/***
* DESCRIPTION:
* In list or report display mode, retrieves the number of items that can fit
* vertically in the visible area. In icon or small icon display mode,
* retrieves the total number of visible items.
*
* PARAMETER(S):
* [I] 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->nColumnWidth)
{
nItemCount = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
}
break;
case LVS_REPORT:
nItemCount = infoPtr->nCountPerColumn;
break;
default:
nItemCount = GETITEMCOUNT(infoPtr);
}
return nItemCount;
}
/* << LISTVIEW_GetEditControl >> */
/* << LISTVIEW_GetExtendedListViewStyle >> */
/***
* DESCRIPTION:
* Retrieves a header handle.
*
* 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;
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 LRESULT LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
LPPOINT lppt)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nColumn;
INT nRow;
BOOL bResult = FALSE;
INT nFirst;
INT nLast;
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lppt != NULL))
{
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
nFirst = ListView_GetTopIndex(hwnd);
nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
if ((nItem >= nFirst) || (nItem <= nLast))
{
nItem -= nFirst;
/* get column */
nColumn = nItem / infoPtr->nCountPerColumn;
/* get row */
nRow = nItem % infoPtr->nCountPerColumn;
/* X coordinate of the column */
lppt->x = nColumn * infoPtr->nColumnWidth + infoPtr->rcList.left;
/* Y coordinate of the item */
lppt->y = nRow * infoPtr->nItemHeight + infoPtr->rcList.top;
bResult = TRUE;
}
break;
case LVS_REPORT:
nFirst = ListView_GetTopIndex(hwnd);
nLast = infoPtr->nCountPerColumn * infoPtr->nCountPerRow + nFirst - 1;
/* get column */
nColumn = nItem / infoPtr->nCountPerColumn;
/* get row */
nRow = nItem % infoPtr->nCountPerColumn;
if ((nItem >= nFirst) || (nItem <= nLast))
{
nItem -= nFirst;
/* get column */
nColumn = nItem / infoPtr->nCountPerColumn;
/* get row */
nRow = nItem % infoPtr->nCountPerColumn;
/* X coordinate of the column */
lppt->x = infoPtr->rcList.left;
/* Y coordinate of the item */
lppt->y = nRow * infoPtr->nItemHeight + infoPtr->rcList.top;
bResult = TRUE;
}
default:
/* TO DO */
}
}
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);
LISTVIEW_ITEM *lpItem;
HDPA hdpaSubItems;
INT nLabelWidth = 0;
INT nStateWidth = 0;
INT nIconWidth = 0;
BOOL bResult = FALSE;
CHAR szDispText[DISP_TEXT_SIZE];
LPSTR pszDispText;
POINT pt;
/*init pointer */
pszDispText = szDispText;
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
{
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
if (hdpaSubItems != NULL)
{
lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
if (lpItem != NULL)
{
if ((LVS_TYPEMASK & lStyle) == LVS_ICON)
{
}
else
{
if (ListView_GetItemPosition(hwnd, nItem, &pt) == TRUE)
{
/* get width of label in pixels */
LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL,
&pszDispText, DISP_TEXT_SIZE);
nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
}
if (infoPtr->himlState != NULL)
{
nStateWidth = infoPtr->iconSize.cx;
}
if (infoPtr->himlSmall == NULL)
{
nIconWidth = infoPtr->iconSize.cx;
}
switch(lprc->left)
{
case LVIR_BOUNDS:
lprc->left = pt.x;
lprc->top = pt.y;
lprc->right = lprc->left + nStateWidth + nIconWidth + nLabelWidth;
lprc->bottom = lprc->top + infoPtr->nItemHeight;
bResult = TRUE;
break;
case LVIR_ICON:
lprc->left = pt.x + nStateWidth;
lprc->top = pt.y;
lprc->right = lprc->left + nIconWidth;
lprc->bottom = lprc->top + infoPtr->nItemHeight;
bResult = TRUE;
break;
case LVIR_LABEL:
lprc->left = pt.x + nIconWidth + nStateWidth;
lprc->top = pt.y;
lprc->right = lprc->left + nLabelWidth;
lprc->bottom = infoPtr->nItemHeight;
bResult = TRUE;
break;
case LVIR_SELECTBOUNDS:
lprc->left = pt.x + nStateWidth;
lprc->top = pt.y;
lprc->right = lprc->left + nIconWidth + nLabelWidth;
lprc->bottom = lprc->top + infoPtr->nItemHeight;
bResult = TRUE;
}
}
}
}
}
return bResult;
}
/***
* 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 == TRUE)
{
lResult = MAKELONG(infoPtr->largeIconSpacing.cx,
infoPtr->largeIconSpacing.cy);
}
else
{
lResult = MAKELONG(infoPtr->smallIconSpacing.cx,
infoPtr->smallIconSpacing.cy);
}
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) == TRUE)
{
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)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
INT nResult = -1;
if (nItem == -1)
{
/* start at begin */
nItem = 0;
}
else
{
/* exclude specified item */
nItem++;
}
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
{
/* TO DO */
}
return nResult;
}
/* << LISTVIEW_GetNumberOfWorkAreas >> */
/***
* DESCRIPTION:
* Retrieves the current origin 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 lpOrigin)
{
LONG lStyle = GetWindowLongA(hwnd, GWL_ID);
BOOL bResult = FALSE;
if ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)
{
/* TO DO */
lpOrigin->x = 0;
lpOrigin->y = 0;
}
else if ((lStyle & LVS_TYPEMASK) == LVS_ICON)
{
/* TO DO */
lpOrigin->x = 0;
lpOrigin->y = 0;
}
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 lpsz)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
HFONT hFont, hOldFont;
HDC hdc;
SIZE textSize;
/* initialize */
ZeroMemory(&textSize, sizeof(SIZE));
if (lpsz != NULL)
{
hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
hdc = GetDC(hwnd);
hOldFont = SelectObject(hdc, hFont);
GetTextExtentPointA(hdc, lpsz, lstrlenA(lpsz), &textSize);
SelectObject(hdc, hOldFont);
ReleaseDC(hwnd, hdc);
}
return textSize.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:
* 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 lprc)
{
/* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
BOOL bResult = FALSE;
if (lprc != NULL)
{
if (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
((lStyle & LVS_TYPEMASK) == LVS_SMALLICON))
{
/* TO DO */
}
}
return bResult;
}
/***
* DESCRIPTION:
* Determines which section of the item was selected (if any).
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] INT : item index
* [IO] LPLVHITTESTINFO : hit test information
*
* RETURN:
* SUCCESS : item index
* FAILURE : -1
*/
static INT LISTVIEW_HitTestItem(HWND hwnd, INT nItem,
LPLVHITTESTINFO lpHitTestInfo)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
HDPA hdpaSubItems;
LISTVIEW_ITEM *lpItem;
INT nOffset;
INT nLabelWidth;
INT nPosX = 0;
CHAR szDispText[DISP_TEXT_SIZE];
LPSTR pszDispText;
/*init pointer */
pszDispText = szDispText;
if ((LVS_TYPEMASK & lStyle) == LVS_LIST)
{
/* calculate offset from start of item (in pixels) */
nOffset = lpHitTestInfo->pt.x % infoPtr->nColumnWidth;
}
else
{
nOffset = lpHitTestInfo->pt.x;
}
/* verify existance of item */
if (nItem < GETITEMCOUNT(infoPtr))
{
/* get item */
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
if (hdpaSubItems != NULL)
{
lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
if (lpItem != NULL)
{
if (infoPtr->himlState != NULL)
{
nPosX += infoPtr->iconSize.cx;
if (nOffset <= nPosX)
{
lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
lpHitTestInfo->iItem = nItem;
lpHitTestInfo->iSubItem = 0;
return nItem;
}
}
if (infoPtr->himlSmall != NULL)
{
nPosX += infoPtr->iconSize.cx;
if (nOffset <= nPosX)
{
lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
lpHitTestInfo->iItem = nItem;
lpHitTestInfo->iSubItem = 0;
return nItem;
}
}
/* get width of label in pixels */
LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL,
&pszDispText, DISP_TEXT_SIZE);
nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
nLabelWidth += nPosX;
if (nOffset <= nLabelWidth)
{
lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
lpHitTestInfo->iItem = nItem;
lpHitTestInfo->iSubItem = 0;
return nItem;
}
}
}
}
/* hit is not on item */
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);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nColumn;
INT nRow;
INT nTopIndex;
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)
{
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
/* get current column */
nColumn = lpHitTestInfo->pt.x / infoPtr->nColumnWidth;
/* get current row */
nRow = lpHitTestInfo->pt.y / infoPtr->nItemHeight;
/* get the index of the first visible item */
nTopIndex = ListView_GetTopIndex(hwnd);
nItem = nColumn * infoPtr->nCountPerColumn + nTopIndex + nRow;
nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo);
break;
case LVS_REPORT:
/* get current row */
nRow = ((lpHitTestInfo->pt.y - infoPtr->rcList.top) /
infoPtr->nItemHeight);
/* get the index of the first visible item */
nTopIndex = ListView_GetTopIndex(hwnd);
nItem = nTopIndex + nRow;
nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo);
break;
default:
/* nItem = LISTVIEW_HitTestItem(hwnd, nItem, 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);
HDITEMA hdi;
INT nNewColumn = -1;
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);
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 lCtrlId = GetWindowLongA(hwnd, GWL_ID);
NMLISTVIEW nmlv;
INT nItem = -1;
HDPA hdpaSubItems;
LISTVIEW_ITEM *lpItem = NULL;
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) == TRUE)
{
/* 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);
/* set scrolling parameters */
LISTVIEW_SetScroll(hwnd);
/* 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;
}
/***
* DESCRIPTION:
* Scrolls the content of a listview.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] INT : amount of horizontal scrolling
* [I] INT : amount of vertical scrolling
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static LRESULT LISTVIEW_Scroll(HWND hwnd, INT nHScroll, INT nVScroll)
{
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nScrollPos = 0;
BOOL bResult = FALSE;
INT nMinRange;
INT nMaxRange;
if (lStyle & WS_HSCROLL)
{
nScrollPos = GetScrollPos(hwnd, SB_HORZ);
GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
nScrollPos += nHScroll;
if ((LVS_TYPEMASK & lStyle) == LVS_LIST)
{
nScrollPos = GetScrollPos(hwnd, SB_HORZ);
GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
nScrollPos += nHScroll;
if ((nMinRange <= nScrollPos) && (nScrollPos <= nMaxRange))
{
bResult = TRUE;
SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
}
}
else
{
/* TO DO */
}
}
if (lStyle & WS_VSCROLL)
{
if ((LVS_TYPEMASK & lStyle) == LVS_REPORT)
{
nScrollPos = GetScrollPos(hwnd, SB_VERT);
GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
nScrollPos += nVScroll;
if ((nMinRange <= nScrollPos) && (nScrollPos <= nMaxRange))
{
bResult = TRUE;
SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
}
}
else
{
/* TO DO */
}
}
if (bResult == TRUE)
{
/* refresh client area */
InvalidateRect(hwnd, NULL, TRUE);
}
return bResult;
}
/***
* 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 the 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 column attributes.
*
* 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);
HDITEMA hdi;
BOOL bResult = FALSE;
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 image list.
*
* 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 item attributes.
*
* 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)
{
/* TO DO */
}
/***
* DESCRIPTION:
* Sets item position.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] INT : item index
* [I] INT : x coordinate
* [I] INT : y coordinate
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static LRESULT LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
INT nPosX, INT nPosY)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
BOOL bResult = FALSE;
if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
{
if (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
((lStyle & LVS_TYPEMASK) == LVS_SMALLICON))
{
/* TO DO */
}
}
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;
return TRUE;
}
/***
* DESCRIPTION:
* Sets the text background 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;
return TRUE;
}
/***
* DESCRIPTION:
* Sort 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 a 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;
HDLAYOUT hl;
WINDOWPOS wp;
/* 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->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
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_REPORT:
/* reset header */
hl.prc = &infoPtr->rcList;
hl.pwpos = &wp;
Header_Layout(infoPtr->hwndHeader, &hl);
SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
wp.flags);
/* set new top coord */
infoPtr->rcList.top = wp.cy;
/* display header */
ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
break;
case LVS_LIST:
break;
default:
/* temporary (until there is support) */
SetWindowLongA(hwnd, GWL_STYLE,
(lpcs->style & ~LVS_TYPEMASK) | LVS_LIST);
}
/* TEMPORARY */
LISTVIEW_UnsupportedStyles(lpcs->style);
/* allocate memory */
infoPtr->hdpaItems = DPA_Create(10);
/* set view dependent information */
LISTVIEW_SetViewInfo(hwnd);
return 0;
}
/***
* DESCRIPTION:
* Destroys the window
*
* PARAMETER(S):
* [I] HWND : window handle
*
* RETURN:
* Zero
*/
static LRESULT LISTVIEW_Destroy(HWND hwnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
/* delete all items */
LISTVIEW_DeleteAllItems(hwnd);
/* destroy dpa */
DPA_Destroy(infoPtr->hdpaItems);
/* destroy header */
if (infoPtr->hwndHeader)
{
DestroyWindow(infoPtr->hwndHeader);
}
/* destroy font */
infoPtr->hFont = (HFONT)0;
if (infoPtr->hDefaultFont)
{
DeleteObject(infoPtr->hDefaultFont);
}
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
{
HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
FillRect((HDC)wParam, &infoPtr->rcList, hBrush);
DeleteObject(hBrush);
bResult = TRUE;
}
return bResult;
}
/***
* DESCRIPTION:
* Gets 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 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_VScroll(HWND hwnd, INT nScrollCode,
INT nScroll, HWND hScrollWnd)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
INT nScrollPos, nOldScrollPos;
INT nMinRange;
INT nMaxRange;
GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
nOldScrollPos = nScrollPos = GetScrollPos(hwnd, SB_VERT);
switch (LVS_TYPEMASK & lStyle)
{
case LVS_REPORT:
switch (nScrollCode)
{
case SB_LINEUP:
if (nScrollPos > nMinRange)
{
nScrollPos--;
}
break;
case SB_LINEDOWN:
if (nScrollPos < nMaxRange)
{
nScrollPos++;
}
break;
case SB_PAGEUP:
if (nScrollPos > nMinRange + infoPtr->nCountPerColumn)
{
nScrollPos -= infoPtr->nCountPerColumn;
}
else
{
nScrollPos = nMinRange;
}
break;
case SB_PAGEDOWN:
if (nScrollPos < nMaxRange - infoPtr->nCountPerColumn)
{
nScrollPos += infoPtr->nCountPerColumn;
}
else
{
nScrollPos = nMaxRange;
}
break;
case SB_THUMBPOSITION:
nScrollPos = nScroll;
break;
}
break;
default:
/* TO DO */
}
/* set new scroll position */
if (nScrollPos != nOldScrollPos)
{
SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
/* refresh client area */
InvalidateRect(hwnd, NULL, TRUE);
}
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 nScrollPos, nOldScrollPos;
INT nMinRange;
INT nMaxRange;
GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
nOldScrollPos = nScrollPos = GetScrollPos(hwnd, SB_HORZ);
switch (LVS_TYPEMASK & lStyle)
{
case LVS_LIST:
/* list display mode horizontal scrolling */
switch (nScrollCode)
{
case SB_LINELEFT:
if (nScrollPos > nMinRange)
{
nScrollPos--;
}
break;
case SB_LINERIGHT:
if (nScrollPos < nMaxRange)
{
nScrollPos++;
}
break;
case SB_PAGELEFT:
if (nScrollPos > nMinRange)
{
nScrollPos = max(nMinRange, nScrollPos - infoPtr->nCountPerRow);
}
else
{
nScrollPos = nMinRange;
}
break;
case SB_PAGERIGHT:
if (nScrollPos < nMaxRange - 1)
{
nScrollPos = min(nMaxRange, nScrollPos + infoPtr->nCountPerRow);
}
else
{
nScrollPos = nMaxRange;
}
break;
case SB_THUMBPOSITION:
nScrollPos = nScroll;
break;
}
break;
case LVS_REPORT:
/* report/details display mode horizontal scrolling */
switch (nScrollCode)
{
case SB_LINELEFT:
if (nScrollPos > nMinRange)
{
nScrollPos--;
}
break;
case SB_LINERIGHT:
if (nScrollPos < nMaxRange)
{
nScrollPos++;
}
break;
case SB_PAGELEFT:
if (nScrollPos > nMinRange)
{
nScrollPos = max(nMinRange, nScrollPos - infoPtr->rcList.right);
}
else
{
nScrollPos = nMinRange;
}
break;
case SB_PAGERIGHT:
if (nScrollPos < nMaxRange)
{
nScrollPos = min(nMaxRange, nScrollPos + infoPtr->rcList.right);
}
else
{
nScrollPos = nMaxRange;
}
break;
case SB_THUMBPOSITION:
nScrollPos = nScroll;
break;
}
break;
default:
/* TO DO */
}
/* set new scroll position */
if (nScrollPos != nOldScrollPos)
{
SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
/* refresh client area */
InvalidateRect(hwnd, NULL, TRUE);
}
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);
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_REPORT:
break;
default:
if (infoPtr->nFocusedItem % infoPtr->nCountPerRow != 0)
{
LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 1);
}
}
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 (infoPtr->nFocusedItem >= infoPtr->nCountPerRow)
{
LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem -
infoPtr->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);
}
case LVS_REPORT:
break;
default:
if (infoPtr->nCountPerRow > 0)
{
}
}
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);
}
default:
if (infoPtr->nCountPerRow > 0)
{
}
}
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:
* Left mouse button double click.
*
* 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;
/* 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:
* Left mouse button down.
*
* 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);
LVHITTESTINFO hitTestInfo;
NMHDR nmh;
INT nItem;
static BOOL bGroupSelect = TRUE;
/* 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;
/* set left button hit coordinates */
hitTestInfo.pt.x = wPosX;
hitTestInfo.pt.y = wPosY;
/* perform hit test */
nItem = ListView_HitTest(hwnd, &hitTestInfo);
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
{
if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
{
if (bGroupSelect == TRUE)
{
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:
* Left mouse button up.
*
* 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);
INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
NMHDR nmh;
if (infoPtr->bLButtonDown == TRUE)
{
/* 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;
/* 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);
/* free listview info */
COMCTL32_Free(infoPtr);
return 0;
}
/***
* DESCRIPTION:
* Handles notification 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)
{
InvalidateRect(hwnd, NULL, TRUE);
}
}
return 0;
}
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 structures 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:
* Draws 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;
if (hdc == 0)
{
hdc = BeginPaint(hwnd, &ps);
LISTVIEW_Refresh(hwnd, hdc);
EndPaint(hwnd, &ps);
}
else
{
LISTVIEW_Refresh(hwnd, hdc);
}
return 0;
}
/***
* DESCRIPTION:
* Right mouse button double click.
*
* 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;
/* 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:
* Right mouse button input.
*
* 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);
LVHITTESTINFO hitTestInfo;
NMHDR nmh;
INT nItem;
/* 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;
/* set hit coordinates */
hitTestInfo.pt.x = wPosX;
hitTestInfo.pt.y = wPosY;
/* perform hit test */
nItem = ListView_HitTest(hwnd, &hitTestInfo);
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:
* Right mouse button up.
*
* 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;
if (infoPtr->bRButtonDown == TRUE)
{
/* 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);
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, FALSE);
if (fRedraw == TRUE)
{
UpdateWindow(hwnd);
}
return 0;
}
/***
* DESCRIPTION:
* Resizes the listview control.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] WORD : new width
* [I] WORD : new height
*
* RETURN:
* Zero
*/
static LRESULT LISTVIEW_Size(HWND hwnd, WORD wWidth, WORD wHeight)
{
LISTVIEW_SetSize(hwnd, GetWindowLongA(hwnd, GWL_STYLE), wWidth, wHeight);
LISTVIEW_SetViewInfo(hwnd);
LISTVIEW_SetScroll(hwnd);
/* 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;
INT lTop = 0;
RECT rc;
switch (lStyle & LVS_TYPEMASK)
{
case LVS_LIST:
if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
{
if (!(lStyle & WS_HSCROLL))
{
INT nHScrollHeight;
nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
if (lHeight > nHScrollHeight)
{
lHeight -= nHScrollHeight;
}
}
}
break;
case LVS_REPORT:
rc.left = 0;
rc.top = 0;
rc.right = lWidth;
rc.bottom = lHeight;
hl.prc = &rc;
hl.pwpos = &wp;
Header_Layout(infoPtr->hwndHeader, &hl);
lTop = wp.cy;
break;
}
infoPtr->rcList.top = lTop;
infoPtr->rcList.left = 0;
infoPtr->rcList.bottom = lHeight;
infoPtr->rcList.right = lWidth;
}
/***
* DESCRIPTION:
* Notification sent when the window style is modified.
*
* 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);
HDLAYOUT hl;
WINDOWPOS wp;
HDC hdc;
RECT rc;
HBRUSH hBrush;
if (wStyleType == GWL_STYLE)
{
/* remove vertical scrollbar */
if (lpss->styleOld & WS_VSCROLL)
{
ShowScrollBar(hwnd, SB_VERT, FALSE);
}
/* remove horizontal scrollbar */
if (lpss->styleOld & WS_HSCROLL)
{
ShowScrollBar(hwnd, SB_HORZ, FALSE);
}
if ((LVS_TYPEMASK & lpss->styleOld) == LVS_REPORT)
{
/* hide header */
ShowWindow(infoPtr->hwndHeader, SW_HIDE);
}
/* erase everything */
GetClientRect(hwnd, &rc);
hdc = GetDC(hwnd);
hBrush = CreateSolidBrush(infoPtr->clrBk);
FillRect(hdc, &rc, hBrush);
DeleteObject(hBrush);
ReleaseDC(hwnd, hdc);
if ((lpss->styleNew & LVS_TYPEMASK) == LVS_REPORT)
{
hl.prc = &rc;
hl.pwpos = &wp;
Header_Layout(infoPtr->hwndHeader, &hl);
SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
wp.flags);
ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
}
else if (((lpss->styleNew & LVS_TYPEMASK) == LVS_ICON) ||
((lpss->styleNew & LVS_TYPEMASK) == LVS_SMALLICON))
{
/* for NOW (it's only temporary) */
SetWindowLongA(hwnd, GWL_STYLE, (lpss->styleNew&~LVS_TYPEMASK)|LVS_LIST);
}
/* TEMPORARY */
LISTVIEW_UnsupportedStyles(lpss->styleNew);
/* set new size */
LISTVIEW_SetSize(hwnd, lpss->styleNew, rc.right, rc.bottom);
/* recalculate attributes */
LISTVIEW_SetViewInfo(hwnd);
/* set scrollbars, if needed */
LISTVIEW_SetScroll(hwnd);
/* invalidate + erase background */
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: */
/* 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_DESTROY:
return LISTVIEW_Destroy(hwnd);
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, LOWORD(lParam), HIWORD(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);
}