Skip to content

fix(gui): scale main-toolbar icons on hi-DPI displays - #294

Merged
got3nks merged 3 commits into
amule-org:masterfrom
Zeyckler:fix/toolbar-hidpi-icons
Jul 4, 2026
Merged

fix(gui): scale main-toolbar icons on hi-DPI displays#294
got3nks merged 3 commits into
amule-org:masterfrom
Zeyckler:fix/toolbar-hidpi-icons

Conversation

@Zeyckler

@Zeyckler Zeyckler commented Jul 4, 2026

Copy link
Copy Markdown

Summary

The main-toolbar icons (Downloads, Shared Files, Networks, etc.) render tiny and blurry on hi-DPI screens (e.g. 4K at 150–200% scaling). They are stored in a fixed 32x32 wxImageList and handed to wxToolBar as plain wxBitmaps, and since the executable declares PerMonitorV2 DPI awareness (#780) they get drawn at 32 physical pixels while the rest of the UI scales.

This PR stores each toolbar icon as a wxBitmapBundle (available since wx 3.2, the project minimum):

  • m_tblist becomes a std::vector<wxBitmapBundle>; AddTool / SetToolNormalBitmap receive bundles, so the toolbar picks a correctly sized bitmap per monitor DPI.
  • Each bundle is built from the original 32px art plus a wxIMAGE_QUALITY_HIGH 2x upscale. The transparency mask is converted to an alpha channel before scaling, otherwise the smooth scaler smears the mask colour into the icon edges (halos). Works for both built-in art and skin PNGs.
  • The hard-coded SetToolBitmapSize(32, 32) is dropped so the toolbar derives the logical size from the bundles and scales it with the monitor's DPI.
  • SetMessagesTool gains a bounds guard: m_CurrentBlinkBitmap starts as a stale sentinel (24) that the old wxImageList::GetBitmap tolerated (returned wxNullBitmap) but vector indexing must not reach.

Since the source art only exists at 32px, the result is a correctly sized, smoothly scaled icon rather than a pixel-perfect one — redrawing the icons as SVG (wxBitmapBundle::FromSVG) can layer on top of this later, as can the same treatment for the client-status / tab / flag image lists.

Test plan

  • clang-format 18 passes on both touched files (matches the CI gate).
  • Code verified against the wx 3.2 API (AddTool, SetToolNormalBitmap and wxToolBarToolBase::SetNormalBitmap all take wxBitmapBundle since 3.2).
  • No local wxWidgets toolchain was available to build; relying on CI builds for compile verification. Visual check on a scaled display (toolbar icons sized correctly at 150/200%, connect-state and message-blink icon swaps still working) would be appreciated.

🤖 Generated with Claude Code

Carlos Barrero and others added 3 commits July 4, 2026 13:00
The toolbar icons (Downloads, Shared Files, etc.) were stored in a
fixed 32x32 wxImageList and handed to wxToolBar as plain wxBitmaps.
Since the executable declares PerMonitorV2 DPI awareness (amule-org#780), those
bitmaps are drawn at 32 *physical* pixels, so on 4K / scaled displays
the icons render tiny and blurry while the rest of the UI scales.

Store each toolbar icon as a wxBitmapBundle instead (wx >= 3.2),
built from the original 32px art plus a wxIMAGE_QUALITY_HIGH 2x
upscale, converting the transparency mask to an alpha channel first
so the scaler doesn't smear the mask colour into the icon edges.
Drop the hard-coded SetToolBitmapSize(32,32) so the toolbar derives
the logical size from the bundles and scales it per monitor DPI.

SetMessagesTool gains a bounds guard because m_CurrentBlinkBitmap
starts as a stale sentinel (24) that the old wxImageList::GetBitmap
tolerated but vector indexing must not.

Co-Authored-By: Claude Fable 5 <[email protected]>
Code-review follow-ups to the wxBitmapBundle toolbar change:

- Add ToolbarSkinEnum (mirroring ClientSkinEnum) so the m_tblist
  indexes duplicated across Apply_Toolbar_Skin, ShowConnectionState,
  OnGUITimer and the constructor are named instead of magic numbers
  whose meaning depends on the Add_Skin_Icon call order.
- Initialize m_CurrentBlinkBitmap to Toolbar_Messages instead of the
  stale sentinel 24 (a fossil amuleDlgImages() resource id, never a
  valid m_tblist index) and drop the SetMessagesTool bounds guard that
  existed only to defend against it; both callers assign a valid index
  right before calling, so behavior is identical.
- Remove the #ifdef __WXCOCOA__ branches in ShowConnectionState and
  SetMessagesTool: the old wxCocoa port was removed from wxWidgets
  before the 3.2 minimum this project requires (modern macOS defines
  __WXOSX_COCOA__), so those lines could never compile again.
- Use the two-bitmap wxBitmapBundle::FromBitmaps overload instead of
  building a wxVector by hand.

Co-Authored-By: Claude Fable 5 <[email protected]>
Fixes the clang-tidy Tier-2 modernize-use-emplace warning on the
wxBitmapBundle fallback path in Add_Skin_Icon.

Co-Authored-By: Claude Fable 5 <[email protected]>
@got3nks

got3nks commented Jul 4, 2026

Copy link
Copy Markdown

Thanks for the contribution, @Zeyckler — clean, well-scoped patch.

Verified locally on all three platforms:

  • Windows 11 ARM64 at 150% and 200% display scaling: toolbar icons now scale with the rest of the UI as expected (bug is visibly gone). Connect / Disconnect / Connecting swap keeps working under scaling.
  • macOS 15 ARM64 (wxOSX Cocoa 3.3.2): built clean, toolbar renders correctly, and the #ifdef __WXCOCOA__ removal doesn't regress fix(ec): avoid GCC -O3 -Wfree-nonheap-object false positive in BuildTranscript #800 — the connect-state icon swap repaints atomically as before.
  • Ubuntu 26.04 ARM64 (wxGTK 3.2): built clean, no visible change (as expected, since wxGTK's own scale-factor was already handling the toolbar pixmaps).

The Messages blink path wasn't exercised in these runs; the vector-index fix (m_CurrentBlinkBitmap(Toolbar_Messages) init and the m_tblist[m_CurrentBlinkBitmap] bounds change) is code-verified but not visually confirmed. Since the state machine is unchanged in structure and the init value moves from an out-of-range sentinel to a valid one, I'm reasonably confident.

Applies to both the monolithic amule and amulegui since amuleDlg.cpp lives in GUI_SOURCES and both targets link it.

Merging once CI is green.

@got3nks
got3nks merged commit 0db667e into amule-org:master Jul 4, 2026
12 checks passed
got3nks pushed a commit that referenced this pull request Jul 5, 2026
The preferences dialog's page list (General, Connection, Directories,
etc.) fed 16x16 bitmaps into a fixed-size wxImageList, so on
DPI-aware builds the icons render at 16 physical pixels — tiny and
blurry on hi-DPI screens, same problem as the main toolbar (#294).

Hand the icons to the list control as wxBitmapBundles instead
(wxListCtrl::SetSmallImages, wx >= 3.2), each built from the 16px art
plus a wxIMAGE_QUALITY_HIGH 2x upscale with the mask converted to an
alpha channel first. The macOS-only right/bottom padding is applied
per resolution so the padded canvas keeps its proportions at 2x.

Co-authored-by: Carlos Barrero <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
Cflsft pushed a commit to Cflsft/amule that referenced this pull request Jul 6, 2026
* fix(gui): scale main-toolbar icons on hi-DPI displays

The toolbar icons (Downloads, Shared Files, etc.) were stored in a
fixed 32x32 wxImageList and handed to wxToolBar as plain wxBitmaps.
Since the executable declares PerMonitorV2 DPI awareness (amule-org#780), those
bitmaps are drawn at 32 *physical* pixels, so on 4K / scaled displays
the icons render tiny and blurry while the rest of the UI scales.

Store each toolbar icon as a wxBitmapBundle instead (wx >= 3.2),
built from the original 32px art plus a wxIMAGE_QUALITY_HIGH 2x
upscale, converting the transparency mask to an alpha channel first
so the scaler doesn't smear the mask colour into the icon edges.
Drop the hard-coded SetToolBitmapSize(32,32) so the toolbar derives
the logical size from the bundles and scales it per monitor DPI.

SetMessagesTool gains a bounds guard because m_CurrentBlinkBitmap
starts as a stale sentinel (24) that the old wxImageList::GetBitmap
tolerated but vector indexing must not.

Co-Authored-By: Claude Fable 5 <[email protected]>

* refactor(gui): name toolbar icon indexes and drop dead code after review

Code-review follow-ups to the wxBitmapBundle toolbar change:

- Add ToolbarSkinEnum (mirroring ClientSkinEnum) so the m_tblist
  indexes duplicated across Apply_Toolbar_Skin, ShowConnectionState,
  OnGUITimer and the constructor are named instead of magic numbers
  whose meaning depends on the Add_Skin_Icon call order.
- Initialize m_CurrentBlinkBitmap to Toolbar_Messages instead of the
  stale sentinel 24 (a fossil amuleDlgImages() resource id, never a
  valid m_tblist index) and drop the SetMessagesTool bounds guard that
  existed only to defend against it; both callers assign a valid index
  right before calling, so behavior is identical.
- Remove the #ifdef __WXCOCOA__ branches in ShowConnectionState and
  SetMessagesTool: the old wxCocoa port was removed from wxWidgets
  before the 3.2 minimum this project requires (modern macOS defines
  __WXOSX_COCOA__), so those lines could never compile again.
- Use the two-bitmap wxBitmapBundle::FromBitmaps overload instead of
  building a wxVector by hand.

Co-Authored-By: Claude Fable 5 <[email protected]>

* style(gui): use emplace_back for the fallback toolbar bundle

Fixes the clang-tidy Tier-2 modernize-use-emplace warning on the
wxBitmapBundle fallback path in Add_Skin_Icon.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Carlos Barrero <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
Cflsft pushed a commit to Cflsft/amule that referenced this pull request Jul 6, 2026
)

The preferences dialog's page list (General, Connection, Directories,
etc.) fed 16x16 bitmaps into a fixed-size wxImageList, so on
DPI-aware builds the icons render at 16 physical pixels — tiny and
blurry on hi-DPI screens, same problem as the main toolbar (amule-org#294).

Hand the icons to the list control as wxBitmapBundles instead
(wxListCtrl::SetSmallImages, wx >= 3.2), each built from the 16px art
plus a wxIMAGE_QUALITY_HIGH 2x upscale with the mask converted to an
alpha channel first. The macOS-only right/bottom padding is applied
per resolution so the padded canvas keeps its proportions at 2x.

Co-authored-by: Carlos Barrero <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants