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