2626#include < uxtheme.h>
2727#include < Vsstyle.h>
2828#include < Vssym32.h>
29+ #include " FileList.h"
2930
3031namespace {
3132constexpr UINT_PTR WINDOW_SUBCLASS_ID = 0 ;
3233constexpr UINT_PTR REBAR_SUBCLASS_ID = 1 ;
3334constexpr UINT_PTR BUTTON_SUBCLASS_ID = 2 ;
3435constexpr UINT_PTR EDIT_SUBCLASS_ID = 3 ;
36+ constexpr UINT_PTR LISTVIEW_SUBCLASS_ID = 4 ;
37+ constexpr UINT_PTR HEADER_SUBCLASS_ID = 5 ;
3538
3639auto GetClassName (HWND hwnd) -> std::wstring
3740{
@@ -135,6 +138,16 @@ void ThemeRenderer::Register(HWND hwnd)
135138 else if (className == WC_EDIT) {
136139 ::SetWindowSubclass (childWindow, DefaultSubclassProc, EDIT_SUBCLASS_ID, reinterpret_cast <DWORD_PTR>(self));
137140 }
141+ else if (className == WC_LISTVIEW) {
142+ ::SetWindowSubclass (childWindow, DefaultSubclassProc, LISTVIEW_SUBCLASS_ID, reinterpret_cast <DWORD_PTR>(self));
143+ HWND hHeader = ListView_GetHeader (childWindow);
144+ if (hHeader) {
145+ ::SetWindowSubclass (hHeader, DefaultSubclassProc, HEADER_SUBCLASS_ID, reinterpret_cast <DWORD_PTR>(self));
146+ }
147+ }
148+ else if (className == WC_TREEVIEW) {
149+ ::SetWindowTheme (childWindow, self->m_isDarkMode ? L" DarkMode_Explorer" : L" Explorer" , nullptr );
150+ }
138151 return TRUE ;
139152 }, reinterpret_cast <LPARAM>(this ));
140153
@@ -164,6 +177,16 @@ void ThemeRenderer::ApplyTheme(HWND hwnd)
164177 ListView_SetTextColor (childWindow, self->m_colors .secondary );
165178 ListView_SetTextBkColor (childWindow, CLR_NONE);
166179 ::SetWindowTheme (childWindow, self->m_isDarkMode ? L" DarkMode_Explorer" : L" Explorer" , nullptr );
180+
181+ HWND hHeader = ListView_GetHeader (childWindow);
182+ if (hHeader) {
183+ ::SetWindowSubclass (hHeader, DefaultSubclassProc, HEADER_SUBCLASS_ID, reinterpret_cast <DWORD_PTR>(self));
184+ }
185+ }
186+ else if (className == WC_TREEVIEW) {
187+ TreeView_SetBkColor (childWindow, self->m_colors .secondary_bg );
188+ TreeView_SetTextColor (childWindow, self->m_colors .secondary );
189+ ::SetWindowTheme (childWindow, self->m_isDarkMode ? L" DarkMode_Explorer" : L" Explorer" , nullptr );
167190 }
168191 return TRUE ;
169192 }, reinterpret_cast <LPARAM>(this ));
@@ -181,6 +204,10 @@ LRESULT CALLBACK ThemeRenderer::DefaultSubclassProc(HWND hWnd, UINT uMsg, WPARAM
181204 return self->ButtonProc (hWnd, uMsg, wParam, lParam);
182205 case EDIT_SUBCLASS_ID:
183206 return self->EditProc (hWnd, uMsg, wParam, lParam);
207+ case LISTVIEW_SUBCLASS_ID:
208+ return self->ListViewProc (hWnd, uMsg, wParam, lParam);
209+ case HEADER_SUBCLASS_ID:
210+ return self->HeaderProc (hWnd, uMsg, wParam, lParam);
184211 default :
185212 break ;
186213 }
@@ -203,6 +230,54 @@ LRESULT ThemeRenderer::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
203230 ::SetBkColor (hdc, m_colors.secondary_bg);
204231 return (LRESULT)(HBRUSH)m_brushes.secondary_bg ;
205232 }
233+ case WM_NOTIFY: {
234+ LPNMHDR nmhdr = (LPNMHDR)lParam;
235+ if (nmhdr->code == NM_CUSTOMDRAW) {
236+ std::wstring className = GetClassName (nmhdr->hwndFrom );
237+ if (className == WC_LISTVIEW) {
238+ LPNMLVCUSTOMDRAW lpCD = (LPNMLVCUSTOMDRAW)lParam;
239+ switch (lpCD->nmcd .dwDrawStage ) {
240+ case CDDS_PREPAINT:
241+ return CDRF_NOTIFYITEMDRAW;
242+ case CDDS_ITEMPREPAINT: {
243+ auto index = static_cast <INT>(lpCD->nmcd .dwItemSpec );
244+ IListViewDataProvider* pDataProvider = reinterpret_cast <IListViewDataProvider*>(::GetWindowLongPtr (nmhdr->hwndFrom , GWLP_USERDATA));
245+
246+ if (m_isDarkMode) {
247+ lpCD->clrText = m_colors.secondary ;
248+ lpCD->clrTextBk = m_colors.secondary_bg ;
249+
250+ if (lpCD->nmcd .uItemState & CDIS_SELECTED) {
251+ lpCD->clrText = m_colors.primary ;
252+ lpCD->clrTextBk = m_colors.primary_bg ;
253+ }
254+ }
255+
256+ if (pDataProvider) {
257+ if (pDataProvider->IsFileOpen (index)) {
258+ ::SelectObject (lpCD->nmcd.hdc, pDataProvider->GetUnderlineFont ());
259+ }
260+ }
261+
262+ return CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;
263+ }
264+ case CDDS_ITEMPOSTPAINT: {
265+ auto index = static_cast <INT>(lpCD->nmcd .dwItemSpec );
266+ IListViewDataProvider* pDataProvider = reinterpret_cast <IListViewDataProvider*>(::GetWindowLongPtr (nmhdr->hwndFrom , GWLP_USERDATA));
267+ if (pDataProvider && pDataProvider->IsItemParent (index)) {
268+ RECT rc {};
269+ ListView_GetSubItemRect (nmhdr->hwndFrom , index, lpCD->iSubItem , LVIR_ICON, &rc);
270+ UINT state = ListView_GetItemState (nmhdr->hwndFrom , index, LVIS_SELECTED | LVIS_DROPHILITED);
271+ bool isSelected = ((state & LVIS_SELECTED) ? (::GetFocus () == nmhdr->hwndFrom ) : ((state & LVIS_DROPHILITED) == LVIS_DROPHILITED));
272+ ImageList_Draw (pDataProvider->GetParentImageList (), ICON_PARENT, lpCD->nmcd .hdc , rc.left , rc.top , ILD_NORMAL | (isSelected ? ILD_SELECTED : 0 ));
273+ }
274+ return CDRF_DODEFAULT;
275+ }
276+ }
277+ }
278+ }
279+ break ;
280+ }
206281 case WM_NCDESTROY:
207282 ::RemoveWindowSubclass (hWnd, DefaultSubclassProc, REBAR_SUBCLASS_ID);
208283 m_windows.erase(hWnd);
@@ -266,7 +341,88 @@ LRESULT ThemeRenderer::EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
266341 }
267342 case WM_NCDESTROY:
268343 ::RemoveWindowSubclass (hWnd, DefaultSubclassProc, EDIT_SUBCLASS_ID);
269- m_windows.erase (hWnd);
344+ break ;
345+ }
346+ return ::DefSubclassProc (hWnd, uMsg, wParam, lParam);
347+ }
348+
349+ LRESULT ThemeRenderer::ListViewProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
350+ {
351+ switch (uMsg) {
352+ case WM_NCDESTROY:
353+ ::RemoveWindowSubclass (hWnd, DefaultSubclassProc, LISTVIEW_SUBCLASS_ID);
354+ break ;
355+ }
356+ return ::DefSubclassProc (hWnd, uMsg, wParam, lParam);
357+ }
358+
359+ LRESULT ThemeRenderer::HeaderProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
360+ {
361+ switch (uMsg) {
362+ case WM_PAINT: {
363+ if (!m_isDarkMode) break ;
364+ PAINTSTRUCT ps;
365+ HDC hdc = BeginPaint (hWnd, &ps);
366+
367+ RECT rcHeader;
368+ GetClientRect (hWnd, &rcHeader);
369+
370+ // Fill background
371+ FillRect (hdc, &rcHeader, m_brushes.secondary_bg );
372+
373+ int count = Header_GetItemCount (hWnd);
374+ for (int i = 0 ; i < count; i++) {
375+ RECT rcItem;
376+ Header_GetItemRect (hWnd, i, &rcItem);
377+
378+ // Draw text
379+ WCHAR text[MAX_PATH];
380+ HDITEM hdi = { .mask = HDI_TEXT | HDI_FORMAT, .pszText = text, .cchTextMax = MAX_PATH };
381+ Header_GetItem (hWnd, i, &hdi);
382+
383+ SetTextColor (hdc, m_colors.secondary );
384+ SetBkMode (hdc, TRANSPARENT);
385+
386+ RECT rcText = rcItem;
387+ rcText.left += 6 ;
388+ DrawText (hdc, text, -1 , &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
389+
390+ // Draw sort arrow
391+ if (hdi.fmt & (HDF_SORTUP | HDF_SORTDOWN)) {
392+ HPEN hPen = CreatePen (PS_SOLID, 1 , m_colors.secondary );
393+ HPEN hOldPen = (HPEN)SelectObject (hdc, hPen);
394+
395+ int x = rcItem.right - 15 ;
396+ int y = rcItem.top + (rcItem.bottom - rcItem.top ) / 2 ;
397+
398+ if (hdi.fmt & HDF_SORTUP) {
399+ MoveToEx (hdc, x, y + 2 , nullptr );
400+ LineTo (hdc, x + 4 , y - 2 );
401+ LineTo (hdc, x + 8 , y + 2 );
402+ LineTo (hdc, x, y + 2 );
403+ } else {
404+ MoveToEx (hdc, x, y - 2 , nullptr );
405+ LineTo (hdc, x + 4 , y + 2 );
406+ LineTo (hdc, x + 8 , y - 2 );
407+ LineTo (hdc, x, y - 2 );
408+ }
409+
410+ SelectObject (hdc, hOldPen);
411+ DeleteObject (hPen);
412+ }
413+
414+ // Draw separator
415+ if (i < count - 1 ) {
416+ RECT rcSep = { rcItem.right - 1 , rcItem.top + 4 , rcItem.right , rcItem.bottom - 4 };
417+ FillRect (hdc, &rcSep, m_brushes.border );
418+ }
419+ }
420+
421+ EndPaint (hWnd, &ps);
422+ return 0 ;
423+ }
424+ case WM_NCDESTROY:
425+ ::RemoveWindowSubclass (hWnd, DefaultSubclassProc, HEADER_SUBCLASS_ID);
270426 break ;
271427 }
272428 return ::DefSubclassProc (hWnd, uMsg, wParam, lParam);
0 commit comments