sd/source/ui/slideshow/slideshowimpl.cxx | 6 + slideshow/source/engine/slideoverlaybutton.cxx | 12 ++ slideshow/source/engine/slideoverlaybutton.hxx | 2 slideshow/source/engine/slideshowimpl.cxx | 147 ++++++++++++++++++++++++- 4 files changed, 165 insertions(+), 2 deletions(-)
New commits: commit b6bec207724d19bb04f7bf2e3deba3a1e70f895e Author: Vladislav Tarakanov <[email protected]> AuthorDate: Wed Jan 7 14:37:24 2026 +0400 Commit: Samuel Mehrbrodt <[email protected]> CommitDate: Mon Jan 26 10:59:04 2026 +0100 tdf#158394 Automatic scaling of icons for navigation bar Added handling for the viewAdded and viewChanged events, which cause navigation bar icons to change if they don't fit the current presentation area size. This handler is only applied when automatic scaling of the navigation bar is enabled, so it shouldn't impact performance when the bar isn't used or a fixed size is selected. Icon sizes: XLarge for UHD and above Large for FHD and up Small for anything smaller than FHD Change-Id: I9f6599291d57aca9991c8d2dd2969d1edb36080e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196157 Reviewed-by: Heiko Tietze <[email protected]> Tested-by: Jenkins Reviewed-by: Samuel Mehrbrodt <[email protected]> diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx index 0f18410a3ad3..92b8b605af5c 100644 --- a/sd/source/ui/slideshow/slideshowimpl.cxx +++ b/sd/source/ui/slideshow/slideshowimpl.cxx @@ -1303,6 +1303,12 @@ bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProp break; } case NavbarButtonSize::Auto: + { + mxShow->setProperty(beans::PropertyValue("NavigationBarAutoscale", -1, + Any(true), + PropertyState_DIRECT_VALUE)); + } + [[fallthrough]]; // Preset default buttons size case NavbarButtonSize::Small: default: { diff --git a/slideshow/source/engine/slideoverlaybutton.cxx b/slideshow/source/engine/slideoverlaybutton.cxx index 2aad5cd793cf..43b72dcd3332 100644 --- a/slideshow/source/engine/slideoverlaybutton.cxx +++ b/slideshow/source/engine/slideoverlaybutton.cxx @@ -83,6 +83,18 @@ void SlideOverlayButton::setVisible(const bool bVisible) mrScreenUpdater.requestImmediateUpdate(); } +void SlideOverlayButton::clear() +{ + mrEventMultiplexer.removeViewHandler( + std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this())); + mrEventMultiplexer.removeClickHandler( + std::dynamic_pointer_cast<MouseEventHandler>(shared_from_this())); + for (auto& item : maViews) + { + item.second->getContentCanvas()->clear(); + } +} + css::geometry::IntegerSize2D SlideOverlayButton::getSize() const { return mxIconBitmap->getSize(); } basegfx::B2DPoint SlideOverlayButton::calcSpritePos(UnoViewSharedPtr const& rView) const diff --git a/slideshow/source/engine/slideoverlaybutton.hxx b/slideshow/source/engine/slideoverlaybutton.hxx index ceec9eed7b59..ab4bb23d6f74 100644 --- a/slideshow/source/engine/slideoverlaybutton.hxx +++ b/slideshow/source/engine/slideoverlaybutton.hxx @@ -66,6 +66,8 @@ public: css::geometry::IntegerSize2D getSize() const; basegfx::B2DPoint calcSpritePos(UnoViewSharedPtr const& rView) const; + void clear(); + private: SlideOverlayButton(css::uno::Reference<css::rendering::XBitmap> xIconBitmap, css::awt::Point pPosition, diff --git a/slideshow/source/engine/slideshowimpl.cxx b/slideshow/source/engine/slideshowimpl.cxx index c84cda86a3ca..71af70f54841 100644 --- a/slideshow/source/engine/slideshowimpl.cxx +++ b/slideshow/source/engine/slideshowimpl.cxx @@ -63,6 +63,9 @@ #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/loader/CannotActivateFactoryException.hpp> +#include <vcl/canvastools.hxx> +#include <vcl/vclenum.hxx> + #include <unoviewcontainer.hxx> #include <transitionfactory.hxx> #include <eventmultiplexer.hxx> @@ -101,6 +104,18 @@ namespace box2d::utils { class box2DWorld; namespace { +constexpr OUString BMP_PREV_SLIDE_SMALL = u"sd/res/prevslide_small.png"_ustr; +constexpr OUString BMP_NEXT_SLIDE_SMALL = u"sd/res/nextslide_small.png"_ustr; +constexpr OUString BMP_MENU_SLIDE_SMALL = u"sd/res/slideshowmenu_small.png"_ustr; + +constexpr OUString BMP_PREV_SLIDE_LARGE = u"sd/res/prevslide_large.png"_ustr; +constexpr OUString BMP_NEXT_SLIDE_LARGE = u"sd/res/nextslide_large.png"_ustr; +constexpr OUString BMP_MENU_SLIDE_LARGE = u"sd/res/slideshowmenu_large.png"_ustr; + +constexpr OUString BMP_PREV_SLIDE_EXTRALARGE = u"sd/res/prevslide_extralarge.png"_ustr; +constexpr OUString BMP_NEXT_SLIDE_EXTRALARGE = u"sd/res/nextslide_extralarge.png"_ustr; +constexpr OUString BMP_MENU_SLIDE_EXTRALARGE = u"sd/res/slideshowmenu_extralarge.png"_ustr; + /** During animations the update() method tells its caller to call it as soon as possible. This gives us more time to render the next frame and still maintain a steady frame rate. This class is responsible for @@ -266,6 +281,9 @@ public: */ bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode ); + + void handleViewChangedEvent( const sal_Int32 width, const sal_Int32 height ); + /** Obtain a MediaTempFile for the specified url. */ virtual std::shared_ptr<avmedia::MediaTempFile> getMediaTempFile(const OUString& aUrl) override; @@ -406,6 +424,11 @@ private: */ void rewindEffectToPreviousSlide(); + void updateNavbarIcons( + const OUString& prevSlideIconPath, + const OUString& contextMenuIconPath, + const OUString& nextSlideIconPath ); + /// all registered views UnoViewContainer maViewContainer; @@ -448,6 +471,8 @@ private: std::shared_ptr<SlideOverlayButton> mpNavigationMenu; std::shared_ptr<SlideOverlayButton> mpNavigationNext; + NavbarButtonSize maCurNavbarBtnSize; + std::shared_ptr<PointerSymbol> mpPointerSymbol; /// the current slide transition sound object: @@ -498,7 +523,8 @@ private: struct SlideShowImpl::SeparateListenerImpl : public EventHandler, public ViewRepaintHandler, public HyperlinkHandler, - public AnimationEventHandler + public AnimationEventHandler, + public ViewEventHandler { SlideShowImpl& mrShow; ScreenUpdater& mrScreenUpdater; @@ -550,6 +576,23 @@ struct SlideShowImpl::SeparateListenerImpl : public EventHandler, { return mrShow.handleAnimationEvent(rNode); } + + // ViewEventHandler + virtual void viewAdded(const UnoViewSharedPtr& rView) override + { + auto size = rView->getUnoView()->getCanvasArea(); + mrShow.handleViewChangedEvent(size.Width, size.Height); + } + + virtual void viewRemoved(const UnoViewSharedPtr& /*rView*/) override { } + + virtual void viewChanged(const UnoViewSharedPtr& rView) override + { + auto size = rView->getUnoView()->getCanvasArea(); + mrShow.handleViewChangedEvent(size.Width, size.Height); + } + + virtual void viewsChanged() override { } }; SlideShowImpl::SlideShowImpl( @@ -574,7 +617,7 @@ SlideShowImpl::SlideShowImpl( mpBox2DDummyPtr(), mpListener(), mpRehearseTimingsActivity(), - mpWaitSymbol(), + maCurNavbarBtnSize(), mpPointerSymbol(), mpCurrentSlideTransitionSound(), mxComponentContext(std::move( xContext )), @@ -1280,6 +1323,52 @@ void SlideShowImpl::rewindEffectToPreviousSlide() maScreenUpdater.commitUpdates(); } +void SlideShowImpl::updateNavbarIcons( + const OUString& prevSlideIconPath, + const OUString& contextMenuIconPath, + const OUString& nextSlideIconPath ) +{ + mpNavigationPrev->clear(); + Bitmap prevSlideBm(prevSlideIconPath); + const uno::Reference<rendering::XBitmap> xPrevSBitmap( vcl::unotools::xBitmapFromBitmap(prevSlideBm) ); + if (xPrevSBitmap.is()) + { + mpNavigationPrev = SlideOverlayButton::create( + xPrevSBitmap, { 20, 10 }, [this](basegfx::B2DPoint) { notifySlideEnded(true); }, + maScreenUpdater, maEventMultiplexer, maViewContainer); + } + + mpNavigationMenu->clear(); + Bitmap menuBm(contextMenuIconPath); + const uno::Reference<rendering::XBitmap> xMenuBitmap( vcl::unotools::xBitmapFromBitmap(menuBm) ); + if (xMenuBitmap.is()) + { + mpNavigationMenu = SlideOverlayButton::create( + xMenuBitmap, { xMenuBitmap->getSize().Width + 48, 10 }, [this](basegfx::B2DPoint pos) { + maListenerContainer.forEach( + [pos](const uno::Reference<presentation::XSlideShowListener>& xListener) { + uno::Reference<presentation::XSlideShowNavigationListener> xNavListener( + xListener, uno::UNO_QUERY); + if (xNavListener.is()) + xNavListener->contextMenuShow( + css::awt::Point(static_cast<sal_Int32>(floor(pos.getX())), + static_cast<sal_Int32>(floor(pos.getY())))); + }); + }, + maScreenUpdater, maEventMultiplexer, maViewContainer); + } + + mpNavigationNext->clear(); + Bitmap nextSlideBm(nextSlideIconPath); + const uno::Reference<rendering::XBitmap> xNextSBitmap( vcl::unotools::xBitmapFromBitmap(nextSlideBm) ); + if (xNextSBitmap.is()) + { + mpNavigationNext = SlideOverlayButton::create( + xNextSBitmap, { 2 * xPrevSBitmap->getSize().Width + 76, 10 }, [this](basegfx::B2DPoint) { notifySlideEnded(false); }, + maScreenUpdater, maEventMultiplexer, maViewContainer); + } +} + sal_Bool SlideShowImpl::startShapeActivity( uno::Reference<drawing::XShape> const& /*xShape*/ ) { @@ -1878,6 +1967,24 @@ sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty ) return true; } + if (rProperty.Name == "NavigationBarAutoscale") + { + bool isAutoscale; + if (!(rProperty.Value >>= isAutoscale)) + return false; + + if (isAutoscale) + { + maEventMultiplexer.addViewHandler( mpListener ); + } + else + { + maEventMultiplexer.removeViewHandler( mpListener ); + } + + return true; + } + if ( rProperty.Name == "PointerSymbolBitmap" ) { uno::Reference<rendering::XBitmap> xBitmap; @@ -2501,6 +2608,42 @@ bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode ) return true; } +void SlideShowImpl::handleViewChangedEvent( const sal_Int32 width, const sal_Int32 height ) +{ + NavbarButtonSize newSize = NavbarButtonSize::Small; + sal_Int32 screenArea = width * height; + if (screenArea >= 3840 * 2160 /* UHD and above */) + { + newSize = NavbarButtonSize::XLarge; + } + else if (screenArea >= 1920 * 1080 /* FHD and above */) + { + newSize = NavbarButtonSize::Large; + } + + if (newSize != maCurNavbarBtnSize) + { + maCurNavbarBtnSize = newSize; + switch ( maCurNavbarBtnSize ) { + case NavbarButtonSize::Large: + { + updateNavbarIcons(BMP_PREV_SLIDE_LARGE, BMP_MENU_SLIDE_LARGE, BMP_NEXT_SLIDE_LARGE); + } + break; + case NavbarButtonSize::XLarge: + { + updateNavbarIcons(BMP_PREV_SLIDE_EXTRALARGE, BMP_MENU_SLIDE_EXTRALARGE, BMP_NEXT_SLIDE_EXTRALARGE); + } + break; + default: + { + updateNavbarIcons(BMP_PREV_SLIDE_SMALL, BMP_MENU_SLIDE_SMALL, BMP_NEXT_SLIDE_SMALL); + } + break; + } + } +} + std::shared_ptr<avmedia::MediaTempFile> SlideShowImpl::getMediaTempFile(const OUString& aUrl) { std::shared_ptr<avmedia::MediaTempFile> aRet;
