/* -*- 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 "PresenterWindowManager.hxx" #include "PresenterController.hxx" #include "PresenterGeometryHelper.hxx" #include "PresenterPaintManager.hxx" #include "PresenterPaneBorderPainter.hxx" #include "PresenterPaneContainer.hxx" #include "PresenterPaneFactory.hxx" #include "PresenterToolBar.hxx" #include "PresenterViewFactory.hxx" #include "PresenterTheme.hxx" #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 { //===== PresenterWindowManager ================================================ PresenterWindowManager::PresenterWindowManager ( const Reference& rxContext, ::rtl::Reference pPaneContainer, ::rtl::Reference pPresenterController) : PresenterWindowManagerInterfaceBase(m_aMutex), mxComponentContext(rxContext), mpPresenterController(std::move(pPresenterController)), mpPaneContainer(std::move(pPaneContainer)), mbIsLayoutPending(true), mbIsLayouting(false), meLayoutMode(LM_Generic), mbIsSlideSorterActive(false), mbIsHelpViewActive(false), mbisPaused(false), mbIsMouseClickPending(false) { } PresenterWindowManager::~PresenterWindowManager() { } void SAL_CALL PresenterWindowManager::disposing() { NotifyDisposing(); SetParentPane(nullptr); Reference xComponent (mxPaneBorderManager, UNO_QUERY); if (xComponent.is()) xComponent->dispose(); mxPaneBorderManager = nullptr; for (const auto& rxPane : mpPaneContainer->maPanes) { if (rxPane->mxBorderWindow.is()) { rxPane->mxBorderWindow->removeWindowListener(this); rxPane->mxBorderWindow->removeFocusListener(this); rxPane->mxBorderWindow->removeMouseListener(this); } } } void PresenterWindowManager::SetParentPane ( const Reference& rxPane) { if (mxParentWindow.is()) { mxParentWindow->removeWindowListener(this); mxParentWindow->removePaintListener(this); mxParentWindow->removeMouseListener(this); mxParentWindow->removeFocusListener(this); } mxParentWindow = nullptr; mxParentCanvas = nullptr; if (rxPane.is()) { mxParentWindow = rxPane->getWindow(); mxParentCanvas = rxPane->getCanvas(); } else { mxParentWindow = nullptr; } if (mxParentWindow.is()) { mxParentWindow->addWindowListener(this); mxParentWindow->addPaintListener(this); mxParentWindow->addMouseListener(this); mxParentWindow->addFocusListener(this); // We paint our own background, make that of the parent window transparent. Reference xPeer (mxParentWindow, UNO_QUERY); if (xPeer.is()) xPeer->setBackground(util::Color(0xff000000)); } } void PresenterWindowManager::SetTheme (const std::shared_ptr& rpTheme) { mpTheme = rpTheme; // Get background bitmap or background color from the theme. if (mpTheme != nullptr) { mpBackgroundBitmap = mpTheme->GetBitmap(OUString(), u"Background"_ustr); } } void PresenterWindowManager::NotifyViewCreation (const Reference& rxView) { PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( mpPaneContainer->FindPaneId(rxView->getResourceId()->getAnchor())); OSL_ASSERT(pDescriptor); if (pDescriptor) { Layout(); mpPresenterController->GetPaintManager()->Invalidate( pDescriptor->mxContentWindow, sal_Int16(awt::InvalidateStyle::TRANSPARENT | awt::InvalidateStyle::CHILDREN)); } } void PresenterWindowManager::SetPanePosSizeAbsolute ( const OUString& rsPaneURL, const double nX, const double nY, const double nWidth, const double nHeight) { PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( mpPaneContainer->FindPaneURL(rsPaneURL)); if (pDescriptor) { if (pDescriptor->mxBorderWindow.is()) pDescriptor->mxBorderWindow->setPosSize( ::sal::static_int_cast(nX), ::sal::static_int_cast(nY), ::sal::static_int_cast(nWidth), ::sal::static_int_cast(nHeight), awt::PosSize::POSSIZE); } } void PresenterWindowManager::SetPaneBorderPainter ( const ::rtl::Reference& rPainter) { mpPaneBorderPainter = rPainter; } //----- XWindowListener ------------------------------------------------------- void SAL_CALL PresenterWindowManager::windowResized (const awt::WindowEvent& rEvent) { ThrowIfDisposed(); if (rEvent.Source == mxParentWindow) { Layout(); } else { Reference xWindow (rEvent.Source,UNO_QUERY); if (xWindow.is()) { UpdateWindowSize(xWindow); // Make sure the background of a transparent window is painted. mpPresenterController->GetPaintManager()->Invalidate(mxParentWindow); } } } void SAL_CALL PresenterWindowManager::windowMoved (const awt::WindowEvent& rEvent) { ThrowIfDisposed(); if (rEvent.Source != mxParentWindow) { Reference xWindow (rEvent.Source,UNO_QUERY); UpdateWindowSize(xWindow); // Make sure the background of a transparent window is painted. mpPresenterController->GetPaintManager()->Invalidate(xWindow); } } void SAL_CALL PresenterWindowManager::windowShown (const lang::EventObject&) {} void SAL_CALL PresenterWindowManager::windowHidden (const lang::EventObject&) {} //----- XPaintListener -------------------------------------------------------- void SAL_CALL PresenterWindowManager::windowPaint (const awt::PaintEvent& rEvent) { ThrowIfDisposed(); if ( ! mxParentWindow.is()) return; if ( ! mxParentCanvas.is()) return; if (mpTheme == nullptr) return; try { if (mbIsLayoutPending) Layout(); PaintBackground(rEvent.UpdateRect); PaintChildren(rEvent); } catch (RuntimeException&) { OSL_FAIL("paint failed!"); } } //----- XMouseListener -------------------------------------------------------- void SAL_CALL PresenterWindowManager::mousePressed (const css::awt::MouseEvent&) { if (!mbIsSlideSorterActive) // tdf#127921 mbIsMouseClickPending = true; } void SAL_CALL PresenterWindowManager::mouseReleased (const css::awt::MouseEvent& rEvent) { if (mbIsMouseClickPending) { mbIsMouseClickPending = false; mpPresenterController->HandleMouseClick(rEvent); } } void SAL_CALL PresenterWindowManager::mouseEntered (const css::awt::MouseEvent&) { mbIsMouseClickPending = false; } void SAL_CALL PresenterWindowManager::mouseExited (const css::awt::MouseEvent&) { mbIsMouseClickPending = false; } //----- XFocusListener -------------------------------------------------------- void SAL_CALL PresenterWindowManager::focusGained (const css::awt::FocusEvent& /*rEvent*/) { ThrowIfDisposed(); } void SAL_CALL PresenterWindowManager::focusLost (const css::awt::FocusEvent&) { ThrowIfDisposed(); } //----- XEventListener -------------------------------------------------------- void SAL_CALL PresenterWindowManager::disposing (const lang::EventObject& rEvent) { if (rEvent.Source == mxParentWindow) mxParentWindow = nullptr; } void PresenterWindowManager::PaintChildren (const awt::PaintEvent& rEvent) const { // Call windowPaint on all children that lie in or touch the // update rectangle. for (const auto& rxPane : mpPaneContainer->maPanes) { try { // Make sure that the pane shall and can be painted. if ( ! rxPane->mbIsActive) continue; if (rxPane->mbIsSprite) continue; if ( ! rxPane->mxPane.is()) continue; if ( ! rxPane->mxBorderWindow.is()) continue; Reference xBorderWindow (rxPane->mxBorderWindow); if ( ! xBorderWindow.is()) continue; // Get the area in which the border of the pane has to be painted. const awt::Rectangle aBorderBox (xBorderWindow->getPosSize()); const awt::Rectangle aBorderUpdateBox( PresenterGeometryHelper::Intersection( rEvent.UpdateRect, aBorderBox)); if (aBorderUpdateBox.Width<=0 || aBorderUpdateBox.Height<=0) continue; const awt::Rectangle aLocalBorderUpdateBox( PresenterGeometryHelper::TranslateRectangle( aBorderUpdateBox, -aBorderBox.X, -aBorderBox.Y)); // Invalidate the area of the content window. mpPresenterController->GetPaintManager()->Invalidate( xBorderWindow, aLocalBorderUpdateBox, sal_Int16(awt::InvalidateStyle::CHILDREN | awt::InvalidateStyle::NOTRANSPARENT)); } catch (RuntimeException&) { OSL_FAIL("paint children failed!"); } } } void PresenterWindowManager::SetLayoutMode (const LayoutMode eMode) { OSL_ASSERT(mpPresenterController); if (meLayoutMode == eMode && !mbIsSlideSorterActive && !mbIsHelpViewActive) return; meLayoutMode = eMode; mbIsSlideSorterActive = false; mbIsHelpViewActive = false; mpPresenterController->RequestViews( mbIsSlideSorterActive, meLayoutMode==LM_Notes, mbIsHelpViewActive); Layout(); NotifyLayoutModeChange(); } void PresenterWindowManager::SetSlideSorterState (bool bIsActive) { if (mbIsSlideSorterActive == bIsActive) return; mbIsSlideSorterActive = bIsActive; if (mbIsSlideSorterActive) mbIsHelpViewActive = false; StoreViewMode(GetViewMode()); mpPresenterController->RequestViews( mbIsSlideSorterActive, meLayoutMode==LM_Notes, mbIsHelpViewActive); Layout(); NotifyLayoutModeChange(); } void PresenterWindowManager::SetHelpViewState (bool bIsActive) { if (mbIsHelpViewActive == bIsActive) return; mbIsHelpViewActive = bIsActive; if (mbIsHelpViewActive) mbIsSlideSorterActive = false; StoreViewMode(GetViewMode()); mpPresenterController->RequestViews( mbIsSlideSorterActive, meLayoutMode==LM_Notes, mbIsHelpViewActive); Layout(); NotifyLayoutModeChange(); } void PresenterWindowManager::SetPauseState (bool bIsPaused) { if (mbisPaused == bIsPaused) return; mbisPaused = bIsPaused; NotifyLayoutModeChange(); } void PresenterWindowManager::SetViewMode (const ViewMode eMode) { switch (eMode) { case VM_Standard: SetSlideSorterState(false); SetHelpViewState(false); SetLayoutMode(LM_Standard); break; case VM_Notes: SetSlideSorterState(false); SetHelpViewState(false); SetLayoutMode(LM_Notes); break; case VM_SlideOverview: SetHelpViewState(false); SetSlideSorterState(true); break; case VM_Help: SetHelpViewState(true); SetSlideSorterState(false); break; } StoreViewMode(eMode); } PresenterWindowManager::ViewMode PresenterWindowManager::GetViewMode() const { if (mbIsHelpViewActive) return VM_Help; else if (mbIsSlideSorterActive) return VM_SlideOverview; else if (meLayoutMode == LM_Notes) return VM_Notes; else return VM_Standard; } void PresenterWindowManager::RestoreViewMode() { sal_Int32 nMode (0); PresenterConfigurationAccess aConfiguration ( mxComponentContext, u"/org.openoffice.Office.PresenterScreen/"_ustr, PresenterConfigurationAccess::READ_ONLY); aConfiguration.GetConfigurationNode(u"Presenter/InitialViewMode"_ustr) >>= nMode; switch (nMode) { default: case 0: SetViewMode(VM_Standard); break; case 1: SetViewMode(VM_Notes); break; case 2: SetViewMode(VM_SlideOverview); break; } } void PresenterWindowManager::StoreViewMode (const ViewMode eViewMode) { try { PresenterConfigurationAccess aConfiguration ( mxComponentContext, u"/org.openoffice.Office.PresenterScreen/"_ustr, PresenterConfigurationAccess::READ_WRITE); aConfiguration.GoToChild(u"Presenter"_ustr); Any aValue; switch (eViewMode) { default: case VM_Standard: aValue <<= sal_Int32(0); break; case VM_Notes: aValue <<= sal_Int32(1); break; case VM_SlideOverview: aValue <<= sal_Int32(2); break; } aConfiguration.SetProperty (u"InitialViewMode"_ustr, aValue); aConfiguration.CommitChanges(); } catch (Exception&) { } } void PresenterWindowManager::AddLayoutListener ( const Reference& rxListener) { maLayoutListeners.push_back(rxListener); } void PresenterWindowManager::RemoveLayoutListener ( const Reference& rxListener) { // Assume that there are no multiple entries. auto iListener = std::find(maLayoutListeners.begin(), maLayoutListeners.end(), rxListener); if (iListener != maLayoutListeners.end()) maLayoutListeners.erase(iListener); } void PresenterWindowManager::Layout() { if (!mxParentWindow.is() || mbIsLayouting) return; mbIsLayoutPending = false; mbIsLayouting = true; mxScaledBackgroundBitmap = nullptr; mxClipPolygon = nullptr; try { if (mbIsSlideSorterActive) LayoutSlideSorterMode(); else if (mbIsHelpViewActive) LayoutHelpMode(); else switch (meLayoutMode) { case LM_Standard: default: LayoutStandardMode(); break; case LM_Notes: LayoutNotesMode(); break; } } catch (Exception&) { OSL_ASSERT(false); throw; } mbIsLayouting = false; } void PresenterWindowManager::LayoutStandardMode() { awt::Rectangle aBox = mxParentWindow->getPosSize(); const double nGoldenRatio ((1 + sqrt(5.0)) / 2); const double nGap (20); const double nHorizontalSlideDivide (aBox.Width / nGoldenRatio); double nSlidePreviewTop (0); // For the current slide view calculate the outer height from the outer // width. This takes into account the slide aspect ratio and thus has to // go over the inner pane size. PresenterPaneContainer::SharedPaneDescriptor pPane ( mpPaneContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL)); if (pPane) { const awt::Size aCurrentSlideOuterBox(CalculatePaneSize( nHorizontalSlideDivide - 1.5*nGap, PresenterPaneFactory::msCurrentSlidePreviewPaneURL)); nSlidePreviewTop = (aBox.Height - aCurrentSlideOuterBox.Height) / 2; double Temp=nGap; /// check whether RTL interface or not if(AllSettings::GetLayoutRTL()) Temp=aBox.Width - aCurrentSlideOuterBox.Width - nGap; SetPanePosSizeAbsolute ( PresenterPaneFactory::msCurrentSlidePreviewPaneURL, Temp, nSlidePreviewTop, aCurrentSlideOuterBox.Width, aCurrentSlideOuterBox.Height); } // For the next slide view calculate the outer height from the outer // width. This takes into account the slide aspect ratio and thus has to // go over the inner pane size. pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNextSlidePreviewPaneURL); if (pPane) { const awt::Size aNextSlideOuterBox (CalculatePaneSize( aBox.Width - nHorizontalSlideDivide - 1.5*nGap, PresenterPaneFactory::msNextSlidePreviewPaneURL)); double Temp=aBox.Width - aNextSlideOuterBox.Width - nGap; /// check whether RTL interface or not if(AllSettings::GetLayoutRTL()) Temp=nGap; SetPanePosSizeAbsolute ( PresenterPaneFactory::msNextSlidePreviewPaneURL, Temp, nSlidePreviewTop, aNextSlideOuterBox.Width, aNextSlideOuterBox.Height); } LayoutToolBar(); } void PresenterWindowManager::LayoutNotesMode() { awt::Rectangle aBox = mxParentWindow->getPosSize(); const geometry::RealRectangle2D aToolBarBox (LayoutToolBar()); const double nGoldenRatio ((1 + sqrt(5.0)) / 2); const double nGap (20); const double nPrimaryWidth (aBox.Width / nGoldenRatio); const double nSecondaryWidth (aBox.Width - nPrimaryWidth); const double nTertiaryWidth (nSecondaryWidth / nGoldenRatio); double nSlidePreviewTop (0); double nNotesViewBottom (aToolBarBox.Y1 - nGap); /// check whether RTL interface or not // The notes view has no fixed aspect ratio. PresenterPaneContainer::SharedPaneDescriptor pPane ( mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNotesPaneURL)); if (pPane) { const geometry::RealSize2D aNotesViewOuterSize( nPrimaryWidth - 1.5*nGap + 0.5, nNotesViewBottom); nSlidePreviewTop = (aBox.Height - aToolBarBox.Y2 + aToolBarBox.Y1 - aNotesViewOuterSize.Height) / 2; /// check whether RTL interface or not double Temp=aBox.Width - aNotesViewOuterSize.Width - nGap; if(AllSettings::GetLayoutRTL()) Temp=nGap; SetPanePosSizeAbsolute ( PresenterPaneFactory::msNotesPaneURL, Temp, nSlidePreviewTop, aNotesViewOuterSize.Width, aNotesViewOuterSize.Height); nNotesViewBottom = nSlidePreviewTop + aNotesViewOuterSize.Height; } // For the current slide view calculate the outer height from the outer // width. This takes into account the slide aspect ratio and thus has to // go over the inner pane size. pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL); if (pPane) { const awt::Size aCurrentSlideOuterBox(CalculatePaneSize( nSecondaryWidth - 1.5*nGap, PresenterPaneFactory::msCurrentSlidePreviewPaneURL)); /// check whether RTL interface or not double Temp=nGap; if(AllSettings::GetLayoutRTL()) Temp=aBox.Width - aCurrentSlideOuterBox.Width - nGap; SetPanePosSizeAbsolute ( PresenterPaneFactory::msCurrentSlidePreviewPaneURL, Temp, nSlidePreviewTop, aCurrentSlideOuterBox.Width, aCurrentSlideOuterBox.Height); } // For the next slide view calculate the outer height from the outer // width. This takes into account the slide aspect ratio and thus has to // go over the inner pane size. pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNextSlidePreviewPaneURL); if (!pPane) return; const awt::Size aNextSlideOuterBox (CalculatePaneSize( nTertiaryWidth, PresenterPaneFactory::msNextSlidePreviewPaneURL)); /// check whether RTL interface or not double Temp=nGap; if(AllSettings::GetLayoutRTL()) Temp=aBox.Width - aNextSlideOuterBox.Width - nGap; SetPanePosSizeAbsolute ( PresenterPaneFactory::msNextSlidePreviewPaneURL, Temp, nNotesViewBottom - aNextSlideOuterBox.Height, aNextSlideOuterBox.Width, aNextSlideOuterBox.Height); } void PresenterWindowManager::LayoutSlideSorterMode() { const geometry::RealRectangle2D aToolBarBox (LayoutToolBar()); awt::Rectangle aWindowBox = mxParentWindow->getPosSize(); const double nGap (20); SetPanePosSizeAbsolute( mpPaneContainer->GetPaneURLForViewURL(PresenterViewFactory::msSlideSorterURL), nGap, nGap, aWindowBox.Width - 2*nGap, aToolBarBox.Y1 - 2*nGap); } void PresenterWindowManager::LayoutHelpMode() { const geometry::RealRectangle2D aToolBarBox (LayoutToolBar()); awt::Rectangle aWindowBox = mxParentWindow->getPosSize(); const double nGap (20); const double nGoldenRatio ((1 + sqrt(5.0)) / 2); const double nWidth = ::std::min(aWindowBox.Width - 2*nGap, aWindowBox.Width/nGoldenRatio); SetPanePosSizeAbsolute( mpPaneContainer->GetPaneURLForViewURL(PresenterViewFactory::msHelpViewURL), (aWindowBox.Width - nWidth)/2, nGap, nWidth, aToolBarBox.Y1 - 2*nGap); } geometry::RealRectangle2D PresenterWindowManager::LayoutToolBar() { double nToolBarWidth (400); double nToolBarHeight (80); // Get access to the tool bar. PresenterPaneContainer::SharedPaneDescriptor pDescriptor( mpPaneContainer->FindPaneURL(PresenterPaneFactory::msToolBarPaneURL)); if (pDescriptor) { PresenterToolBarView* pToolBarView = dynamic_cast(pDescriptor->mxView.get()); if (pToolBarView != nullptr && pToolBarView->GetPresenterToolBar().is()) { geometry::RealSize2D aSize (pToolBarView->GetPresenterToolBar()->GetMinimalSize()); if (mpPaneBorderPainter.is()) { const awt::Rectangle aBox (mpPaneBorderPainter->addBorder ( PresenterPaneFactory::msToolBarPaneURL, awt::Rectangle( 0, 0, PresenterGeometryHelper::Round(aSize.Width), PresenterGeometryHelper::Round(aSize.Height)), css::drawing::framework::BorderType_TOTAL_BORDER)); nToolBarWidth = aBox.Width; nToolBarHeight = aBox.Height; } else { nToolBarWidth = aSize.Width + 20; nToolBarHeight = aSize.Height + 10; } } } const awt::Rectangle aBox = mxParentWindow->getPosSize(); const double nToolBarX ((aBox.Width - nToolBarWidth) / 2); const double nToolBarY (aBox.Height - nToolBarHeight); SetPanePosSizeAbsolute( PresenterPaneFactory::msToolBarPaneURL, nToolBarX, nToolBarY, nToolBarWidth, nToolBarHeight); return geometry::RealRectangle2D( nToolBarX, nToolBarY, nToolBarX + nToolBarWidth - 1, nToolBarY + nToolBarHeight - 1); } awt::Size PresenterWindowManager::CalculatePaneSize ( const double nOuterWidth, const OUString& rsPaneURL) { // Calculate the inner width by removing the pane border. awt::Rectangle aInnerBox (mpPaneBorderPainter->RemoveBorder ( rsPaneURL, awt::Rectangle(0,0, sal_Int32(nOuterWidth+0.5),sal_Int32(nOuterWidth)), drawing::framework::BorderType_TOTAL_BORDER)); // Calculate the inner height with the help of the slide aspect ratio. const double nCurrentSlideInnerHeight ( aInnerBox.Width / mpPresenterController->GetSlideAspectRatio()); // Add the pane border to get the outer box. awt::Rectangle aOuterBox (mpPaneBorderPainter->AddBorder ( rsPaneURL, awt::Rectangle(0,0, aInnerBox.Width,sal_Int32(nCurrentSlideInnerHeight+0.5)), drawing::framework::BorderType_TOTAL_BORDER)); return awt::Size(aOuterBox.Width, aOuterBox.Height); } void PresenterWindowManager::NotifyLayoutModeChange() { document::EventObject aEvent; aEvent.Source = Reference(static_cast(this)); LayoutListenerContainer aContainerCopy (maLayoutListeners); for (const auto& rxListener : aContainerCopy) { if (rxListener.is()) { try { rxListener->notifyEvent(aEvent); } catch (lang::DisposedException&) { RemoveLayoutListener(rxListener); } catch (RuntimeException&) { } } } } void PresenterWindowManager::NotifyDisposing() { lang::EventObject aEvent; aEvent.Source = static_cast(this); LayoutListenerContainer aContainer; aContainer.swap(maLayoutListeners); for (auto& rxListener : aContainer) { if (rxListener.is()) { try { rxListener->disposing(aEvent); } catch (lang::DisposedException&) { } catch (RuntimeException&) { } } } } void PresenterWindowManager::UpdateWindowSize (const Reference& rxBorderWindow) { PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( mpPaneContainer->FindBorderWindow(rxBorderWindow)); if (pDescriptor) { mxClipPolygon = nullptr; // ToTop is called last because it may invalidate the iterator. if ( ! mbIsLayouting) mpPaneContainer->ToTop(pDescriptor); } } void PresenterWindowManager::PaintBackground (const awt::Rectangle& rUpdateBox) { if ( ! mxParentWindow.is()) return; Reference xDevice (mxParentCanvas->getDevice()); if ( ! xDevice.is()) return; // Create a polygon for the background and for clipping. Reference xBackgroundPolygon ( PresenterGeometryHelper::CreatePolygon(mxParentWindow->getPosSize(), xDevice)); if ( ! mxClipPolygon.is()) mxClipPolygon = CreateClipPolyPolygon(); // Create View- and RenderState structs. const rendering::ViewState aViewState( geometry::AffineMatrix2D(1,0,0, 0,1,0), PresenterGeometryHelper::CreatePolygon(rUpdateBox, xDevice)); rendering::RenderState aRenderState ( geometry::AffineMatrix2D(1,0,0, 0,1,0), mxClipPolygon, Sequence(4), rendering::CompositeOperation::SOURCE); // Paint the background. if (!mpBackgroundBitmap) return; ProvideBackgroundBitmap(); if (mxScaledBackgroundBitmap.is()) { const geometry::IntegerSize2D aBitmapSize(mxScaledBackgroundBitmap->getSize()); Sequence aTextures { { geometry::AffineMatrix2D( aBitmapSize.Width,0,0, 0,aBitmapSize.Height,0), 1, 0, mxScaledBackgroundBitmap, nullptr, nullptr, rendering::StrokeAttributes(), rendering::TexturingMode::REPEAT, rendering::TexturingMode::REPEAT } }; mxParentCanvas->fillTexturedPolyPolygon( xBackgroundPolygon, aViewState, aRenderState, aTextures); } else { const util::Color aBackgroundColor (mpBackgroundBitmap->maReplacementColor); auto pDeviceColor = aRenderState.DeviceColor.getArray(); pDeviceColor[0] = ((aBackgroundColor >> 16) & 0x0ff) / 255.0; pDeviceColor[1] = ((aBackgroundColor >> 8) & 0x0ff) / 255.0; pDeviceColor[2] = ((aBackgroundColor >> 0) & 0x0ff) / 255.0; pDeviceColor[3] = ((aBackgroundColor >> 24) & 0x0ff) / 255.0; mxParentCanvas->fillPolyPolygon( xBackgroundPolygon, aViewState, aRenderState); } } void PresenterWindowManager::ProvideBackgroundBitmap() { if ( mxScaledBackgroundBitmap.is()) return; Reference xBitmap (mpBackgroundBitmap->GetNormalBitmap()); if (!xBitmap.is()) return; const bool bStretchVertical (mpBackgroundBitmap->meVerticalTexturingMode == PresenterBitmapDescriptor::Stretch); const bool bStretchHorizontal (mpBackgroundBitmap->meHorizontalTexturingMode == PresenterBitmapDescriptor::Stretch); if (bStretchHorizontal || bStretchVertical) { geometry::RealSize2D aSize; if (bStretchVertical) aSize.Height = mxParentWindow->getPosSize().Height; else aSize.Height = xBitmap->getSize().Height; if (bStretchHorizontal) aSize.Width = mxParentWindow->getPosSize().Width; else aSize.Width = xBitmap->getSize().Width; mxScaledBackgroundBitmap = xBitmap->getScaledBitmap(aSize, false); } else { mxScaledBackgroundBitmap = std::move(xBitmap); } } Reference PresenterWindowManager::CreateClipPolyPolygon() const { // Create a clip polygon that includes the whole update area but has the // content windows as holes. const sal_Int32 nPaneCount (mpPaneContainer->maPanes.size()); ::std::vector aRectangles; aRectangles.reserve(1+nPaneCount); aRectangles.push_back(mxParentWindow->getPosSize()); for (const auto& pDescriptor : mpPaneContainer->maPanes) { if ( ! pDescriptor->mbIsActive) continue; if ( ! pDescriptor->mbIsOpaque) continue; if ( ! pDescriptor->mxBorderWindow.is() || ! pDescriptor->mxContentWindow.is()) continue; Reference xWindow (pDescriptor->mxBorderWindow, UNO_QUERY); if (xWindow.is() && ! xWindow->isVisible()) continue; const awt::Rectangle aOuterBorderBox (pDescriptor->mxBorderWindow->getPosSize()); awt::Rectangle aInnerBorderBox (pDescriptor->mxContentWindow->getPosSize()); aInnerBorderBox.X += aOuterBorderBox.X; aInnerBorderBox.Y += aOuterBorderBox.Y; aRectangles.push_back(aInnerBorderBox); } Reference xPolyPolygon ( PresenterGeometryHelper::CreatePolygon( aRectangles, mxParentCanvas->getDevice())); if (xPolyPolygon.is()) xPolyPolygon->setFillRule(rendering::FillRule_EVEN_ODD); return xPolyPolygon; } void PresenterWindowManager::Update() { mxClipPolygon = nullptr; mbIsLayoutPending = true; mpPresenterController->GetPaintManager()->Invalidate(mxParentWindow); } void PresenterWindowManager::ThrowIfDisposed() const { if (rBHelper.bDisposed || rBHelper.bInDispose) { throw lang::DisposedException ( u"PresenterWindowManager has already been disposed"_ustr, const_cast(static_cast(this))); } } } // end of namespace ::sdext::presenter /* vim:set shiftwidth=4 softtabstop=4 expandtab: */