1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/settings.hxx>
21 #include "PresenterWindowManager.hxx"
22 #include "PresenterController.hxx"
23 #include "PresenterGeometryHelper.hxx"
24 #include "PresenterPaintManager.hxx"
25 #include "PresenterPaneBorderPainter.hxx"
26 #include "PresenterPaneContainer.hxx"
27 #include "PresenterPaneFactory.hxx"
28 #include "PresenterToolBar.hxx"
29 #include "PresenterViewFactory.hxx"
30 #include "PresenterTheme.hxx"
31 #include <com/sun/star/awt/InvalidateStyle.hpp>
32 #include <com/sun/star/awt/PosSize.hpp>
33 #include <com/sun/star/awt/XWindow2.hpp>
34 #include <com/sun/star/awt/XWindowPeer.hpp>
35 #include <com/sun/star/rendering/CompositeOperation.hpp>
36 #include <com/sun/star/rendering/FillRule.hpp>
37 #include <com/sun/star/rendering/Texture.hpp>
38 #include <com/sun/star/rendering/TexturingMode.hpp>
39 #include <math.h>
40 
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::drawing::framework;
44 
45 namespace sdext::presenter {
46 
47 //===== PresenterWindowManager ================================================
48 
PresenterWindowManager(const Reference<XComponentContext> & rxContext,const::rtl::Reference<PresenterPaneContainer> & rpPaneContainer,const::rtl::Reference<PresenterController> & rpPresenterController)49 PresenterWindowManager::PresenterWindowManager (
50     const Reference<XComponentContext>& rxContext,
51     const ::rtl::Reference<PresenterPaneContainer>& rpPaneContainer,
52     const ::rtl::Reference<PresenterController>& rpPresenterController)
53     : PresenterWindowManagerInterfaceBase(m_aMutex),
54       mxComponentContext(rxContext),
55       mpPresenterController(rpPresenterController),
56       mxParentWindow(),
57       mxParentCanvas(),
58       mxPaneBorderManager(),
59       mpPaneBorderPainter(),
60       mpPaneContainer(rpPaneContainer),
61       mbIsLayoutPending(true),
62       mbIsLayouting(false),
63       mpTheme(),
64       mpBackgroundBitmap(),
65       mxScaledBackgroundBitmap(),
66       mxClipPolygon(),
67       meLayoutMode(LM_Generic),
68       mbIsSlideSorterActive(false),
69       mbIsHelpViewActive(false),
70       mbisPaused(false),
71       maLayoutListeners(),
72       mbIsMouseClickPending(false)
73 {
74 
75 }
76 
~PresenterWindowManager()77 PresenterWindowManager::~PresenterWindowManager()
78 {
79 }
80 
disposing()81 void SAL_CALL PresenterWindowManager::disposing()
82 {
83     NotifyDisposing();
84 
85     SetParentPane(nullptr);
86 
87     Reference<lang::XComponent> xComponent (mxPaneBorderManager, UNO_QUERY);
88     if (xComponent.is())
89         xComponent->dispose();
90     mxPaneBorderManager = nullptr;
91 
92     for (const auto& rxPane : mpPaneContainer->maPanes)
93     {
94         if (rxPane->mxBorderWindow.is())
95         {
96             rxPane->mxBorderWindow->removeWindowListener(this);
97             rxPane->mxBorderWindow->removeFocusListener(this);
98             rxPane->mxBorderWindow->removeMouseListener(this);
99         }
100     }
101 }
102 
SetParentPane(const Reference<drawing::framework::XPane> & rxPane)103 void PresenterWindowManager::SetParentPane (
104     const Reference<drawing::framework::XPane>& rxPane)
105 {
106     if (mxParentWindow.is())
107     {
108         mxParentWindow->removeWindowListener(this);
109         mxParentWindow->removePaintListener(this);
110         mxParentWindow->removeMouseListener(this);
111         mxParentWindow->removeFocusListener(this);
112     }
113     mxParentWindow = nullptr;
114     mxParentCanvas = nullptr;
115 
116     if (rxPane.is())
117     {
118         mxParentWindow = rxPane->getWindow();
119         mxParentCanvas = rxPane->getCanvas();
120     }
121     else
122     {
123         mxParentWindow = nullptr;
124     }
125 
126     if (mxParentWindow.is())
127     {
128         mxParentWindow->addWindowListener(this);
129         mxParentWindow->addPaintListener(this);
130         mxParentWindow->addMouseListener(this);
131         mxParentWindow->addFocusListener(this);
132 
133         // We paint our own background, make that of the parent window transparent.
134         Reference<awt::XWindowPeer> xPeer (mxParentWindow, UNO_QUERY);
135         if (xPeer.is())
136             xPeer->setBackground(util::Color(0xff000000));
137     }
138 }
139 
SetTheme(const std::shared_ptr<PresenterTheme> & rpTheme)140 void PresenterWindowManager::SetTheme (const std::shared_ptr<PresenterTheme>& rpTheme)
141 {
142     mpTheme = rpTheme;
143 
144     // Get background bitmap or background color from the theme.
145 
146     if (mpTheme != nullptr)
147     {
148         mpBackgroundBitmap = mpTheme->GetBitmap(OUString(), "Background");
149     }
150 }
151 
NotifyViewCreation(const Reference<XView> & rxView)152 void PresenterWindowManager::NotifyViewCreation (const Reference<XView>& rxView)
153 {
154     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
155         mpPaneContainer->FindPaneId(rxView->getResourceId()->getAnchor()));
156     OSL_ASSERT(pDescriptor);
157     if (pDescriptor)
158     {
159         Layout();
160 
161         mpPresenterController->GetPaintManager()->Invalidate(
162             pDescriptor->mxContentWindow,
163             sal_Int16(awt::InvalidateStyle::TRANSPARENT
164             | awt::InvalidateStyle::CHILDREN));
165     }
166 }
167 
SetPanePosSizeAbsolute(const OUString & rsPaneURL,const double nX,const double nY,const double nWidth,const double nHeight)168 void PresenterWindowManager::SetPanePosSizeAbsolute (
169     const OUString& rsPaneURL,
170     const double nX,
171     const double nY,
172     const double nWidth,
173     const double nHeight)
174 {
175     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
176         mpPaneContainer->FindPaneURL(rsPaneURL));
177     if (pDescriptor)
178     {
179         if (pDescriptor->mxBorderWindow.is())
180             pDescriptor->mxBorderWindow->setPosSize(
181                 ::sal::static_int_cast<sal_Int32>(nX),
182                 ::sal::static_int_cast<sal_Int32>(nY),
183                 ::sal::static_int_cast<sal_Int32>(nWidth),
184                 ::sal::static_int_cast<sal_Int32>(nHeight),
185                 awt::PosSize::POSSIZE);
186     }
187 }
188 
SetPaneBorderPainter(const::rtl::Reference<PresenterPaneBorderPainter> & rPainter)189 void PresenterWindowManager::SetPaneBorderPainter (
190     const ::rtl::Reference<PresenterPaneBorderPainter>& rPainter)
191 {
192     mpPaneBorderPainter = rPainter;
193 }
194 
195 //----- XWindowListener -------------------------------------------------------
196 
windowResized(const awt::WindowEvent & rEvent)197 void SAL_CALL PresenterWindowManager::windowResized (const awt::WindowEvent& rEvent)
198 {
199     ThrowIfDisposed();
200     if (rEvent.Source == mxParentWindow)
201     {
202         Layout();
203     }
204     else
205     {
206         Reference<awt::XWindow> xWindow (rEvent.Source,UNO_QUERY);
207         if (xWindow.is())
208         {
209             UpdateWindowSize(xWindow);
210 
211             // Make sure the background of a transparent window is painted.
212             mpPresenterController->GetPaintManager()->Invalidate(mxParentWindow);
213         }
214     }
215 }
216 
windowMoved(const awt::WindowEvent & rEvent)217 void SAL_CALL PresenterWindowManager::windowMoved (const awt::WindowEvent& rEvent)
218 {
219     ThrowIfDisposed();
220     if (rEvent.Source != mxParentWindow)
221     {
222         Reference<awt::XWindow> xWindow (rEvent.Source,UNO_QUERY);
223         UpdateWindowSize(xWindow);
224 
225         // Make sure the background of a transparent window is painted.
226         mpPresenterController->GetPaintManager()->Invalidate(xWindow);
227     }
228 }
229 
windowShown(const lang::EventObject &)230 void SAL_CALL PresenterWindowManager::windowShown (const lang::EventObject&) {}
231 
windowHidden(const lang::EventObject &)232 void SAL_CALL PresenterWindowManager::windowHidden (const lang::EventObject&) {}
233 
234 //----- XPaintListener --------------------------------------------------------
235 
windowPaint(const awt::PaintEvent & rEvent)236 void SAL_CALL PresenterWindowManager::windowPaint (const awt::PaintEvent& rEvent)
237 {
238     ThrowIfDisposed();
239 
240     if ( ! mxParentWindow.is())
241         return;
242     if ( ! mxParentCanvas.is())
243         return;
244 
245     if (mpTheme == nullptr)
246         return;
247 
248     try
249     {
250         if (mbIsLayoutPending)
251             Layout();
252         PaintBackground(rEvent.UpdateRect);
253         PaintChildren(rEvent);
254     }
255     catch (RuntimeException&)
256     {
257         OSL_FAIL("paint failed!");
258     }
259 }
260 
261 //----- XMouseListener --------------------------------------------------------
262 
mousePressed(const css::awt::MouseEvent &)263 void SAL_CALL PresenterWindowManager::mousePressed (const css::awt::MouseEvent&)
264 {
265     if (!mbIsSlideSorterActive) // tdf#127921
266         mbIsMouseClickPending = true;
267 }
268 
mouseReleased(const css::awt::MouseEvent & rEvent)269 void SAL_CALL PresenterWindowManager::mouseReleased (const css::awt::MouseEvent& rEvent)
270 {
271     if (mbIsMouseClickPending)
272     {
273         mbIsMouseClickPending = false;
274         mpPresenterController->HandleMouseClick(rEvent);
275     }
276 }
277 
mouseEntered(const css::awt::MouseEvent &)278 void SAL_CALL PresenterWindowManager::mouseEntered (const css::awt::MouseEvent&)
279 {
280     mbIsMouseClickPending = false;
281 }
282 
mouseExited(const css::awt::MouseEvent &)283 void SAL_CALL PresenterWindowManager::mouseExited (const css::awt::MouseEvent&)
284 {
285     mbIsMouseClickPending = false;
286 }
287 
288 //----- XFocusListener --------------------------------------------------------
289 
focusGained(const css::awt::FocusEvent &)290 void SAL_CALL PresenterWindowManager::focusGained (const css::awt::FocusEvent& /*rEvent*/)
291 {
292     ThrowIfDisposed();
293 }
294 
focusLost(const css::awt::FocusEvent &)295 void SAL_CALL PresenterWindowManager::focusLost (const css::awt::FocusEvent&)
296 {
297     ThrowIfDisposed();
298 }
299 
300 //----- XEventListener --------------------------------------------------------
301 
disposing(const lang::EventObject & rEvent)302 void SAL_CALL PresenterWindowManager::disposing (const lang::EventObject& rEvent)
303 {
304     if (rEvent.Source == mxParentWindow)
305         mxParentWindow = nullptr;
306 }
307 
308 
PaintChildren(const awt::PaintEvent & rEvent) const309 void PresenterWindowManager::PaintChildren (const awt::PaintEvent& rEvent) const
310 {
311     // Call windowPaint on all children that lie in or touch the
312     // update rectangle.
313     for (const auto& rxPane : mpPaneContainer->maPanes)
314     {
315         try
316         {
317             // Make sure that the pane shall and can be painted.
318             if ( ! rxPane->mbIsActive)
319                 continue;
320             if (rxPane->mbIsSprite)
321                 continue;
322             if ( ! rxPane->mxPane.is())
323                 continue;
324             if ( ! rxPane->mxBorderWindow.is())
325                 continue;
326             Reference<awt::XWindow> xBorderWindow (rxPane->mxBorderWindow);
327             if ( ! xBorderWindow.is())
328                 continue;
329 
330             // Get the area in which the border of the pane has to be painted.
331             const awt::Rectangle aBorderBox (xBorderWindow->getPosSize());
332             const awt::Rectangle aBorderUpdateBox(
333                 PresenterGeometryHelper::Intersection(
334                     rEvent.UpdateRect,
335                     aBorderBox));
336             if (aBorderUpdateBox.Width<=0 || aBorderUpdateBox.Height<=0)
337                 continue;
338 
339             const awt::Rectangle aLocalBorderUpdateBox(
340                 PresenterGeometryHelper::TranslateRectangle(
341                     aBorderUpdateBox,
342                     -aBorderBox.X,
343                     -aBorderBox.Y));
344 
345             // Invalidate the area of the content window.
346             mpPresenterController->GetPaintManager()->Invalidate(
347                 xBorderWindow,
348                 aLocalBorderUpdateBox,
349                 sal_Int16(awt::InvalidateStyle::CHILDREN
350                     | awt::InvalidateStyle::NOTRANSPARENT));
351         }
352         catch (RuntimeException&)
353         {
354             OSL_FAIL("paint children failed!");
355         }
356     }
357 }
358 
SetLayoutMode(const LayoutMode eMode)359 void PresenterWindowManager::SetLayoutMode (const LayoutMode eMode)
360 {
361     OSL_ASSERT(mpPresenterController);
362 
363     if (meLayoutMode == eMode
364         && !mbIsSlideSorterActive
365         && !mbIsHelpViewActive)
366         return;
367 
368     meLayoutMode = eMode;
369     mbIsSlideSorterActive = false;
370     mbIsHelpViewActive = false;
371 
372     mpPresenterController->RequestViews(
373         mbIsSlideSorterActive,
374         meLayoutMode==LM_Notes,
375         mbIsHelpViewActive);
376     Layout();
377     NotifyLayoutModeChange();
378 }
379 
SetSlideSorterState(bool bIsActive)380 void PresenterWindowManager::SetSlideSorterState (bool bIsActive)
381 {
382     if (mbIsSlideSorterActive == bIsActive)
383         return;
384 
385     mbIsSlideSorterActive = bIsActive;
386     if (mbIsSlideSorterActive)
387         mbIsHelpViewActive = false;
388     StoreViewMode(GetViewMode());
389 
390     mpPresenterController->RequestViews(
391         mbIsSlideSorterActive,
392         meLayoutMode==LM_Notes,
393         mbIsHelpViewActive);
394     Layout();
395     NotifyLayoutModeChange();
396 }
397 
SetHelpViewState(bool bIsActive)398 void PresenterWindowManager::SetHelpViewState (bool bIsActive)
399 {
400     if (mbIsHelpViewActive == bIsActive)
401         return;
402 
403     mbIsHelpViewActive = bIsActive;
404     if (mbIsHelpViewActive)
405         mbIsSlideSorterActive = false;
406     StoreViewMode(GetViewMode());
407 
408     mpPresenterController->RequestViews(
409         mbIsSlideSorterActive,
410         meLayoutMode==LM_Notes,
411         mbIsHelpViewActive);
412     Layout();
413     NotifyLayoutModeChange();
414 }
415 
SetPauseState(bool bIsPaused)416 void PresenterWindowManager::SetPauseState (bool bIsPaused)
417 {
418     if (mbisPaused == bIsPaused)
419         return;
420 
421     mbisPaused = bIsPaused;
422 
423     NotifyLayoutModeChange();
424 }
425 
SetViewMode(const ViewMode eMode)426 void PresenterWindowManager::SetViewMode (const ViewMode eMode)
427 {
428     switch (eMode)
429     {
430         case VM_Standard:
431             SetSlideSorterState(false);
432             SetHelpViewState(false);
433             SetLayoutMode(LM_Standard);
434             break;
435 
436         case VM_Notes:
437             SetSlideSorterState(false);
438             SetHelpViewState(false);
439             SetLayoutMode(LM_Notes);
440             break;
441 
442         case VM_SlideOverview:
443             SetHelpViewState(false);
444             SetSlideSorterState(true);
445             break;
446 
447         case VM_Help:
448             SetHelpViewState(true);
449             SetSlideSorterState(false);
450             break;
451     }
452 
453     StoreViewMode(eMode);
454 }
455 
GetViewMode() const456 PresenterWindowManager::ViewMode PresenterWindowManager::GetViewMode() const
457 {
458     if (mbIsHelpViewActive)
459         return VM_Help;
460     else if (mbIsSlideSorterActive)
461         return VM_SlideOverview;
462     else if (meLayoutMode == LM_Notes)
463         return VM_Notes;
464     else
465         return VM_Standard;
466 }
467 
RestoreViewMode()468 void PresenterWindowManager::RestoreViewMode()
469 {
470     sal_Int32 nMode (0);
471     PresenterConfigurationAccess aConfiguration (
472         mxComponentContext,
473         "/org.openoffice.Office.PresenterScreen/",
474         PresenterConfigurationAccess::READ_ONLY);
475     aConfiguration.GetConfigurationNode("Presenter/InitialViewMode") >>= nMode;
476     switch (nMode)
477     {
478         default:
479         case 0:
480             SetViewMode(VM_Standard);
481             break;
482 
483         case 1:
484             SetViewMode(VM_Notes);
485             break;
486 
487         case 2:
488             SetViewMode(VM_SlideOverview);
489             break;
490     }
491 }
492 
StoreViewMode(const ViewMode eViewMode)493 void PresenterWindowManager::StoreViewMode (const ViewMode eViewMode)
494 {
495     try
496     {
497         PresenterConfigurationAccess aConfiguration (
498             mxComponentContext,
499             "/org.openoffice.Office.PresenterScreen/",
500             PresenterConfigurationAccess::READ_WRITE);
501         aConfiguration.GoToChild("Presenter");
502         Any aValue;
503         switch (eViewMode)
504         {
505             default:
506             case VM_Standard:
507                 aValue <<= sal_Int32(0);
508                 break;
509 
510             case VM_Notes:
511                 aValue <<= sal_Int32(1);
512                 break;
513 
514             case VM_SlideOverview:
515                 aValue <<= sal_Int32(2);
516                 break;
517         }
518 
519         aConfiguration.SetProperty ("InitialViewMode", aValue);
520         aConfiguration.CommitChanges();
521     }
522     catch (Exception&)
523     {
524     }
525 }
526 
AddLayoutListener(const Reference<document::XEventListener> & rxListener)527 void PresenterWindowManager::AddLayoutListener (
528     const Reference<document::XEventListener>& rxListener)
529 {
530     maLayoutListeners.push_back(rxListener);
531 }
532 
RemoveLayoutListener(const Reference<document::XEventListener> & rxListener)533 void PresenterWindowManager::RemoveLayoutListener (
534     const Reference<document::XEventListener>& rxListener)
535 {
536     // Assume that there are no multiple entries.
537     auto iListener = std::find(maLayoutListeners.begin(), maLayoutListeners.end(), rxListener);
538     if (iListener != maLayoutListeners.end())
539         maLayoutListeners.erase(iListener);
540 }
541 
Layout()542 void PresenterWindowManager::Layout()
543 {
544     if (!mxParentWindow.is() || mbIsLayouting)
545         return;
546 
547     mbIsLayoutPending = false;
548     mbIsLayouting = true;
549     mxScaledBackgroundBitmap = nullptr;
550     mxClipPolygon = nullptr;
551 
552     try
553     {
554         if (mbIsSlideSorterActive)
555             LayoutSlideSorterMode();
556         else if (mbIsHelpViewActive)
557             LayoutHelpMode();
558         else
559             switch (meLayoutMode)
560             {
561                 case LM_Standard:
562                 default:
563                     LayoutStandardMode();
564                     break;
565 
566                 case LM_Notes:
567                     LayoutNotesMode();
568                     break;
569             }
570     }
571     catch (Exception&)
572     {
573         OSL_ASSERT(false);
574         throw;
575     }
576 
577     mbIsLayouting = false;
578 }
579 
LayoutStandardMode()580 void PresenterWindowManager::LayoutStandardMode()
581 {
582     awt::Rectangle aBox = mxParentWindow->getPosSize();
583 
584     const double nGoldenRatio ((1 + sqrt(5.0)) / 2);
585     const double nGap (20);
586     const double nHorizontalSlideDivide (aBox.Width / nGoldenRatio);
587     double nSlidePreviewTop (0);
588 
589 
590     // For the current slide view calculate the outer height from the outer
591     // width.  This takes into account the slide aspect ratio and thus has to
592     // go over the inner pane size.
593     PresenterPaneContainer::SharedPaneDescriptor pPane (
594         mpPaneContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL));
595     if (pPane)
596     {
597         const awt::Size aCurrentSlideOuterBox(CalculatePaneSize(
598             nHorizontalSlideDivide - 1.5*nGap,
599             PresenterPaneFactory::msCurrentSlidePreviewPaneURL));
600         nSlidePreviewTop = (aBox.Height - aCurrentSlideOuterBox.Height) / 2;
601         double Temp=nGap;
602         /// check whether RTL interface or not
603         if(AllSettings::GetLayoutRTL())
604             Temp=aBox.Width - aCurrentSlideOuterBox.Width - nGap;
605         SetPanePosSizeAbsolute (
606             PresenterPaneFactory::msCurrentSlidePreviewPaneURL,
607             Temp,
608             nSlidePreviewTop,
609             aCurrentSlideOuterBox.Width,
610             aCurrentSlideOuterBox.Height);
611     }
612 
613     // For the next slide view calculate the outer height from the outer
614     // width.  This takes into account the slide aspect ratio and thus has to
615     // go over the inner pane size.
616     pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNextSlidePreviewPaneURL);
617     if (pPane)
618     {
619         const awt::Size aNextSlideOuterBox (CalculatePaneSize(
620             aBox.Width - nHorizontalSlideDivide - 1.5*nGap,
621             PresenterPaneFactory::msNextSlidePreviewPaneURL));
622         double Temp=aBox.Width - aNextSlideOuterBox.Width - nGap;
623         /// check whether RTL interface or not
624         if(AllSettings::GetLayoutRTL())
625             Temp=nGap;
626         SetPanePosSizeAbsolute (
627             PresenterPaneFactory::msNextSlidePreviewPaneURL,
628             Temp,
629             nSlidePreviewTop,
630             aNextSlideOuterBox.Width,
631             aNextSlideOuterBox.Height);
632     }
633 
634     LayoutToolBar();
635 }
636 
LayoutNotesMode()637 void PresenterWindowManager::LayoutNotesMode()
638 {
639     awt::Rectangle aBox = mxParentWindow->getPosSize();
640 
641     const geometry::RealRectangle2D aToolBarBox (LayoutToolBar());
642 
643     const double nGoldenRatio ((1 + sqrt(5.0)) / 2);
644     const double nGap (20);
645     const double nPrimaryWidth (aBox.Width / nGoldenRatio);
646     const double nSecondaryWidth (aBox.Width - nPrimaryWidth);
647     const double nTertiaryWidth (nSecondaryWidth / nGoldenRatio);
648     double nSlidePreviewTop (0);
649     double nNotesViewBottom (aToolBarBox.Y1 - nGap);
650      /// check whether RTL interface or not
651 
652 
653     // The notes view has no fixed aspect ratio.
654     PresenterPaneContainer::SharedPaneDescriptor pPane (
655         mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNotesPaneURL));
656     if (pPane)
657     {
658         const geometry::RealSize2D aNotesViewOuterSize(
659             nPrimaryWidth - 1.5*nGap + 0.5,
660             nNotesViewBottom);
661         nSlidePreviewTop = (aBox.Height
662             - aToolBarBox.Y2 + aToolBarBox.Y1 - aNotesViewOuterSize.Height) / 2;
663         /// check whether RTL interface or not
664         double Temp=aBox.Width - aNotesViewOuterSize.Width - nGap;
665         if(AllSettings::GetLayoutRTL())
666             Temp=nGap;
667         SetPanePosSizeAbsolute (
668             PresenterPaneFactory::msNotesPaneURL,
669             Temp,
670             nSlidePreviewTop,
671             aNotesViewOuterSize.Width,
672             aNotesViewOuterSize.Height);
673         nNotesViewBottom = nSlidePreviewTop + aNotesViewOuterSize.Height;
674     }
675 
676     // For the current slide view calculate the outer height from the outer
677     // width.  This takes into account the slide aspect ratio and thus has to
678     // go over the inner pane size.
679     pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msCurrentSlidePreviewPaneURL);
680     if (pPane)
681     {
682         const awt::Size aCurrentSlideOuterBox(CalculatePaneSize(
683             nSecondaryWidth - 1.5*nGap,
684             PresenterPaneFactory::msCurrentSlidePreviewPaneURL));
685         /// check whether RTL interface or not
686         double Temp=nGap;
687         if(AllSettings::GetLayoutRTL())
688             Temp=aBox.Width - aCurrentSlideOuterBox.Width - nGap;
689         SetPanePosSizeAbsolute (
690             PresenterPaneFactory::msCurrentSlidePreviewPaneURL,
691             Temp,
692             nSlidePreviewTop,
693             aCurrentSlideOuterBox.Width,
694             aCurrentSlideOuterBox.Height);
695     }
696 
697     // For the next slide view calculate the outer height from the outer
698     // width.  This takes into account the slide aspect ratio and thus has to
699     // go over the inner pane size.
700     pPane = mpPaneContainer->FindPaneURL(PresenterPaneFactory::msNextSlidePreviewPaneURL);
701     if (!pPane)
702         return;
703 
704     const awt::Size aNextSlideOuterBox (CalculatePaneSize(
705         nTertiaryWidth,
706         PresenterPaneFactory::msNextSlidePreviewPaneURL));
707     /// check whether RTL interface or not
708     double Temp=nGap;
709     if(AllSettings::GetLayoutRTL())
710         Temp=aBox.Width - aNextSlideOuterBox.Width - nGap;
711     SetPanePosSizeAbsolute (
712         PresenterPaneFactory::msNextSlidePreviewPaneURL,
713         Temp,
714         nNotesViewBottom - aNextSlideOuterBox.Height,
715         aNextSlideOuterBox.Width,
716         aNextSlideOuterBox.Height);
717 
718 
719 }
720 
LayoutSlideSorterMode()721 void PresenterWindowManager::LayoutSlideSorterMode()
722 {
723     const geometry::RealRectangle2D aToolBarBox (LayoutToolBar());
724 
725     awt::Rectangle aWindowBox = mxParentWindow->getPosSize();
726     const double nGap (20);
727     SetPanePosSizeAbsolute(
728         mpPaneContainer->GetPaneURLForViewURL(PresenterViewFactory::msSlideSorterURL),
729         nGap,
730         nGap,
731         aWindowBox.Width - 2*nGap,
732         aToolBarBox.Y1 - 2*nGap);
733 }
734 
LayoutHelpMode()735 void PresenterWindowManager::LayoutHelpMode()
736 {
737     const geometry::RealRectangle2D aToolBarBox (LayoutToolBar());
738 
739     awt::Rectangle aWindowBox = mxParentWindow->getPosSize();
740     const double nGap (20);
741     const double nGoldenRatio ((1 + sqrt(5.0)) / 2);
742     const double nWidth = ::std::min(aWindowBox.Width - 2*nGap, aWindowBox.Width/nGoldenRatio);
743     SetPanePosSizeAbsolute(
744         mpPaneContainer->GetPaneURLForViewURL(PresenterViewFactory::msHelpViewURL),
745         (aWindowBox.Width - nWidth)/2,
746         nGap,
747         nWidth,
748         aToolBarBox.Y1 - 2*nGap);
749 }
750 
LayoutToolBar()751 geometry::RealRectangle2D PresenterWindowManager::LayoutToolBar()
752 {
753     double nToolBarWidth (400);
754     double nToolBarHeight (80);
755 
756     // Get access to the tool bar.
757     PresenterPaneContainer::SharedPaneDescriptor pDescriptor(
758         mpPaneContainer->FindPaneURL(PresenterPaneFactory::msToolBarPaneURL));
759     if (pDescriptor)
760     {
761         PresenterToolBarView* pToolBarView
762             = dynamic_cast<PresenterToolBarView*>(pDescriptor->mxView.get());
763         if (pToolBarView != nullptr && pToolBarView->GetPresenterToolBar().is())
764         {
765             geometry::RealSize2D aSize (pToolBarView->GetPresenterToolBar()->GetMinimalSize());
766 
767             if (mpPaneBorderPainter.is())
768             {
769                 const awt::Rectangle aBox (mpPaneBorderPainter->addBorder (
770                     PresenterPaneFactory::msToolBarPaneURL,
771                     awt::Rectangle(
772                         0,
773                         0,
774                         PresenterGeometryHelper::Round(aSize.Width),
775                         PresenterGeometryHelper::Round(aSize.Height)),
776                     css::drawing::framework::BorderType_TOTAL_BORDER));
777 
778                 nToolBarWidth = aBox.Width;
779                 nToolBarHeight = aBox.Height;
780             }
781             else
782             {
783                 nToolBarWidth = aSize.Width + 20;
784                 nToolBarHeight = aSize.Height + 10;
785             }
786         }
787     }
788 
789     const awt::Rectangle aBox = mxParentWindow->getPosSize();
790     const double nToolBarX ((aBox.Width - nToolBarWidth) / 2);
791     const double nToolBarY (aBox.Height - nToolBarHeight);
792     SetPanePosSizeAbsolute(
793         PresenterPaneFactory::msToolBarPaneURL,
794         nToolBarX,
795         nToolBarY,
796         nToolBarWidth,
797         nToolBarHeight);
798 
799     return geometry::RealRectangle2D(
800         nToolBarX,
801         nToolBarY,
802         nToolBarX + nToolBarWidth - 1,
803         nToolBarY + nToolBarHeight - 1);
804 }
805 
CalculatePaneSize(const double nOuterWidth,const OUString & rsPaneURL)806 awt::Size PresenterWindowManager::CalculatePaneSize (
807     const double nOuterWidth,
808     const OUString& rsPaneURL)
809 {
810     // Calculate the inner width by removing the pane border.
811     awt::Rectangle aInnerBox (mpPaneBorderPainter->RemoveBorder (
812         rsPaneURL,
813         awt::Rectangle(0,0,
814             sal_Int32(nOuterWidth+0.5),sal_Int32(nOuterWidth)),
815         drawing::framework::BorderType_TOTAL_BORDER));
816 
817     // Calculate the inner height with the help of the slide aspect ratio.
818     const double nCurrentSlideInnerHeight (
819         aInnerBox.Width / mpPresenterController->GetSlideAspectRatio());
820 
821     // Add the pane border to get the outer box.
822     awt::Rectangle aOuterBox (mpPaneBorderPainter->AddBorder (
823         rsPaneURL,
824         awt::Rectangle(0,0,
825             aInnerBox.Width,sal_Int32(nCurrentSlideInnerHeight+0.5)),
826         drawing::framework::BorderType_TOTAL_BORDER));
827 
828     return awt::Size(aOuterBox.Width, aOuterBox.Height);
829 }
830 
NotifyLayoutModeChange()831 void PresenterWindowManager::NotifyLayoutModeChange()
832 {
833     document::EventObject aEvent;
834     aEvent.Source = Reference<XInterface>(static_cast<XWeak*>(this));
835 
836     LayoutListenerContainer aContainerCopy (maLayoutListeners);
837     for (const auto& rxListener : aContainerCopy)
838     {
839         if (rxListener.is())
840         {
841             try
842             {
843                 rxListener->notifyEvent(aEvent);
844             }
845             catch (lang::DisposedException&)
846             {
847                 RemoveLayoutListener(rxListener);
848             }
849             catch (RuntimeException&)
850             {
851             }
852         }
853     }
854 }
855 
NotifyDisposing()856 void PresenterWindowManager::NotifyDisposing()
857 {
858     lang::EventObject aEvent;
859     aEvent.Source = static_cast<XWeak*>(this);
860 
861     LayoutListenerContainer aContainer;
862     aContainer.swap(maLayoutListeners);
863     for (auto& rxListener : aContainer)
864     {
865         if (rxListener.is())
866         {
867             try
868             {
869                 rxListener->disposing(aEvent);
870             }
871             catch (lang::DisposedException&)
872             {
873             }
874             catch (RuntimeException&)
875             {
876             }
877         }
878     }
879 }
880 
UpdateWindowSize(const Reference<awt::XWindow> & rxBorderWindow)881 void PresenterWindowManager::UpdateWindowSize (const Reference<awt::XWindow>& rxBorderWindow)
882 {
883     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
884         mpPaneContainer->FindBorderWindow(rxBorderWindow));
885     if (pDescriptor)
886     {
887         mxClipPolygon = nullptr;
888 
889         // ToTop is called last because it may invalidate the iterator.
890         if ( ! mbIsLayouting)
891             mpPaneContainer->ToTop(pDescriptor);
892     }
893 }
894 
PaintBackground(const awt::Rectangle & rUpdateBox)895 void PresenterWindowManager::PaintBackground (const awt::Rectangle& rUpdateBox)
896 {
897     if ( ! mxParentWindow.is())
898         return;
899 
900     Reference<rendering::XGraphicDevice> xDevice (mxParentCanvas->getDevice());
901     if ( ! xDevice.is())
902         return;
903 
904     // Create a polygon for the background and for clipping.
905     Reference<rendering::XPolyPolygon2D> xBackgroundPolygon (
906         PresenterGeometryHelper::CreatePolygon(mxParentWindow->getPosSize(), xDevice));
907     if ( ! mxClipPolygon.is())
908         mxClipPolygon = CreateClipPolyPolygon();
909 
910     // Create View- and RenderState structs.
911     const rendering::ViewState aViewState(
912         geometry::AffineMatrix2D(1,0,0, 0,1,0),
913         PresenterGeometryHelper::CreatePolygon(rUpdateBox, xDevice));
914     rendering::RenderState aRenderState (
915         geometry::AffineMatrix2D(1,0,0, 0,1,0),
916         mxClipPolygon,
917         Sequence<double>(4),
918         rendering::CompositeOperation::SOURCE);
919 
920     // Paint the background.
921     if (!mpBackgroundBitmap)
922         return;
923 
924     ProvideBackgroundBitmap();
925 
926     if (mxScaledBackgroundBitmap.is())
927     {
928         const geometry::IntegerSize2D aBitmapSize(mxScaledBackgroundBitmap->getSize());
929         Sequence<rendering::Texture> aTextures
930         {
931             {
932                 geometry::AffineMatrix2D( aBitmapSize.Width,0,0, 0,aBitmapSize.Height,0),
933                 1,
934                 0,
935                 mxScaledBackgroundBitmap,
936                 nullptr,
937                 nullptr,
938                 rendering::StrokeAttributes(),
939                 rendering::TexturingMode::REPEAT,
940                 rendering::TexturingMode::REPEAT
941             }
942         };
943 
944         mxParentCanvas->fillTexturedPolyPolygon(
945             xBackgroundPolygon,
946             aViewState,
947             aRenderState,
948             aTextures);
949     }
950     else
951     {
952         const util::Color aBackgroundColor (mpBackgroundBitmap->maReplacementColor);
953         aRenderState.DeviceColor[0] = ((aBackgroundColor >> 16) & 0x0ff) / 255.0;
954         aRenderState.DeviceColor[1] = ((aBackgroundColor >> 8) & 0x0ff) / 255.0;
955         aRenderState.DeviceColor[2] = ((aBackgroundColor >> 0) & 0x0ff) / 255.0;
956         aRenderState.DeviceColor[3] = ((aBackgroundColor >> 24) & 0x0ff) / 255.0;
957         mxParentCanvas->fillPolyPolygon(
958             xBackgroundPolygon,
959             aViewState,
960             aRenderState);
961     }
962 }
963 
ProvideBackgroundBitmap()964 void PresenterWindowManager::ProvideBackgroundBitmap()
965 {
966     if (  mxScaledBackgroundBitmap.is())
967         return;
968 
969     Reference<rendering::XBitmap> xBitmap (mpBackgroundBitmap->GetNormalBitmap());
970     if (!xBitmap.is())
971         return;
972 
973     const bool bStretchVertical (mpBackgroundBitmap->meVerticalTexturingMode
974         == PresenterBitmapDescriptor::Stretch);
975     const bool bStretchHorizontal (mpBackgroundBitmap->meHorizontalTexturingMode
976         == PresenterBitmapDescriptor::Stretch);
977     if (bStretchHorizontal || bStretchVertical)
978     {
979         geometry::RealSize2D aSize;
980         if (bStretchVertical)
981             aSize.Height = mxParentWindow->getPosSize().Height;
982         else
983             aSize.Height = xBitmap->getSize().Height;
984         if (bStretchHorizontal)
985             aSize.Width = mxParentWindow->getPosSize().Width;
986         else
987             aSize.Width = xBitmap->getSize().Width;
988         mxScaledBackgroundBitmap = xBitmap->getScaledBitmap(aSize, false);
989     }
990     else
991     {
992         mxScaledBackgroundBitmap = xBitmap;
993     }
994 }
995 
CreateClipPolyPolygon() const996 Reference<rendering::XPolyPolygon2D> PresenterWindowManager::CreateClipPolyPolygon() const
997 {
998     // Create a clip polygon that includes the whole update area but has the
999     // content windows as holes.
1000     const sal_Int32 nPaneCount (mpPaneContainer->maPanes.size());
1001     ::std::vector<awt::Rectangle> aRectangles;
1002     aRectangles.reserve(1+nPaneCount);
1003     aRectangles.push_back(mxParentWindow->getPosSize());
1004     for (const auto& pDescriptor : mpPaneContainer->maPanes)
1005     {
1006         if ( ! pDescriptor->mbIsActive)
1007             continue;
1008         if ( ! pDescriptor->mbIsOpaque)
1009             continue;
1010         if ( ! pDescriptor->mxBorderWindow.is() || ! pDescriptor->mxContentWindow.is())
1011             continue;
1012         Reference<awt::XWindow2> xWindow (pDescriptor->mxBorderWindow, UNO_QUERY);
1013         if (xWindow.is() && ! xWindow->isVisible())
1014             continue;
1015 
1016         const awt::Rectangle aOuterBorderBox (pDescriptor->mxBorderWindow->getPosSize());
1017         awt::Rectangle aInnerBorderBox (pDescriptor->mxContentWindow->getPosSize());
1018         aInnerBorderBox.X += aOuterBorderBox.X;
1019         aInnerBorderBox.Y += aOuterBorderBox.Y;
1020         aRectangles.push_back(aInnerBorderBox);
1021     }
1022     Reference<rendering::XPolyPolygon2D> xPolyPolygon (
1023         PresenterGeometryHelper::CreatePolygon(
1024             aRectangles,
1025             mxParentCanvas->getDevice()));
1026     if (xPolyPolygon.is())
1027         xPolyPolygon->setFillRule(rendering::FillRule_EVEN_ODD);
1028     return xPolyPolygon;
1029 }
1030 
Update()1031 void PresenterWindowManager::Update()
1032 {
1033     mxClipPolygon = nullptr;
1034     mbIsLayoutPending = true;
1035 
1036     mpPresenterController->GetPaintManager()->Invalidate(mxParentWindow);
1037 }
1038 
ThrowIfDisposed() const1039 void PresenterWindowManager::ThrowIfDisposed() const
1040 {
1041     if (rBHelper.bDisposed || rBHelper.bInDispose)
1042     {
1043         throw lang::DisposedException (
1044             "PresenterWindowManager has already been disposed",
1045             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1046     }
1047 }
1048 
1049 } // end of namespace ::sdext::presenter
1050 
1051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1052