/* -*- 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 <utility>
#include <vcl/settings.hxx>
#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 <com/sun/star/awt/InvalidateStyle.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <com/sun/star/awt/XWindow2.hpp>
#include <com/sun/star/awt/XWindowPeer.hpp>
#include <com/sun/star/rendering/CompositeOperation.hpp>
#include <com/sun/star/rendering/FillRule.hpp>
#include <com/sun/star/rendering/Texture.hpp>
#include <com/sun/star/rendering/TexturingMode.hpp>
#include <math.h>
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<XComponentContext>& rxContext,
::rtl::Reference<PresenterPaneContainer> pPaneContainer,
::rtl::Reference<PresenterController> 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<lang::XComponent> 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<drawing::framework::XPane>& 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<awt::XWindowPeer> xPeer (mxParentWindow, UNO_QUERY);
if (xPeer.is())
xPeer->setBackground(util::Color(0xff000000));
}
}
void PresenterWindowManager::SetTheme (const std::shared_ptr<PresenterTheme>& 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<XView>& 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<sal_Int32>(nX),
::sal::static_int_cast<sal_Int32>(nY),
::sal::static_int_cast<sal_Int32>(nWidth),
::sal::static_int_cast<sal_Int32>(nHeight),
awt::PosSize::POSSIZE);
}
}
void PresenterWindowManager::SetPaneBorderPainter (
const ::rtl::Reference<PresenterPaneBorderPainter>& rPainter)
{
mpPaneBorderPainter = rPainter;
}
//----- XWindowListener -------------------------------------------------------
void SAL_CALL PresenterWindowManager::windowResized (const awt::WindowEvent& rEvent)
{
ThrowIfDisposed();
if (rEvent.Source == mxParentWindow)
{
Layout();
}
else
{
Reference<awt::XWindow> 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<awt::XWindow> 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<awt::XWindow> 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<document::XEventListener>& rxListener)
{
maLayoutListeners.push_back(rxListener);
}
void PresenterWindowManager::RemoveLayoutListener (
const Reference<document::XEventListener>& 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<PresenterToolBarView*>(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<XInterface>(static_cast<XWeak*>(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<XWeak*>(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<awt::XWindow>& 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<rendering::XGraphicDevice> xDevice (mxParentCanvas->getDevice());
if ( ! xDevice.is())
return;
// Create a polygon for the background and for clipping.
Reference<rendering::XPolyPolygon2D> 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<double>(4),
rendering::CompositeOperation::SOURCE);
// Paint the background.
if (!mpBackgroundBitmap)
return;
ProvideBackgroundBitmap();
if (mxScaledBackgroundBitmap.is())
{
const geometry::IntegerSize2D aBitmapSize(mxScaledBackgroundBitmap->getSize());
Sequence<rendering::Texture> 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<rendering::XBitmap> 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<rendering::XPolyPolygon2D> 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<awt::Rectangle> 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<awt::XWindow2> 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<rendering::XPolyPolygon2D> 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<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
}
}
} // end of namespace ::sdext::presenter
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V636 The expression was implicitly cast from 'int' type to 'double' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y;.
↑ V785 Constant expression in switch statement.