+// ----------------------------------------------------------------------------
+// custom draw stuff
+// ----------------------------------------------------------------------------
+
+// see comment at the end of wxListCtrl::GetColumn()
+#ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300
+
+static RECT GetCustomDrawnItemRect(const NMCUSTOMDRAW& nmcd)
+{
+ RECT rc;
+ wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_BOUNDS, rc);
+
+ RECT rcIcon;
+ wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_ICON, rcIcon);
+
+ // exclude the icon part, neither the selection background nor focus rect
+ // should cover it
+ rc.left = rcIcon.right;
+
+ return rc;
+}
+
+static
+bool HandleSubItemPrepaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont, int colCount)
+{
+ NMCUSTOMDRAW& nmcd = pLVCD->nmcd;
+
+ HDC hdc = nmcd.hdc;
+ HWND hwndList = nmcd.hdr.hwndFrom;
+ const int col = pLVCD->iSubItem;
+ const DWORD item = nmcd.dwItemSpec;
+
+ // the font must be valid, otherwise we wouldn't be painting the item at all
+ SelectInHDC selFont(hdc, hfont);
+
+ // get the rectangle to paint
+ int subitem = colCount ? col + 1 : col;
+ RECT rc;
+ wxGetListCtrlSubItemRect(hwndList, item, subitem, LVIR_BOUNDS, rc);
+ rc.left += 6;
+
+ // get the image and text to draw
+ wxChar text[512];
+ LV_ITEM it;
+ wxZeroMemory(it);
+ it.mask = LVIF_TEXT | LVIF_IMAGE;
+ it.iItem = item;
+ it.iSubItem = col;
+ it.pszText = text;
+ it.cchTextMax = WXSIZEOF(text);
+ ListView_GetItem(hwndList, &it);
+
+ HIMAGELIST himl = ListView_GetImageList(hwndList, LVSIL_SMALL);
+ if ( himl && ImageList_GetImageCount(himl) )
+ {
+ if ( it.iImage != -1 )
+ {
+ ImageList_Draw(himl, it.iImage, hdc, rc.left, rc.top,
+ nmcd.uItemState & CDIS_SELECTED ? ILD_SELECTED
+ : ILD_TRANSPARENT);
+ }
+
+ // notice that even if this item doesn't have any image, the list
+ // control still leaves space for the image in the first column if the
+ // image list is not empty (presumably so that items with and without
+ // images align?)
+ if ( it.iImage != -1 || it.iSubItem == 0 )
+ {
+ int wImage, hImage;
+ ImageList_GetIconSize(himl, &wImage, &hImage);
+
+ rc.left += wImage + 2;
+ }
+ }
+
+ ::SetBkMode(hdc, TRANSPARENT);
+
+ UINT fmt = DT_SINGLELINE |
+#ifndef __WXWINCE__
+ DT_WORD_ELLIPSIS |
+#endif // __WXWINCE__
+ DT_NOPREFIX |
+ DT_VCENTER;
+
+ LV_COLUMN lvCol;
+ wxZeroMemory(lvCol);
+ lvCol.mask = LVCF_FMT;
+ if ( ListView_GetColumn(hwndList, col, &lvCol) )
+ {
+ switch ( lvCol.fmt & LVCFMT_JUSTIFYMASK )
+ {
+ case LVCFMT_LEFT:
+ fmt |= DT_LEFT;
+ break;
+
+ case LVCFMT_CENTER:
+ fmt |= DT_CENTER;
+ break;
+
+ case LVCFMT_RIGHT:
+ fmt |= DT_RIGHT;
+ break;
+ }
+ }
+ //else: failed to get alignment, assume it's DT_LEFT (default)
+
+ DrawText(hdc, text, -1, &rc, fmt);
+
+ return true;
+}
+
+static void HandleItemPostpaint(NMCUSTOMDRAW nmcd)
+{
+ if ( nmcd.uItemState & CDIS_FOCUS )
+ {
+ RECT rc = GetCustomDrawnItemRect(nmcd);
+
+ // don't use the provided HDC, it's in some strange state by now
+ ::DrawFocusRect(WindowHDC(nmcd.hdr.hwndFrom), &rc);
+ }
+}
+
+// pLVCD->clrText and clrTextBk should contain the colours to use
+static void HandleItemPaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont)
+{
+ NMCUSTOMDRAW& nmcd = pLVCD->nmcd; // just a shortcut
+
+ const HWND hwndList = nmcd.hdr.hwndFrom;
+ const int item = nmcd.dwItemSpec;
+
+ // unfortunately we can't trust CDIS_SELECTED, it is often set even when
+ // the item is not at all selected for some reason (comctl32 6), but we
+ // also can't always trust ListView_GetItem() as it could return the old
+ // item status if we're called just after the (de)selection, so remember
+ // the last item to gain selection and also check for it here
+ for ( int i = -1;; )
+ {
+ i = ListView_GetNextItem(hwndList, i, LVNI_SELECTED);
+ if ( i == -1 )
+ {
+ nmcd.uItemState &= ~CDIS_SELECTED;
+ break;
+ }
+
+ if ( i == item )
+ {
+ nmcd.uItemState |= CDIS_SELECTED;
+ break;
+ }
+ }
+
+ // same thing for CDIS_FOCUS (except simpler as there is only one of them)
+ //
+ // NB: cast is needed to work around the bug in mingw32 headers which don't
+ // have it inside ListView_GetNextItem() itself (unlike SDK ones)
+ if ( ::GetFocus() == hwndList &&
+ ListView_GetNextItem(
+ hwndList, static_cast<WPARAM>(-1), LVNI_FOCUSED) == item )
+ {
+ nmcd.uItemState |= CDIS_FOCUS;
+ }
+ else
+ {
+ nmcd.uItemState &= ~CDIS_FOCUS;
+ }
+
+ if ( nmcd.uItemState & CDIS_SELECTED )
+ {
+ int syscolFg, syscolBg;
+ if ( ::GetFocus() == hwndList )
+ {
+ syscolFg = COLOR_HIGHLIGHTTEXT;
+ syscolBg = COLOR_HIGHLIGHT;
+ }
+ else // selected but unfocused
+ {
+ syscolFg = COLOR_WINDOWTEXT;
+ syscolBg = COLOR_BTNFACE;
+
+ // don't grey out the icon in this case neither
+ nmcd.uItemState &= ~CDIS_SELECTED;
+ }
+
+ pLVCD->clrText = ::GetSysColor(syscolFg);
+ pLVCD->clrTextBk = ::GetSysColor(syscolBg);
+ }
+ //else: not selected, use normal colours from pLVCD
+
+ HDC hdc = nmcd.hdc;
+ RECT rc = GetCustomDrawnItemRect(nmcd);
+
+ ::SetTextColor(hdc, pLVCD->clrText);
+ ::FillRect(hdc, &rc, AutoHBRUSH(pLVCD->clrTextBk));
+
+ // we could use CDRF_NOTIFYSUBITEMDRAW here but it results in weird repaint
+ // problems so just draw everything except the focus rect from here instead
+ const int colCount = Header_GetItemCount(ListView_GetHeader(hwndList));
+ for ( int col = 0; col < colCount; col++ )
+ {
+ pLVCD->iSubItem = col;
+ HandleSubItemPrepaint(pLVCD, hfont, colCount);
+ }
+
+ HandleItemPostpaint(nmcd);
+}
+
+static WXLPARAM HandleItemPrepaint(wxListCtrl *listctrl,
+ LPNMLVCUSTOMDRAW pLVCD,
+ wxListItemAttr *attr)
+{
+ if ( !attr )
+ {
+ // nothing to do for this item
+ return CDRF_DODEFAULT;
+ }
+
+
+ // set the colours to use for text drawing
+ pLVCD->clrText = attr->HasTextColour()
+ ? wxColourToRGB(attr->GetTextColour())
+ : wxColourToRGB(listctrl->GetTextColour());
+ pLVCD->clrTextBk = attr->HasBackgroundColour()
+ ? wxColourToRGB(attr->GetBackgroundColour())
+ : wxColourToRGB(listctrl->GetBackgroundColour());
+
+ // select the font if non default one is specified
+ if ( attr->HasFont() )
+ {
+ wxFont font = attr->GetFont();
+ if ( font.GetEncoding() != wxFONTENCODING_SYSTEM )
+ {
+ // the standard control ignores the font encoding/charset, at least
+ // with recent comctl32.dll versions (5 and 6, it uses to work with
+ // 4.something) so we have to draw the item entirely ourselves in
+ // this case
+ HandleItemPaint(pLVCD, GetHfontOf(font));
+ return CDRF_SKIPDEFAULT;
+ }
+
+ ::SelectObject(pLVCD->nmcd.hdc, GetHfontOf(font));
+
+ return CDRF_NEWFONT;
+ }
+
+ return CDRF_DODEFAULT;
+}