Listview M2

Dimitrie O. Paun dpaun at rogers.com
Tue Oct 8 01:06:33 CDT 2002


This patch beautifies *and* optimizes GetItemMeasures beyond words! :)))
I _really_ hope this one brings closure to the rectangle work...

ChangeLog
  Unify LISTVIEW_UpdateLargeItemLabelRect, and GetItemMeasures
  Optimize GetItemMeasures to the max
  Centralize the DrawText's DT_* flags.

--- dlls/comctl32/listview.c.M1	Tue Oct  8 00:36:11 2002
+++ dlls/comctl32/listview.c	Tue Oct  8 01:53:45 2002
@@ -233,8 +233,10 @@
 /* Border for the icon caption */
 #define CAPTION_BORDER  2
 
-/* Standard DrawText flags for LISTVIEW_UpdateLargeItemLabelRect and LISTVIEW_DrawLargeItem */
-#define LISTVIEW_DTFLAGS  DT_TOP | DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL
+/* Standard DrawText flags */
+#define LV_ML_DT_FLAGS  (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
+#define LV_FL_DT_FLAGS  (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_NOCLIP)
+#define LV_SL_DT_FLAGS  (DT_TOP | DT_EDITCONTROL | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS)
 
 /* Dump the LISTVIEW_INFO structure to the debug channel */
 #define LISTVIEW_DUMP(iP) do { \
@@ -287,7 +289,6 @@
 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT);
 static LRESULT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT);
 static LRESULT LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, LPLVITEMW);
-static BOOL LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO *, int, RECT*);
 static LRESULT LISTVIEW_GetColumnT(LISTVIEW_INFO *, INT, LPLVCOLUMNW, BOOL);
 static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND);
 static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND);
@@ -1247,105 +1248,6 @@
 }
 
 /***
- * DESCRIPTION:          [INTERNAL]
- * Update the bounding rectangle around the text under a large icon.
- * This depends on whether it has the focus or not.
- * On entry the rectangle's top, left and right should be set.
- * On return the bottom will also be set and the width may have been
- * modified.
- *
- * PARAMETER
- * [I] infoPtr : pointer to the listview structure
- * [I] nItem : the item for which we are calculating this
- * [I/O] rect : the rectangle to be updated
- *
- * This appears to be weird, even in the Microsoft implementation.
- */
-static BOOL LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO *infoPtr, int nItem, RECT *rect)
-{
-    HDC hdc = GetDC (infoPtr->hwndSelf);
-    HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
-    UINT uFormat = LISTVIEW_DTFLAGS | DT_CALCRECT;
-    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
-    RECT rcText = *rect;
-    RECT rcBack = *rect;
-    BOOL focused, selected;
-    int dx, dy, old_wid, new_wid;
-    LVITEMW lvItem;
-
-    TRACE("%s, focus item=%d, cur item=%d\n",
-	  (infoPtr->bFocus) ? "Window has focus" : "Window not focused",
-	  infoPtr->nFocusedItem, nItem);
-
-
-    focused = infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED); 
-    selected = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
-
-    uFormat |= (focused) ? DT_NOCLIP : DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
-
-    /* We (aim to) display the full text.  In Windows 95 it appears to
-     * calculate the size assuming the specified font and then it draws
-     * the text in that region with the specified font except scaled to
-     * 10 point (or the height of the system font or ...).  Thus if the
-     * window has 24 point Helvetica the highlit rectangle will be
-     * taller than the text and if it is 7 point Helvetica then the text
-     * will be clipped.
-     * For now we will simply say that it is the correct size to display
-     * the text in the specified font.
-     */
-    lvItem.mask = LVIF_TEXT;
-    lvItem.iItem = nItem;
-    lvItem.iSubItem = 0;
-    lvItem.pszText = szDispText;
-    lvItem.cchTextMax = DISP_TEXT_SIZE;
-    if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
-
-    InflateRect(&rcText, -2, 0);
-    DrawTextW (hdc, lvItem.pszText, -1, &rcText, uFormat);
-    /* Microsoft, in their great wisdom, have decided that the rectangle
-     * returned by DrawText on DT_CALCRECT will only guarantee the dimension,
-     * not the location.  So we have to do the centring ourselves (and take
-     * responsibility for agreeing off-by-one consistency with them).
-     */
-
-    old_wid = rcText.right - rcText.left;
-    new_wid = rcBack.right - rcBack.left;
-    dx = rcBack.left - rcText.left + (new_wid-old_wid)/2;
-    dy = rcBack.top - rcText.top;
-    OffsetRect (&rcText, dx, dy);
-
-    if (focused)
-    {
-	rcText.bottom += 2;
-	InflateRect(&rcText, 2, 0);
-    }
-    else /* not focused, may or may not be selected */
-    {
-        /*
-         * We need to have the bottom to be an intergal number of
-         * text lines (ntmHeight) below text top that is less than
-         * or equal to the nItemHeight.
-         */
-        INT lh = infoPtr->nItemHeight - infoPtr->iconSize.cy - 
-		 ICON_TOP_PADDING - ICON_BOTTOM_PADDING;
-        INT ih = (lh / infoPtr->ntmHeight) * infoPtr->ntmHeight;
-        rcText.bottom = min(rcText.bottom, rcText.top + ih);
-        rcText.bottom += 1;
-    }
-    *rect = rcText;
-
-    TRACE("%s and %s, bounding rect=(%d,%d)-(%d,%d)\n",
-	  (focused) ? "focused(full text)" : "not focused",
-	  (selected) ? "selected" : "not selected",
-	  rect->left, rect->top, rect->right, rect->bottom);
-
-    SelectObject (hdc, hOldFont);
-    ReleaseDC (infoPtr->hwndSelf, hdc);
-
-    return TRUE;
-}
-
-/***
  * DESCRIPTION:            [INTERNAL]
  * Compute the rectangles of an item.  This is to localize all
  * the computations in one place. If you are not interested in some
@@ -1384,8 +1286,10 @@
 {
     UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
     BOOL doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
+    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
     RECT Box, Icon, Label;
     POINT Origin;
+    LVITEMW lvItem;
 
     /* This should be very cheap to compute */
     if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return FALSE;
@@ -1426,6 +1330,21 @@
     Box.right = Box.left + infoPtr->nItemWidth;
     Box.bottom = Box.top + infoPtr->nItemHeight;
 
+    /* get what we need from the item before hand, so we make
+     * only one request. This can speed up things, if data
+     * is stored on the app side */
+    if (doLabel || (doIcon && uView == LVS_REPORT))
+    {
+	lvItem.mask = 0;
+	if (doIcon) lvItem.mask |= LVIF_INDENT;
+	if (doLabel) lvItem.mask |= LVIF_TEXT;
+	lvItem.iItem = nItem;
+	lvItem.iSubItem = 0;
+    	lvItem.pszText = szDispText;
+    	lvItem.cchTextMax = DISP_TEXT_SIZE;
+	if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
+    }
+
     /************************************************************/
     /* compute ICON bounding box (ala LVM_GETITEMRECT)          */
     /************************************************************/
@@ -1449,16 +1368,7 @@
 	{
 	    /* do indent */
 	    Icon.left = Box.left;
-	    if (uView == LVS_REPORT)
-	    {
-		LVITEMW lvItem;
-
-		lvItem.mask = LVIF_INDENT;
-		lvItem.iItem = nItem;
-		lvItem.iSubItem = 0;
-		if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
-		Icon.left += infoPtr->iconSize.cx * lvItem.iIndent;
-	    }
+	    if (uView == LVS_REPORT) Icon.left += infoPtr->iconSize.cx * lvItem.iIndent;
 	    if (infoPtr->himlState) Icon.left += infoPtr->iconStateSize.cx;
 	    Icon.top    = Box.top;
 	    Icon.right  = Icon.left;
@@ -1474,39 +1384,56 @@
     /************************************************************/
     if (doLabel)
     {
+	SIZE labelSize = { 0, 0 };
+		
+        if (is_textT(lvItem.pszText, TRUE))
+        {
+    	    HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
+    	    HDC hdc = GetDC(infoPtr->hwndSelf);
+    	    HFONT hOldFont = SelectObject(hdc, hFont);
+	    UINT uFormat;
+	    RECT rcText;
+
+	    /* compute rough rectangle where the label will go */
+	    SetRectEmpty(&rcText);
+	    rcText.right = infoPtr->nItemWidth - 2;
+	    rcText.bottom = infoPtr->nItemHeight;
+	    if (uView == LVS_ICON) 
+		rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
+
+	    /* now figure out the flags */
+	    if (uView == LVS_ICON)
+		uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS;
+	    else
+		uFormat = LV_SL_DT_FLAGS;
+	    
+    	    DrawTextW (hdc, lvItem.pszText, -1, &rcText, uFormat | DT_CALCRECT);
+
+	    labelSize.cx = rcText.right - rcText.left;
+	    labelSize.cy = rcText.bottom - rcText.top;
+
+    	    SelectObject(hdc, hOldFont);
+    	    ReleaseDC(infoPtr->hwndSelf, hdc);
+	}
+
 	if (uView == LVS_ICON)
 	{
-	    INT nLabelWidth;
-
-	    Label.left = Box.left;
+	    if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
+		labelSize.cy = (labelSize.cy / infoPtr->ntmHeight) * infoPtr->ntmHeight;
+	    Label.left = Box.left + (infoPtr->iconSpacing.cx - labelSize.cx) / 2;
 	    Label.top  = Box.top + ICON_TOP_PADDING_HITABLE +
 		         infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
-
-	    nLabelWidth = LISTVIEW_GetLabelWidth(infoPtr, nItem);
-	    if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
-	    {
-		Label.left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
-		Label.right = Label.left + nLabelWidth;
-		Label.bottom = Label.top + infoPtr->ntmHeight + 1;
-		Label.bottom += HEIGHT_PADDING;
-	    }
-	    else
-	    {
-		Label.right = Label.left + infoPtr->nItemWidth;
-		Label.bottom = Label.top + infoPtr->nItemHeight + HEIGHT_PADDING;
-		LISTVIEW_UpdateLargeItemLabelRect (infoPtr, nItem, &Label);
-	    }
+	    Label.right = Label.left + labelSize.cx;
+	    Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING;
 	}
 	else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
 	{
-	    INT nLabelWidth;
-
 	    Label.left = Icon.right;
 	    Label.top = Box.top;
-	    nLabelWidth = LISTVIEW_GetLabelWidth(infoPtr, nItem);
-	    nLabelWidth += TRAILING_PADDING;
-	    if (infoPtr->himlSmall) nLabelWidth += IMAGE_PADDING;
-	    Label.right = min(Label.left + nLabelWidth, Box.right);
+	    Label.right = Label.left;
+	    if (infoPtr->himlSmall) Label.right += IMAGE_PADDING;
+	    Label.right += labelSize.cx + TRAILING_PADDING;
+	    if (Label.right > Box.right) Label.right = Box.right;
 	    Label.bottom = Label.top + infoPtr->nItemHeight;
 	}
   
@@ -3037,8 +2964,7 @@
 
     if (lvItem.iImage) FIXME("Draw the image for the subitem\n");
     
-    DrawTextW(hdc, lvItem.pszText, -1, &rcItem, 
-	      DT_SINGLELINE | DT_VCENTER | DT_WORD_ELLIPSIS | align);
+    DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | align);
 
     return TRUE;
 }
@@ -3131,8 +3057,7 @@
 	if(lprcFocus) *lprcFocus = rcItem;
 	if (lvItem.state & LVIS_SELECTED)
 	    ExtTextOutW(hdc, rcItem.left, rcItem.top, ETO_OPAQUE, &rcItem, 0, 0, 0);
-        DrawTextW(hdc, lvItem.pszText, -1, &rcItem, 
-	          DT_SINGLELINE | DT_VCENTER | DT_WORD_ELLIPSIS | DT_CENTER);
+        DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | DT_CENTER);
     }
 
     set_text_attr(hdc, &ta);
@@ -3157,7 +3082,7 @@
 {
   WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
   LVITEMW lvItem;
-  UINT uFormat = LISTVIEW_DTFLAGS;
+  UINT uFormat;
   RECT rcIcon, rcFocus, rcLabel, *lprcFocus;
 
   TRACE("(hdc=%x, nItem=%d, rcItem=%s)\n", hdc, nItem, debugrect(&rcItem));
@@ -3234,7 +3159,7 @@
    * wrapping and both word and end ellipsis.  (I don't yet know about path
    * ellipsis)
    */
-  uFormat |= lprcFocus ?  DT_NOCLIP : DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
+  uFormat = lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS;
 
   /* state icons */
   if (infoPtr->himlState != NULL)
@@ -5233,7 +5158,6 @@
     lvItem.cchTextMax = DISP_TEXT_SIZE;
     if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0;
   
-    /* FIXME: is this right? What if the label is very long? */ 
     return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
 }
 




More information about the wine-patches mailing list