Merge branch 'generic-listctrl-hidpi-images'

Support high DPI images in generic wxListCtrl.

See #22916.
This commit is contained in:
Vadim Zeitlin 2022-10-26 02:39:28 +02:00
commit 5845312825
4 changed files with 104 additions and 77 deletions

View file

@ -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_

View file

@ -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;

View file

@ -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"
@ -1134,19 +1136,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 = nullptr;
smallImages = nullptr;
}
// ignore alignment if there is not enough space anyhow
@ -1175,16 +1177,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(),
@ -1592,8 +1593,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 +1752,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 +3303,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))
if ( HasFlag(wxLC_ICON) && m_normal_images )
{
m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
wxDrawImageBitmap(this, *m_normal_images, index, *dc, x, y);
}
else if ( HasFlag(wxLC_SMALL_ICON) && (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 );
}
else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
}
else if ( InReportView() && (m_small_image_list))
{
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 )
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 | wxLC_LIST | wxLC_REPORT) && m_small_images )
{
m_small_image_list->GetSize( index, width, height );
}
else if ( HasFlag(wxLC_LIST) && m_small_image_list )
{
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
{
@ -3345,28 +3330,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 +3389,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 +4015,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 +4612,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 +5442,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) )

View file

@ -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
{