From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- sd/source/console/PresenterToolBar.cxx | 2013 ++++++++++++++++++++++++++++++++ 1 file changed, 2013 insertions(+) create mode 100644 sd/source/console/PresenterToolBar.cxx (limited to 'sd/source/console/PresenterToolBar.cxx') diff --git a/sd/source/console/PresenterToolBar.cxx b/sd/source/console/PresenterToolBar.cxx new file mode 100644 index 0000000000..5e7c770df2 --- /dev/null +++ b/sd/source/console/PresenterToolBar.cxx @@ -0,0 +1,2013 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "PresenterToolBar.hxx" + +#include "PresenterBitmapContainer.hxx" +#include "PresenterCanvasHelper.hxx" +#include "PresenterGeometryHelper.hxx" +#include "PresenterPaintManager.hxx" +#include "PresenterTimer.hxx" +#include "PresenterWindowManager.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace sdext::presenter { + +const sal_Int32 gnGapSize (20); + +namespace { + + class Text + { + public: + Text(); + Text ( + OUString sText, + PresenterTheme::SharedFontDescriptor pFont); + + void SetText (const OUString& rsText); + const OUString& GetText() const; + const PresenterTheme::SharedFontDescriptor& GetFont() const; + + void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState, + const awt::Rectangle& rBoundingBox); + + geometry::RealRectangle2D GetBoundingBox ( + const Reference& rxCanvas); + + private: + OUString msText; + PresenterTheme::SharedFontDescriptor mpFont; + }; + + class ElementMode + { + public: + ElementMode(); + ElementMode(const ElementMode&) = delete; + ElementMode& operator=(const ElementMode&) = delete; + + SharedBitmapDescriptor mpIcon; + OUString msAction; + Text maText; + + void ReadElementMode ( + const Reference& rxProperties, + const OUString& rsModeName, + std::shared_ptr const & rpDefaultMode, + ::sdext::presenter::PresenterToolBar::Context const & rContext); + }; + typedef std::shared_ptr SharedElementMode; + +} // end of anonymous namespace + +class PresenterToolBar::Context +{ +public: + Context() = default; + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + Reference mxPresenterHelper; + css::uno::Reference mxCanvas; +}; + +//===== PresenterToolBar::Element ============================================= + +namespace { + typedef cppu::WeakComponentImplHelper< + css::document::XEventListener, + css::frame::XStatusListener + > ElementInterfaceBase; + + class Element + : private ::cppu::BaseMutex, + public ElementInterfaceBase + { + public: + explicit Element (::rtl::Reference pToolBar); + Element(const Element&) = delete; + Element& operator=(const Element&) = delete; + + virtual void SAL_CALL disposing() override; + + virtual void SetModes ( + const SharedElementMode& rpNormalMode, + const SharedElementMode& rpMouseOverMode, + const SharedElementMode& rpSelectedMode, + const SharedElementMode& rpDisabledMode, + const SharedElementMode& rpMouseOverSelectedMode); + void CurrentSlideHasChanged(); + void SetLocation (const awt::Point& rLocation); + void SetSize (const geometry::RealSize2D& rSize); + virtual void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState) = 0; + awt::Size const & GetBoundingSize ( + const Reference& rxCanvas); + awt::Rectangle GetBoundingBox() const; + virtual bool SetState (const bool bIsOver, const bool bIsPressed); + void Invalidate (const bool bSynchronous); + bool IsOutside (const awt::Rectangle& rBox); + virtual bool IsFilling() const; + void UpdateState(); + + // lang::XEventListener + + virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override; + + // document::XEventListener + + virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override; + + // frame::XStatusListener + + virtual void SAL_CALL statusChanged (const css::frame::FeatureStateEvent& rEvent) override; + + protected: + ::rtl::Reference mpToolBar; + awt::Point maLocation; + awt::Size maSize; + SharedElementMode mpNormal; + SharedElementMode mpMouseOver; + SharedElementMode mpSelected; + SharedElementMode mpDisabled; + SharedElementMode mpMouseOverSelected; + SharedElementMode mpMode; + bool mbIsOver; + bool mbIsPressed; + bool mbIsSelected; + + virtual awt::Size CreateBoundingSize ( + const Reference& rxCanvas) = 0; + + bool IsEnabled() const { return mbIsEnabled;} + private: + bool mbIsEnabled; + }; + +} // end of anonymous namespace + +class PresenterToolBar::ElementContainerPart + : public ::std::vector > +{ +}; + +//===== Button ================================================================ + +namespace { + + class Button : public Element + { + public: + static ::rtl::Reference Create ( + const ::rtl::Reference& rpToolBar); + + virtual void SAL_CALL disposing() override; + + virtual void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState) override; + + // lang::XEventListener + + virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override; + + protected: + virtual awt::Size CreateBoundingSize ( + const Reference& rxCanvas) override; + + private: + bool mbIsListenerRegistered; + + Button (const ::rtl::Reference& rpToolBar); + void Initialize(); + void PaintIcon ( + const Reference& rxCanvas, + const sal_Int32 nTextHeight, + const rendering::ViewState& rViewState); + PresenterBitmapDescriptor::Mode GetMode() const; + }; + +//===== Label ================================================================= + + class Label : public Element + { + public: + explicit Label (const ::rtl::Reference& rpToolBar); + + void SetText (const OUString& rsText); + virtual void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState) override; + virtual bool SetState (const bool bIsOver, const bool bIsPressed) override; + + protected: + virtual awt::Size CreateBoundingSize ( + const Reference& rxCanvas) override; + }; + +// Some specialized controls. + + class TimeFormatter + { + public: + static OUString FormatTime (const oslDateTime& rTime); + }; + + class TimeLabel : public Label + { + public: + void ConnectToTimer(); + virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0; + protected: + explicit TimeLabel(const ::rtl::Reference& rpToolBar); + using Element::disposing; + virtual void SAL_CALL disposing() override; + private: + class Listener : public PresenterClockTimer::Listener + { + public: + explicit Listener (::rtl::Reference xLabel) + : mxLabel(std::move(xLabel)) {} + virtual ~Listener() {} + virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override + { if (mxLabel.is()) mxLabel->TimeHasChanged(rCurrentTime); } + private: + ::rtl::Reference mxLabel; + }; + std::shared_ptr mpListener; + }; + + class CurrentTimeLabel : public TimeLabel + { + public: + static ::rtl::Reference Create ( + const ::rtl::Reference& rpToolBar); + virtual void SetModes ( + const SharedElementMode& rpNormalMode, + const SharedElementMode& rpMouseOverMode, + const SharedElementMode& rpSelectedMode, + const SharedElementMode& rpDisabledMode, + const SharedElementMode& rpMouseOverSelectedMode) override; + private: + CurrentTimeLabel (const ::rtl::Reference& rpToolBar); + virtual ~CurrentTimeLabel() override; + virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override; + }; + + class PresentationTimeLabel : public TimeLabel, public IPresentationTime + { + public: + static ::rtl::Reference Create ( + const ::rtl::Reference& rpToolBar); + virtual void SetModes ( + const SharedElementMode& rpNormalMode, + const SharedElementMode& rpMouseOverMode, + const SharedElementMode& rpSelectedMode, + const SharedElementMode& rpDisabledMode, + const SharedElementMode& rpMouseOverSelectedMode) override; + virtual void restart() override; + virtual bool isPaused() override; + virtual void setPauseStatus(const bool pauseStatus) override; + const TimeValue& getPauseTimeValue() const; + void setPauseTimeValue(const TimeValue pauseTime); + private: + TimeValue maStartTimeValue; + TimeValue pauseTimeValue; + PresentationTimeLabel (const ::rtl::Reference& rpToolBar); + bool paused; + virtual ~PresentationTimeLabel() override; + virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override; + }; + + class VerticalSeparator : public Element + { + public: + explicit VerticalSeparator (const ::rtl::Reference& rpToolBar); + virtual void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState) override; + virtual bool IsFilling() const override; + + protected: + virtual awt::Size CreateBoundingSize ( + const Reference& rxCanvas) override; + }; + + class HorizontalSeparator : public Element + { + public: + explicit HorizontalSeparator (const ::rtl::Reference& rpToolBar); + virtual void Paint ( + const Reference& rxCanvas, + const rendering::ViewState& rViewState) override; + virtual bool IsFilling() const override; + + protected: + virtual awt::Size CreateBoundingSize ( + const Reference& rxCanvas) override; + }; +} // end of anonymous namespace + +//===== PresenterToolBar ====================================================== + +PresenterToolBar::PresenterToolBar ( + const Reference& rxContext, + css::uno::Reference xWindow, + css::uno::Reference xCanvas, + ::rtl::Reference pPresenterController, + const Anchor eAnchor) + : PresenterToolBarInterfaceBase(m_aMutex), + mxComponentContext(rxContext), + mxWindow(std::move(xWindow)), + mxCanvas(std::move(xCanvas)), + mpPresenterController(std::move(pPresenterController)), + mbIsLayoutPending(false), + meAnchor(eAnchor) +{ +} + +void PresenterToolBar::Initialize ( + const OUString& rsConfigurationPath) +{ + try + { + CreateControls(rsConfigurationPath); + + if (mxWindow.is()) + { + mxWindow->addWindowListener(this); + mxWindow->addPaintListener(this); + mxWindow->addMouseListener(this); + mxWindow->addMouseMotionListener(this); + + Reference xPeer (mxWindow, UNO_QUERY); + if (xPeer.is()) + xPeer->setBackground(util::Color(0xff000000)); + + mxWindow->setVisible(true); + } + + mxSlideShowController = mpPresenterController->GetSlideShowController(); + UpdateSlideNumber(); + mbIsLayoutPending = true; + } + catch (RuntimeException&) + { + mpCurrentContainerPart.reset(); + maElementContainer.clear(); + throw; + } +} + +PresenterToolBar::~PresenterToolBar() +{ +} + +void SAL_CALL PresenterToolBar::disposing() +{ + if (mxWindow.is()) + { + mxWindow->removeWindowListener(this); + mxWindow->removePaintListener(this); + mxWindow->removeMouseListener(this); + mxWindow->removeMouseMotionListener(this); + mxWindow = nullptr; + } + + // Dispose tool bar elements. + for (const auto& rxPart : maElementContainer) + { + OSL_ASSERT(rxPart != nullptr); + for (const rtl::Reference& pElement : *rxPart) + { + if (pElement) + { + Reference xComponent = pElement; + if (xComponent.is()) + xComponent->dispose(); + } + } + } + + mpCurrentContainerPart.reset(); + maElementContainer.clear(); +} + +void PresenterToolBar::InvalidateArea ( + const awt::Rectangle& rRepaintBox, + const bool bSynchronous) +{ + std::shared_ptr xManager(mpPresenterController->GetPaintManager()); + if (!xManager) + return; + xManager->Invalidate( + mxWindow, + rRepaintBox, + bSynchronous); +} + +void PresenterToolBar::RequestLayout() +{ + mbIsLayoutPending = true; + + std::shared_ptr xManager(mpPresenterController->GetPaintManager()); + if (!xManager) + return; + + xManager->Invalidate(mxWindow); +} + +geometry::RealSize2D const & PresenterToolBar::GetMinimalSize() +{ + if (mbIsLayoutPending) + Layout(mxCanvas); + return maMinimalSize; +} + +const ::rtl::Reference& PresenterToolBar::GetPresenterController() const +{ + return mpPresenterController; +} + +const Reference& PresenterToolBar::GetComponentContext() const +{ + return mxComponentContext; +} + +//----- lang::XEventListener ------------------------------------------------- + +void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject) +{ + if (rEventObject.Source == mxWindow) + mxWindow = nullptr; +} + +//----- XWindowListener ------------------------------------------------------- + +void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent&) +{ + mbIsLayoutPending = true; +} + +void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent&) {} + +void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject&) +{ + mbIsLayoutPending = true; +} + +void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject&) {} + +//----- XPaintListener -------------------------------------------------------- +void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent) +{ + if ( ! mxCanvas.is()) + return; + + if ( ! mbIsPresenterViewActive) + return; + + const rendering::ViewState aViewState ( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice())); + + if (mbIsLayoutPending) + Layout(mxCanvas); + + Paint(rEvent.UpdateRect, aViewState); + + // Make the back buffer visible. + Reference xSpriteCanvas (mxCanvas, UNO_QUERY); + if (xSpriteCanvas.is()) + xSpriteCanvas->updateScreen(false); +} + +//----- XMouseListener -------------------------------------------------------- +void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent) +{ + ThrowIfDisposed(); + CheckMouseOver(rEvent, true, true); +} + +void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent) +{ + ThrowIfDisposed(); + CheckMouseOver(rEvent, true); +} + +void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent) +{ + ThrowIfDisposed(); + CheckMouseOver(rEvent, true); +} + +void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent) +{ + ThrowIfDisposed(); + CheckMouseOver(rEvent, false); + } + +//----- XMouseMotionListener -------------------------------------------------- + +void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent) +{ + ThrowIfDisposed(); + CheckMouseOver(rEvent, true); + } + +void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent&) +{ + ThrowIfDisposed(); +} + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL PresenterToolBar::setCurrentPage (const Reference& rxSlide) +{ + if (rxSlide != mxCurrentSlide) + { + mxCurrentSlide = rxSlide; + UpdateSlideNumber(); + } +} + +Reference SAL_CALL PresenterToolBar::getCurrentPage() +{ + return mxCurrentSlide; +} + + +void PresenterToolBar::CreateControls ( + const OUString& rsConfigurationPath) +{ + if ( ! mxWindow.is()) + return; + + // Expand the macro in the bitmap file names. + PresenterConfigurationAccess aConfiguration ( + mxComponentContext, + "/org.openoffice.Office.PresenterScreen/", + PresenterConfigurationAccess::READ_ONLY); + + mpCurrentContainerPart = std::make_shared(); + maElementContainer.clear(); + maElementContainer.push_back(mpCurrentContainerPart); + + Reference xToolBarNode ( + aConfiguration.GetConfigurationNode(rsConfigurationPath), + UNO_QUERY); + if (!xToolBarNode.is()) + return; + + Reference xEntries ( + PresenterConfigurationAccess::GetConfigurationNode(xToolBarNode, "Entries"), + UNO_QUERY); + Context aContext; + aContext.mxPresenterHelper = mpPresenterController->GetPresenterHelper(); + aContext.mxCanvas = mxCanvas; + if (xEntries.is() + && aContext.mxPresenterHelper.is() + && aContext.mxCanvas.is()) + { + PresenterConfigurationAccess::ForAll( + xEntries, + [this, &aContext] (OUString const&, uno::Reference const& xProps) + { + return this->ProcessEntry(xProps, aContext); + }); + } +} + +void PresenterToolBar::ProcessEntry ( + const Reference& rxProperties, + Context const & rContext) +{ + if ( ! rxProperties.is()) + return; + + // Type has to be present. + OUString sType; + if ( ! (PresenterConfigurationAccess::GetProperty(rxProperties, "Type") >>= sType)) + return; + + // Read mode specific values. + SharedElementMode pNormalMode = std::make_shared(); + SharedElementMode pMouseOverMode = std::make_shared(); + SharedElementMode pSelectedMode = std::make_shared(); + SharedElementMode pDisabledMode = std::make_shared(); + SharedElementMode pMouseOverSelectedMode = std::make_shared(); + pNormalMode->ReadElementMode(rxProperties, "Normal", pNormalMode, rContext); + pMouseOverMode->ReadElementMode(rxProperties, "MouseOver", pNormalMode, rContext); + pSelectedMode->ReadElementMode(rxProperties, "Selected", pNormalMode, rContext); + pDisabledMode->ReadElementMode(rxProperties, "Disabled", pNormalMode, rContext); + pMouseOverSelectedMode->ReadElementMode(rxProperties, "MouseOverSelected", pSelectedMode, rContext); + + // Create new element. + ::rtl::Reference pElement; + if ( sType == "Button" ) + pElement = Button::Create(this); + else if ( sType == "CurrentTimeLabel" ) + pElement = CurrentTimeLabel::Create(this); + else if ( sType == "PresentationTimeLabel" ) + pElement = PresentationTimeLabel::Create(this); + else if ( sType == "VerticalSeparator" ) + pElement.set(new VerticalSeparator(this)); + else if ( sType == "HorizontalSeparator" ) + pElement.set(new HorizontalSeparator(this)); + else if ( sType == "Label" ) + pElement.set(new Label(this)); + else if ( sType == "ChangeOrientation" ) + { + mpCurrentContainerPart = std::make_shared(); + maElementContainer.push_back(mpCurrentContainerPart); + return; + } + if (pElement.is()) + { + pElement->SetModes( pNormalMode, pMouseOverMode, pSelectedMode, pDisabledMode, pMouseOverSelectedMode); + pElement->UpdateState(); + if (mpCurrentContainerPart) + mpCurrentContainerPart->push_back(pElement); + } +} + +void PresenterToolBar::Layout ( + const Reference& rxCanvas) +{ + if (maElementContainer.empty()) + return; + + mbIsLayoutPending = false; + + const awt::Rectangle aWindowBox (mxWindow->getPosSize()); + ::std::vector aPartSizes (maElementContainer.size()); + geometry::RealSize2D aTotalSize (0,0); + bool bIsHorizontal (true); + sal_Int32 nIndex (0); + double nTotalHorizontalGap (0); + sal_Int32 nGapCount (0); + for (const auto& rxPart : maElementContainer) + { + geometry::RealSize2D aSize (CalculatePartSize(rxCanvas, rxPart, bIsHorizontal)); + + // Remember the size of each part for later. + aPartSizes[nIndex] = aSize; + + // Add gaps between elements. + if (rxPart->size()>1 && bIsHorizontal) + { + nTotalHorizontalGap += (rxPart->size() - 1) * gnGapSize; + nGapCount += rxPart->size() - 1; + } + + // Orientation changes for each part. + bIsHorizontal = !bIsHorizontal; + // Width is accumulated. + aTotalSize.Width += aSize.Width; + // Height is the maximum height of all parts. + aTotalSize.Height = ::std::max(aTotalSize.Height, aSize.Height); + ++nIndex; + } + // Add gaps between parts. + if (maElementContainer.size() > 1) + { + nTotalHorizontalGap += (maElementContainer.size() - 1) * gnGapSize; + nGapCount += maElementContainer.size()-1; + } + + // Done to introduce gap between the end of the toolbar and the last button + aTotalSize.Width += gnGapSize/2; + + // Calculate the minimal size so that the window size of the tool bar + // can be adapted accordingly. + maMinimalSize = aTotalSize; + maMinimalSize.Width += nTotalHorizontalGap; + + // Calculate the gaps between elements. + double nGapWidth (0); + if (nGapCount > 0) + { + if (aTotalSize.Width + nTotalHorizontalGap > aWindowBox.Width) + nTotalHorizontalGap = aWindowBox.Width - aTotalSize.Width; + nGapWidth = nTotalHorizontalGap / nGapCount; + } + + // Determine the location of the left edge. + double nX (0); + switch (meAnchor) + { + case Left : nX = 0; break; + case Center: nX = (aWindowBox.Width - aTotalSize.Width - nTotalHorizontalGap) / 2; break; + } + + // Place the parts. + double nY ((aWindowBox.Height - aTotalSize.Height) / 2); + bIsHorizontal = true; + + /* push front or back ? ... */ + /// check whether RTL interface or not + if(!AllSettings::GetLayoutRTL()){ + nIndex = 0; + for (const auto& rxPart : maElementContainer) + { + geometry::RealRectangle2D aBoundingBox( + nX, nY, + nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height); + + // Add space for gaps between elements. + if (rxPart->size() > 1 && bIsHorizontal) + aBoundingBox.X2 += (rxPart->size() - 1) * nGapWidth; + + LayoutPart(rxCanvas, rxPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal); + bIsHorizontal = !bIsHorizontal; + nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth; + ++nIndex; + } + } + else { + ElementContainer::iterator iPart; + ElementContainer::iterator iBegin (maElementContainer.begin()); + for (iPart=maElementContainer.end()-1, nIndex=2; iPart!=iBegin-1; --iPart, --nIndex) + { + geometry::RealRectangle2D aBoundingBox( + nX, nY, + nX+aPartSizes[nIndex].Width, nY+aTotalSize.Height); + + // Add space for gaps between elements. + if ((*iPart)->size() > 1) + if (bIsHorizontal) + aBoundingBox.X2 += ((*iPart)->size()-1) * nGapWidth; + + LayoutPart(rxCanvas, *iPart, aBoundingBox, aPartSizes[nIndex], bIsHorizontal); + bIsHorizontal = !bIsHorizontal; + nX += aBoundingBox.X2 - aBoundingBox.X1 + nGapWidth; + } + } + + // The whole window has to be repainted. + std::shared_ptr xManager(mpPresenterController->GetPaintManager()); + if (!xManager) + return; + xManager->Invalidate(mxWindow); +} + +geometry::RealSize2D PresenterToolBar::CalculatePartSize ( + const Reference& rxCanvas, + const SharedElementContainerPart& rpPart, + const bool bIsHorizontal) +{ + geometry::RealSize2D aTotalSize (0,0); + + if (mxWindow.is()) + { + // Calculate the summed width of all elements. + for (const auto& rxElement : *rpPart) + { + if (!rxElement) + continue; + + const awt::Size aBSize (rxElement->GetBoundingSize(rxCanvas)); + if (bIsHorizontal) + { + aTotalSize.Width += aBSize.Width; + if (aBSize.Height > aTotalSize.Height) + aTotalSize.Height = aBSize.Height; + } + else + { + aTotalSize.Height += aBSize.Height; + if (aBSize.Width > aTotalSize.Width) + aTotalSize.Width = aBSize.Width; + } + } + } + return aTotalSize; +} + +void PresenterToolBar::LayoutPart ( + const Reference& rxCanvas, + const SharedElementContainerPart& rpPart, + const geometry::RealRectangle2D& rBoundingBox, + const geometry::RealSize2D& rPartSize, + const bool bIsHorizontal) +{ + double nGap (0); + if (rpPart->size() > 1) + { + if (bIsHorizontal) + nGap = (rBoundingBox.X2 - rBoundingBox.X1 - rPartSize.Width) / (rpPart->size()-1); + else + nGap = (rBoundingBox.Y2 - rBoundingBox.Y1 - rPartSize.Height) / (rpPart->size()-1); + } + + // Place the elements. + double nX (rBoundingBox.X1); + double nY (rBoundingBox.Y1); + + /// check whether RTL interface or not + if(!AllSettings::GetLayoutRTL()){ + for (auto& rxElement : *rpPart) + { + if (!rxElement) + continue; + + const awt::Size aElementSize (rxElement->GetBoundingSize(rxCanvas)); + if (bIsHorizontal) + { + if (rxElement->IsFilling()) + { + nY = rBoundingBox.Y1; + rxElement->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1)); + } + else + nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2; + rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY))); + nX += aElementSize.Width + nGap; + } + else + { + if (rxElement->IsFilling()) + { + nX = rBoundingBox.X1; + rxElement->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aElementSize.Height)); + } + else + nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aElementSize.Width) / 2; + rxElement->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY))); + nY += aElementSize.Height + nGap; + } + } + } + else { + ElementContainerPart::const_iterator iElement; + ElementContainerPart::const_iterator iBegin (rpPart->begin()); + + for (iElement=rpPart->end()-1; iElement!=iBegin-1; --iElement) + { + if (iElement->get() == nullptr) + continue; + + const awt::Size aElementSize ((*iElement)->GetBoundingSize(rxCanvas)); + if (bIsHorizontal) + { + if ((*iElement)->IsFilling()) + { + nY = rBoundingBox.Y1; + (*iElement)->SetSize(geometry::RealSize2D(aElementSize.Width, rBoundingBox.Y2 - rBoundingBox.Y1)); + } + else + nY = rBoundingBox.Y1 + (rBoundingBox.Y2-rBoundingBox.Y1 - aElementSize.Height) / 2; + (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY))); + nX += aElementSize.Width + nGap; + } + else + { + // reverse presentation time with current time + if (iElement==iBegin){ + iElement=iBegin+2; + } + else if (iElement==iBegin+2){ + iElement=iBegin; + } + const awt::Size aNewElementSize ((*iElement)->GetBoundingSize(rxCanvas)); + if ((*iElement)->IsFilling()) + { + nX = rBoundingBox.X1; + (*iElement)->SetSize(geometry::RealSize2D(rBoundingBox.X2 - rBoundingBox.X1, aNewElementSize.Height)); + } + else + nX = rBoundingBox.X1 + (rBoundingBox.X2-rBoundingBox.X1 - aNewElementSize.Width) / 2; + (*iElement)->SetLocation(awt::Point(sal_Int32(0.5 + nX), sal_Int32(0.5 + nY))); + nY += aNewElementSize.Height + nGap; + + // return the index as it was before the reversing + if (iElement==iBegin) + iElement=iBegin+2; + else if (iElement==iBegin+2) + iElement=iBegin; + } + } + } +} + +void PresenterToolBar::Paint ( + const awt::Rectangle& rUpdateBox, + const rendering::ViewState& rViewState) +{ + OSL_ASSERT(mxCanvas.is()); + + for (const auto& rxPart : maElementContainer) + { + for (auto& rxElement : *rxPart) + { + if (rxElement) + { + if ( ! rxElement->IsOutside(rUpdateBox)) + rxElement->Paint(mxCanvas, rViewState); + } + } + } +} + +void PresenterToolBar::UpdateSlideNumber() +{ + if( mxSlideShowController.is() ) + { + for (const auto& rxPart : maElementContainer) + { + for (auto& rxElement : *rxPart) + { + if (rxElement) + rxElement->CurrentSlideHasChanged(); + } + } + } +} + +void PresenterToolBar::CheckMouseOver ( + const css::awt::MouseEvent& rEvent, + const bool bOverWindow, + const bool bMouseDown) +{ + css::awt::MouseEvent rTemp =rEvent; + if(AllSettings::GetLayoutRTL()){ + awt::Rectangle aWindowBox = mxWindow->getPosSize(); + rTemp.X=aWindowBox.Width-rTemp.X; + } + for (const auto& rxPart : maElementContainer) + { + for (auto& rxElement : *rxPart) + { + if (!rxElement) + continue; + + awt::Rectangle aBox (rxElement->GetBoundingBox()); + const bool bIsOver = bOverWindow + && aBox.X <= rTemp.X + && aBox.Width+aBox.X-1 >= rTemp.X + && aBox.Y <= rTemp.Y + && aBox.Height+aBox.Y-1 >= rTemp.Y; + rxElement->SetState( + bIsOver, + bIsOver && rTemp.Buttons!=0 && bMouseDown && rTemp.ClickCount>0); + } + } +} + +void PresenterToolBar::ThrowIfDisposed() const +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + "PresenterToolBar has already been disposed", + const_cast(static_cast(this))); + } +} + +//===== PresenterToolBarView ================================================== + +PresenterToolBarView::PresenterToolBarView ( + const Reference& rxContext, + const Reference& rxViewId, + const rtl::Reference<::sd::DrawController>& rxController, + const ::rtl::Reference& rpPresenterController) + : PresenterToolBarViewInterfaceBase(m_aMutex), + mxViewId(rxViewId), + mpPresenterController(rpPresenterController) +{ + try + { + Reference xCC(rxController->getConfigurationController(),UNO_SET_THROW); + mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW); + + mxWindow = mxPane->getWindow(); + mxCanvas = mxPane->getCanvas(); + + mpToolBar = new PresenterToolBar( + rxContext, + mxWindow, + mxCanvas, + rpPresenterController, + PresenterToolBar::Center); + mpToolBar->Initialize("PresenterScreenSettings/ToolBars/ToolBar"); + + if (mxWindow.is()) + { + mxWindow->addPaintListener(this); + + Reference xPeer (mxWindow, UNO_QUERY); + if (xPeer.is()) + xPeer->setBackground(util::Color(0xff000000)); + + mxWindow->setVisible(true); + } + } + catch (RuntimeException&) + { + mxViewId = nullptr; + throw; + } +} + +PresenterToolBarView::~PresenterToolBarView() +{ +} + +void SAL_CALL PresenterToolBarView::disposing() +{ + Reference xComponent = mpToolBar; + mpToolBar = nullptr; + if (xComponent.is()) + xComponent->dispose(); + + if (mxWindow.is()) + { + mxWindow->removePaintListener(this); + mxWindow = nullptr; + } + mxCanvas = nullptr; + mxViewId = nullptr; + mxPane = nullptr; + mpPresenterController = nullptr; +} + +const ::rtl::Reference& PresenterToolBarView::GetPresenterToolBar() const +{ + return mpToolBar; +} + +//----- XPaintListener -------------------------------------------------------- + +void SAL_CALL PresenterToolBarView::windowPaint (const css::awt::PaintEvent& rEvent) +{ + awt::Rectangle aWindowBox (mxWindow->getPosSize()); + mpPresenterController->GetCanvasHelper()->Paint( + mpPresenterController->GetViewBackground(mxViewId->getResourceURL()), + mxCanvas, + rEvent.UpdateRect, + awt::Rectangle(0,0,aWindowBox.Width, aWindowBox.Height), + awt::Rectangle()); +} + +//----- lang::XEventListener ------------------------------------------------- + +void SAL_CALL PresenterToolBarView::disposing (const lang::EventObject& rEventObject) +{ + if (rEventObject.Source == mxWindow) + mxWindow = nullptr; +} + +//----- XResourceId ----------------------------------------------------------- + +Reference SAL_CALL PresenterToolBarView::getResourceId() +{ + return mxViewId; +} + +sal_Bool SAL_CALL PresenterToolBarView::isAnchorOnly() +{ + return false; +} + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL PresenterToolBarView::setCurrentPage (const Reference& rxSlide) +{ + Reference xToolBar = mpToolBar; + if (xToolBar.is()) + xToolBar->setCurrentPage(rxSlide); +} + +Reference SAL_CALL PresenterToolBarView::getCurrentPage() +{ + return nullptr; +} + +//===== PresenterToolBar::Element ============================================= + +namespace { + +Element::Element ( + ::rtl::Reference pToolBar) + : ElementInterfaceBase(m_aMutex), + mpToolBar(std::move(pToolBar)), + mbIsOver(false), + mbIsPressed(false), + mbIsSelected(false), + mbIsEnabled(true) +{ + if (mpToolBar) + { + OSL_ASSERT(mpToolBar->GetPresenterController().is()); + OSL_ASSERT(mpToolBar->GetPresenterController()->GetWindowManager().is()); + } +} + +void Element::SetModes ( + const SharedElementMode& rpNormalMode, + const SharedElementMode& rpMouseOverMode, + const SharedElementMode& rpSelectedMode, + const SharedElementMode& rpDisabledMode, + const SharedElementMode& rpMouseOverSelectedMode) +{ + mpNormal = rpNormalMode; + mpMouseOver = rpMouseOverMode; + mpSelected = rpSelectedMode; + mpDisabled = rpDisabledMode; + mpMouseOverSelected = rpMouseOverSelectedMode; + mpMode = rpNormalMode; +} + +void Element::disposing() +{ +} + +awt::Size const & Element::GetBoundingSize ( + const Reference& rxCanvas) +{ + maSize = CreateBoundingSize(rxCanvas); + return maSize; +} + +awt::Rectangle Element::GetBoundingBox() const +{ + return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, maSize.Height); +} + +void Element::CurrentSlideHasChanged() +{ + UpdateState(); +} + +void Element::SetLocation (const awt::Point& rLocation) +{ + maLocation = rLocation; +} + +void Element::SetSize (const geometry::RealSize2D& rSize) +{ + maSize = awt::Size(sal_Int32(0.5+rSize.Width), sal_Int32(0.5+rSize.Height)); +} + +bool Element::SetState ( + const bool bIsOver, + const bool bIsPressed) +{ + bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed); + bool bClicked (mbIsPressed && bIsOver && ! bIsPressed); + + mbIsOver = bIsOver; + mbIsPressed = bIsPressed; + + // When the element is disabled then ignore mouse over or selection. + // When the element is selected then ignore mouse over. + if ( ! mbIsEnabled) + mpMode = mpDisabled; + else if (mbIsSelected && mbIsOver) + mpMode = mpMouseOverSelected; + else if (mbIsSelected) + mpMode = mpSelected; + else if (mbIsOver) + mpMode = mpMouseOver; + else + mpMode = mpNormal; + + if (bClicked && mbIsEnabled) + { + if (mpMode) + { + do + { + if (mpMode->msAction.isEmpty()) + break; + + if (!mpToolBar) + break; + + if (!mpToolBar->GetPresenterController()) + break; + + mpToolBar->GetPresenterController()->DispatchUnoCommand(mpMode->msAction); + mpToolBar->RequestLayout(); + } + while (false); + } + + } + else if (bModified) + { + Invalidate(true); + } + + return bModified; +} + +void Element::Invalidate (const bool bSynchronous) +{ + OSL_ASSERT(mpToolBar.is()); + mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous); +} + +bool Element::IsOutside (const awt::Rectangle& rBox) +{ + if (rBox.X >= maLocation.X+maSize.Width) + return true; + else if (rBox.Y >= maLocation.Y+maSize.Height) + return true; + else if (maLocation.X >= rBox.X+rBox.Width) + return true; + else if (maLocation.Y >= rBox.Y+rBox.Height) + return true; + else + return false; +} + + +bool Element::IsFilling() const +{ + return false; +} + +void Element::UpdateState() +{ + OSL_ASSERT(mpToolBar); + OSL_ASSERT(mpToolBar->GetPresenterController()); + + if (!mpMode) + return; + + util::URL aURL (mpToolBar->GetPresenterController()->CreateURLFromString(mpMode->msAction)); + Reference xDispatch (mpToolBar->GetPresenterController()->GetDispatch(aURL)); + if (xDispatch.is()) + { + xDispatch->addStatusListener(this, aURL); + xDispatch->removeStatusListener(this, aURL); + } +} + +//----- lang::XEventListener -------------------------------------------------- + +void SAL_CALL Element::disposing (const css::lang::EventObject&) {} + +//----- document::XEventListener ---------------------------------------------- + +void SAL_CALL Element::notifyEvent (const css::document::EventObject&) +{ + UpdateState(); +} + +//----- frame::XStatusListener ------------------------------------------------ + +void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& rEvent) +{ + bool bIsSelected (mbIsSelected); + bool bIsEnabled (rEvent.IsEnabled); + rEvent.State >>= bIsSelected; + + if (bIsSelected != mbIsSelected || bIsEnabled != mbIsEnabled) + { + mbIsEnabled = bIsEnabled; + mbIsSelected = bIsSelected; + SetState(mbIsOver, mbIsPressed); + mpToolBar->RequestLayout(); + } +} + +} // end of anonymous namespace + +//===== ElementMode =========================================================== + +namespace { + +ElementMode::ElementMode() +{ +} + +void ElementMode::ReadElementMode ( + const Reference& rxElementProperties, + const OUString& rsModeName, + std::shared_ptr const & rpDefaultMode, + ::sdext::presenter::PresenterToolBar::Context const & rContext) +{ + try + { + Reference xNode ( + PresenterConfigurationAccess::GetProperty(rxElementProperties, rsModeName), + UNO_QUERY); + Reference xProperties ( + PresenterConfigurationAccess::GetNodeProperties(xNode, OUString())); + if (!xProperties.is() && rpDefaultMode != nullptr) + { + // The mode is not specified. Use the given, possibly empty, + // default mode instead. + mpIcon = rpDefaultMode->mpIcon; + msAction = rpDefaultMode->msAction; + maText = rpDefaultMode->maText; + } + + // Read action. + if ( ! (PresenterConfigurationAccess::GetProperty(xProperties, "Action") >>= msAction)) + if (rpDefaultMode != nullptr) + msAction = rpDefaultMode->msAction; + + // Read text and font + OUString sText(rpDefaultMode != nullptr ? rpDefaultMode->maText.GetText() : OUString()); + PresenterConfigurationAccess::GetProperty(xProperties, "Text") >>= sText; + Reference xFontNode ( + PresenterConfigurationAccess::GetProperty(xProperties, "Font"), UNO_QUERY); + PresenterTheme::SharedFontDescriptor pFont(PresenterTheme::ReadFont( + xFontNode, rpDefaultMode != nullptr ? rpDefaultMode->maText.GetFont() + : PresenterTheme::SharedFontDescriptor())); + maText = Text(sText,pFont); + + // Read bitmaps to display as icons. + Reference xIconNode ( + PresenterConfigurationAccess::GetProperty(xProperties, "Icon"), UNO_QUERY); + mpIcon = PresenterBitmapContainer::LoadBitmap( + xIconNode, "", rContext.mxPresenterHelper, rContext.mxCanvas, + rpDefaultMode != nullptr ? rpDefaultMode->mpIcon : SharedBitmapDescriptor()); + } + catch(Exception&) + { + OSL_ASSERT(false); + } +} + +} // end of anonymous namespace + +//===== Button ================================================================ + +namespace { + +::rtl::Reference Button::Create ( + const ::rtl::Reference& rpToolBar) +{ + ::rtl::Reference