/* -*- 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 "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 ( const OUString& rsText, const PresenterTheme::SharedFontDescriptor& rpFont); 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 (const ::rtl::Reference& rpToolBar); 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 (const ::rtl::Reference& rxLabel) : mxLabel(rxLabel) {} 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, const css::uno::Reference& rxWindow, const css::uno::Reference& rxCanvas, const ::rtl::Reference& rpPresenterController, const Anchor eAnchor) : PresenterToolBarInterfaceBase(m_aMutex), mxComponentContext(rxContext), mxWindow(rxWindow), mxCanvas(rxCanvas), mpPresenterController(rpPresenterController), 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 Reference& rxController, const ::rtl::Reference& rpPresenterController) : PresenterToolBarViewInterfaceBase(m_aMutex), mxViewId(rxViewId), mpPresenterController(rpPresenterController) { try { Reference xCM (rxController, UNO_QUERY_THROW); Reference xCC(xCM->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 ( const ::rtl::Reference& rpToolBar) : ElementInterfaceBase(m_aMutex), mpToolBar(rpToolBar), 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