Listvew N5 (Try 2)

Dimitrie O. Paun dpaun at rogers.com
Thu Oct 10 13:30:16 CDT 2002


This is the good one :)

ChangeLog
  Move the custom draw notifications into the Draw.*Item functions.

--- dlls/comctl32/listview.c.N4	Thu Oct 10 13:20:49 2002
+++ dlls/comctl32/listview.c	Thu Oct 10 14:26:01 2002
@@ -28,6 +28,7 @@
  *   -- Drawing optimizations.
  *   -- Hot item handling.
  *   -- Expand large item in ICON mode when the cursor is flying over the icon or text.
+ *   -- Support CustonDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs)
  *
  * Notifications:
  *   LISTVIEW_Notify : most notifications from children (editbox and header)
@@ -667,69 +668,27 @@
     notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr);
 }
 
-static BOOL notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, RECT rc)
+static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, LISTVIEW_INFO *infoPtr, HDC hdc, LPRECT rcBounds, LVITEMW *lpLVItem)
 {
-    NMLVCUSTOMDRAW nmlvcd;
-
-    TRACE("(dwDrawStage=%lx, hdc=%x, rc=?)\n", dwDrawStage, hdc);
-
-    nmlvcd.nmcd.dwDrawStage = dwDrawStage;
-    nmlvcd.nmcd.hdc         = hdc;
-    nmlvcd.nmcd.rc          = rc;
-    nmlvcd.nmcd.dwItemSpec  = 0;
-    nmlvcd.nmcd.uItemState  = 0;
-    nmlvcd.nmcd.lItemlParam = 0;
-    nmlvcd.clrText          = infoPtr->clrText;
-    nmlvcd.clrTextBk        = infoPtr->clrBk;
-
-    return (BOOL)notify_hdr(infoPtr, NM_CUSTOMDRAW, &nmlvcd.nmcd.hdr);
+    ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW));
+    lpnmlvcd->nmcd.hdc         = hdc;
+    lpnmlvcd->nmcd.rc          = *rcBounds;
+    if (lpLVItem)
+    {
+	lpnmlvcd->nmcd.dwItemSpec  = lpLVItem->iItem;
+        if (lpLVItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED;
+	if (lpLVItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS;
+	if (lpLVItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT;
+	lpnmlvcd->nmcd.lItemlParam = lpLVItem->lParam;
+    }
+    lpnmlvcd->clrText          = infoPtr->clrText;
+    lpnmlvcd->clrTextBk        = infoPtr->clrBk;
 }
 
-/* FIXME: we should inline this where it's called somehow
- * I think we need to pass in the structure
- */
-static BOOL notify_customdrawitem (LISTVIEW_INFO *infoPtr, HDC hdc, UINT iItem, UINT iSubItem, UINT uItemDrawState)
+static inline DWORD notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
 {
-    NMLVCUSTOMDRAW nmlvcd;
-    UINT uItemState;
-    RECT itemRect;
-    LVITEMW item;
-    BOOL bReturn;
-
-    item.iItem = iItem;
-    item.iSubItem = 0;
-    item.mask = LVIF_PARAM;
-    if (!LISTVIEW_GetItemT(infoPtr, &item, TRUE)) return FALSE;
-
-    uItemState = 0;
-
-    if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_SELECTED)) uItemState |= CDIS_SELECTED;
-    if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_FOCUSED)) uItemState |= CDIS_FOCUS;
-    if (iItem == infoPtr->nHotItem)       uItemState |= CDIS_HOT;
-
-    itemRect.left = LVIR_BOUNDS;
-    LISTVIEW_GetItemRect(infoPtr, iItem, &itemRect);
-
-    nmlvcd.nmcd.dwDrawStage = CDDS_ITEM | uItemDrawState;
-    nmlvcd.nmcd.hdc         = hdc;
-    nmlvcd.nmcd.rc          = itemRect;
-    nmlvcd.nmcd.dwItemSpec  = iItem;
-    nmlvcd.nmcd.uItemState  = uItemState;
-    nmlvcd.nmcd.lItemlParam = item.lParam;
-    nmlvcd.clrText          = infoPtr->clrText;
-    nmlvcd.clrTextBk        = infoPtr->clrBk;
-    nmlvcd.iSubItem         = iSubItem;
-
-    TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
-          nmlvcd.nmcd.dwDrawStage, nmlvcd.nmcd.hdc, nmlvcd.nmcd.dwItemSpec,
-          nmlvcd.nmcd.uItemState, nmlvcd.nmcd.lItemlParam);
-
-    bReturn = notify_hdr(infoPtr, NM_CUSTOMDRAW, &nmlvcd.nmcd.hdr);
-
-    infoPtr->clrText = nmlvcd.clrText;
-    infoPtr->clrBk   = nmlvcd.clrTextBk;
-    
-    return bReturn;
+    lpnmlvcd->nmcd.dwDrawStage = dwDrawStage;
+    return notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr);
 }
 
 /******** Item iterator functions **********************************/
@@ -3071,15 +3030,18 @@
  * [I] INT : item index
  * [I] INT : subitem index
  * [I] RECT * : clipping rectangle
+ * [I] cdmode : custom draw mode
  *
  * RETURN:
  *   Success: TRUE
  *   Failure: FALSE
  */
 static BOOL LISTVIEW_DrawSubItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, 
-		                 INT nSubItem, RECT rcItem, UINT align)
+		                 INT nSubItem, RECT rcItem, UINT align, DWORD cdmode)
 {
-    WCHAR szDispText[DISP_TEXT_SIZE];
+    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+    DWORD cditemmode = CDRF_DODEFAULT;
+    NMLVCUSTOMDRAW nmlvcd;
     LVITEMW lvItem;
 
     TRACE("(hdc=%x, nItem=%d, nSubItem=%d, rcItem=%s)\n", 
@@ -3091,15 +3053,24 @@
     lvItem.iSubItem = nSubItem;
     lvItem.cchTextMax = DISP_TEXT_SIZE;
     lvItem.pszText = szDispText;
-    *lvItem.pszText = '\0';
     if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
-    
     TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
 
+    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcItem, &lvItem);
+    if (cdmode & CDRF_NOTIFYITEMDRAW)
+        cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
+    if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
+
+    /* FIXME: set the text attr in here, they may change! */
+
     if (lvItem.iImage) FIXME("Draw the image for the subitem\n");
     
     DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | align);
 
+postpaint:
+    if (cditemmode & CDRF_NOTIFYPOSTPAINT)
+        notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+
     return TRUE;
 }
 
@@ -3113,16 +3084,19 @@
  * [I] hdc : device context handle
  * [I] nItem : item index
  * [I] rcItem : item rectangle
+ * [I] cdmode : custom draw mode
  *
  * RETURN:
- *   TRUE: if item is focused
- *   FALSE: otherwise
+ *   Success: TRUE
+ *   Failure: FALSE
  */
-static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem)
+static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, DWORD cdmode)
 {
-    WCHAR szDispText[DISP_TEXT_SIZE];
+    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+    DWORD cditemmode = CDRF_DODEFAULT;
     INT nLabelWidth, imagePadding = 0;
     RECT* lprcFocus, rcOrig = rcItem;
+    NMLVCUSTOMDRAW nmlvcd;
     LVITEMW lvItem;
     TEXTATTR ta;
 
@@ -3135,7 +3109,6 @@
     lvItem.iSubItem = 0;
     lvItem.cchTextMax = DISP_TEXT_SIZE;
     lvItem.pszText = szDispText;
-    *lvItem.pszText = '\0';
     if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
 
@@ -3143,6 +3116,11 @@
     lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
     if (lprcFocus) SetRectEmpty(lprcFocus);
 
+    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcItem, &lvItem);
+    if (cdmode & CDRF_NOTIFYITEMDRAW)
+        cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
+    if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
+
     /* do indent */  
     rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
 
@@ -3175,8 +3153,7 @@
     }
 
     /* Don't bother painting item being edited */
-    if (infoPtr->bEditing && lprcFocus) 
-    	return FALSE;
+    if (infoPtr->bEditing && lprcFocus) goto postpaint;
 
     select_text_attr(infoPtr, hdc, lvItem.state & LVIS_SELECTED, &ta);
 
@@ -3193,9 +3170,12 @@
 	    ExtTextOutW(hdc, rcItem.left, rcItem.top, ETO_OPAQUE, &rcItem, 0, 0, 0);
         DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | DT_CENTER);
     }
-
     set_text_attr(hdc, &ta);
-    return lprcFocus != NULL;
+
+postpaint:
+    if (cditemmode & CDRF_NOTIFYPOSTPAINT)
+        notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+    return TRUE;
 }
 
 /***
@@ -3206,16 +3186,18 @@
  * [I] infoPtr : valid pointer to the listview structure
  * [I] hdc : device context handle
  * [I] nItem : item index
+ * [I] cdmode : custom draw mode
  *
  * RETURN:
- *   TRUE: if item is focused
- *   FALSE: otherwise
+ *   Success: TRUE
+ *   Failure: FALSE
  */
-static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, DWORD cdmode)
+static BOOL LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, DWORD cdmode)
 {
     WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     DWORD cditemmode = CDRF_DODEFAULT;
-    RECT rcIcon, rcLabel, *lprcFocus;
+    RECT rcBounds, rcIcon, rcLabel, *lprcFocus;
+    NMLVCUSTOMDRAW nmlvcd;
     LVITEMW lvItem;
     UINT uFormat;
     TEXTATTR ta;
@@ -3229,18 +3211,23 @@
     lvItem.iSubItem = 0;
     lvItem.pszText = szDispText;
     lvItem.cchTextMax = DISP_TEXT_SIZE;
-    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return;
+    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     TRACE("   lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
 
     /* now check if we need to update the focus rectangle */
     lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
   
-    if (!LISTVIEW_GetItemMeasures(infoPtr, nItem, NULL, NULL, &rcIcon, &rcLabel)) return;
+    if (!LISTVIEW_GetItemMeasures(infoPtr, nItem, NULL, &rcBounds, &rcIcon, &rcLabel)) return FALSE;
 
+    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBounds, &lvItem);
     if (cdmode & CDRF_NOTIFYITEMDRAW)
-        cditemmode = notify_customdrawitem (infoPtr, hdc, nItem, 0, CDDS_ITEMPREPAINT);
+        cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
     if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
 
+    /* FIXME: pass the mnlvcd to select text attr */
+    infoPtr->clrText = nmlvcd.clrText;
+    infoPtr->clrBk   = nmlvcd.clrTextBk;
+    
     /* Set the item to the boundary box for now */
     TRACE("rcIcon=%s, rcLabel=%s\n", debugrect(&rcIcon), debugrect(&rcLabel));
 
@@ -3295,7 +3282,9 @@
 
 postpaint:    
     if (cditemmode & CDRF_NOTIFYPOSTPAINT)
-        notify_customdrawitem(infoPtr, hdc, nItem, 0, CDDS_ITEMPOSTPAINT);
+        notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+
+    return TRUE;
 }
 
 /***
@@ -3381,7 +3370,6 @@
     INT nColumnCount, nFirstCol, nLastCol;
     RECT rcItem, rcClip, rcFullSelect;
     BOOL bFullSelected, isFocused;
-    DWORD cditemmode = CDRF_DODEFAULT;
     TEXTATTR tmpTa, oldTa;
     COLUMNCACHE *lpCols;
     LVCOLUMNW lvColumn;
@@ -3449,15 +3437,17 @@
     {
 	nDrawPosY = i.nItem * infoPtr->nItemHeight;
 
+    	isFocused = FALSE;	    
 	/* compute the full select rectangle, if needed */
 	if (bFullSelected)
 	{
 	    item.mask = LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
-	    item.stateMask = LVIS_SELECTED;
+	    item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
 	    item.iItem = i.nItem;
 	    item.iSubItem = 0;
   	    if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
-	     
+	    
+	    isFocused = item.state & LVIS_FOCUSED;
 	    rcFullSelect.left = lpCols[0].rc.left + REPORT_MARGINX +
 	    			infoPtr->iconSize.cx * item.iIndent +
 				(infoPtr->himlSmall ? infoPtr->iconSize.cx : 0);
@@ -3473,7 +3463,6 @@
 	    ExtTextOutW(hdc, rcFullSelect.left, rcFullSelect.top, ETO_OPAQUE, &rcFullSelect, 0, 0, 0);
 	    
 	/* iterate through the invalidated columns */
-    	isFocused = FALSE;	    
 	for (j = nFirstCol; j <= nLastCol; j++)
 	{
 	    rcItem = lpCols[j].rc;
@@ -3487,17 +3476,10 @@
 
 	    if (rgntype == COMPLEXREGION && !RectVisible(hdc, &rcItem)) continue;
 
-	    if (cdmode & CDRF_NOTIFYITEMDRAW)
-		cditemmode = notify_customdrawitem (infoPtr, hdc, i.nItem, j, CDDS_ITEMPREPAINT);
-	    if (cditemmode & CDRF_SKIPDEFAULT) continue;
-
 	    if (j == 0)
-		isFocused = LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem);
+		LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem, cdmode);
 	    else
-		LISTVIEW_DrawSubItem(infoPtr, hdc, i.nItem, j, rcItem, lpCols[j].align);
-
-	    if (cditemmode & CDRF_NOTIFYPOSTPAINT)
-		notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
+		LISTVIEW_DrawSubItem(infoPtr, hdc, i.nItem, j, rcItem, lpCols[j].align, cdmode);
 	}
 
 	/* Adjust focus if we have it, and we are in full select */
@@ -3524,7 +3506,6 @@
  */
 static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
 {
-    DWORD cditemmode = CDRF_DODEFAULT;
     POINT Origin, Position;
     RECT rcItem;
     ITERATOR i;
@@ -3537,10 +3518,6 @@
     
     while(iterator_next(&i))
     {
-        if (cdmode & CDRF_NOTIFYITEMDRAW)
-            cditemmode = notify_customdrawitem (infoPtr, hdc, i.nItem, 0, CDDS_ITEMPREPAINT);
-        if (cditemmode & CDRF_SKIPDEFAULT) continue;
-
 	if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue;
 	rcItem.left = Position.x;
 	rcItem.top = Position.y;
@@ -3548,11 +3525,7 @@
 	rcItem.right = rcItem.left + infoPtr->nItemWidth;
 	OffsetRect(&rcItem, Origin.x, Origin.y);
 
-        LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem);
-
-        if (cditemmode & CDRF_NOTIFYPOSTPAINT)
-            notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
-
+        LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem, cdmode);
     }
     iterator_destroy(&i);
 }
@@ -3611,25 +3584,27 @@
 static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
 {
     UINT uView = LISTVIEW_GetType(infoPtr);
+    NMLVCUSTOMDRAW nmlvcd;
     HFONT hOldFont;
     DWORD cdmode;
     RECT rcClient;
 
     LISTVIEW_DUMP(infoPtr);
   
+    infoPtr->bIsDrawing = TRUE;
+
     GetClientRect(infoPtr->hwndSelf, &rcClient);
-  
-    cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, hdc, rcClient);
-    if (cdmode == CDRF_SKIPDEFAULT) return;
+ 
+    /* select font */
+    hOldFont = SelectObject(hdc, infoPtr->hFont);
 
-    infoPtr->bIsDrawing = TRUE;
+    customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, NULL);
+    cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
+    if (cdmode & CDRF_SKIPDEFAULT) goto enddraw;
 
     /* nothing to draw */
     if(infoPtr->nItemCount == 0) goto enddraw;
 
-    /* select font */
-    hOldFont = SelectObject(hdc, infoPtr->hFont);
-
     if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
 	LISTVIEW_RefreshOwnerDraw(infoPtr, hdc);
     else if (uView == LVS_ICON)
@@ -3643,12 +3618,12 @@
     if (infoPtr->bFocus && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
 	DrawFocusRect(hdc, &infoPtr->rcFocus);
 
-    /* unselect objects */
-    SelectObject(hdc, hOldFont);
-
 enddraw:
     if (cdmode & CDRF_NOTIFYPOSTPAINT)
-	notify_customdraw(infoPtr, CDDS_POSTPAINT, hdc, rcClient);
+	notify_customdraw(infoPtr, CDDS_POSTPAINT, &nmlvcd);
+
+    /* unselect objects */
+    SelectObject(hdc, hOldFont);
 
     infoPtr->bIsDrawing = FALSE;
 }




More information about the wine-patches mailing list