/*
 * Listview control
 *
 * Copyright 1998 Eric Kohl
 *
 * NOTES
 *   This is just a dummy control. An author is needed! Any volunteers?
 *   I will only improve this control once in a while.
 *     Eric <ekohl@abo.rhein-zeitung.de>
 *
 * TODO:
 *   - Most messages.
 *   - Most notifications.
 */

#include "windows.h"
#include "commctrl.h"
#include "listview.h"
#include "win.h"
#include "debug.h"


#define LISTVIEW_GetInfoPtr(wndPtr) ((LISTVIEW_INFO *)wndPtr->wExtra[0])


static VOID
LISTVIEW_Refresh (WND *wndPtr, HDC32 hdc)
{
//    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);



}



// << LISTVIEW_ApproximateViewRect >>
// << LISTVIEW_Arrange >>
// << LISTVIEW_CreateDragImage >>


static LRESULT
LISTVIEW_DeleteAllItems (WND *wndPtr)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    INT32 nItem;
    LISTVIEW_ITEM *lpItem;
    NMLISTVIEW nmlv;
    BOOL32 bNotify;

    if (infoPtr->nItemCount == 0)
	return TRUE;

    TRACE (listview, "\n");

    /* send LVN_DELETEALLITEMS notification */
    ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code     = LVN_DELETEALLITEMS;
    nmlv.iItem        = -1;
    bNotify =
	!(BOOL32)SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
				 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    nmlv.hdr.code     = LVN_DELETEITEM;

    for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) {
	/* send notification */
	if (bNotify) {
	    nmlv.iItem = nItem;
	    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
			    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);
	}

	/* get item pointer */
	lpItem = (LISTVIEW_ITEM*)DPA_GetPtr (infoPtr->hdpaItems, nItem);
	if (lpItem) {
	    /* delete item strings */
	    if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACK32A))
		COMCTL32_Free (lpItem->pszText);

	    /* free item data */
	    COMCTL32_Free (lpItem);
	}
    }

    DPA_DeleteAllPtrs (infoPtr->hdpaItems);
    infoPtr->nItemCount = 0;

    return TRUE;
}


static LRESULT
LISTVIEW_DeleteColumn (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    INT32 nColumn = (INT32)wParam;

    /* FIXME ??? */
    if (infoPtr->nItemCount > 0)
	return FALSE;

    if (!SendMessage32A (infoPtr->hwndHeader, HDM_DELETEITEM, wParam, 0))
	return FALSE;

    infoPtr->nColumnCount--;

    FIXME (listview, "semi stub!\n");

    return TRUE;
}


static LRESULT
LISTVIEW_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    INT32 nItem = (INT32)wParam;
    LISTVIEW_ITEM *lpItem;
    NMLISTVIEW nmlv;

    if ((nItem < 0) || (nItem >= infoPtr->nItemCount))
	return FALSE;

    TRACE (listview, "(%d)\n", nItem);

    /* send notification */
    ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code     = LVN_DELETEITEM;
    nmlv.iItem        = nItem;
    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    /* remove from item array */
    lpItem = (LISTVIEW_ITEM*)DPA_DeletePtr (infoPtr->hdpaItems, nItem);

    /* delete item strings */
    if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACK32A))
	COMCTL32_Free (lpItem->pszText);

    /* free item data */
    COMCTL32_Free (lpItem);

    infoPtr->nItemCount--;

    return TRUE;
}


// << LISTVIEW_EditLabel >>
// << LISTVIEW_EnsureVisible >>
// << LISTVIEW_FindItem >>


static LRESULT
LISTVIEW_GetBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    return infoPtr->clrBk;
}


// << LISTVIEW_GetBkImage >>
// << LISTVIEW_GetCallbackMask >>


static LRESULT
LISTVIEW_GetColumn32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVCOLUMN32A lpcol = (LPLVCOLUMN32A)lParam;
    INT32 nIndex = (INT32)wParam;
    HDITEM32A hdi;

    if (!lpcol)
	return FALSE;

    TRACE (listview, "(%d %p)\n", nIndex, lpcol);

    ZeroMemory (&hdi, sizeof(HDITEM32A));

    if (lpcol->mask & LVCF_FMT)
	hdi.mask |= HDI_FORMAT;

    if (lpcol->mask & LVCF_WIDTH)
        hdi.mask |= HDI_WIDTH;

    if (lpcol->mask & LVCF_TEXT)
        hdi.mask |= (HDI_TEXT | HDI_FORMAT);

    if (lpcol->mask & LVCF_IMAGE)
        hdi.mask |= HDI_IMAGE;

    if (lpcol->mask & LVCF_ORDER)
        hdi.mask |= HDI_ORDER;

    if (!SendMessage32A (infoPtr->hwndHeader, HDM_GETITEM32A,
		    wParam, (LPARAM)&hdi))
	return FALSE;

    if (lpcol->mask & LVCF_FMT) {
	lpcol->fmt = 0;

	if (hdi.fmt & HDF_LEFT)
	    lpcol->fmt |= LVCFMT_LEFT;
	else if (hdi.fmt & HDF_RIGHT)
	    lpcol->fmt |= LVCFMT_RIGHT;
	else if (hdi.fmt & HDF_CENTER)
	    lpcol->fmt |= LVCFMT_CENTER;

	if (hdi.fmt & HDF_IMAGE)
	    lpcol->fmt |= LVCFMT_COL_HAS_IMAGES;
    }

    if (lpcol->mask & LVCF_WIDTH)
	lpcol->cx = hdi.cxy;

    if ((lpcol->mask & LVCF_TEXT) && (lpcol->pszText) && (hdi.pszText))
	lstrcpyn32A (lpcol->pszText, hdi.pszText, lpcol->cchTextMax);

    if (lpcol->mask & LVCF_IMAGE)
	lpcol->iImage = hdi.iImage;

    if (lpcol->mask & LVCF_ORDER)
	lpcol->iOrder = hdi.iOrder;

    return TRUE;
}


// << LISTVIEW_GetColumn32W >>
// << LISTVIEW_GetColumnOrderArray >>


__inline__ static LRESULT
LISTVIEW_GetColumnWidth (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    HDITEM32A hdi;

    hdi.mask = HDI_WIDTH;
    if (SendMessage32A (infoPtr->hwndHeader, HDM_GETITEM32A,
			wParam, (LPARAM)&hdi))
	return hdi.cxy;

    return 0;
}


// << LISTVIEW_GetCountPerPage >>
// << LISTVIEW_GetEditControl >>
// << LISTVIEW_GetExtendedListviewStyle >>


__inline__ static LRESULT
LISTVIEW_GetHeader (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    return infoPtr->hwndHeader;
}


// << LISTVIEW_GetHotCursor >>
// << LISTVIEW_GetHotItem >>
// << LISTVIEW_GetHoverTime >>


static LRESULT
LISTVIEW_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    TRACE (listview, "(0x%08x)\n", wParam);

    switch (wParam) {
	case LVSIL_NORMAL:
	    return (LRESULT)infoPtr->himlNormal;

	case LVSIL_SMALL:
	    return (LRESULT)infoPtr->himlSmall;

	case LVSIL_STATE:
	    return (LRESULT)infoPtr->himlState;
    }

    return (LRESULT)NULL;
}


// << LISTVIEW_GetISearchString >>


static LRESULT
LISTVIEW_GetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVITEM32A lpItem = (LPLVITEM32A)lParam;
    LISTVIEW_ITEM *lpRow, *lpSubItem;

    if (!lpItem)
	return FALSE;

    if ((lpItem->iItem < 0) || (lpItem->iItem >= infoPtr->nItemCount))
	return FALSE;

    if ((lpItem->iSubItem < 0) || (lpItem->iSubItem >= infoPtr->nColumnCount))
	return FALSE;

    FIXME (listview, "(%d %d %p)\n",
	   lpItem->iItem, lpItem->iSubItem, lpItem);

    lpRow = DPA_GetPtr (infoPtr->hdpaItems, lpItem->iItem);
    if (!lpRow)
	return FALSE;

    lpSubItem = &lpRow[lpItem->iSubItem];
    if (!lpSubItem)
	return FALSE;

    if (lpItem->mask & LVIF_STATE)
	lpItem->state = lpSubItem->state & lpItem->stateMask;

    if (lpItem->mask & LVIF_TEXT) {
	if (lpSubItem->pszText == LPSTR_TEXTCALLBACK32A)
	    lpItem->pszText = LPSTR_TEXTCALLBACK32A;
	else
	    Str_GetPtr32A (lpSubItem->pszText, lpItem->pszText,
			   lpItem->cchTextMax);
    }

    if (lpItem->mask & LVIF_IMAGE)
	 lpItem->iImage = lpSubItem->iImage;

    if (lpItem->mask & LVIF_PARAM)
	lpItem->lParam = lpSubItem->lParam;

    if (lpItem->mask & LVIF_INDENT)
	lpItem->iIndent = lpSubItem->iIndent;

    return TRUE;
}


// << LISTVIEW_GetItem32W >>


__inline__ static LRESULT
LISTVIEW_GetItemCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    return infoPtr->nItemCount;
}


static LRESULT
LISTVIEW_GetItemPosition (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPPOINT32 lpPt = (LPPOINT32)lParam;
    INT32 nIndex = (INT32)wParam;

    if (!lpPt)
	return FALSE;
    if ((nIndex < 0) || (nIndex >= infoPtr->nItemCount))
	return FALSE;

    FIXME (listview, "returning position [0,0]!\n");
    lpPt->x = 0;
    lpPt->y = 0;

    return TRUE;
}


// << LISTVIEW_GetItemRect >>
// << LISTVIEW_GetItemSpacing >>
// << LISTVIEW_GetItemState >>


static LRESULT
LISTVIEW_GetItemText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVITEM32A lpItem = (LPLVITEM32A)lParam;
    INT32 nItem = (INT32)wParam;
    LISTVIEW_ITEM *lpRow, *lpSubItem;

    TRACE (listview, "(%d %p)\n", nItem, lpItem);

    lpRow = DPA_GetPtr (infoPtr->hdpaItems, lpItem->iItem);
    if (!lpRow)
	return 0;

    lpSubItem = &lpRow[lpItem->iSubItem];
    if (!lpSubItem)
	return 0;

    if (lpSubItem->pszText == LPSTR_TEXTCALLBACK32A) {
	lpItem->pszText = LPSTR_TEXTCALLBACK32A;
	return 0;
    }
    else
	return Str_GetPtr32A (lpSubItem->pszText, lpItem->pszText,
			      lpItem->cchTextMax);
}


// << LISTVIEW_GetItemText32A >>


static LRESULT
LISTVIEW_GetNextItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    INT32 nStart = (INT32)wParam;
    UINT32 uFlags = (UINT32)LOWORD(lParam);

    FIXME (listview, "(%d, 0x%x): semi stub!\n", nStart, uFlags);

    if (infoPtr->nItemCount <= 0)
	return -1;

    /* just a simple (preliminary) hack */
    if (nStart == -1)
	return 0;
    else if (nStart < infoPtr->nItemCount - 1)
	return nStart + 1;
    else
	return -1;

    return -1;
}


// << LISTVIEW_GetNumberOfWorkAreas >>
// << LISTVIEW_GetOrigin >>


static LRESULT
LISTVIEW_GetSelectedCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    TRACE (listview, ": empty stub (returns 0)!\n");

    return 0;
}


// << LISTVIEW_GetSelectionMark >>


static LRESULT
LISTVIEW_GetStringWidth32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPSTR lpsz = (LPSTR)lParam;
    HFONT32 hFont, hOldFont;
    HDC32 hdc;
    SIZE32 size;

    if (!lpsz)
	return 0;

    TRACE (listview, "(%s)\n", lpsz);

    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
    hdc = GetDC32 (0);
    hOldFont = SelectObject32 (hdc, hFont);
    GetTextExtentPoint32A (hdc, lpsz, lstrlen32A(lpsz), &size);
    SelectObject32 (hdc, hOldFont);
    ReleaseDC32 (0, hdc);

    TRACE (listview, "-- ret=%d\n", size.cx);

    return (LRESULT)size.cx;
}




__inline__ static LRESULT
LISTVIEW_GetTextBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    return infoPtr->clrTextBk;
}


__inline__ static LRESULT
LISTVIEW_GetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    return infoPtr->clrText;
}


static LRESULT
LISTVIEW_HitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
//    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVHITTESTINFO lpht = (LPLVHITTESTINFO)lParam;

    FIXME (listview, "(%p): stub!\n", lpht);

    /* FIXME: preliminary */
    lpht->flags = LVHT_NOWHERE;
    lpht->iItem = -1;
    lpht->iSubItem = 0;

    return -1;
}


static LRESULT
LISTVIEW_InsertColumn32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVCOLUMN32A lpcol = (LPLVCOLUMN32A)lParam;
    INT32 nIndex = (INT32)wParam;
    HDITEM32A hdi;
    INT32 nResult;

    if ((!lpcol) || (infoPtr->nItemCount > 0))
	return -1;

    FIXME (listview, "(%d %p): semi stub!\n", nIndex, lpcol);

    ZeroMemory (&hdi, sizeof(HDITEM32A));

    if (lpcol->mask & LVCF_FMT) {
	if (nIndex == 0)
	    hdi.fmt |= HDF_LEFT;
	else if (lpcol->fmt & LVCFMT_LEFT)
	    hdi.fmt |= HDF_LEFT;
	else if (lpcol->fmt & LVCFMT_RIGHT)
	    hdi.fmt |= HDF_RIGHT;
	else if (lpcol->fmt & LVCFMT_CENTER)
	    hdi.fmt |= HDF_CENTER;

	if (lpcol->fmt & LVCFMT_COL_HAS_IMAGES)
	    hdi.fmt |= HDF_IMAGE;
	    
	hdi.mask |= HDI_FORMAT;
    }

    if (lpcol->mask & LVCF_WIDTH) {
        hdi.mask |= HDI_WIDTH;
	hdi.cxy = lpcol->cx;
    }
    
    if (lpcol->mask & LVCF_TEXT) {
        hdi.mask |= (HDI_TEXT | HDI_FORMAT);
	hdi.pszText = lpcol->pszText;
	hdi.fmt |= HDF_STRING;
    }

    if (lpcol->mask & LVCF_IMAGE) {
        hdi.mask |= HDI_IMAGE;
	hdi.iImage = lpcol->iImage;
    }

    if (lpcol->mask & LVCF_ORDER) {
        hdi.mask |= HDI_ORDER;
	hdi.iOrder = lpcol->iOrder;
    }

    nResult = SendMessage32A (infoPtr->hwndHeader, HDM_INSERTITEM32A,
			      wParam, (LPARAM)&hdi);
    if (nResult == -1)
	return -1;

    infoPtr->nColumnCount++;

    return nResult;
}


// << LISTVIEW_InsertColumn32W >>


static LRESULT
LISTVIEW_InsertItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVITEM32A lpItem = (LPLVITEM32A)lParam;
    LISTVIEW_ITEM *lpListItem;
    INT32 nIndex;
    NMLISTVIEW nmlv;

    if (!lpItem)
	return -1;

    if ((!infoPtr->nColumnCount) || (lpItem->iSubItem))
	return -1;

    FIXME (listview, "(%d %p)\n", lpItem->iItem, lpItem);
    FIXME (listview, "(%p %p)\n", infoPtr, infoPtr->hdpaItems);

    lpListItem = (LISTVIEW_ITEM*)COMCTL32_Alloc (infoPtr->nColumnCount * sizeof(LISTVIEW_ITEM));
    nIndex = DPA_InsertPtr (infoPtr->hdpaItems, lpItem->iItem, lpListItem);
    if (nIndex == -1)
	return -1;

    if (lpItem->mask & LVIF_STATE)
	lpListItem[0].state = lpItem->state;

    if (lpItem->mask & LVIF_TEXT) {
	if (lpItem->pszText == LPSTR_TEXTCALLBACK32A)
	    lpListItem[0].pszText = LPSTR_TEXTCALLBACK32A;
	else
	    Str_SetPtr32A (&lpListItem[0].pszText, lpItem->pszText);
    }

    if (lpItem->mask & LVIF_IMAGE)
	lpListItem[0].iImage = lpItem->iImage;

    if (lpItem->mask & LVIF_PARAM)
	lpListItem[0].lParam = lpItem->lParam;

    if (lpItem->mask & LVIF_INDENT)
	lpListItem[0].iIndent = lpItem->iIndent;

    infoPtr->nItemCount++;

    /* send notification */
    ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code     = LVN_INSERTITEM;
    nmlv.iItem        = nIndex;
    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    return nIndex;
}


// << LISTVIEW_InsertItem32W >>


static LRESULT
LISTVIEW_RedrawItems (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
//    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    FIXME (listview, "(%d - %d): empty stub!\n",
	   (INT32)wParam, (INT32)lParam);

    return TRUE;
}



static LRESULT
LISTVIEW_SetBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    if (!infoPtr)
	return FALSE;

    /* set background color */
    TRACE (listview, "0x%06lx\n", (COLORREF)lParam);
    infoPtr->clrBk = (COLORREF)lParam;

    return TRUE;
}


static LRESULT
LISTVIEW_SetColumn32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVCOLUMN32A lpcol = (LPLVCOLUMN32A)lParam;
    INT32 nIndex = (INT32)wParam;
    HDITEM32A hdi;

    if (!lpcol)
	return -1;

    FIXME (listview, "(%d %p): semi stub!\n", nIndex, lpcol);

    ZeroMemory (&hdi, sizeof(HDITEM32A));

    if (lpcol->mask & LVCF_FMT) {
	if (nIndex == 0)
	    hdi.fmt |= HDF_LEFT;
	else if (lpcol->fmt & LVCFMT_LEFT)
	    hdi.fmt |= HDF_LEFT;
	else if (lpcol->fmt & LVCFMT_RIGHT)
	    hdi.fmt |= HDF_RIGHT;
	else if (lpcol->fmt & LVCFMT_CENTER)
	    hdi.fmt |= HDF_CENTER;

	if (lpcol->fmt & LVCFMT_COL_HAS_IMAGES)
	    hdi.fmt |= HDF_IMAGE;
	    
	hdi.mask |= HDI_FORMAT;
    }

    if (lpcol->mask & LVCF_WIDTH) {
        hdi.mask |= HDI_WIDTH;
	hdi.cxy = lpcol->cx;
    }
    
    if (lpcol->mask & LVCF_TEXT) {
        hdi.mask |= (HDI_TEXT | HDI_FORMAT);
	hdi.pszText = lpcol->pszText;
	hdi.fmt |= HDF_STRING;
    }

    if (lpcol->mask & LVCF_IMAGE) {
        hdi.mask |= HDI_IMAGE;
	hdi.iImage = lpcol->iImage;
    }

    if (lpcol->mask & LVCF_ORDER) {
        hdi.mask |= HDI_ORDER;
	hdi.iOrder = lpcol->iOrder;
    }

    return (LRESULT)SendMessage32A (infoPtr->hwndHeader, HDM_SETITEM32A,
				    wParam, (LPARAM)&hdi);
}




static LRESULT
LISTVIEW_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    HIMAGELIST himlTemp = 0;

    TRACE (listview, "(0x%08x 0x%08lx)\n", wParam, lParam);

    switch (wParam) {
	case LVSIL_NORMAL:
	    himlTemp = infoPtr->himlNormal;
	    infoPtr->himlNormal = (HIMAGELIST)lParam;
	    return (LRESULT)himlTemp;

	case LVSIL_SMALL:
	    himlTemp = infoPtr->himlSmall;
	    infoPtr->himlSmall = (HIMAGELIST)lParam;
	    return (LRESULT)himlTemp;

	case LVSIL_STATE:
	    himlTemp = infoPtr->himlState;
	    infoPtr->himlState = (HIMAGELIST)lParam;
	    return (LRESULT)himlTemp;
    }

    return (LRESULT)NULL;
}



static LRESULT
LISTVIEW_SetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPLVITEM32A lpItem = (LPLVITEM32A)lParam;
    LISTVIEW_ITEM *lpRow, *lpSubItem;
    NMLISTVIEW nmlv;

    if (!lpItem)
	return FALSE;

    if ((lpItem->iItem < 0) || (lpItem->iItem >= infoPtr->nItemCount))
	return FALSE;

    if ((lpItem->iSubItem < 0) || (lpItem->iSubItem >= infoPtr->nColumnCount))
	return FALSE;

    /* send LVN_ITEMCHANGING notification */
    ZeroMemory (&nmlv, sizeof (NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code     = LVN_ITEMCHANGING;
    nmlv.iItem        = lpItem->iItem;
    nmlv.iSubItem     = lpItem->iSubItem;
    nmlv.uChanged     = lpItem->mask;

    if (!SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
			 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv))
	return FALSE;

    TRACE (listview, "(%d %d %p)\n",
	   lpItem->iItem, lpItem->iSubItem, lpItem);

    lpRow = DPA_GetPtr (infoPtr->hdpaItems, lpItem->iItem);
    if (!lpRow)
	return FALSE;

    lpSubItem = &lpRow[lpItem->iSubItem];
    if (!lpSubItem)
	return FALSE;

    if (lpItem->mask & LVIF_STATE)
	lpSubItem->state = (lpSubItem->state & lpItem->stateMask) | lpItem->state;

    if (lpItem->mask & LVIF_TEXT) {
	if (lpItem->pszText == LPSTR_TEXTCALLBACK32A) {
	    if ((lpSubItem->pszText) &&
		(lpSubItem->pszText != LPSTR_TEXTCALLBACK32A))
		COMCTL32_Free (lpSubItem->pszText);
	    lpSubItem->pszText = LPSTR_TEXTCALLBACK32A;
	}
	else {
	    if (lpSubItem->pszText == LPSTR_TEXTCALLBACK32A)
		lpSubItem->pszText = NULL;
	    Str_SetPtr32A (&lpSubItem->pszText, lpItem->pszText);
	}
    }

    if (lpItem->mask & LVIF_IMAGE)
	lpSubItem->iImage = lpItem->iImage;

    if (lpItem->mask & LVIF_PARAM)
	lpSubItem->lParam = lpItem->lParam;

    if (lpItem->mask & LVIF_INDENT)
	lpSubItem->iIndent = lpItem->iIndent;

    /* send LVN_ITEMCHANGED notification */
    nmlv.hdr.code = LVN_ITEMCHANGED;
    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    return TRUE;
}


// << LISTVIEW_SetItem32W >>
// << LISTVIEW_SetItemCount >>


static LRESULT
LISTVIEW_SetItemPosition (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    INT32 nIndex = (INT32)wParam;

    if ((nIndex < 0) || (nIndex >= infoPtr->nItemCount))
	return FALSE;

    FIXME (listview, "setting position [%d, %d]!\n",
	   (INT32)LOWORD(lParam), (INT32)HIWORD(lParam));

    /* FIXME: set position */

    return TRUE;
}


static LRESULT
LISTVIEW_SetTextBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    if (!infoPtr)
	return FALSE;

    /* set text background color */
    TRACE (listview, "0x%06lx\n", (COLORREF)lParam);
    infoPtr->clrTextBk = (COLORREF)lParam;

    return TRUE;
}


static LRESULT
LISTVIEW_SetTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    if (!infoPtr)
	return FALSE;

    /* set text color */
    TRACE (listview, "0x%06lx\n", (COLORREF)lParam);
    infoPtr->clrText = (COLORREF)lParam;

    return TRUE;
}



static LRESULT
LISTVIEW_SortItems (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
//    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    FIXME (listview, "empty stub!\n");

    /* fake success */
    return TRUE;
}




static LRESULT
LISTVIEW_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    /* info structure is created at NCCreate */
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LOGFONT32A logFont;
    DWORD dwStyle = WS_CHILD | WS_VISIBLE; 

    TRACE (listview, "styles 0x%08lx 0x%08lx\n",
	   wndPtr->dwStyle, wndPtr->dwExStyle);

    /* initialize info structure */
    infoPtr->clrBk = CLR_NONE;
    infoPtr->clrText = RGB(0, 0, 0); /* preliminary */
    infoPtr->clrTextBk = RGB(255, 255, 255); /* preliminary */

    if (!(wndPtr->dwStyle & LVS_REPORT) ||
	 (wndPtr->dwStyle & LVS_NOCOLUMNHEADER))
	dwStyle |= HDS_HIDDEN;
    if (!(wndPtr->dwStyle & LVS_NOSORTHEADER))
	dwStyle |= HDS_BUTTONS;

    /* create header */
    infoPtr->hwndHeader =
	CreateWindow32A (WC_HEADER32A, "", dwStyle,
			 0, 0, 0, 0, wndPtr->hwndSelf,
			 (HMENU32)0, wndPtr->hInstance, NULL);

    /* get default font (icon title) */
    SystemParametersInfo32A (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
    infoPtr->hDefaultFont = CreateFontIndirect32A (&logFont);
    infoPtr->hFont = infoPtr->hDefaultFont;

    /* set header font */
    SendMessage32A (infoPtr->hwndHeader, WM_SETFONT,
		    (WPARAM32)infoPtr->hFont, (LPARAM)TRUE);

    infoPtr->hdpaItems = DPA_Create (10);

    return 0;
}


static LRESULT
LISTVIEW_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    /* delete all items */
    LISTVIEW_DeleteAllItems (wndPtr);

    /* destroy dpa */
    DPA_Destroy (infoPtr->hdpaItems);

    /* destroy header */
    if (infoPtr->hwndHeader)
	DestroyWindow32 (infoPtr->hwndHeader);

    /* destroy font */
    infoPtr->hFont = (HFONT32)0;
    if (infoPtr->hDefaultFont)
	DeleteObject32 (infoPtr->hDefaultFont);

    

    return 0;
}


static LRESULT
LISTVIEW_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    if (infoPtr->clrBk == CLR_NONE) {
	return SendMessage32A (GetParent32 (wndPtr->hwndSelf),
			       WM_ERASEBKGND, wParam, lParam);
    }
    else {
	HBRUSH32 hBrush = CreateSolidBrush32 (infoPtr->clrBk);
	FillRect32 ((HDC32)wParam, &infoPtr->rcList, hBrush);
	DeleteObject32 (hBrush);
	return FALSE;
    }

    return TRUE;
}


__inline__ static LRESULT
LISTVIEW_GetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    return infoPtr->hFont;
}


// << LISTVIEW_HScroll >>
// << LISTVIEW_KeyDown >>


static LRESULT
LISTVIEW_KillFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMHDR nmh;

    FIXME (listview, "semi stub!\n");

    nmh.hwndFrom = wndPtr->hwndSelf;
    nmh.idFrom   = wndPtr->wIDmenu;
    nmh.code = NM_KILLFOCUS;

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmh);

    infoPtr->bFocus = FALSE;

    return 0;
}


static LRESULT
LISTVIEW_LButtonDblClk (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMLISTVIEW nmlv;

    FIXME (listview, "semi stub!\n");

    ZeroMemory (&nmlv, sizeof(NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code = NM_DBLCLK;
    nmlv.iItem    = -1;
    nmlv.iSubItem = 0;
    nmlv.ptAction.x = (INT32)LOWORD(lParam);
    nmlv.ptAction.y = (INT32)HIWORD(lParam);

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    return 0;
}


static LRESULT
LISTVIEW_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMLISTVIEW nmlv;

    FIXME (listview, "semi stub!\n");

    ZeroMemory (&nmlv, sizeof(NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code = NM_CLICK;
    nmlv.iItem    = -1;
    nmlv.iSubItem = 0;
    nmlv.ptAction.x = (INT32)LOWORD(lParam);
    nmlv.ptAction.y = (INT32)HIWORD(lParam);

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    if (!infoPtr->bFocus)
	SetFocus32 (wndPtr->hwndSelf);

    return 0;
}


static LRESULT
LISTVIEW_NCCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr;

    /* allocate memory for info structure */
    infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc (sizeof(LISTVIEW_INFO));
    wndPtr->wExtra[0] = (DWORD)infoPtr;

    if (infoPtr == NULL) {
	ERR (listview, "could not allocate info memory!\n");
	return 0;
    }

    if ((LISTVIEW_INFO*)wndPtr->wExtra[0] != infoPtr) {
	ERR (listview, "pointer assignment error!\n");
	return 0;
    }

    return DefWindowProc32A (wndPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
}


static LRESULT
LISTVIEW_NCDestroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);




    /* free list view info data */
    COMCTL32_Free (infoPtr);

    return 0;
}


static LRESULT
LISTVIEW_Notify (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    LPNMHDR lpnmh = (LPNMHDR)lParam;

    if (lpnmh->hwndFrom == infoPtr->hwndHeader) {

	FIXME (listview, "WM_NOTIFY from header!\n");
    }
    else {

	FIXME (listview, "WM_NOTIFY from unknown source!\n");
    }

    return 0;
}


static LRESULT
LISTVIEW_Paint (WND *wndPtr, WPARAM32 wParam)
{
    HDC32 hdc;
    PAINTSTRUCT32 ps;

    hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
    LISTVIEW_Refresh (wndPtr, hdc);
    if (!wParam)
	EndPaint32 (wndPtr->hwndSelf, &ps);
    return 0;
}


static LRESULT
LISTVIEW_RButtonDblClk (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMLISTVIEW nmlv;

    FIXME (listview, "semi stub!\n");

    ZeroMemory (&nmlv, sizeof(NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code = NM_RDBLCLK;
    nmlv.iItem    = -1;
    nmlv.iSubItem = 0;
    nmlv.ptAction.x = (INT32)LOWORD(lParam);
    nmlv.ptAction.y = (INT32)HIWORD(lParam);

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    return 0;
}


static LRESULT
LISTVIEW_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMLISTVIEW nmlv;

    FIXME (listview, "semi stub!\n");

    ZeroMemory (&nmlv, sizeof(NMLISTVIEW));
    nmlv.hdr.hwndFrom = wndPtr->hwndSelf;
    nmlv.hdr.idFrom   = wndPtr->wIDmenu;
    nmlv.hdr.code = NM_RCLICK;
    nmlv.iItem    = -1;
    nmlv.iSubItem = 0;
    nmlv.ptAction.x = (INT32)LOWORD(lParam);
    nmlv.ptAction.y = (INT32)HIWORD(lParam);

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmlv);

    return 0;
}


static LRESULT
LISTVIEW_SetFocus (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    NMHDR nmh;

    FIXME (listview, "semi stub!\n");

    nmh.hwndFrom = wndPtr->hwndSelf;
    nmh.idFrom   = wndPtr->wIDmenu;
    nmh.code = NM_SETFOCUS;

    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmh);

    infoPtr->bFocus = TRUE;

    return 0;
}


static LRESULT
LISTVIEW_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);
    HFONT32 hFont = (HFONT32)wParam;

    infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;

    /* set header font */
    SendMessage32A (infoPtr->hwndHeader, WM_SETFONT, wParam, lParam);

    /* reinitialize the listview */
    


    if (lParam) {
	/* force redraw */


    }

    return 0;
}




static LRESULT
LISTVIEW_Size (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
    LISTVIEW_INFO *infoPtr = LISTVIEW_GetInfoPtr(wndPtr);

    GetClientRect32 (wndPtr->hwndSelf, &infoPtr->rcList);

    if (wndPtr->dwStyle & LVS_REPORT) {
	HDLAYOUT hl;
	WINDOWPOS32 wp;
	RECT32 rc;

	rc.top = 0;
	rc.left = 0;
	rc.right = LOWORD(lParam);
	rc.bottom = HIWORD(lParam);

	hl.prc = &rc;
	hl.pwpos = &wp;
	SendMessage32A (infoPtr->hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hl);

	SetWindowPos32 (infoPtr->hwndHeader, wndPtr->hwndSelf,
			wp.x, wp.y, wp.cx, wp.cy, wp.flags);

	infoPtr->rcList.top += wp.cy;
    }

    return 0;
}


LRESULT WINAPI
LISTVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
{
    WND *wndPtr = WIN_FindWndPtr(hwnd);

    switch (uMsg)
    {
//	case LVM_APPROXIMATEVIEWRECT:
//	case LVM_ARRANGE:
//	case LVM_CREATEDRAGIMAGE:

	case LVM_DELETEALLITEMS:
	    return LISTVIEW_DeleteAllItems (wndPtr);

	case LVM_DELETECOLUMN:
	    return LISTVIEW_DeleteColumn (wndPtr, wParam, lParam);

	case LVM_DELETEITEM:
	    return LISTVIEW_DeleteItem (wndPtr, wParam, lParam);

//	case LVM_EDITLABEL:
//	case LVM_ENSUREVISIBLE:
//	case LVM_FINDITEM:

	case LVM_GETBKCOLOR:
	    return LISTVIEW_GetBkColor (wndPtr, wParam, lParam);

//	case LVM_GETBKIMAGE:
//	case LVM_GETCALLBACKMASK:

	case LVM_GETCOLUMN32A:
	    return LISTVIEW_GetColumn32A (wndPtr, wParam, lParam);

//	case LVM_GETCOLUMN32W:
//	case LVM_GETCOLUMNORDERARRAY:

	case LVM_GETCOLUMNWIDTH:
	    return LISTVIEW_GetColumnWidth (wndPtr, wParam, lParam);

//	case LVM_GETCOUNTPERPAGE:
//	case LVM_GETEDITCONTROL:
//	case LVM_GETEXTENDEDLISTVIEWSTYLE:

	case LVM_GETHEADER:
	    return LISTVIEW_GetHeader (wndPtr, wParam, lParam);

//	case LVM_GETHOTCURSOR:
//	case LVM_GETHOTITEM:
//	case LVM_GETHOVERTIME:

	case LVM_GETIMAGELIST:
	    return LISTVIEW_GetImageList (wndPtr, wParam, lParam);

//	case LVM_GETISEARCHSTRING:

	case LVM_GETITEM32A:
	    return LISTVIEW_GetItem32A (wndPtr, wParam, lParam);

//	case LVM_GETITEM32W:

	case LVM_GETITEMCOUNT:
	    return LISTVIEW_GetItemCount (wndPtr, wParam, lParam);

	case LVM_GETITEMPOSITION:
	    return LISTVIEW_GetItemPosition (wndPtr, wParam, lParam);

//	case LVM_GETITEMRECT:
//	case LVM_GETITEMSPACING:
//	case LVM_GETITEMSTATE:

	case LVM_GETITEMTEXT32A:
	    return LISTVIEW_GetItemText32A (wndPtr, wParam, lParam);

//	case LVM_GETITEMTEXT32W:

	case LVM_GETNEXTITEM:
	    return LISTVIEW_GetNextItem (wndPtr, wParam, lParam);

//	case LVM_GETNUMBEROFWORKAREAS:
//	case LVM_GETORIGIN:

	case LVM_GETSELECTEDCOUNT:
	    return LISTVIEW_GetSelectedCount (wndPtr, wParam, lParam);

//	case LVM_GETSELECTIONMARK:

	case LVM_GETSTRINGWIDTH32A:
	    return LISTVIEW_GetStringWidth32A (wndPtr, wParam, lParam);

//	case LVM_GETSTRINGWIDTH32W:
//	case LVM_GETSUBITEMRECT:

	case LVM_GETTEXTBKCOLOR:
	    return LISTVIEW_GetTextBkColor (wndPtr, wParam, lParam);

	case LVM_GETTEXTCOLOR:
	    return LISTVIEW_GetTextColor (wndPtr, wParam, lParam);

//	case LVM_GETTOOLTIPS:
//	case LVM_GETTOPINDEX:
//	case LVM_GETUNICODEFORMAT:
//	case LVM_GETVIEWRECT:
//	case LVM_GETWORKAREAS:

	case LVM_HITTEST:
	    return LISTVIEW_HitTest (wndPtr, wParam, lParam);

	case LVM_INSERTCOLUMN32A:
	    return LISTVIEW_InsertColumn32A (wndPtr, wParam, lParam);

//	case LVM_INSERTCOLUMN32W:

	case LVM_INSERTITEM32A:
	    return LISTVIEW_InsertItem32A (wndPtr, wParam, lParam);

//	case LVM_INSERTITEM32W:

	case LVM_REDRAWITEMS:
	    return LISTVIEW_RedrawItems (wndPtr, wParam, lParam);

//	case LVM_SCROLL:

	case LVM_SETBKCOLOR:
	    return LISTVIEW_SetBkColor (wndPtr, wParam, lParam);

//	case LVM_SETBKIMAGE:
//	case LVM_SETCALLBACKMASK:

	case LVM_SETCOLUMN32A:
	    return LISTVIEW_SetColumn32A (wndPtr, wParam, lParam);

//	case LVM_SETCOLUMN32W:
//	case LVM_SETCOLUMNORDERARRAY:
//	case LVM_SETCOLUMNWIDTH:
//	case LVM_SETEXTENDEDLISTVIEWSTYLE:
//	case LVM_SETHOTCURSOR:
//	case LVM_SETHOTITEM:
//	case LVM_SETHOVERTIME:
//	case LVM_SETICONSPACING:
	
	case LVM_SETIMAGELIST:
	    return LISTVIEW_SetImageList (wndPtr, wParam, lParam);

	case LVM_SETITEM32A:
	    return LISTVIEW_SetItem32A (wndPtr, wParam, lParam);

//	case LVM_SETITEM32W:
//	case LVM_SETITEMCOUNT:

	case LVM_SETITEMPOSITION:
	    return LISTVIEW_SetItemPosition (wndPtr, wParam, lParam);

//	case LVM_SETITEMPOSITION32:
//	case LVM_SETITEMSTATE:
//	case LVM_SETITEMTEXT:
//	case LVM_SETSELECTIONMARK:

	case LVM_SETTEXTBKCOLOR:
	    return LISTVIEW_SetTextBkColor (wndPtr, wParam, lParam);

	case LVM_SETTEXTCOLOR:
	    return LISTVIEW_SetTextColor (wndPtr, wParam, lParam);

//	case LVM_SETTOOLTIPS:
//	case LVM_SETUNICODEFORMAT:
//	case LVM_SETWORKAREAS:

	case LVM_SORTITEMS:
	    return LISTVIEW_SortItems (wndPtr, wParam, lParam);

//	case LVM_SUBITEMHITTEST:
//	case LVM_UPDATE:



//	case WM_CHAR:
//	case WM_COMMAND:

	case WM_CREATE:
	    return LISTVIEW_Create (wndPtr, wParam, lParam);

	case WM_DESTROY:
	    return LISTVIEW_Destroy (wndPtr, wParam, lParam);

	case WM_ERASEBKGND:
	    return LISTVIEW_EraseBackground (wndPtr, wParam, lParam);

	case WM_GETDLGCODE:
	    return DLGC_WANTTAB | DLGC_WANTARROWS;

	case WM_GETFONT:
	    return LISTVIEW_GetFont (wndPtr, wParam, lParam);

//	case WM_HSCROLL:
//	case WM_KEYDOWN:

	case WM_KILLFOCUS:
	    return LISTVIEW_KillFocus (wndPtr, wParam, lParam);

	case WM_LBUTTONDBLCLK:
	    return LISTVIEW_LButtonDblClk (wndPtr, wParam, lParam);

	case WM_LBUTTONDOWN:
	    return LISTVIEW_LButtonDown (wndPtr, wParam, lParam);

//	case WM_MOUSEMOVE:
//	    return LISTVIEW_MouseMove (wndPtr, wParam, lParam);

	case WM_NCCREATE:
	    return LISTVIEW_NCCreate (wndPtr, wParam, lParam);

	case WM_NCDESTROY:
	    return LISTVIEW_NCDestroy (wndPtr, wParam, lParam);

	case WM_NOTIFY:
	    return LISTVIEW_Notify (wndPtr, wParam, lParam);

	case WM_PAINT:
	    return LISTVIEW_Paint (wndPtr, wParam);

	case WM_RBUTTONDBLCLK:
	    return LISTVIEW_RButtonDblClk (wndPtr, wParam, lParam);

	case WM_RBUTTONDOWN:
	    return LISTVIEW_RButtonDown (wndPtr, wParam, lParam);

	case WM_SETFOCUS:
	    return LISTVIEW_SetFocus (wndPtr, wParam, lParam);

	case WM_SETFONT:
	    return LISTVIEW_SetFont (wndPtr, wParam, lParam);

//	case WM_SETREDRAW:

	case WM_SIZE:
	    return LISTVIEW_Size (wndPtr, wParam, lParam);

//	case WM_TIMER:
//	case WM_VSCROLL:
//	case WM_WINDOWPOSCHANGED:
//	case WM_WININICHANGE:

	default:
	    if (uMsg >= WM_USER)
		ERR (listview, "unknown msg %04x wp=%08x lp=%08lx\n",
		     uMsg, wParam, lParam);
	    return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
    }
    return 0;
}


VOID
LISTVIEW_Register (VOID)
{
    WNDCLASS32A wndClass;

    if (GlobalFindAtom32A (WC_LISTVIEW32A)) return;

    ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
    wndClass.lpfnWndProc   = (WNDPROC32)LISTVIEW_WindowProc;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(LISTVIEW_INFO *);
    wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
    wndClass.hbrBackground = (HBRUSH32)(COLOR_WINDOW + 1);
    wndClass.lpszClassName = WC_LISTVIEW32A;
 
    RegisterClass32A (&wndClass);
}


VOID
LISTVIEW_Unregister (VOID)
{
    if (GlobalFindAtom32A (WC_LISTVIEW32A))
	UnregisterClass32A (WC_LISTVIEW32A, (HINSTANCE32)NULL);
}