From 7265896631f1dca03bca2eaf04b203cf79376cf5 Mon Sep 17 00:00:00 2001 From: Huw Campbell Date: Sun, 22 Feb 2026 21:00:05 +1100 Subject: [PATCH] Get the basic tile view layout looking ok --- dll/win32/comctl32/listview.c | 71 +++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/dll/win32/comctl32/listview.c b/dll/win32/comctl32/listview.c index 1d372d4725c..ab8fb41b641 100644 --- a/dll/win32/comctl32/listview.c +++ b/dll/win32/comctl32/listview.c @@ -253,6 +253,11 @@ typedef struct tagLISTVIEW_INFO INT nItemHeight; INT nItemWidth; + /* tile settings */ + INT tileWidth; + INT tileHeight; + INT tileLines; + /* sorting */ PFNLVCOMPARE pfnCompare; /* sorting callback pointer */ LPARAM lParamSort; @@ -1671,6 +1676,11 @@ static INT LISTVIEW_CreateHeader(LISTVIEW_INFO *infoPtr) if (infoPtr->hwndHeader) return 0; + /* initialise tile view defaults */ + infoPtr->tileWidth = 0; /* auto-calculate */ + infoPtr->tileHeight = 0; /* auto-calculate */ + infoPtr->tileLines = 3; /* auto-calculate */ + TRACE("Creating header for list %p\n", infoPtr->hwndSelf); /* setup creation flags */ @@ -1770,7 +1780,7 @@ static inline void LISTVIEW_InvalidateSubItem(const LISTVIEW_INFO *infoPtr, INT RECT rcBox; if(!is_redrawing(infoPtr)) return; - assert (infoPtr->uView == LV_VIEW_DETAILS); + assert (infoPtr->uView == LV_VIEW_DETAILS || infoPtr->uView == LV_VIEW_TILE); LISTVIEW_GetOrigin(infoPtr, &Origin); LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox); @@ -2064,7 +2074,7 @@ static INT LISTVIEW_UpdateHScroll(LISTVIEW_INFO *infoPtr) { horzInfo.nMax = infoPtr->nItemWidth; } - else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON */ + else /* LV_VIEW_ICON, or LV_VIEW_SMALLICON or LV_VIEW_TILE */ { RECT rcView; @@ -2310,11 +2320,16 @@ static void LISTVIEW_GetItemOrigin(const LISTVIEW_INFO *infoPtr, INT nItem, LPPO lpptPosition->x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem); lpptPosition->y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem); } + else if (infoPtr->uView == LV_VIEW_TILE) { + INT nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); + lpptPosition->x = nItem % nCountPerRow * infoPtr->nItemWidth; + lpptPosition->y = nItem / nCountPerRow * infoPtr->nItemHeight; + } else if (infoPtr->uView == LV_VIEW_LIST) { INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); - lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth; - lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight; + lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth; + lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight; } else /* LV_VIEW_DETAILS */ { @@ -2380,7 +2395,7 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW 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(infoPtr->uView == LV_VIEW_DETAILS); + if (lpLVItem->iSubItem) assert(infoPtr->uView == LV_VIEW_DETAILS || infoPtr->uView == LV_VIEW_TILE); if (infoPtr->uView == LV_VIEW_ICON && (lprcBox || lprcLabel)) { assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED)); @@ -2398,10 +2413,10 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW /************************************************************/ /* compute the box rectangle (it should be cheap to do) */ /************************************************************/ - if (lpLVItem->iSubItem || infoPtr->uView == LV_VIEW_DETAILS) + if (infoPtr->uView == LV_VIEW_DETAILS) lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem); - if (lpLVItem->iSubItem) + if (lpLVItem->iSubItem && infoPtr->uView == LV_VIEW_DETAILS) { Box = lpColumnInfo->rcHeader; } @@ -2437,6 +2452,18 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW Icon.bottom += infoPtr->iconSize.cy; } } + else if (infoPtr->uView == LV_VIEW_TILE) + { + Icon.left = Box.left + state_width; + Icon.top = Box.top; + Icon.right = Icon.left; + Icon.bottom = Icon.top; + if (infoPtr->himlNormal) + { + Icon.right += infoPtr->iconSize.cx; + Icon.bottom += infoPtr->iconSize.cy; + } + } else /* LV_VIEW_SMALLICON, LV_VIEW_LIST or LV_VIEW_DETAILS */ { Icon.left = Box.left + state_width; @@ -2488,7 +2515,8 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW } } - if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && infoPtr->uView == LV_VIEW_DETAILS)) + /* for details mode we can use the column size for the label size. */ + if ((lpLVItem->iSubItem || (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)) && infoPtr->uView == LV_VIEW_DETAILS) { labelSize.cx = infoPtr->nItemWidth; labelSize.cy = infoPtr->nItemHeight; @@ -2546,6 +2574,13 @@ calc_label: } Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING; } + else if (infoPtr->uView == LV_VIEW_TILE) + { + Label.left = Icon.right; + Label.top = Box.top; + Label.right = Label.left + labelSize.cx; + Label.bottom = Box.bottom; + } else if (infoPtr->uView == LV_VIEW_DETAILS) { Label.left = Icon.right; @@ -2935,6 +2970,7 @@ static void LISTVIEW_GetAreaRect(const LISTVIEW_INFO *infoPtr, LPRECT lprcView) { case LV_VIEW_ICON: case LV_VIEW_SMALLICON: + case LV_VIEW_TILE: for (i = 0; i < infoPtr->nItemCount; i++) { x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, i); @@ -3053,6 +3089,12 @@ static INT LISTVIEW_CalculateItemWidth(const LISTVIEW_INFO *infoPtr) nItemWidth = rcHeader.right; } } + else if (infoPtr->uView == LV_VIEW_TILE) { + if (infoPtr->tileWidth > 0) + nItemWidth = infoPtr->tileWidth; + else + nItemWidth = infoPtr->iconSize.cx + ICON_LR_PADDING * 2 + 200; + } else /* LV_VIEW_SMALLICON, or LV_VIEW_LIST */ { WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; @@ -3099,6 +3141,10 @@ static INT LISTVIEW_CalculateItemHeight(const LISTVIEW_INFO *infoPtr) if (infoPtr->uView == LV_VIEW_ICON) nItemHeight = infoPtr->iconSpacing.cy; + else if (infoPtr->uView == LV_VIEW_TILE) { + // TODO, think about the line heights? + nItemHeight = infoPtr->iconSize.cy; + } else { nItemHeight = infoPtr->ntmHeight; @@ -4769,7 +4815,7 @@ static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const N } /* item icons */ - himl = (infoPtr->uView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); + himl = ((infoPtr->uView == LV_VIEW_ICON || infoPtr->uView == LV_VIEW_TILE) ? infoPtr->himlNormal : infoPtr->himlSmall); if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon)) { UINT style; @@ -9343,12 +9389,14 @@ static BOOL LISTVIEW_SetUnicodeFormat( LISTVIEW_INFO *infoPtr, BOOL unicode) static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView) { HIMAGELIST himl; + BOOL newIsSmall; if (infoPtr->uView == nView) return 1; if ((INT)nView < 0 || nView > LV_VIEW_MAX) return -1; infoPtr->uView = nView; + newIsSmall = nView != LV_VIEW_ICON && nView != LV_VIEW_TILE; SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); ShowWindow(infoPtr->hwndHeader, SW_HIDE); @@ -9356,8 +9404,8 @@ static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView) ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE); SetRectEmpty(&infoPtr->rcFocus); - himl = (nView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); - set_icon_size(&infoPtr->iconSize, himl, nView != LV_VIEW_ICON); + himl = newIsSmall ? infoPtr->himlSmall : infoPtr->himlNormal; + set_icon_size(&infoPtr->iconSize, himl, newIsSmall); LISTVIEW_UpdateItemSize(infoPtr); switch (nView) @@ -9380,6 +9428,7 @@ static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView) wp.flags | ((infoPtr->dwStyle & LVS_NOCOLUMNHEADER) ? SWP_HIDEWINDOW : SWP_SHOWWINDOW)); break; } + case LV_VIEW_TILE: case LV_VIEW_LIST: break; } -- 2.51.2