From cb9993211475657cd5f562753f8ffc338654038b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 25 Aug 2023 20:19:56 +0200 Subject: [PATCH] Add support for specifying high DPI animations in XRC Deprecate wxXmlResourceHandler::GetAnimation() function which returns just a single animation and add a new GetAnimations() replacing it. Use the new function in wxAnimationCtrl XRC handler to pass all the animations defined in the XRC file to the control. --- docs/doxygen/overviews/xrc_format.h | 4 +- include/wx/xrc/xmlres.h | 10 +++- include/wx/xrc/xmlreshandler.h | 21 +++++-- src/xrc/xh_animatctrl.cpp | 86 ++++++++++++++++++----------- src/xrc/xmlreshandler.cpp | 24 ++++++++ 5 files changed, 105 insertions(+), 40 deletions(-) diff --git a/docs/doxygen/overviews/xrc_format.h b/docs/doxygen/overviews/xrc_format.h index 235dcd927d..acbdfa6724 100644 --- a/docs/doxygen/overviews/xrc_format.h +++ b/docs/doxygen/overviews/xrc_format.h @@ -653,7 +653,9 @@ controls cannot have children. @beginTable @hdr3col{property, type, description} @row3col{animation, @ref overview_xrcformat_type_url, - Animation file to load into the control (default: none).} + Animation file to load into the control or, since wxWindow 3.3.0, multiple + semicolon-separated files in order of increasing size, corresponding to + multiple versions of the animation for different resolutions (default: none).} @row3col{inactive-bitmap, @ref overview_xrcformat_type_bitmap, Bitmap to use when not playing the animation (default: the default).} @endTable diff --git a/include/wx/xrc/xmlres.h b/include/wx/xrc/xmlres.h index 8cc356b9cc..868c5eb216 100644 --- a/include/wx/xrc/xmlres.h +++ b/include/wx/xrc/xmlres.h @@ -621,11 +621,19 @@ public: wxImageList *GetImageList(const wxString& param = wxT("imagelist")) override; #if wxUSE_ANIMATIONCTRL + // Get all the animations defined in the given parameter which may contain + // more than one semicolon-separated paths. + wxAnimationBundle GetAnimations(const wxString& param = wxT("animation"), + wxAnimationCtrlBase* ctrl = nullptr) override; + +#if WXWIN_COMPATIBILITY_3_2 + wxDEPRECATED_MSG("Use GetAnimations() instead") // Gets an animation creating it using the provided control (so that it // will be compatible with it) if any. wxAnimation* GetAnimation(const wxString& param = wxT("animation"), wxAnimationCtrlBase* ctrl = nullptr) override; -#endif +#endif // WXWIN_COMPATIBILITY_3_2 +#endif // wxUSE_ANIMATIONCTRL // Gets a font. wxFont GetFont(const wxString& param = wxT("font"), wxWindow* parent = nullptr) override; diff --git a/include/wx/xrc/xmlreshandler.h b/include/wx/xrc/xmlreshandler.h index be71ad7af9..7c0dc4773d 100644 --- a/include/wx/xrc/xmlreshandler.h +++ b/include/wx/xrc/xmlreshandler.h @@ -22,6 +22,7 @@ #include "wx/window.h" class WXDLLIMPEXP_FWD_CORE wxAnimation; +class WXDLLIMPEXP_FWD_CORE wxAnimationBundle; class WXDLLIMPEXP_FWD_CORE wxAnimationCtrlBase; class WXDLLIMPEXP_FWD_XML wxXmlNode; @@ -109,9 +110,15 @@ public: virtual wxImageList *GetImageList(const wxString& param = wxT("imagelist")) = 0; #if wxUSE_ANIMATIONCTRL + virtual wxAnimationBundle GetAnimations(const wxString& param = wxT("animation"), + wxAnimationCtrlBase* ctrl = nullptr) = 0; + +#if WXWIN_COMPATIBILITY_3_2 + wxDEPRECATED_BUT_USED_INTERNALLY_MSG("Use GetAnimations() instead") virtual wxAnimation* GetAnimation(const wxString& param = wxT("animation"), wxAnimationCtrlBase* ctrl = nullptr) = 0; -#endif +#endif // WXWIN_COMPATIBILITY_3_2 +#endif // wxUSE_ANIMATIONCTRL virtual wxFont GetFont(const wxString& param = wxT("font"), wxWindow* parent = nullptr) = 0; virtual bool GetBoolAttr(const wxString& attr, bool defaultv) = 0; @@ -377,12 +384,14 @@ protected: } #if wxUSE_ANIMATIONCTRL + wxAnimationBundle GetAnimations(const wxString& param = wxT("animation"), + wxAnimationCtrlBase* ctrl = nullptr); + +#if WXWIN_COMPATIBILITY_3_2 wxAnimation* GetAnimation(const wxString& param = wxT("animation"), - wxAnimationCtrlBase* ctrl = nullptr) - { - return GetImpl()->GetAnimation(param, ctrl); - } -#endif + wxAnimationCtrlBase* ctrl = nullptr); +#endif // WXWIN_COMPATIBILITY_3_2 +#endif // wxUSE_ANIMATIONCTRL wxFont GetFont(const wxString& param = wxT("font"), wxWindow* parent = nullptr) diff --git a/src/xrc/xh_animatctrl.cpp b/src/xrc/xh_animatctrl.cpp index 59f82559d1..0e65a2b630 100644 --- a/src/xrc/xh_animatctrl.cpp +++ b/src/xrc/xh_animatctrl.cpp @@ -58,9 +58,9 @@ wxObject *wxAnimationCtrlXmlHandler::DoCreateResource() if ( GetBool("hidden", 0) == 1 ) ctrl->Hide(); - std::unique_ptr animation(GetAnimation("animation", ctrl)); - if ( animation ) - ctrl->SetAnimation(*animation); + const auto animations = GetAnimations("animation", ctrl); + if ( animations.IsOk() ) + ctrl->SetAnimation(animations); // if no inactive-bitmap has been provided, GetBitmapBundle() will return // an empty bundle, which just tells wxAnimationCtrl to use the default @@ -78,39 +78,61 @@ bool wxAnimationCtrlXmlHandler::CanHandle(wxXmlNode *node) IsOfClass(node, wxT("wxGenericAnimationCtrl")); } +wxAnimationBundle +wxXmlResourceHandlerImpl::GetAnimations(const wxString& param, + wxAnimationCtrlBase* ctrl) +{ + wxString paths = GetFilePath(GetParamNode(param)); + if ( paths.empty() ) + return {}; + + wxAnimationBundle animations; + for ( const auto& name: wxSplit(paths, ';', '\0') ) + { + // create compatible animation object + wxAnimation ani; + if ( ctrl ) + ani = ctrl->CreateAnimation(); + + // load the animation from file +#if wxUSE_FILESYSTEM + wxFSFile * const + fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE); + if ( fsfile ) + { + ani.Load(*fsfile->GetStream()); + delete fsfile; + } +#else + ani.LoadFile(name); +#endif + + if ( !ani.IsOk() ) + { + ReportParamError + ( + param, + wxString::Format("cannot create animation from \"%s\"", name) + ); + return {}; + } + + animations.Add(ani); + } + + return animations; +} + +#if WXWIN_COMPATIBILITY_3_2 + wxAnimation* wxXmlResourceHandlerImpl::GetAnimation(const wxString& param, wxAnimationCtrlBase* ctrl) { - wxString name = GetFilePath(GetParamNode(param)); - if ( name.empty() ) - return nullptr; + const auto animations = GetAnimations(param, ctrl); - // load the animation from file - std::unique_ptr ani(ctrl ? new wxAnimation(ctrl->CreateAnimation()) - : new wxAnimation); -#if wxUSE_FILESYSTEM - wxFSFile * const - fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE); - if ( fsfile ) - { - ani->Load(*fsfile->GetStream()); - delete fsfile; - } -#else - ani->LoadFile(name); -#endif - - if ( !ani->IsOk() ) - { - ReportParamError - ( - param, - wxString::Format("cannot create animation from \"%s\"", name) - ); - return nullptr; - } - - return ani.release(); + return animations.IsOk() ? new wxAnimation(animations.GetAll()[0]) : nullptr; } +#endif // WXWIN_COMPATIBILITY_3_2 + #endif // wxUSE_XRC && wxUSE_ANIMATIONCTRL diff --git a/src/xrc/xmlreshandler.cpp b/src/xrc/xmlreshandler.cpp index 6362a4acff..f50127c230 100644 --- a/src/xrc/xmlreshandler.cpp +++ b/src/xrc/xmlreshandler.cpp @@ -14,6 +14,10 @@ #include "wx/xrc/xmlreshandler.h" +#if wxUSE_ANIMATIONCTRL + #include "wx/animate.h" +#endif + wxIMPLEMENT_ABSTRACT_CLASS(wxXmlResourceHandler, wxObject); wxXmlResourceHandlerImplBase* wxXmlResourceHandler::GetImpl() const @@ -65,4 +69,24 @@ void wxXmlResourceHandler::AddWindowStyles() XRC_ADD_STYLE(wxWS_EX_PROCESS_UI_UPDATES); } +#if wxUSE_ANIMATIONCTRL + +wxAnimationBundle +wxXmlResourceHandler::GetAnimations(const wxString& param, + wxAnimationCtrlBase* ctrl) +{ + return GetImpl()->GetAnimations(param, ctrl); +} + +#if WXWIN_COMPATIBILITY_3_2 +wxAnimation* +wxXmlResourceHandler::GetAnimation(const wxString& param, + wxAnimationCtrlBase* ctrl) +{ + return GetImpl()->GetAnimation(param, ctrl); +} +#endif // WXWIN_COMPATIBILITY_3_2 + +#endif // wxUSE_ANIMATIONCTRL + #endif // wxUSE_XRC