ee4554b0ac
and cid#1555264 COPY_INSTEAD_OF_MOVE cid#1555280 COPY_INSTEAD_OF_MOVE cid#1555303 COPY_INSTEAD_OF_MOVE cid#1555313 COPY_INSTEAD_OF_MOVE cid#1555314 COPY_INSTEAD_OF_MOVE cid#1555323 COPY_INSTEAD_OF_MOVE cid#1555333 COPY_INSTEAD_OF_MOVE cid#1555338 COPY_INSTEAD_OF_MOVE cid#1555349 COPY_INSTEAD_OF_MOVE cid#1555364 COPY_INSTEAD_OF_MOVE cid#1555379 COPY_INSTEAD_OF_MOVE cid#1555398 COPY_INSTEAD_OF_MOVE cid#1555410 COPY_INSTEAD_OF_MOVE cid#1555411 COPY_INSTEAD_OF_MOVE cid#1555416 COPY_INSTEAD_OF_MOVE cid#1555429 COPY_INSTEAD_OF_MOVE cid#1555434 COPY_INSTEAD_OF_MOVE cid#1555441 COPY_INSTEAD_OF_MOVE cid#1555446 COPY_INSTEAD_OF_MOVE cid#1555480 COPY_INSTEAD_OF_MOVE cid#1555490 COPY_INSTEAD_OF_MOVE cid#1555524 COPY_INSTEAD_OF_MOVE cid#1555527 COPY_INSTEAD_OF_MOVE cid#1555531 COPY_INSTEAD_OF_MOVE cid#1555578 COPY_INSTEAD_OF_MOVE cid#1555581 COPY_INSTEAD_OF_MOVE cid#1555591 COPY_INSTEAD_OF_MOVE cid#1555614 COPY_INSTEAD_OF_MOVE cid#1555619 COPY_INSTEAD_OF_MOVE cid#1555633 COPY_INSTEAD_OF_MOVE cid#1555654 COPY_INSTEAD_OF_MOVE cid#1555707 COPY_INSTEAD_OF_MOVE cid#1555712 COPY_INSTEAD_OF_MOVE cid#1555746 COPY_INSTEAD_OF_MOVE cid#1555763 COPY_INSTEAD_OF_MOVE Change-Id: Ibcc1a3649c5663328e60474c06e51902aa74db52 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175407 Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Tested-by: Jenkins
1044 lines
32 KiB
C++
1044 lines
32 KiB
C++
/* -*- 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: */
|