Skip to content

Commit

Permalink
Fix support for high DPI icons in generic wxListCtrl
Browse files Browse the repository at this point in the history
This is a cherry pick of the merge commit 5845312 (Merge branch
'generic-listctrl-hidpi-images', 2022-10-26) from master including the
following commits:

* Support high DPI bitmaps in wxGenericListCtrl.
* Rename variable to have a less confusing name.
* Add wxDrawImageBitmap() helper and use it in wx{List,Tree}Ctrl.
* Don't duplicate same code for small icon, list and report modes.

See #22907, #22916.
  • Loading branch information
vadz committed Jan 26, 2023
1 parent c1b27f3 commit f16387b
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 78 deletions.
2 changes: 1 addition & 1 deletion docs/changes.txt
Expand Up @@ -255,7 +255,7 @@ All (GUI):
- Improve wxWebView::RunScriptAsync() performance (Tobias Taschner, #22781).
- Fix data race when processing events generated in a worker thread.
- Fix compilation problem in wx/propgrid/editors.h (Loïc Bartoletti, #22875).
- Fix wxGenericTreeCtrl icons rendering in high DPI (Gerhard Stein, #22887).
- Fix wxGeneric{List,Tree}Ctrl high DPI icons (Gerhard Stein, #22887, #22916).
- Add macros for event tables for missing wxWebView events (PB, #22949).
- Improve month selection in wxGenericCalendarCtrl (Lauri Nurmi, #22853).
- Fix maximum length of wxPropertyGrid editors (#23033).
Expand Down
41 changes: 41 additions & 0 deletions include/wx/generic/private/drawbitmap.h
@@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/generic/private/drawbitmap.h
// Purpose: Small helper for drawing images.
// Author: Vadim Zeitlin
// Created: 2022-10-25
// Copyright: (c) 2022 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////

#ifndef _WX_GENERIC_PRIVATE_DRAWBITMAP_H_
#define _WX_GENERIC_PRIVATE_DRAWBITMAP_H_

#include "wx/dc.h"
#include "wx/window.h"
#include "wx/withimages.h"

// Just a trivial wrapper for wxDC::DrawBitmap() using wxWithImages: this is
// used in several places in the generic wxListCtrl and wxTreeCtrl code.
inline void
wxDrawImageBitmap(wxWindow* window,
const wxWithImages& images,
int image,
wxDC& dc,
int x,
int y)
{
dc.DrawBitmap(images.GetImageBitmapFor(window, image),
x, y,
true /* use mask */);
}

// Overload for the controls deriving from both wxWindow and wxWithImages, as
// both wxListCtrl and wxTreeCtrl do.
template <typename T>
inline void
wxDrawImageBitmap(T* window, int image, wxDC& dc, int x, int y)
{
wxDrawImageBitmap(window, *window, image, dc, x, y);
}

#endif // _WX_GENERIC_PRIVATE_DRAWBITMAP_H_
12 changes: 7 additions & 5 deletions include/wx/generic/private/listctrl.h
Expand Up @@ -640,7 +640,7 @@ class wxListMainWindow : public wxWindow
void DrawImage( int index, wxDC *dc, int x, int y );
void GetImageSize( int index, int &width, int &height ) const;

void SetImageList( wxImageList *imageList, int which );
void SetImages( wxWithImages *images, const int which );
void SetItemSpacing( int spacing, bool isSmall = false );
int GetItemSpacing( bool isSmall = false );

Expand Down Expand Up @@ -694,8 +694,9 @@ class wxListMainWindow : public wxWindow
SetItem( info );
}

wxImageList* GetSmallImageList() const
{ return m_small_image_list; }
wxWithImages* GetSmallImages() const
{ return m_small_images; }


// set the scrollbars and update the positions of the items
void RecalculatePositions();
Expand Down Expand Up @@ -811,8 +812,9 @@ class wxListMainWindow : public wxWindow
bool m_dirty;

wxColour *m_highlightColour;
wxImageList *m_small_image_list;
wxImageList *m_normal_image_list;
wxWithImages *m_small_images;
wxWithImages *m_normal_images;

int m_small_spacing;
int m_normal_spacing;
bool m_hasFocus;
Expand Down
94 changes: 40 additions & 54 deletions src/generic/listctrl.cpp
Expand Up @@ -35,6 +35,8 @@

#include "wx/imaglist.h"
#include "wx/renderer.h"

#include "wx/generic/private/drawbitmap.h"
#include "wx/generic/private/listctrl.h"
#include "wx/generic/private/widthcalc.h"

Expand Down Expand Up @@ -1118,19 +1120,19 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
// and the width of the icon, if any
int ix = 0, iy = 0; // init them just to suppress the compiler warnings
const int image = item.m_image;
wxImageList *imageList;
wxWithImages *smallImages;
if ( image != -1 )
{
imageList = m_owner->GetSmallImageList();
if ( imageList )
smallImages = m_owner->GetSmallImages();
if ( smallImages )
{
imageList->GetSize(image, ix, iy);
smallImages->GetImageLogicalSize(this, image, ix, iy);
wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
}
}
else
{
imageList = NULL;
smallImages = NULL;
}

// ignore alignment if there is not enough space anyhow
Expand Down Expand Up @@ -1159,16 +1161,15 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h);

// if we have an image, draw it on the right of the label
if ( imageList )
if ( smallImages )
{
imageList->Draw
(
image,
dc,
xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
HEADER_OFFSET_Y + (h - iy)/2,
wxIMAGELIST_DRAW_TRANSPARENT
);
wxDrawImageBitmap
(
this, *smallImages, image,
dc,
xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
HEADER_OFFSET_Y + (h - iy)/2
);
}

dc.DrawText( item.GetText(),
Expand Down Expand Up @@ -1576,8 +1577,8 @@ void wxListMainWindow::Init()
m_headerWidth =
m_lineHeight = 0;

m_small_image_list = NULL;
m_normal_image_list = NULL;
m_small_images = NULL;
m_normal_images = NULL;

m_small_spacing = 30;
m_normal_spacing = 40;
Expand Down Expand Up @@ -1735,10 +1736,10 @@ wxCoord wxListMainWindow::GetLineHeight() const
wxCoord y;
dc.GetTextExtent(wxT("H"), NULL, &y);

if ( m_small_image_list && m_small_image_list->GetImageCount() )
if ( m_small_images && m_small_images->GetImageCount() )
{
int iw = 0, ih = 0;
m_small_image_list->GetSize(0, iw, ih);
m_small_images->GetImageLogicalSize(this, 0, iw, ih);
y = wxMax(y, ih);
}

Expand Down Expand Up @@ -3286,41 +3287,25 @@ void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )

void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
{
if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
{
m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
}
else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
}
else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
if ( HasFlag(wxLC_ICON) && m_normal_images )
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
wxDrawImageBitmap(this, *m_normal_images, index, *dc, x, y);
}
else if ( InReportView() && (m_small_image_list))
else if ( HasFlag(wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT) && m_small_images )
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y);
}
}

void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
{
if ( HasFlag(wxLC_ICON) && m_normal_image_list )
{
m_normal_image_list->GetSize( index, width, height );
}
else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
if ( HasFlag(wxLC_ICON) && m_normal_images )
{
m_small_image_list->GetSize( index, width, height );
m_normal_images->GetImageLogicalSize(this, index, width, height);
}
else if ( HasFlag(wxLC_LIST) && m_small_image_list )
else if ( HasFlag(wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT) && m_small_images )
{
m_small_image_list->GetSize( index, width, height );
}
else if ( InReportView() && m_small_image_list )
{
m_small_image_list->GetSize( index, width, height );
m_small_images->GetImageLogicalSize(this, index, width, height);
}
else
{
Expand All @@ -3329,28 +3314,29 @@ void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
}
}

void wxListMainWindow::SetImageList( wxImageList *imageList, int which )

void wxListMainWindow::SetImages( wxWithImages *images, const int which )
{
m_dirty = true;

// calc the spacing from the icon size
int width = 0;

if ((imageList) && (imageList->GetImageCount()) )
if ((images) && (images->HasImages()) )
{
int height;
imageList->GetSize(0, width, height);
images->GetImageLogicalSize(this, 0, width, height);
}

if (which == wxIMAGE_LIST_NORMAL)
{
m_normal_image_list = imageList;
m_normal_images = images;
m_normal_spacing = width + 8;
}

if (which == wxIMAGE_LIST_SMALL)
{
m_small_image_list = imageList;
m_small_images = images;
m_small_spacing = width + 14;
m_lineHeight = 0; // ensure that the line height will be recalc'd
}
Expand Down Expand Up @@ -3387,10 +3373,10 @@ wxListMainWindow::ComputeMinHeaderWidth(const wxListHeaderData* column) const
const int image = column->GetImage();
if ( image != -1 )
{
if ( m_small_image_list )
if ( m_small_images )
{
int ix = 0, iy = 0;
m_small_image_list->GetSize(image, ix, iy);
m_small_images->GetImageLogicalSize(this, image, ix, iy);
width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
}
}
Expand Down Expand Up @@ -4013,9 +3999,9 @@ void wxListMainWindow::RecalculatePositions()
const size_t count = GetItemCount();

int iconSpacing;
if ( HasFlag(wxLC_ICON) && m_normal_image_list )
if ( HasFlag(wxLC_ICON) && m_normal_images )
iconSpacing = m_normal_spacing;
else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
else if ( HasFlag(wxLC_SMALL_ICON) && m_small_images )
iconSpacing = m_small_spacing;
else
iconSpacing = 0;
Expand Down Expand Up @@ -4610,10 +4596,10 @@ void wxListMainWindow::InsertItem( wxListItem &item )
{
// Reset the buffered height if it's not big enough for the new image.
int image = item.GetImage();
if ( m_small_image_list && image != -1 && InReportView() )
if ( m_small_images && image != -1 && InReportView() )
{
int imageWidth, imageHeight;
m_small_image_list->GetSize(image, imageWidth, imageHeight);
m_small_images->GetImageLogicalSize(this, image, imageWidth, imageHeight);

if ( imageHeight > m_lineHeight )
m_lineHeight = 0;
Expand Down Expand Up @@ -5440,7 +5426,7 @@ long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const

void wxGenericListCtrl::DoUpdateImages(int which )
{
m_mainWin->SetImageList( GetUpdatedImageList(which), which );
m_mainWin->SetImages( GetImages(which), which );
}

bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) )
Expand Down
34 changes: 16 additions & 18 deletions src/generic/treectlg.cpp
Expand Up @@ -38,6 +38,8 @@

#include "wx/renderer.h"

#include "wx/generic/private/drawbitmap.h"

#ifdef __WXMAC__
#include "wx/osx/private.h"
#endif
Expand Down Expand Up @@ -2648,24 +2650,23 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
if ( state != wxTREE_ITEMSTATE_NONE )
{
wxDCClipper clip(dc, item->GetX(), item->GetY(), state_w, total_h);
dc.DrawBitmap( m_imagesState.GetImageBitmapFor(this, state),
item->GetX(),
item->GetY() +
(total_h > state_h ? (total_h-state_h)/2
: 0),
true /* use mask */ );

wxDrawImageBitmap(this, m_imagesState, state,
dc,
item->GetX(),
item->GetY() +
total_h > state_h ? (total_h-state_h)/2 : 0);
}

if ( image != NO_IMAGE )
{
wxDCClipper clip(dc, item->GetX() + state_w, item->GetY(),
image_w, total_h);
dc.DrawBitmap( GetImageBitmapFor(this, image),
item->GetX() + state_w,
item->GetY() +
(total_h > image_h ? (total_h-image_h)/2
: 0),
true /* use mask */ );
wxDrawImageBitmap(this, image,
dc,
item->GetX() + state_w,
item->GetY() +
total_h > image_h ? (total_h-image_h)/2 : 0);
}

dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
Expand Down Expand Up @@ -2832,16 +2833,13 @@ wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item,
if ( item->IsSelected() )
image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;

const wxBitmap& bmp = m_imagesButtons.GetImageBitmapFor(this, image);

// we need logical coordinates for wxDC.
int image_h = FromPhys(bmp.GetHeight()),
image_w = FromPhys(bmp.GetWidth());
int image_w, image_h;
m_imagesButtons.GetImageLogicalSize(this, image, image_w, image_h);
int xx = x - image_w/2;
int yy = y_mid - image_h/2;

wxDCClipper clip(dc, xx, yy, image_w, image_h);
dc.DrawBitmap( bmp, xx, yy, true /* use mask */ );
wxDrawImageBitmap(this, m_imagesButtons, image, dc, xx, yy);
}
else // no custom buttons
{
Expand Down

0 comments on commit f16387b

Please sign in to comment.