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