diff --git a/include/wx/bmpbndl.h b/include/wx/bmpbndl.h index 6872a142bd..646c006b72 100644 --- a/include/wx/bmpbndl.h +++ b/include/wx/bmpbndl.h @@ -15,6 +15,7 @@ #include "wx/vector.h" class wxBitmapBundleImpl; +class WXDLLIMPEXP_FWD_CORE wxImageList; class WXDLLIMPEXP_FWD_CORE wxWindow; // It should be possible to implement SVG rasterizing without raw bitmap @@ -132,6 +133,11 @@ public: const wxVector& bundles, const wxSize& sizeDefault); + // Create wxImageList and fill it with the images from the given bundles in + // the sizes appropriate for the DPI scaling used for the specified window. + static wxImageList* + CreateImageList(wxWindow* win, const wxVector& bundles); + private: typedef wxObjectDataPtr wxBitmapBundleImplPtr; diff --git a/include/wx/msw/notebook.h b/include/wx/msw/notebook.h index b6a05ce637..e2c2d31915 100644 --- a/include/wx/msw/notebook.h +++ b/include/wx/msw/notebook.h @@ -62,14 +62,6 @@ public: bool SetPageText(size_t nPage, const wxString& strText) wxOVERRIDE; wxString GetPageText(size_t nPage) const wxOVERRIDE; - // image list stuff: each page may have an image associated with it. All - // the images belong to an image list, so you have to - // 1) create an image list - // 2) associate it with the notebook - // 3) set for each page it's image - // associate image list with a control - void SetImageList(wxImageList* imageList) wxOVERRIDE; - // sets/returns item's image index in the current image list int GetPageImage(size_t nPage) const wxOVERRIDE; bool SetPageImage(size_t nPage, int nImage) wxOVERRIDE; @@ -161,6 +153,9 @@ protected: // remove one page from the notebook, without deleting virtual wxNotebookPage *DoRemovePage(size_t nPage) wxOVERRIDE; + // update the image list used by the native control + virtual void OnImagesChanged() wxOVERRIDE; + // get the page rectangle for the current notebook size // // returns empty rectangle if an error occurs, do test for it diff --git a/include/wx/withimages.h b/include/wx/withimages.h index 9c4d7e785c..d9a6f929ca 100644 --- a/include/wx/withimages.h +++ b/include/wx/withimages.h @@ -11,8 +11,12 @@ #define _WX_WITHIMAGES_H_ #include "wx/defs.h" +#include "wx/bmpbndl.h" #include "wx/icon.h" #include "wx/imaglist.h" +#include "wx/vector.h" + +class WXDLLIMPEXP_FWD_CORE wxWindow; // ---------------------------------------------------------------------------- // wxWithImages: mix-in for classes using indices for image access @@ -26,6 +30,8 @@ public: NO_IMAGE = -1 }; + typedef wxVector Images; + wxWithImages() { m_imageList = NULL; @@ -40,6 +46,12 @@ public: // Return the number of images, possibly 0. int GetImageCount() const { + if ( !m_images.empty() ) + { + // Cast is safe, we don't risk having more than INT_MAX images. + return static_cast(m_images.size()); + } + return m_imageList ? m_imageList->GetImageCount() : 0; } @@ -49,11 +61,28 @@ public: return GetImageCount() != 0; } + // Sets the images to use. + // + // Override OnImagesChanged() in the derived class to update the actually + // shown images. + void SetImages(const Images& images) + { + m_images = images; + + OnImagesChanged(); + } + // Sets the image list to use, it is *not* deleted by the control. + // + // This function is virtual for compatibility, as it could be overridden in + // the existing application code, however it should not be overridden in wx + // itself, where OnImagesChanged() should be overridden instead. virtual void SetImageList(wxImageList* imageList) { FreeIfNeeded(); m_imageList = imageList; + + OnImagesChanged(); } // As SetImageList() but we will delete the image list ourselves. @@ -67,6 +96,33 @@ public: wxImageList* GetImageList() const { return m_imageList; } protected: + // This function is called when the images associated with the control + // change, due to either SetImages() or SetImageList() being called. + // + // It ought to be pure virtual, but isn't because there could be existing + // application code inheriting from this class and not overriding it + // (because this function hadn't existed when this code was written). + virtual void OnImagesChanged() { } + + // This helper function can be used from OnImagesChanged() if the derived + // class actually needs to use wxImageList: it ensures that m_imageList is + // updated from m_images, if the latter is not empty, using the images of + // the appropriate size for the given window. + void UpdateImageListIfNecessary(wxWindow* win) + { + if ( m_images.empty() ) + return; + + // Note that we can't just call AssignImageList() here to avoid + // infinite recursion. + FreeIfNeeded(); + m_imageList = wxBitmapBundle::CreateImageList(win, m_images); + + // We always own it as we created it ourselves. + m_ownsImageList = true; + } + + // Return true if we have a valid image list. bool HasImageList() const { return m_imageList != NULL; } @@ -96,6 +152,9 @@ private: } + // The images we use: if this vector is not empty, m_imageList is not used. + Images m_images; + // The associated image list or NULL. wxImageList* m_imageList; diff --git a/interface/wx/withimages.h b/interface/wx/withimages.h index 011718b22f..e5b6f4d008 100644 --- a/interface/wx/withimages.h +++ b/interface/wx/withimages.h @@ -39,9 +39,28 @@ public: */ bool HasImages() const; + /** + Set the images to use for the items in the control. + + This function allows to specify the images to use in multiple different + resolutions, letting the control to select the appropriate one for its + DPI scaling. For this reason, it should be preferred to using the + functions taking wxImageList, which has a fixed size, in the new code. + + @param images Non empty vector of bitmap bundles. Valid image indexes + for the items in this control are determined by the size of this + vector. + + @since 3.1.6 + */ + void SetImages(const wxVector& images); + /** Sets the image list for the page control and takes ownership of the list. + This function exists for compatibility only, please use SetImages() in + the new code. + @see wxImageList, SetImageList() */ void AssignImageList(wxImageList* imageList); @@ -50,6 +69,9 @@ public: Sets the image list to use. It does not take ownership of the image list, you must delete it yourself. + This function exists for compatibility only, please use SetImages() in + the new code. + @see wxImageList, AssignImageList() */ virtual void SetImageList(wxImageList* imageList); diff --git a/samples/notebook/notebook.cpp b/samples/notebook/notebook.cpp index b009ad5f5f..f5da371790 100644 --- a/samples/notebook/notebook.cpp +++ b/samples/notebook/notebook.cpp @@ -397,18 +397,13 @@ MyFrame::MyFrame() m_panel = NULL; m_bookCtrl = NULL; - // create a dummy image list with a few icons + // use some random images for the book control pages const wxSize imageSize(32, 32); - m_imageList = new wxImageList(imageSize.GetWidth(), imageSize.GetHeight()); - m_imageList-> - Add(wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, imageSize)); - m_imageList-> - Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, imageSize)); - m_imageList-> - Add(wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, imageSize)); - m_imageList-> - Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, imageSize)); + m_images.push_back(wxArtProvider::GetBitmapBundle(wxART_INFORMATION, wxART_OTHER, imageSize)); + m_images.push_back(wxArtProvider::GetBitmapBundle(wxART_QUESTION, wxART_OTHER, imageSize)); + m_images.push_back(wxArtProvider::GetBitmapBundle(wxART_WARNING, wxART_OTHER, imageSize)); + m_images.push_back(wxArtProvider::GetBitmapBundle(wxART_ERROR, wxART_OTHER, imageSize)); m_panel = new wxPanel(this); @@ -442,8 +437,6 @@ MyFrame::~MyFrame() #if USE_LOG delete wxLog::SetActiveTarget(m_logTargetOld); #endif // USE_LOG - - delete m_imageList; } // DISPATCH_ON_TYPE() macro is an ugly way to write the "same" code for @@ -565,7 +558,7 @@ void MyFrame::RecreateBook() // wxToolbook doesn't work without icons so always use them for it. if ( m_chkShowImages || m_type == Type_Toolbook ) { - m_bookCtrl->SetImageList(m_imageList); + m_bookCtrl->SetImages(m_images); } if ( oldBook ) diff --git a/samples/notebook/notebook.h b/samples/notebook/notebook.h index 05857c7216..ac7d13197c 100644 --- a/samples/notebook/notebook.h +++ b/samples/notebook/notebook.h @@ -131,7 +131,7 @@ private: wxBoxSizer *m_sizerFrame; - wxImageList *m_imageList; + wxBookCtrlBase::Images m_images; wxDECLARE_EVENT_TABLE(); }; diff --git a/src/common/bmpbndl.cpp b/src/common/bmpbndl.cpp index 7a98fde781..567326bc57 100644 --- a/src/common/bmpbndl.cpp +++ b/src/common/bmpbndl.cpp @@ -22,9 +22,10 @@ #endif // WX_PRECOMP #include "wx/bmpbndl.h" -#include "wx/icon.h" -#include "wx/window.h" #include "wx/filename.h" +#include "wx/icon.h" +#include "wx/imaglist.h" +#include "wx/window.h" #include "wx/private/bmpbndl.h" @@ -556,6 +557,32 @@ wxBitmapBundle::GetConsensusSizeFor(wxWindow* win, return sizePreferred; } +/* static */ +wxImageList* +wxBitmapBundle::CreateImageList(wxWindow* win, + const wxVector& bundles) +{ + wxCHECK_MSG( win, NULL, "must have a valid window" ); + wxCHECK_MSG( !bundles.empty(), NULL, "should have some images" ); + + // We arbitrarily choose the default size of the first bundle as the + // default size for the image list too, as it's not clear what else could + // we do here. Note that this size is only used to break the tie in case + // the same number of bundles prefer two different sizes, so it's not going + // to matter at all in most cases. + const wxSize + size = GetConsensusSizeFor(win, bundles, bundles[0].GetDefaultSize()); + + wxImageList* const iml = new wxImageList(size.x, size.y); + + for ( size_t n = 0; n < bundles.size(); ++n ) + { + iml->Add(bundles[n].GetBitmap(size)); + } + + return iml; +} + // ============================================================================ // wxBitmapBundleImpl implementation // ============================================================================ diff --git a/src/msw/notebook.cpp b/src/msw/notebook.cpp index 5f281aaaae..2b4f20b006 100644 --- a/src/msw/notebook.cpp +++ b/src/msw/notebook.cpp @@ -447,14 +447,22 @@ bool wxNotebook::SetPageImage(size_t nPage, int nImage) return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0; } -void wxNotebook::SetImageList(wxImageList* imageList) +void wxNotebook::OnImagesChanged() { - wxNotebookBase::SetImageList(imageList); + HIMAGELIST himl; - if ( imageList ) + if ( HasImages() ) { - (void) TabCtrl_SetImageList(GetHwnd(), GetHimagelistOf(imageList)); + UpdateImageListIfNecessary(this); + + himl = GetHimagelistOf(GetImageList()); } + else + { + himl = 0; + } + + (void) TabCtrl_SetImageList(GetHwnd(), himl); } // ----------------------------------------------------------------------------