From df0f236038bdfa775ee93d016b8500cd6337d9b9 Mon Sep 17 00:00:00 2001 From: Bill Medland Date: Wed, 27 Feb 2002 01:24:39 +0000 Subject: [PATCH] Centre text correctly for the selected item. Draw complete background for the selected item. Calculate the size of a large icon more correctly (including multiline labels). --- dlls/comctl32/listview.c | 93 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index 903c976e53b..7c20b43339f 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -257,6 +257,7 @@ static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMW lpLVItem); static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem); static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem); static void LISTVIEW_FillBackground(HWND hwnd, HDC hdc, LPRECT rc); +static void ListView_UpdateLargeItemLabelRect (HWND hwnd, const LISTVIEW_INFO* infoPtr, int nItem, RECT *rect); /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/ #define KEY_DELAY 450 @@ -3275,7 +3276,7 @@ static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, LVITEMW lvItem; UINT uFormat = DT_TOP | DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL ; - /* Maintain this format in line with the one in LISTVIEW_UpdateLargeItemRect*/ + /* Maintain this format in line with the one in LISTVIEW_UpdateLargeItemLabelRect*/ RECT rcTemp; TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, bottom=%d)\n", @@ -3420,8 +3421,20 @@ static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem, */ if (uFormat & DT_NOCLIP) { + RECT rcBack=rcItem; HBRUSH hBrush = CreateSolidBrush(GetBkColor (hdc)); + int dx, dy, old_wid, new_wid; DrawTextW (hdc, lvItem.pszText, -1, &rcItem, uFormat | DT_CALCRECT); + /* 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 = rcItem.right-rcItem.left; + new_wid = rcBack.right - rcBack.left; + dx = rcBack.left - rcItem.left + (new_wid-old_wid)/2; + dy = rcBack.top - rcItem.top; + OffsetRect (&rcItem, dx, dy); FillRect(hdc, &rcItem, hBrush); DeleteObject(hBrush); } @@ -5535,6 +5548,68 @@ static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, LPPOINT lpptPosition) return bResult; } +/*** + * 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. + * + * This appears to be weird, even in the Microsoft implementation. + */ + +static void ListView_UpdateLargeItemLabelRect ( + HWND hwnd, /* The window of the listview */ + const LISTVIEW_INFO *infoPtr, /* The listview itself */ + int nItem, /* The item for which we are calculating this */ + RECT *rect) /* The rectangle to be updated */ +{ + HDC hdc = GetDC (hwnd); + HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); + + if (infoPtr->bFocus && infoPtr->nFocusedItem == nItem) + { + /* 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. + */ + LVITEMW lvItem; + lvItem.mask = LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + /* We will specify INTERNAL and so will receive back a const + * pointer to the text, rather than specifying a buffer to which + * to copy it. + */ + LISTVIEW_GetItemW (hwnd, &lvItem, TRUE); + DrawTextW (hdc, lvItem.pszText, -1, rect, DT_CALCRECT | + DT_NOCLIP | DT_EDITCONTROL | DT_TOP | DT_CENTER | + DT_WORDBREAK | DT_NOPREFIX); + /* Maintain this DT_* list in line with LISTVIEW_DrawLargeItem */ + } + else + { + /* As far as I can see the text region seems to be trying to be + * "tall enough for two lines of text". Once again (comctl32.dll ver + * 5.81?) it measures this on the basis of the selected font and then + * draws it with the same font except in 10 point size. This can lead + * to more or less than the two rows appearing. + * Question; are we supposed to be including DT_EXTERNALLEADING? + * Question; should the width be shrunk to the space required to + * display the two lines? + */ + rect->bottom = rect->top + 2 * infoPtr->ntmHeight; + } + + SelectObject (hdc, hOldFont); + ReleaseDC (hwnd, hdc); +} /*** * DESCRIPTION: @@ -5557,6 +5632,12 @@ static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, LPPOINT lpptPosition) * RETURN: * SUCCESS : TRUE * FAILURE : FALSE + * + * NOTES + * Note that the bounding rectangle of the label in the LVS_ICON view depends + * upon whether the window has the focus currently and on whether the item + * is the one with the focus. Ensure that the control's record of which + * item has the focus agrees with the items' records. */ static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc) { @@ -5670,9 +5751,8 @@ static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc) { lprc->left += 1; lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1; + ListView_UpdateLargeItemLabelRect (hwnd, infoPtr, nItem, lprc); } - - lprc->bottom = lprc->top + infoPtr->ntmHeight + HEIGHT_PADDING; } } } @@ -5741,6 +5821,7 @@ static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc) { if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE) { + RECT label_rect; INT text_left, text_right, icon_left, text_pos_x; /* for style LVS_ICON bounds * left = min(icon.left, text.left) @@ -5778,7 +5859,10 @@ static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc) + infoPtr->iconSize.cy + 1 + ICON_BOTTOM_PADDING; - lprc->bottom += (infoPtr->ntmHeight + HEIGHT_PADDING); + CopyRect (&label_rect, lprc); + label_rect.top = lprc->bottom; + ListView_UpdateLargeItemLabelRect (hwnd, infoPtr, nItem, &label_rect); + UnionRect (lprc, lprc, &label_rect); } } } @@ -7243,6 +7327,7 @@ static LRESULT LISTVIEW_SetIconSpacing(HWND hwnd, DWORD spacing) if (uView == LVS_ICON) infoPtr->iconSpacing.cy = infoPtr->iconSize.cy + infoPtr->ntmHeight + ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_OFFSET; + /* FIXME. I don't think so; I think it is based on twice the ntmHeight */ else /* FIXME: unknown computation for non LVS_ICON - this is a guess */ infoPtr->iconSpacing.cy = LISTVIEW_GetItemHeight(hwnd); }