Listview Q3

Dimitrie O. Paun dpaun at rogers.com
Mon Oct 14 19:45:51 CDT 2002


With this change, the drawing code becomes nice and uniform,
which is A Good Thing (TM) for future enhancements.

ChangeLog
  Teach GetItemMetrics to deal with subitems in report mode as well
  Unify Draw{,Sub}Item, simplify RefreshReport.

--- dlls/comctl32/listview.c.Q2	Mon Oct 14 19:36:37 2002
+++ dlls/comctl32/listview.c	Mon Oct 14 20:39:36 2002
@@ -1572,6 +1572,7 @@
     TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE));
 	
     /* Be smart and try to figure out the minimum we have to do */
+    if (lpLVItem->iSubItem) assert(uView == LVS_REPORT);
     if (lprcBounds)
     {
 	if (uView == LVS_REPORT) doIcon = TRUE;
@@ -1589,11 +1590,18 @@
     /************************************************************/
     /* compute the box rectangle (it should be cheap to do)     */
     /************************************************************/
-    Box.left = 0;
+    if (lpLVItem->iSubItem)
+    {
+        if (!Header_GetItemRect(infoPtr->hwndHeader, lpLVItem->iSubItem, &Box)) return FALSE;
+    }
+    else
+    {
+	Box.left = 0;
+	Box.right = infoPtr->nItemWidth;
+    }
     Box.top = 0;
-    Box.right = infoPtr->nItemWidth;
     Box.bottom = infoPtr->nItemHeight;
-
+		
     /************************************************************/
     /* compute STATEICON bounding box                           */
     /************************************************************/
@@ -1609,14 +1617,21 @@
 	else
 	{
 	    /* we need the ident in report mode, if we don't have it, we fail */
-	    assert(uView != LVS_REPORT || (lpLVItem->mask & LVIF_INDENT));
 	    State.left = Box.left;
-	    if (uView == LVS_REPORT) State.left += infoPtr->iconSize.cx * lpLVItem->iIndent;
+	    if (uView == LVS_REPORT) 
+	    {
+		State.left += REPORT_MARGINX;
+		if (lpLVItem->iSubItem == 0)
+		{
+		    assert(lpLVItem->mask & LVIF_INDENT);
+		    State.left += infoPtr->iconSize.cx * lpLVItem->iIndent;
+		}
+	    }
 	    State.top  = Box.top;
 	}	
 	State.right    = State.left;
 	State.bottom   = State.top;
-	if (infoPtr->himlState)
+	if (infoPtr->himlState && lpLVItem->iSubItem == 0)
 	{
 	    State.right  += infoPtr->iconStateSize.cx;
 	    State.bottom += infoPtr->iconStateSize.cy;
@@ -1647,10 +1662,11 @@
 	else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
 	{
 	    Icon.left = State.right;
-	    if (infoPtr->himlState) Icon.left += IMAGE_PADDING;
+	    if (!IsRectEmpty(&State)) Icon.left += IMAGE_PADDING;
 	    Icon.top    = Box.top;
 	    Icon.right  = Icon.left;
-	    if (infoPtr->himlSmall) Icon.right += infoPtr->iconSize.cx;
+	    /* FIXME: add suport for icons for subitems */
+	    if (infoPtr->himlSmall && lpLVItem->iSubItem == 0) Icon.right += infoPtr->iconSize.cx;
 	    Icon.bottom = Icon.top + infoPtr->nItemHeight;
 	}
 	if(lprcIcon) *lprcIcon = Icon;
@@ -1664,12 +1680,13 @@
     {
 	SIZE labelSize = { 0, 0 };
 
-	if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT))
+	if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && uView == LVS_REPORT))
 	{
 	   labelSize.cx = infoPtr->nItemWidth;
 	   labelSize.cy = infoPtr->nItemHeight;
 	   goto calc_label;
 	}
+	
 	/* we need the text in non owner draw mode */
 	assert(lpLVItem->mask & LVIF_TEXT);
 	if (is_textT(lpLVItem->pszText, TRUE))
@@ -1722,10 +1739,9 @@
 	else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
 	{
 	    Label.left = Icon.right;
-	    if (infoPtr->himlSmall) Label.left += IMAGE_PADDING;
+	    if (!IsRectEmpty(&Icon) || !IsRectEmpty(&State)) Label.left += IMAGE_PADDING;
 	    Label.top = Box.top;
-	    Label.right = Label.left + labelSize.cx;
-	    if (Label.right > Box.right) Label.right = Box.right;
+	    Label.right = min(Label.left + labelSize.cx, Box.right - (uView == LVS_REPORT ? REPORT_MARGINX : 0));
 	    Label.bottom = Label.top + infoPtr->nItemHeight;
 	}
   
@@ -3227,66 +3243,13 @@
 
 /***
  * DESCRIPTION:
- * Draws a subitem.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] HDC : device context handle
- * [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, DWORD cdmode)
-{
-    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
-    DWORD cditemmode = CDRF_DODEFAULT;
-    NMLVCUSTOMDRAW nmlvcd;
-    LVITEMW lvItem;
-
-    TRACE("(hdc=%x, nItem=%d, nSubItem=%d, rcItem=%s)\n", 
-	   hdc, nItem, nSubItem, debugrect(&rcItem));
-
-    /* get information needed for drawing the item */
-    lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
-    lvItem.iItem = nItem;
-    lvItem.iSubItem = nSubItem;
-    lvItem.cchTextMax = DISP_TEXT_SIZE;
-    lvItem.pszText = szDispText;
-    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;
-
-    if (lvItem.iImage) FIXME("Draw the image for the subitem\n");
-
-    select_text_attr(infoPtr, hdc, &nmlvcd);
-    DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | align);
-
-postpaint:
-    if (cditemmode & CDRF_NOTIFYPOSTPAINT)
-        notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
-
-    return TRUE;
-}
-
-
-/***
- * DESCRIPTION:
  * Draws an item.
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
  * [I] hdc : device context handle
  * [I] nItem : item index
+ * [I] nSubItem : subitem index
  * [I] pos : item position in client coordinates
  * [I] cdmode : custom draw mode
  *
@@ -3294,7 +3257,7 @@
  *   Success: TRUE
  *   Failure: FALSE
  */
-static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, POINT pos, DWORD cdmode)
+static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem, POINT pos, DWORD cdmode)
 {
     UINT uFormat, uView = infoPtr->dwStyle & LVS_TYPEMASK;
     WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
@@ -3307,11 +3270,12 @@
     TRACE("(hdc=%x, nItem=%d)\n", hdc, nItem);
 
     /* get information needed for drawing the item */
-    lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
+    lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
+    if (nSubItem == 0) lvItem.mask |= LVIF_STATE;
     if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT;
     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
     lvItem.iItem = nItem;
-    lvItem.iSubItem = 0;
+    lvItem.iSubItem = nSubItem;
     lvItem.cchTextMax = DISP_TEXT_SIZE;
     lvItem.pszText = szDispText;
     if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
@@ -3333,7 +3297,7 @@
     if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
 
     /* state icons */
-    if (infoPtr->himlState)
+    if (infoPtr->himlState && !IsRectEmpty(&rcState))
     {
         UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
         if (uStateImage)
@@ -3342,24 +3306,46 @@
 
     /* small icons */
     himl = (uView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall);
-    if (himl && lvItem.iImage >= 0)
+    if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon))
 	ImageList_Draw(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top,
 			(lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus) ? ILD_SELECTED : ILD_NORMAL);
 
     /* Don't bother painting item being edited */
-    if (infoPtr->bEditing && lprcFocus) goto postpaint;
+    if (infoPtr->bEditing && lprcFocus && nSubItem == 0) goto postpaint;
 
     select_text_attr(infoPtr, hdc, &nmlvcd);
 
-    rcSelect = rcLabel;
-    if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
-	rcSelect.right = rcBox.right;
+    /* draw the selection background, if we're drawing the main item */
+    if (nSubItem == 0)
+    {
+	rcSelect = rcLabel;
+    	if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
+	    rcSelect.right = rcBox.right;
    
-    if (lvItem.state & LVIS_SELECTED) 
-        ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, 0, 0, 0);
-    if(lprcFocus) *lprcFocus = rcSelect;
-    
-    uFormat = (uView == LVS_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS | DT_CENTER);
+    	if (lvItem.state & LVIS_SELECTED) 
+            ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, 0, 0, 0);
+    	if(lprcFocus) *lprcFocus = rcSelect;
+    }
+   
+    /* figure out the text drawing flags */
+    uFormat = (uView == LVS_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS);
+    if (uView == LVS_ICON)
+	uFormat = (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS);
+    else 
+    {
+	INT align = DT_LEFT;
+	
+	if (nSubItem)
+	{
+    	    LVCOLUMNW lvColumn;
+	    lvColumn.mask = LVCF_FMT;
+	    LISTVIEW_GetColumnT(infoPtr, nSubItem, &lvColumn, TRUE);
+	    TRACE("lvColumn=%s\n", debuglvcolumn_t(&lvColumn, TRUE));
+	    if (lvColumn.fmt & LVCFMT_RIGHT) align = DT_RIGHT;
+	    else if (lvColumn.fmt & LVCFMT_CENTER)align = DT_CENTER;
+	}
+	uFormat |= align;
+    }
     DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat);
 
 postpaint:
@@ -3454,12 +3440,10 @@
  */
 static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
 {
-    INT rgntype, nDrawPosY, j;
-    INT nColumnCount, nFirstCol, nLastCol;
-    RECT rcItem, rcClip;
+    INT rgntype, nColumnCount, nFirstCol, nLastCol, nCol;
+    RECT rcClip;
     COLUMNCACHE *lpCols;
-    LVCOLUMNW lvColumn;
-    POINT ptOrig;
+    POINT Origin, Position;
     ITERATOR i;
 
     TRACE("()\n");
@@ -3472,34 +3456,21 @@
     nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
     lpCols = COMCTL32_Alloc(nColumnCount * sizeof(COLUMNCACHE));
     if (!lpCols) return;
-    for (j = 0; j < nColumnCount; j++) 
+    for (nCol = 0; nCol < nColumnCount; nCol++) 
     {
-    	Header_GetItemRect(infoPtr->hwndHeader, j, &lpCols[j].rc);
-	TRACE("lpCols[%d].rc=%s\n", j, debugrect(&lpCols[j].rc));
+    	Header_GetItemRect(infoPtr->hwndHeader, nCol, &lpCols[nCol].rc);
+	TRACE("lpCols[%d].rc=%s\n", nCol, debugrect(&lpCols[nCol].rc));
     }
     
     /* Get scroll info once before loop */
-    if (!LISTVIEW_GetOrigin(infoPtr, &ptOrig)) return;
+    if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return;
     
     /* we now narrow the columns as well */
     nLastCol = nColumnCount - 1;
     for(nFirstCol = 0; nFirstCol < nColumnCount; nFirstCol++)
-	if (lpCols[nFirstCol].rc.right + ptOrig.x >= rcClip.left) break;
+	if (lpCols[nFirstCol].rc.right + Origin.x >= rcClip.left) break;
     for(nLastCol = nColumnCount - 1; nLastCol >= 0; nLastCol--)
-	if (lpCols[nLastCol].rc.left + ptOrig.x < rcClip.right) break;
-
-    /* cache the per-column information before we start drawing */
-    for (j = nFirstCol; j <= nLastCol; j++)
-    {
-	lvColumn.mask = LVCF_FMT;
-	LISTVIEW_GetColumnT(infoPtr, j, &lvColumn, TRUE);
-	TRACE("lvColumn=%s\n", debuglvcolumn_t(&lvColumn, TRUE));
-	lpCols[j].align = DT_LEFT;
-	if (lvColumn.fmt & LVCFMT_RIGHT)
-	    lpCols[j].align = DT_RIGHT;
-	else if (lvColumn.fmt & LVCFMT_CENTER)
-	    lpCols[j].align = DT_CENTER;
-    }
+	if (lpCols[nLastCol].rc.left + Origin.x < rcClip.right) break;
 
     /* figure out what we need to draw */
     iterator_visibleitems(&i, infoPtr, hdc);
@@ -3510,29 +3481,24 @@
     /* iterate through the invalidated rows */
     while(iterator_prev(&i))
     {
-	nDrawPosY = i.nItem * infoPtr->nItemHeight;
-
 	/* iterate through the invalidated columns */
-	for (j = nFirstCol; j <= nLastCol; j++)
+	for (nCol = nFirstCol; nCol <= nLastCol; nCol++)
 	{
-	    rcItem = lpCols[j].rc;
-	    rcItem.left += REPORT_MARGINX;
-	    rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
-	    rcItem.top = nDrawPosY;
-	    rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+	    if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue;
+	    Position.x += Origin.x;
+	    Position.y += Origin.y;
 
-	    /* Offset the Scroll Bar Pos */
-	    OffsetRect(&rcItem, ptOrig.x, ptOrig.y);
-
-	    if (rgntype == COMPLEXREGION && !RectVisible(hdc, &rcItem)) continue;
-
-	    if (j == 0)
+	    if (rgntype == COMPLEXREGION)
 	    {
-		POINT pos = { rcItem.left, rcItem.top };
-		LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, pos, cdmode);
+	        RECT rcItem;
+	        rcItem.left = Position.x + lpCols[nCol].rc.left;
+	        rcItem.right = rcItem.left + (lpCols[nCol].rc.right - lpCols[nCol].rc.left);
+	        rcItem.top = Position.y;
+	        rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+		if (!RectVisible(hdc, &rcItem)) continue;
 	    }
-	    else
-		LISTVIEW_DrawSubItem(infoPtr, hdc, i.nItem, j, rcItem, lpCols[j].align, cdmode);
+
+	    LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, nCol, Position, cdmode);
 	}
     }
     iterator_destroy(&i);
@@ -3570,7 +3536,7 @@
 	Position.x += Origin.x;
 	Position.y += Origin.y;
 
-        LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, Position, cdmode);
+        LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, 0, Position, cdmode);
     }
     iterator_destroy(&i);
 }




More information about the wine-patches mailing list