From 502e189f47f5d97b656ffd1e20872052f449bad7 Mon Sep 17 00:00:00 2001 From: Gerhard Stein Date: Sat, 22 Oct 2022 21:35:58 +0200 Subject: [PATCH 1/4] Support high DPI bitmaps in wxGenericListCtrl Use wxWithImages::GetImageBitmapFor() instead of wxImageList in this control code to ensure that we use the provided high DPI bitmaps, if we have them, instead of always scaling up the fixed-size image list images. Closes #22907. --- include/wx/generic/private/listctrl.h | 12 ++-- src/generic/listctrl.cpp | 89 ++++++++++++++------------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index 5135ce9db7..d10561372b 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -640,7 +640,7 @@ public: 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 ); @@ -694,8 +694,9 @@ public: 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(); @@ -811,8 +812,9 @@ protected: 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; diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 3da7620e68..101db48819 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -1134,13 +1134,13 @@ 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 *imageList; if ( image != -1 ) { - imageList = m_owner->GetSmallImageList(); + imageList = m_owner->GetSmallImages(); if ( imageList ) { - imageList->GetSize(image, ix, iy); + imageList->GetImageLogicalSize(this, image, ix, iy); wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; } } @@ -1177,14 +1177,12 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) // if we have an image, draw it on the right of the label if ( imageList ) { - imageList->Draw - ( - image, - dc, - xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, - HEADER_OFFSET_Y + (h - iy)/2, - wxIMAGELIST_DRAW_TRANSPARENT - ); + wxBitmap bmp = imageList->GetImageBitmapFor(this, image); + dc.DrawBitmap( + bmp, + xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, + HEADER_OFFSET_Y + (h - iy)/2 + ); } dc.DrawText( item.GetText(), @@ -1592,8 +1590,8 @@ void wxListMainWindow::Init() m_headerWidth = m_lineHeight = 0; - m_small_image_list = nullptr; - m_normal_image_list = nullptr; + m_small_images = nullptr; + m_normal_images = nullptr; m_small_spacing = 30; m_normal_spacing = 40; @@ -1751,10 +1749,10 @@ wxCoord wxListMainWindow::GetLineHeight() const wxCoord y; dc.GetTextExtent(wxT("H"), nullptr, &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); } @@ -3302,41 +3300,45 @@ 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)) + if ( HasFlag(wxLC_ICON) && (m_normal_images)) { - m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + const auto bmp = m_normal_images->GetImageBitmapFor(this, index); + dc->DrawBitmap(bmp, x, y); } - else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list)) + else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_images)) { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + const auto bmp = m_small_images->GetImageBitmapFor(this, index); + dc->DrawBitmap(bmp, x, y); } - else if ( HasFlag(wxLC_LIST) && (m_small_image_list)) + else if ( HasFlag(wxLC_LIST) && (m_small_images)) { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + const auto bmp = m_small_images->GetImageBitmapFor(this, index); + dc->DrawBitmap(bmp, x, y); } - else if ( InReportView() && (m_small_image_list)) + else if ( InReportView() && (m_small_images)) { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + const auto bmp = m_small_images->GetImageBitmapFor(this, index); + dc->DrawBitmap(bmp, x, y); } } void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const { - if ( HasFlag(wxLC_ICON) && m_normal_image_list ) + if ( HasFlag(wxLC_ICON) && m_normal_images ) { - m_normal_image_list->GetSize( index, width, height ); + m_normal_images->GetImageLogicalSize(this, index, width, height); } - else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list ) + else if ( HasFlag(wxLC_SMALL_ICON) && m_small_images ) { - m_small_image_list->GetSize( index, width, height ); + m_small_images->GetImageLogicalSize(this, index, width, height); } - else if ( HasFlag(wxLC_LIST) && m_small_image_list ) + else if ( HasFlag(wxLC_LIST) && m_small_images ) { - m_small_image_list->GetSize( index, width, height ); + m_small_images->GetImageLogicalSize(this, index, width, height); } - else if ( InReportView() && m_small_image_list ) + else if ( InReportView() && m_small_images ) { - m_small_image_list->GetSize( index, width, height ); + m_small_images->GetImageLogicalSize(this, index, width, height); } else { @@ -3345,28 +3347,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 } @@ -3403,10 +3406,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; } } @@ -4029,9 +4032,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; @@ -4626,10 +4629,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; @@ -5456,7 +5459,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) ) From 69648b432236c92d2b8fa93db80354ee3d325d97 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 25 Oct 2022 23:09:31 +0200 Subject: [PATCH 2/4] Rename variable to have a less confusing name After the changes of the last commit this variable is not of wxImageList type any more, so its name became confusing, so rename it and also be a bit more precise by indicating that it corresponds to the small, and not normal, images. No real changes. --- src/generic/listctrl.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 101db48819..7da2027cfc 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -1134,19 +1134,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; - wxWithImages *imageList; + wxWithImages *smallImages; if ( image != -1 ) { - imageList = m_owner->GetSmallImages(); - if ( imageList ) + smallImages = m_owner->GetSmallImages(); + if ( smallImages ) { - imageList->GetImageLogicalSize(this, image, ix, iy); + smallImages->GetImageLogicalSize(this, image, ix, iy); wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; } } else { - imageList = nullptr; + smallImages = nullptr; } // ignore alignment if there is not enough space anyhow @@ -1175,9 +1175,9 @@ 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 ) { - wxBitmap bmp = imageList->GetImageBitmapFor(this, image); + wxBitmap bmp = smallImages->GetImageBitmapFor(this, image); dc.DrawBitmap( bmp, xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, From 6dd4e73ea3fe8354ac70d2510c0351754a0741ac Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 25 Oct 2022 23:44:20 +0200 Subject: [PATCH 3/4] Add wxDrawImageBitmap() helper and use it in wx{List,Tree}Ctrl Add a helper function calling wxDC::DrawBitmap() and hiding its ugly "useMask" boolean parameter which was also error-prone, e.g. some recently modified code passed wxIMAGELIST_DRAW_TRANSPARENT to it by mistake. No real changes, this is just a refactoring. --- include/wx/generic/private/drawbitmap.h | 41 +++++++++++++++++++++++++ src/generic/listctrl.cpp | 27 ++++++++-------- src/generic/treectlg.cpp | 34 ++++++++++---------- 3 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 include/wx/generic/private/drawbitmap.h diff --git a/include/wx/generic/private/drawbitmap.h b/include/wx/generic/private/drawbitmap.h new file mode 100644 index 0000000000..af6d64e596 --- /dev/null +++ b/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 +// 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 +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_ diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 7da2027cfc..2816dc1d40 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -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" @@ -1177,12 +1179,13 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) // if we have an image, draw it on the right of the label if ( smallImages ) { - wxBitmap bmp = smallImages->GetImageBitmapFor(this, image); - dc.DrawBitmap( - bmp, - xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, - HEADER_OFFSET_Y + (h - iy)/2 - ); + wxDrawImageBitmap + ( + this, *smallImages, image, + dc, + xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, + HEADER_OFFSET_Y + (h - iy)/2 + ); } dc.DrawText( item.GetText(), @@ -3302,23 +3305,19 @@ void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y ) { if ( HasFlag(wxLC_ICON) && (m_normal_images)) { - const auto bmp = m_normal_images->GetImageBitmapFor(this, index); - dc->DrawBitmap(bmp, x, y); + wxDrawImageBitmap(this, *m_normal_images, index, *dc, x, y); } else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_images)) { - const auto bmp = m_small_images->GetImageBitmapFor(this, index); - dc->DrawBitmap(bmp, x, y); + wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); } else if ( HasFlag(wxLC_LIST) && (m_small_images)) { - const auto bmp = m_small_images->GetImageBitmapFor(this, index); - dc->DrawBitmap(bmp, x, y); + wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); } else if ( InReportView() && (m_small_images)) { - const auto bmp = m_small_images->GetImageBitmapFor(this, index); - dc->DrawBitmap(bmp, x, y); + wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); } } diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 0c4d1c9477..98f444c25a 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -38,6 +38,8 @@ #include "wx/renderer.h" +#include "wx/generic/private/drawbitmap.h" + #ifdef __WXMAC__ #include "wx/osx/private.h" #endif @@ -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); @@ -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 { From c94399121fae15bdfca78bfed242e4733cae1cce Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 25 Oct 2022 23:47:38 +0200 Subject: [PATCH 4/4] Don't duplicate same code for small icon, list and report modes Handle all of them in a single condition instead of using three different ones. No real changes. --- src/generic/listctrl.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 2816dc1d40..2bbe14cf10 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -3303,19 +3303,11 @@ void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y ) { - if ( HasFlag(wxLC_ICON) && (m_normal_images)) + if ( HasFlag(wxLC_ICON) && m_normal_images ) { wxDrawImageBitmap(this, *m_normal_images, index, *dc, x, y); } - else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_images)) - { - wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); - } - else if ( HasFlag(wxLC_LIST) && (m_small_images)) - { - wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); - } - else if ( InReportView() && (m_small_images)) + else if ( HasFlag(wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT) && m_small_images ) { wxDrawImageBitmap(this, *m_small_images, index, *dc, x, y); } @@ -3327,15 +3319,7 @@ void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const { m_normal_images->GetImageLogicalSize(this, index, width, height); } - else if ( HasFlag(wxLC_SMALL_ICON) && m_small_images ) - { - m_small_images->GetImageLogicalSize(this, index, width, height); - } - else if ( HasFlag(wxLC_LIST) && m_small_images ) - { - m_small_images->GetImageLogicalSize(this, index, width, height); - } - else if ( InReportView() && m_small_images ) + else if ( HasFlag(wxLC_SMALL_ICON | wxLC_LIST | wxLC_REPORT) && m_small_images ) { m_small_images->GetImageLogicalSize(this, index, width, height); }