In Cemu we utilize the ListCtrl to show a list of games.
However, after enabling the experimental dark mode for Windows we encountered quite a few issues. They seem to stem from the fact that the dark mode essentially forces all rendering to be done by wxWidgets instead of windows itself.
After digging, I found a number of fixes that make the dark mode render more identically to the white mode.
Scroll to the bottom of this PR description for the before/after results, and comparisons between the white and dark mode after these changes.
Previously, columns were able to overflow the next column. I made it so that the checkboxes and images can be drawn partially, like the white mode also does.
In Cemu's game list we allow the user to hide columns by setting the column width to 0, which has worked over a number of Windows versions by now. I think overflowing the next column should basically
Something to keep in mind is that dragging a column would previously temporarily shrink the overflown items.
ListView_GetSubItemRect has a bug in the code where if you query the bounds for the first column, it'll always return the bounds of the entire row instead (for example, rc.left = 0, rc.right = 1000). The code already had a partial workaround by setting rc.right to the next column's starting position.
However, this doesn't account for the fact that a user might've dragged the column with index 0 to be in the middle or end. where the left position should be more then just 0. This causes the column to always be rendered at the left, or to be completely invisible when combined with the change above.
To fix this, I've added another workaround to wxListCtrl::GetSubItemRect to accumulate the widths of the preceding, ordered columns to decide where this column (or subItem, technically), starts.
An additional fix is that checkboxes will use the column start for deciding where to draw, instead of using listctrl->FromDIP(GAP_BETWEEN_CHECKBOX_AND_TEXT); to decide the starting position. The white mode also allows you to reorder the columns so that the checkboxes are not at the start.
This is a bit of a complicated change, but it was required to replicate the native drawing.
There was already code that tried to prevent drawing the background color of a row behind any icons or checkboxes. However, it assumed that the first row was always at rc.left = 0 (which isn't the case when the columns are reordered, see the issue above) so it would just clear the entire row at once except for a bit at the start.
However, its not guaranteed that an image or checkbox isn't at the second or third row, or that the 0th column is put later in the list. Hence its required to clear each row item individually, and the code can't clear the entire row at once with, for example, the red background color thats used in the listctrl sample for just that row.
The new code still clears each row entirely too, but this is just done so that we can draw the selected effect background even behind the images. It doesn't use the red background color that's set for that row.
Windows seems to not be super strict with how and where they add gaps and distances. You'll see in the comparisons that I layered the white and dark mode with various DPI settings to get as close as possible. The new values might seem a bit arbitrary, but I've theorized that they might've just been eyeballed by a Microsoft engineer at some point for whatever looked good.
My goal isn't for it to be perfect, but the blanket 6 units that was re-added was definitely inaccurate to whatever the white mode did. It seems in general that the 0th column has some additional padding added, but only when an image is used.
All other columns with images seem to have a tiny 1 unit pixel distance before the image.
There also seems to be a slight y offset. I don't think this is bad enough to require a fix, and might be caused by the headers being slightly different sizes.
I think there's still improvements possible here, but I think this is a big step forwards. It also happens to fix a weird icon offset that Cemu suffered from. Feel free to test it on other Windows versions though.
For testing, I used the ListCtrl sample with very minor modifications for testing. For the DPI testing I changed the compatibility settings in Windows to be controlled by the Application with 400% DPI.
The testing was done on Windows 11 Pro 25H2, OS build was 26200.6899.
To induce all of the bugs listed above, enable checkboxes, drag the 0th column to the right and hover over a row.
Without this PR, it looks like this on trunk:
image.png (view on web)
After the PR, it looks like this:
Screenshot.2025-11-04.134529.png (view on web)
At 100%, it looks like this (I used imgsli to make it easier to compare between the white and dark mode):
https://imgsli.com/NDI2Mzgw
At 400% DPI, it looks like this:
https://imgsli.com/NDI2MzYy
https://github.com/wxWidgets/wxWidgets/pull/25950
(1 file)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@Crementif pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Since this is somewhat of a successor to #24424, I'm pinging @PBfordev.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Thanks for the fixes, I'll try to look at them a.s.a.p. but probably not today.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@Crementif, thanks for the work as well as heads up. TBH, I basically forgot everything about the code.
OTOH, if you are familiar with the code, perhaps you could have a look at #23846. I looked into it, even added extensive message tracking, but could not figure the fix.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
The imgsli looks nice. The only difference I notice at both DPI is the (lack of) right-padding in the 3rd, right aligned, column.
Maybe add a note to the hardcoded values that these are supposed to be used without 'FromDIP` so they won't be accidentally added in the future.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
In Cemu's game list we allow the user to hide columns by setting the column width to 0, which has worked over a number of Windows versions by now. I think overflowing the next column should basically
Something seems to be missing here?
Fixes [...]
I wonder if it's worth splitting this PR in separate commits fixing individual issues here as they seem to be rather independent. I could do it myself, but please let me know if I'm missing something and there is some hidden dependency between them.
Prevent listctrl row item to overflow beyond the column width
I'm a bit surprised you haven't decided to set up a clipping rect to fix this. Wouldn't this be more robust and, perhaps, even simpler than the changes you made?
Windows seems to not be super strict with how and where they add gaps and distances.
Thanks for the chuckle due to this nice understatement. See #25297 for an example of how unstrict (unserious?) exactly it is.
For testing, I used the ListCtrl sample with very minor modifications for testing.
Just to keep everything in one place, these modification are basically just
diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index 6cb49bcf87..d304860b66 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -1157,6 +1157,7 @@ void MyListCtrl::LogColEvent(const wxListEvent& event, const wxString& name) void MyListCtrl::OnColBeginDrag(wxListEvent& event) { LogColEvent( event, "OnColBeginDrag" ); + return; if ( event.GetColumn() == 0 ) {
(note that you can just wx_msw_dark_mode=2 in the environment to force the use of dark mode for any wx application, no need to change the code for this).
I haven't had time to actually test this yet, but I've looked at the changes and they all reasonable to me, so I plan to apply them soon, probably as a series of separate commits unless you tell me not to do it or I fail to split them.
Thanks again for all the fixes, they're definitely appreciated!
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Thanks for all the interest :)
OTOH, if you are familiar with the code, perhaps you could have a look at #23846. I looked into it, even added extensive message tracking, but could not figure the fix.
@PBfordev The hot tracking is not broken I think (well, if you mean the hover-over effect). It was previously (and with this PR still is) being cleared by the full row background clearing code. There's a comment in the code that says that the hover rectangle doesn't get drawn at all when the theme is set to DarkMode_Explorer, but at least on my windows version it does seem to show a hover effect.
I thought about also fixing the hover-over effect by listening to NM_HOVER and then drawing it manually, but I decided that since it doesn't cause a regression, its better to not balloon this PR even further.
The only difference I notice at both DPI is the (lack of) right-padding in the 3rd, right aligned, column.
@MaartenBent Yeah, I think it might be easy to address, but this I like your suggestion of making it clearer that the magic values shouldn't be changed into DPI aware.
I'm a bit surprised you haven't decided to set up a clipping rect to fix this. Wouldn't this be more robust and, perhaps, even simpler than the changes you made?
@vadz Oh, that would've probably been helpful if I had known about it, assuming its an existing type used elsewhere. Could definitely be replaced. In general, I think some of the math in that function might be unnecessary, since the rc.left < rc.right if statements should remove the need for a lot of the clamping that's done. But I didn't want to mess with it too much once I had things working and made screenshots.
I haven't had time to actually test this yet, but I've looked at the changes and they all reasonable to me, so I plan to apply them soon, probably as a series of separate commits unless you tell me not to do it or I fail to split them.
Of course, whatever works best for the project or the maintainers. I appreciate you offering to split it up into smaller commits, because it is all a bit intertwined. I do think it might be useful to mention this PR in those commits, since PBfordev's PR text and the comments were quite useful to get a look at the bigger picture and reasons behind those decisions.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
You were right, it wasn't that simple to split this into independent commits, so I finally mostly gave up and left all appearance-related changes together in the last commit of #25961. I still split out a couple of small changes, hopefully without breaking anything it — but please let me know there if I did!
Thanks again for your work on this!
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()