From ced845f00655ee0dc563b8af1692f2b600effaea Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 7 Nov 2021 21:46:42 +0000 Subject: [PATCH] Update wxTreeCtrl and its sample to work with wxBitmapBundle Override OnImagesChanged() to call UpdateImageListIfNecessary() even in wxGenericTreeCtrl for now, although in the future it would really make sense to stop using wxImageList in its implementation and just use wxBitmapBundle directly instead. wxMSW is the only one which really needs an image list, as it's required by the native control. Also update the sample, even though it doesn't look very nice because its icons are only available in a single size, so we have to always scale them. --- include/wx/generic/treectlg.h | 3 ++ include/wx/msw/treectrl.h | 2 ++ include/wx/qt/treectrl.h | 4 +++ samples/treectrl/treetest.cpp | 67 ++++++++++++++++++++++++----------- samples/treectrl/treetest.h | 7 +++- src/common/treebase.cpp | 1 + src/generic/treectlg.cpp | 38 ++++++++++---------- src/msw/treectrl.cpp | 18 ++++++++++ src/qt/treectrl.cpp | 15 ++++++++ 9 files changed, 116 insertions(+), 39 deletions(-) diff --git a/include/wx/generic/treectlg.h b/include/wx/generic/treectlg.h index 67a2a39fd1..dda068bf4f 100644 --- a/include/wx/generic/treectlg.h +++ b/include/wx/generic/treectlg.h @@ -287,6 +287,9 @@ protected: // overridden wxWindow methods virtual void DoThaw() wxOVERRIDE; + virtual void OnImagesChanged() wxOVERRIDE; + void UpdateAfterImageListChange(); + // misc helpers void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted); diff --git a/include/wx/msw/treectrl.h b/include/wx/msw/treectrl.h index 0e62b89197..08d42f7062 100644 --- a/include/wx/msw/treectrl.h +++ b/include/wx/msw/treectrl.h @@ -212,6 +212,8 @@ protected: virtual bool MSWShouldSetDefaultFont() const wxOVERRIDE { return false; } + virtual void OnImagesChanged() wxOVERRIDE; + // SetImageList helper void SetAnyImageList(wxImageList *imageList, int which); diff --git a/include/wx/qt/treectrl.h b/include/wx/qt/treectrl.h index 473f2c1f09..9744243bf8 100644 --- a/include/wx/qt/treectrl.h +++ b/include/wx/qt/treectrl.h @@ -135,10 +135,14 @@ protected: virtual wxTreeItemId DoTreeHitTest(const wxPoint& point, int& flags) const wxOVERRIDE; + virtual void OnImagesChanged() wxOVERRIDE; + private: void SendDeleteEvent(const wxTreeItemId &item); wxTreeItemId GetNext(const wxTreeItemId &item) const; + void DoUpdateIconsSize(wxImageList *imageList); + wxQTreeWidget *m_qtTreeWidget; wxDECLARE_DYNAMIC_CLASS(wxTreeCtrl); }; diff --git a/samples/treectrl/treetest.cpp b/samples/treectrl/treetest.cpp index 83a0b89e5e..db0d5c94cf 100644 --- a/samples/treectrl/treetest.cpp +++ b/samples/treectrl/treetest.cpp @@ -688,7 +688,7 @@ void MyFrame::OnSetImageSize(wxCommandEvent& WXUNUSED(event)) if ( size == -1 ) return; - m_treeCtrl->CreateImageList(size); + m_treeCtrl->CreateImages(size); wxGetApp().SetShowImages(true); } @@ -696,12 +696,12 @@ void MyFrame::OnToggleImages(wxCommandEvent& WXUNUSED(event)) { if ( wxGetApp().ShowImages() ) { - m_treeCtrl->CreateImageList(-1); + m_treeCtrl->CreateImages(-1); wxGetApp().SetShowImages(false); } else { - m_treeCtrl->CreateImageList(0); + m_treeCtrl->CreateImages(0); wxGetApp().SetShowImages(true); } } @@ -730,7 +730,7 @@ void MyFrame::OnToggleAlternateImages(wxCommandEvent& WXUNUSED(event)) bool alternateImages = m_treeCtrl->AlternateImages(); m_treeCtrl->SetAlternateImages(!alternateImages); - m_treeCtrl->CreateImageList(0); + m_treeCtrl->CreateImages(0); } void MyFrame::OnToggleAlternateStates(wxCommandEvent& WXUNUSED(event)) @@ -955,14 +955,14 @@ MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id, { m_reverseSort = false; - CreateImageList(); + CreateImages(16); CreateStateImageList(); // Add some items to the tree AddTestItemsToTree(NUM_CHILDREN_PER_LEVEL, NUM_LEVELS); } -void MyTreeCtrl::CreateImageList(int size) +void MyTreeCtrl::CreateImages(int size) { if ( size == -1 ) { @@ -974,8 +974,7 @@ void MyTreeCtrl::CreateImageList(int size) else m_imageSize = size; - // Make an image list containing small icons - wxImageList *images = new wxImageList(size, size, true); + const wxSize iconSize(size, size); // should correspond to TreeCtrlIcon_xxx enum wxIcon icons[5]; @@ -990,8 +989,6 @@ void MyTreeCtrl::CreateImageList(int size) } else { - wxSize iconSize(size, size); - icons[TreeCtrlIcon_File] = icons[TreeCtrlIcon_FileSelected] = wxArtProvider::GetIcon(wxART_NORMAL_FILE, wxART_LIST, iconSize); icons[TreeCtrlIcon_Folder] = @@ -999,20 +996,50 @@ void MyTreeCtrl::CreateImageList(int size) icons[TreeCtrlIcon_FolderOpened] = wxArtProvider::GetIcon(wxART_FOLDER, wxART_LIST, iconSize); } + // Make a vector of bundles corresponding to the icons. We use a custom + // bundle implementation here as we always scale the icons, even at 100% + // DPI, to ensure they are of the desired size. + wxVector images; + + class FixedSizeImpl : public wxBitmapBundleImpl + { + public: + FixedSizeImpl(const wxSize& sizeDef, const wxIcon& icon) + : m_sizeDef(sizeDef), + m_icon(icon) + { + } + + wxSize GetDefaultSize() const wxOVERRIDE + { + return m_sizeDef; + } + + wxSize GetPreferredSizeAtScale(double scale) const wxOVERRIDE + { + return m_sizeDef*scale; + } + + wxBitmap GetBitmap(const wxSize& size) wxOVERRIDE + { + wxBitmap bmp(m_icon); + if ( size != bmp.GetSize() ) + wxBitmap::Rescale(bmp, size); + + return bmp; + } + + private: + const wxSize m_sizeDef; + const wxIcon m_icon; + }; + for ( size_t i = 0; i < WXSIZEOF(icons); i++ ) { - int sizeOrig = icons[0].GetWidth(); - if ( size == sizeOrig ) - { - images->Add(icons[i]); - } - else - { - images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size))); - } + images.push_back(wxBitmapBundle::FromImpl(new FixedSizeImpl(iconSize, icons[i]))); } - AssignImageList(images); + SetImages(images); } void MyTreeCtrl::CreateStateImageList(bool del) diff --git a/samples/treectrl/treetest.h b/samples/treectrl/treetest.h index 865a39d1fa..68ae3d4d54 100644 --- a/samples/treectrl/treetest.h +++ b/samples/treectrl/treetest.h @@ -107,7 +107,12 @@ public: void GetItemsRecursively(const wxTreeItemId& idParent, wxTreeItemIdValue cookie = 0); - void CreateImageList(int size = 16); + // This function behaves differently depending on the value of size: + // - If it's -1, it turns off the use of images entirely. + // - If it's 0, it reuses the last used size. + // - If it's strictly positive, it creates icons in this size. + void CreateImages(int size); + void CreateButtonsImageList(int size = 11); void CreateStateImageList(bool del = false); diff --git a/src/common/treebase.cpp b/src/common/treebase.cpp index 0145469e60..988e288c5b 100644 --- a/src/common/treebase.cpp +++ b/src/common/treebase.cpp @@ -172,6 +172,7 @@ wxTreeCtrlBase::wxTreeCtrlBase() m_quickBestSize = true; Bind(wxEVT_CHAR_HOOK, &wxTreeCtrlBase::OnCharHook, this); + Bind(wxEVT_DPI_CHANGED, &wxTreeCtrlBase::WXHandleDPIChanged, this); } wxTreeCtrlBase::~wxTreeCtrlBase() diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 01f14f24ef..f988234a1c 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -2424,9 +2424,18 @@ void wxGenericTreeCtrl::CalculateLineHeight() m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing } -void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) +void wxGenericTreeCtrl::OnImagesChanged() +{ + if ( HasImages() ) + { + UpdateImageListIfNecessary(this); + + UpdateAfterImageListChange(); + } +} + +void wxGenericTreeCtrl::UpdateAfterImageListChange() { - wxWithImages::SetImageList(imageList); m_dirty = true; if (m_anchor) @@ -2434,33 +2443,26 @@ void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) // Don't do any drawing if we're setting the list to NULL, // since we may be in the process of deleting the tree control. - if (imageList) + if (GetImageList()) CalculateLineHeight(); } +void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) +{ + wxWithImages::SetImageList(imageList); + UpdateAfterImageListChange(); +} + void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList) { m_imagesState.SetImageList(imageList); - m_dirty = true; - - if (m_anchor) - m_anchor->RecursiveResetSize(); - - // Don't do any drawing if we're setting the list to NULL, - // since we may be in the process of deleting the tree control. - if (imageList) - CalculateLineHeight(); + UpdateAfterImageListChange(); } void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList) { m_imagesButtons.SetImageList(imageList); - m_dirty = true; - - if (m_anchor) - m_anchor->RecursiveResetSize(); - - CalculateLineHeight(); + UpdateAfterImageListChange(); } void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList *imageList) diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 4524cc2bcc..8b63438d0d 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -931,6 +931,24 @@ void wxTreeCtrl::SetStateImageList(wxImageList *imageList) SetAnyImageList(imageList, TVSIL_STATE); } +void wxTreeCtrl::OnImagesChanged() +{ + wxImageList* imageList; + + if ( HasImages() ) + { + UpdateImageListIfNecessary(this); + + imageList = GetImageList(); + } + else + { + imageList = NULL; + } + + SetAnyImageList(imageList, TVSIL_NORMAL); +} + size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively) const { diff --git a/src/qt/treectrl.cpp b/src/qt/treectrl.cpp index e1d5845a88..441c667fdb 100644 --- a/src/qt/treectrl.cpp +++ b/src/qt/treectrl.cpp @@ -613,12 +613,27 @@ void wxTreeCtrl::SetImageList(wxImageList *imageList) { wxWithImages::SetImageList(imageList); + DoUpdateIconsSize(imageList); +} + +void wxTreeCtrl::DoUpdateIconsSize(wxImageList *imageList) +{ int width, height; imageList->GetSize(0, width, height); m_qtTreeWidget->ResizeIcons(QSize(width, height)); m_qtTreeWidget->update(); } +void wxTreeCtrl::OnImagesChanged() +{ + if ( HasImages() ) + { + UpdateImageListIfNecessary(this); + + DoUpdateIconsSize(GetImageList()); + } +} + void wxTreeCtrl::SetStateImageList(wxImageList *imageList) { m_imagesState.SetImageList(imageList);