#include "stdafx.h" #include "CListCtrl_Sortable.h" #include "Resource.h" #include BEGIN_MESSAGE_MAP(CListCtrl_Sortable, CListCtrl) ON_NOTIFY_REFLECT_EX(LVN_COLUMNCLICK, OnHeaderClick) // Column Click END_MESSAGE_MAP() namespace { bool IsThemeEnabled() { HMODULE hinstDll; bool XPStyle = false; bool (__stdcall *pIsAppThemed)(); bool (__stdcall *pIsThemeActive)(); // Test if operating system has themes enabled hinstDll = ::LoadLibrary(_T("UxTheme.dll")); if (hinstDll) { (FARPROC&)pIsAppThemed = ::GetProcAddress(hinstDll, "IsAppThemed"); (FARPROC&)pIsThemeActive = ::GetProcAddress(hinstDll,"IsThemeActive"); ::FreeLibrary(hinstDll); if (pIsAppThemed != NULL && pIsThemeActive != NULL) { if (pIsAppThemed() && pIsThemeActive()) { // Test if application has themes enabled by loading the proper DLL hinstDll = LoadLibrary(_T("comctl32.dll")); if (hinstDll) { DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hinstDll, "DllGetVersion"); ::FreeLibrary(hinstDll); if (pDllGetVersion != NULL) { DLLVERSIONINFO dvi; ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); HRESULT hRes = pDllGetVersion ((DLLVERSIONINFO *) &dvi); if (SUCCEEDED(hRes)) XPStyle = dvi.dwMajorVersion >= 6; } } } } } return XPStyle; } LRESULT EnableWindowTheme(HWND hwnd, LPCWSTR app, LPCWSTR idlist) { HMODULE hinstDll; HRESULT (__stdcall *pSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); HANDLE (__stdcall *pOpenThemeData)(HWND hwnd, LPCWSTR pszClassList); HRESULT (__stdcall *pCloseThemeData)(HANDLE hTheme); hinstDll = ::LoadLibrary(_T("UxTheme.dll")); if (hinstDll) { (FARPROC&)pOpenThemeData = ::GetProcAddress(hinstDll, "OpenThemeData"); (FARPROC&)pCloseThemeData = ::GetProcAddress(hinstDll, "CloseThemeData"); (FARPROC&)pSetWindowTheme = ::GetProcAddress(hinstDll, "SetWindowTheme"); ::FreeLibrary(hinstDll); if (pSetWindowTheme && pOpenThemeData && pCloseThemeData) { HANDLE theme = pOpenThemeData(hwnd,L"ListView"); if (theme!=NULL) { VERIFY(pCloseThemeData(theme)==S_OK); return pSetWindowTheme(hwnd, app, idlist); } } } return S_FALSE; } } BOOL CListCtrl_Sortable::OnHeaderClick(NMHDR* pNMHDR, LRESULT* pResult) { NMLISTVIEW* pLV = reinterpret_cast(pNMHDR); SetFocus(); // Ensure other controls gets kill-focus int colIndex = pLV->iSubItem; if (m_SortCol==colIndex) { m_Ascending = !m_Ascending; } else { m_SortCol = colIndex; m_Ascending = true; } if (SortColumn(m_SortCol, m_Ascending)) SetSortArrow(m_SortCol, m_Ascending); return FALSE; // Let parent-dialog get chance } void CListCtrl_Sortable::SetSortArrow(int colIndex, bool ascending) { if (IsThemeEnabled()) { #if (_WIN32_WINNT >= 0x501) for(int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i) { HDITEM hditem = {0}; hditem.mask = HDI_FORMAT; VERIFY( GetHeaderCtrl()->GetItem( i, &hditem ) ); hditem.fmt &= ~(HDF_SORTDOWN|HDF_SORTUP); if (i == colIndex) { hditem.fmt |= ascending ? HDF_SORTUP : HDF_SORTDOWN; } VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) ); } #endif } else { UINT bitmapID = m_Ascending ? IDB_UPARROW : IDB_DOWNARROW; for(int i = 0; i < GetHeaderCtrl()->GetItemCount(); ++i) { HDITEM hditem = {0}; hditem.mask = HDI_BITMAP | HDI_FORMAT; VERIFY( GetHeaderCtrl()->GetItem( i, &hditem ) ); if (hditem.fmt & HDF_BITMAP && hditem.fmt & HDF_BITMAP_ON_RIGHT) { if (hditem.hbm) { DeleteObject(hditem.hbm); hditem.hbm = NULL; } hditem.fmt &= ~(HDF_BITMAP|HDF_BITMAP_ON_RIGHT); VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) ); } if (i == colIndex) { hditem.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT; hditem.hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(bitmapID), IMAGE_BITMAP, 0,0, LR_LOADMAP3DCOLORS); VERIFY( hditem.hbm!=NULL ); VERIFY( CListCtrl::GetHeaderCtrl()->SetItem( i, &hditem ) ); } } } } void CListCtrl_Sortable::PreSubclassWindow() { CListCtrl::PreSubclassWindow(); // Focus retangle is not painted properly without double-buffering #if (_WIN32_WINNT >= 0x501) SetExtendedStyle(LVS_EX_DOUBLEBUFFER | GetExtendedStyle()); #endif SetExtendedStyle(GetExtendedStyle() | LVS_EX_FULLROWSELECT); SetExtendedStyle(GetExtendedStyle() | LVS_EX_HEADERDRAGDROP); EnableWindowTheme(GetSafeHwnd(), L"Explorer", NULL); } void CListCtrl_Sortable::ResetSortOrder() { m_Ascending = true; m_SortCol = -1; SetSortArrow(m_SortCol, m_Ascending); } // The column version of GetItemData(), one can specify an unique // identifier when using InsertColumn() int CListCtrl_Sortable::GetColumnData(int col) const { LVCOLUMN lvc = {0}; lvc.mask = LVCF_SUBITEM; VERIFY( GetColumn(col, &lvc) ); return lvc.iSubItem; } void CListCtrl_Sortable::SetSortColumn(int columnIndex, bool ascending) { m_SortCol = columnIndex; m_Ascending = ascending; if (SortColumn(m_SortCol, m_Ascending)) { SetSortArrow(m_SortCol, m_Ascending); } }