Opened 23 months ago

Last modified 12 months ago

#18236 confirmed enhancement

wxArtProvider API improvement suggestions

Reported by: juliansmart Owned by:
Priority: normal Milestone: 3.2.0
Component: GUI-all Version: dev-latest
Keywords: wxArtProvider, HiDPI, retina, bitmap Cc:
Blocked By: Blocking: #18474
Patch: no

Description (last modified by vadz)

Dear all,

These are my proposals for wxArtProvider changes to help with HiDPI adaptation.

The problem at present is that all the heavy lifting has to be done on the application side, namely choice of bitmaps for the current resolution, taking into account both Windows-style and Mac-style scaling. However, the application doesn’t currently have all the information necessary to do this properly – no window pointer is passed to wxArtProvider::CreateBitmap. And wxArtProvider’s caching can’t distinguish between bitmaps with different scaling factors on Mac, so if the monitor or individual window resolution changed and bitmaps with different scale factors are required, the wrong bitmap will be returned since bitmaps are cached by requested client size.

It’s also not made clear by the current API whether CreateBitmap should perform scaling or whether it’s handled by wxWidgets. Ideally, we’d like wxWidgets to decide what bitmap size is required and for the application to simply return that specific size. (Except for where we depend on the windowing system to return a resolution-appropriate size, but that can be handled as currently with platform-specific providers.)

In order for wxWidgets to take on more bitmap selection decision-making, it needs to know what bitmap sizes the application can provide. It can then choose the best one for a given PPI. So I propose three main new functions to be overridden by the application (in addition to several which are used to implement scaling but can be reimplemented by the application). For compatibility, these are completely optional, and without them existing internal wxWidgets code, and applications, will work as usual. The functions are ProvideBitmap, GetAvailableBitmapCount, and GetAvailableBitmapSize:

   ProvideBitmap should be defined by art providers that will also provide
   size information and will do NO scaling, letting wxWidgets choose appropriate
   scaling unless overridden by the provider.
virtual wxBitmap ProvideBitmap(const wxArtID& id,
                               const wxArtClient& client,
                               const wxSize& size);

   Enumerate unscaled available bitmaps in ascending size order.
   If 0 is returned, we don't know what bitmaps are available.
virtual size_t GetAvailableBitmapCount(const wxArtID& id,
                                       const wxArtClient& client);
virtual wxSize GetAvailableBitmapSize(size_t idx,
                                      const wxArtID& id,
                                      const wxArtClient& client);

Instead of calling GetBitmap, wxWidgets and applications call GetScaledBitmap:

static wxBitmap GetScaledBitmap(const wxArtID& id,
                                const wxArtClient& client,
                                const wxSize& szDIP,
                                wxWindow* window);

If no art providers have overridden the new functions, GetScaledBitmap will fall back to GetBitmap. The new functionality offers some flexibility in that by setting an option, the application can choose whether the nearest, smaller, or larger bitmap will be chosen (or an exact scaled bitmap used). The application can also choose (for Mac) whether hi-res bitmaps will be used on retina, by overriding GetBitmapScale.

So, applications don’t have to worry about when and how to apply scaling but can simply make available a set of bitmaps and their sizes. In my applications, I have 6 sizes per image (16x16, 24x24, 32x32, 48x48, 64x64, and 128x128).

GTK+3 is not considered at present but this scheme accommodates either Mac-style or Windows-style scaling so it should be straightforward to add if/when bitmap scaling is working consistently in wxGTK+3.

Some notes about HiDPI in wxGTK+2 are provided for the function wxArtProvider::FromDIP, for a scaling method that works in my applications (as getting PPI is not reliable) - but it’s perhaps too kludgy to be provided officially.

I haven’t tested this code as it’s for discussion purposes – it’s derived in part from my own HiDPI code. I hope it’s of some help in moving towards something useful.


Attachments (2)

artprov.h download (14.7 KB) - added by juliansmart 23 months ago.
Art provider class header file
artprov.cpp download (24.4 KB) - added by juliansmart 23 months ago.
Art provider class implementation file

Download all attachments as: .zip

Change History (4)

Changed 23 months ago by juliansmart

Art provider class header file

Changed 23 months ago by juliansmart

Art provider class implementation file

comment:1 Changed 23 months ago by vadz

  • Description modified (diff)
  • Milestone changed from future to 3.2.0
  • Status changed from new to confirmed

Thanks for the code and the explanations! I'll reply to this on wx-dev as I think it's more convenient to discuss it there.

comment:2 Changed 12 months ago by vadz

  • Blocking 18474 added
Note: See TracTickets for help on using tickets.