From 8d661b6bf8e2adc1a73fb2489f0689cdfaa52a66 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Tue, 3 May 2016 21:55:55 +0400 Subject: [PATCH 1/4] Clarify and change a drawing fix for wxMSW ListCtrl with wxLC_VRULES Since 9eaba6927648cf2989a3fddf4a5e2deea1d62708 a fix was added for leaving behind trailing pixels when resizing a column in a ListCtrl that uses wxLC_VRULES. This fix is only needed for ComCtl32.dll versions prior to 6.0. Make the fix conditional and explain the (rare) conditions under which the problem still occurs. Also see #747. --- src/msw/listctrl.cpp | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b699719fcc..b590ebce93 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -3098,16 +3098,42 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) if (GetItemRect(itemCount - 1, itemRect)) { - // this is a fix for bug 673394: erase the pixels which we would - // otherwise leave on the screen - static const int gap = 2; - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(GetBackgroundColour())); - dc.DrawRectangle(0, firstItemRect.GetY() - gap, - clientSize.GetWidth(), gap); + /* + This is a fix for ticket #747: erase the pixels which we would + otherwise leave on the screen. - dc.SetPen(pen); - dc.SetBrush(*wxTRANSPARENT_BRUSH); + The drawing of the rectangle as a fix to erase trailing pixels + when resizing a column is only needed for ComCtl32 prior to + 6.0, i.e. when not using a manifest in which case 5.82 is + used. And even then it only happens when "Show window contents + while dragging" is enabled under Windows, resulting in live + updates when resizing columns. Note that even with that setting + on, at least under Windows 7 and 10 no live updating is done when + using ComCtl32 5.82. + + Revision b66c3a67519caa9debfd76e6d74954eaebfa56d9 made this fix + almost redundant, except that when you do NOT handle + EVT_LIST_COL_DRAGGING (or do and skip the event) the trailing + pixels still appear. In case of wanting to reproduce the problem + in the listctrl sample: comment out handling oF + EVT_LIST_COL_DRAGGING and also set useDrawFix to false and gap to + 2 (not 0). + */ + + static const bool useDrawFix = wxApp::GetComCtl32Version() < 600; + + static const int gap = useDrawFix ? 2 : 0; + + if (useDrawFix) + { + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(wxBrush(GetBackgroundColour())); + dc.DrawRectangle(0, firstItemRect.GetY() - gap, + clientSize.GetWidth(), gap); + + dc.SetPen(pen); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + } const int numCols = GetColumnCount(); wxVector indexArray(numCols); From 761f05c6494562f9941cdd84614cd587709ad338 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Wed, 4 May 2016 02:47:56 +0400 Subject: [PATCH 2/4] Improve wxMSW ListCtrl drawing of horizontal rules Appending an item in the listctrl sample results in two horizontal lines drawn next to each other while they should be overlapping. Fix by drawing only the bottom line of each item instead of skipping the first one (should have been the top visible item since 6443de026310552cacd68a6d0318e73d14929680) and drawing the last one in the list (should have been bottom visible item). --- src/msw/listctrl.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b590ebce93..4355256ce2 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -3071,22 +3071,13 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) if (drawHRules) { const long top = GetTopItem(); - for ( int i = top; i < top + GetCountPerPage() + 1; i++ ) + const long bottom = wxMin(top + GetCountPerPage(), itemCount - 1); + for ( long i = top; i <= bottom; i++ ) { if (GetItemRect(i, itemRect)) { - int cy = itemRect.GetTop(); - if (i != 0) // Don't draw the first one - { - dc.DrawLine(0, cy, clientSize.x, cy); - } - // Draw last line - if (i == itemCount - 1) - { - cy = itemRect.GetBottom(); - dc.DrawLine(0, cy, clientSize.x, cy); - break; - } + const int cy = itemRect.GetBottom(); + dc.DrawLine(0, cy, clientSize.x, cy); } } } From d382107ea240010de96e5780b017738f89ac3439 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Wed, 4 May 2016 03:13:43 +0400 Subject: [PATCH 3/4] Slightly improve wxMSW ListCtrl drawing of vertical rules Draw the vertical rules with Y coordinates related to the top and bottom visible item which makes more sense than using the first and last item. --- src/msw/listctrl.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 4355256ce2..59f70aa200 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -3066,12 +3066,20 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) dc.SetBrush(* wxTRANSPARENT_BRUSH); wxSize clientSize = GetClientSize(); - wxRect itemRect; + + const int countPerPage = GetCountPerPage(); + if (countPerPage < 0) + { + // Can be -1 in which case it's useless to try to draw rules. + return; + } + + const long top = GetTopItem(); + const long bottom = wxMin(top + countPerPage, itemCount - 1); if (drawHRules) { - const long top = GetTopItem(); - const long bottom = wxMin(top + GetCountPerPage(), itemCount - 1); + wxRect itemRect; for ( long i = top; i <= bottom; i++ ) { if (GetItemRect(i, itemRect)) @@ -3084,10 +3092,10 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) if (drawVRules) { - wxRect firstItemRect; - GetItemRect(0, firstItemRect); + wxRect topItemRect, bottomItemRect; + GetItemRect(top, topItemRect); - if (GetItemRect(itemCount - 1, itemRect)) + if (GetItemRect(bottom, bottomItemRect)) { /* This is a fix for ticket #747: erase the pixels which we would @@ -3119,7 +3127,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) { dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(GetBackgroundColour())); - dc.DrawRectangle(0, firstItemRect.GetY() - gap, + dc.DrawRectangle(0, topItemRect.GetY() - gap, clientSize.GetWidth(), gap); dc.SetPen(pen); @@ -3136,13 +3144,13 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) return; } - int x = itemRect.GetX(); + int x = bottomItemRect.GetX(); for (int col = 0; col < numCols; col++) { int colWidth = GetColumnWidth(indexArray[col]); x += colWidth ; - dc.DrawLine(x-1, firstItemRect.GetY() - gap, - x-1, itemRect.GetBottom()); + dc.DrawLine(x-1, topItemRect.GetY() - gap, + x-1, bottomItemRect.GetBottom()); } } } From 374db28747a90bdced3ad05005e5d5ef406cbc18 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Wed, 4 May 2016 11:19:21 +0400 Subject: [PATCH 4/4] Fix wxMSW ListCtrl drawing of horizontal rules for new items When adding a new item to a wxMSW ListCtrl that uses horizontal rules the painting is horizontally clipped to the left of the control and the rightmost column and the rule doesn't extend beyond that as it does when doing a full repaint. Fix by refreshing the part to the right of the rightmost column. This also reverts 02c8973a575d14a66898533293ab58dd30447616 which became unnecessary now. Also see #17158. --- src/msw/listctrl.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 59f70aa200..3f38b4713b 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -709,15 +709,7 @@ bool wxListCtrl::SetColumnWidth(int col, int width) else if ( width == wxLIST_AUTOSIZE_USEHEADER) width = LVSCW_AUTOSIZE_USEHEADER; - if ( !ListView_SetColumnWidth(GetHwnd(), col, width) ) - return false; - - // Failure to explicitly refresh the control with horizontal rules results - // in corrupted rules display. - if ( HasFlag(wxLC_HRULES) ) - Refresh(); - - return true; + return ListView_SetColumnWidth(GetHwnd(), col, width) != 0; } // ---------------------------------------------------------------------------- @@ -3077,6 +3069,9 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) const long top = GetTopItem(); const long bottom = wxMin(top + countPerPage, itemCount - 1); + wxRect clipRect; + dc.GetClippingBox(clipRect); + if (drawHRules) { wxRect itemRect; @@ -3085,9 +3080,24 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) if (GetItemRect(i, itemRect)) { const int cy = itemRect.GetBottom(); - dc.DrawLine(0, cy, clientSize.x, cy); + dc.DrawLine(clipRect.x, cy, clipRect.GetRight() + 1, cy); } } + + /* + The drawing can be clipped horizontally to the rightmost column. This + happens when an item is added (and visible) and results in a + horizontal rule being clipped instead of drawn across the entire list + control. In that case we request for the part to the right of the + rightmost column to be drawn as well. + */ + if ( clipRect.GetRight() != clientSize.GetWidth() - 1 + && clipRect.width) + { + RefreshRect(wxRect(clipRect.GetRight(), clipRect.y, + clientSize.x - clipRect.width, clipRect.height), + false /* erase background? */); + } } if (drawVRules)