1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/settings.hxx>
22 #include "PresenterSlideSorter.hxx"
23 #include "PresenterButton.hxx"
24 #include "PresenterCanvasHelper.hxx"
25 #include "PresenterGeometryHelper.hxx"
26 #include "PresenterPaintManager.hxx"
27 #include "PresenterPaneBase.hxx"
28 #include "PresenterScrollBar.hxx"
29 #include "PresenterUIPainter.hxx"
30 #include "PresenterWindowManager.hxx"
31 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
32 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
33 #include <com/sun/star/rendering/XBitmapCanvas.hpp>
34 #include <com/sun/star/rendering/CompositeOperation.hpp>
35 #include <com/sun/star/rendering/TextDirection.hpp>
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::drawing::framework
;
44 const sal_Int32
gnVerticalGap (10);
45 const sal_Int32
gnVerticalBorder (10);
46 const sal_Int32
gnHorizontalGap (10);
47 const sal_Int32
gnHorizontalBorder (10);
49 const double gnMinimalPreviewWidth (200);
50 const double gnPreferredPreviewWidth (300);
51 const double gnMaximalPreviewWidth (400);
52 const sal_Int32
gnPreferredColumnCount (6);
53 const double gnMinimalHorizontalPreviewGap(15);
54 const double gnPreferredHorizontalPreviewGap(25);
55 const double gnMaximalHorizontalPreviewGap(50);
56 const double gnPreferredVerticalPreviewGap(25);
58 const sal_Int32
gnHorizontalLabelBorder (3);
59 const sal_Int32
gnHorizontalLabelPadding (5);
61 const sal_Int32
gnVerticalButtonPadding (gnVerticalGap
);
64 namespace sdext::presenter
{
67 sal_Int32
round (const double nValue
) { return sal::static_int_cast
<sal_Int32
>(0.5 + nValue
); }
68 sal_Int32
floor (const double nValue
) { return sal::static_int_cast
<sal_Int32
>(nValue
); }
71 //===== PresenterSlideSorter::Layout ==========================================
73 class PresenterSlideSorter::Layout
76 explicit Layout (const ::rtl::Reference
<PresenterScrollBar
>& rpVerticalScrollBar
);
78 void Update (const geometry::RealRectangle2D
& rBoundingBox
, const double nSlideAspectRatio
);
79 void SetupVisibleArea();
80 void UpdateScrollBars();
81 bool IsScrollBarNeeded (const sal_Int32 nSlideCount
);
82 geometry::RealPoint2D
GetLocalPosition (const geometry::RealPoint2D
& rWindowPoint
) const;
83 geometry::RealPoint2D
GetWindowPosition(const geometry::RealPoint2D
& rLocalPoint
) const;
84 sal_Int32
GetColumn (const geometry::RealPoint2D
& rLocalPoint
) const;
85 sal_Int32
GetRow (const geometry::RealPoint2D
& rLocalPoint
,
86 const bool bReturnInvalidValue
= false) const;
87 sal_Int32
GetSlideIndexForPosition (const css::geometry::RealPoint2D
& rPoint
) const;
88 css::geometry::RealPoint2D
GetPoint (
89 const sal_Int32 nSlideIndex
,
90 const sal_Int32 nRelativeHorizontalPosition
,
91 const sal_Int32 nRelativeVerticalPosition
) const;
92 css::awt::Rectangle
GetBoundingBox (const sal_Int32 nSlideIndex
) const;
93 void ForAllVisibleSlides (const ::std::function
<void (sal_Int32
)>& rAction
);
94 sal_Int32
GetFirstVisibleSlideIndex() const;
95 sal_Int32
GetLastVisibleSlideIndex() const;
96 bool SetHorizontalOffset (const double nOffset
);
97 bool SetVerticalOffset (const double nOffset
);
99 css::geometry::RealRectangle2D maBoundingBox
;
100 css::geometry::IntegerSize2D maPreviewSize
;
101 sal_Int32 mnHorizontalOffset
;
102 sal_Int32 mnVerticalOffset
;
103 sal_Int32 mnHorizontalGap
;
104 sal_Int32 mnVerticalGap
;
105 sal_Int32 mnHorizontalBorder
;
106 sal_Int32 mnVerticalBorder
;
107 sal_Int32 mnRowCount
;
108 sal_Int32 mnColumnCount
;
109 sal_Int32 mnSlideCount
;
110 sal_Int32 mnFirstVisibleColumn
;
111 sal_Int32 mnLastVisibleColumn
;
112 sal_Int32 mnFirstVisibleRow
;
113 sal_Int32 mnLastVisibleRow
;
116 ::rtl::Reference
<PresenterScrollBar
> mpVerticalScrollBar
;
118 sal_Int32
GetIndex (const sal_Int32 nRow
, const sal_Int32 nColumn
) const;
119 sal_Int32
GetRow (const sal_Int32 nSlideIndex
) const;
120 sal_Int32
GetColumn (const sal_Int32 nSlideIndex
) const;
123 //==== PresenterSlideSorter::MouseOverManager =================================
125 class PresenterSlideSorter::MouseOverManager
129 const Reference
<container::XIndexAccess
>& rxSlides
,
130 const std::shared_ptr
<PresenterTheme
>& rpTheme
,
131 const Reference
<awt::XWindow
>& rxInvalidateTarget
,
132 const std::shared_ptr
<PresenterPaintManager
>& rpPaintManager
);
133 MouseOverManager(const MouseOverManager
&) = delete;
134 MouseOverManager
& operator=(const MouseOverManager
&) = delete;
137 const sal_Int32 nSlideIndex
,
138 const Reference
<rendering::XCanvas
>& rxCanvas
,
139 const Reference
<rendering::XPolyPolygon2D
>& rxClip
);
142 const sal_Int32 nSlideIndex
,
143 const awt::Rectangle
& rBox
);
146 Reference
<rendering::XCanvas
> mxCanvas
;
147 const Reference
<container::XIndexAccess
> mxSlides
;
148 SharedBitmapDescriptor mpLeftLabelBitmap
;
149 SharedBitmapDescriptor mpCenterLabelBitmap
;
150 SharedBitmapDescriptor mpRightLabelBitmap
;
151 PresenterTheme::SharedFontDescriptor mpFont
;
152 sal_Int32 mnSlideIndex
;
153 awt::Rectangle maSlideBoundingBox
;
155 Reference
<rendering::XBitmap
> mxBitmap
;
156 Reference
<awt::XWindow
> mxInvalidateTarget
;
157 std::shared_ptr
<PresenterPaintManager
> mpPaintManager
;
160 const Reference
<rendering::XCanvas
>& rxCanvas
);
161 /** Create a bitmap that shows the given text and is not wider than the
164 Reference
<rendering::XBitmap
> CreateBitmap (
165 const OUString
& rsText
,
166 const sal_Int32 nMaximalWidth
) const;
168 geometry::IntegerSize2D
CalculateLabelSize (
169 const OUString
& rsText
) const;
170 OUString
GetFittingText (const OUString
& rsText
, const double nMaximalWidth
) const;
171 void PaintButtonBackground (
172 const Reference
<rendering::XCanvas
>& rxCanvas
,
173 const geometry::IntegerSize2D
& rSize
) const;
176 //==== PresenterSlideSorter::CurrentSlideFrameRenderer ========================
178 class PresenterSlideSorter::CurrentSlideFrameRenderer
181 CurrentSlideFrameRenderer (
182 const css::uno::Reference
<css::uno::XComponentContext
>& rxContext
,
183 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
);
185 void PaintCurrentSlideFrame (
186 const awt::Rectangle
& rSlideBoundingBox
,
187 const Reference
<rendering::XCanvas
>& rxCanvas
,
188 const geometry::RealRectangle2D
& rClipBox
);
190 /** Enlarge the given rectangle to include the current slide indicator.
192 awt::Rectangle
GetBoundingBox (
193 const awt::Rectangle
& rSlideBoundingBox
);
196 SharedBitmapDescriptor mpTopLeft
;
197 SharedBitmapDescriptor mpTop
;
198 SharedBitmapDescriptor mpTopRight
;
199 SharedBitmapDescriptor mpLeft
;
200 SharedBitmapDescriptor mpRight
;
201 SharedBitmapDescriptor mpBottomLeft
;
202 SharedBitmapDescriptor mpBottom
;
203 SharedBitmapDescriptor mpBottomRight
;
204 sal_Int32 mnTopFrameSize
;
205 sal_Int32 mnLeftFrameSize
;
206 sal_Int32 mnRightFrameSize
;
207 sal_Int32 mnBottomFrameSize
;
209 static void PaintBitmapOnce(
210 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
211 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
212 const Reference
<rendering::XPolyPolygon2D
>& rxClip
,
215 static void PaintBitmapTiled(
216 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
217 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
218 const geometry::RealRectangle2D
& rClipBox
,
222 const double nHeight
);
225 //===== PresenterSlideSorter ==================================================
227 PresenterSlideSorter::PresenterSlideSorter (
228 const Reference
<uno::XComponentContext
>& rxContext
,
229 const Reference
<XResourceId
>& rxViewId
,
230 const Reference
<frame::XController
>& rxController
,
231 const ::rtl::Reference
<PresenterController
>& rpPresenterController
)
232 : PresenterSlideSorterInterfaceBase(m_aMutex
),
233 mxComponentContext(rxContext
),
238 mpPresenterController(rpPresenterController
),
239 mxSlideShowController(mpPresenterController
->GetSlideShowController()),
241 mbIsLayoutPending(true),
243 mpVerticalScrollBar(),
245 mpMouseOverManager(),
246 mnSlideIndexMousePressed(-1),
247 mnCurrentSlideIndex(-1),
249 maSeparatorColor(0x00ffffff),
250 maCurrentSlideFrameBoundingBox(),
251 mpCurrentSlideFrameRenderer(),
254 if ( ! rxContext
.is()
256 || ! rxController
.is()
257 || ! rpPresenterController
)
259 throw lang::IllegalArgumentException();
262 if ( ! mxSlideShowController
.is())
263 throw RuntimeException();
267 // Get pane and window.
268 Reference
<XControllerManager
> xCM (rxController
, UNO_QUERY_THROW
);
269 Reference
<XConfigurationController
> xCC (
270 xCM
->getConfigurationController(), UNO_SET_THROW
);
271 Reference
<lang::XMultiComponentFactory
> xFactory (
272 mxComponentContext
->getServiceManager(), UNO_SET_THROW
);
274 mxPane
.set(xCC
->getResource(rxViewId
->getAnchor()), UNO_QUERY_THROW
);
275 mxWindow
= mxPane
->getWindow();
277 // Add window listener.
278 mxWindow
->addWindowListener(this);
279 mxWindow
->addPaintListener(this);
280 mxWindow
->addMouseListener(this);
281 mxWindow
->addMouseMotionListener(this);
282 mxWindow
->setVisible(true);
284 // Remember the current slide.
285 mnCurrentSlideIndex
= mxSlideShowController
->getCurrentSlideIndex();
287 // Create the scroll bar.
288 mpVerticalScrollBar
.set(
289 new PresenterVerticalScrollBar(
292 mpPresenterController
->GetPaintManager(),
293 [this] (double const offset
) { return this->SetVerticalOffset(offset
); }));
295 mpCloseButton
= PresenterButton::Create(
297 mpPresenterController
,
298 mpPresenterController
->GetTheme(),
301 "SlideSorterCloser");
303 if (mpPresenterController
->GetTheme() != nullptr)
305 PresenterTheme::SharedFontDescriptor
pFont (
306 mpPresenterController
->GetTheme()->GetFont("ButtonFont"));
308 maSeparatorColor
= pFont
->mnColor
;
311 // Create the layout.
312 mpLayout
= std::make_shared
<Layout
>(mpVerticalScrollBar
);
314 // Create the preview cache.
316 xFactory
->createInstanceWithContext(
317 "com.sun.star.drawing.PresenterPreviewCache",
320 Reference
<container::XIndexAccess
> xSlides (mxSlideShowController
, UNO_QUERY
);
321 mxPreviewCache
->setDocumentSlides(xSlides
, rxController
->getModel());
322 mxPreviewCache
->addPreviewCreationNotifyListener(this);
325 mpLayout
->mnSlideCount
= xSlides
->getCount();
328 // Create the mouse over manager.
329 mpMouseOverManager
.reset(new MouseOverManager(
330 Reference
<container::XIndexAccess
>(mxSlideShowController
, UNO_QUERY
),
331 mpPresenterController
->GetTheme(),
333 mpPresenterController
->GetPaintManager()));
335 // Listen for changes of the current slide.
336 Reference
<beans::XPropertySet
> xControllerProperties (rxController
, UNO_QUERY_THROW
);
337 xControllerProperties
->addPropertyChangeListener(
341 // Move the current slide in the center of the window.
342 const awt::Rectangle
aCurrentSlideBBox (mpLayout
->GetBoundingBox(mnCurrentSlideIndex
));
343 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
344 SetHorizontalOffset(aCurrentSlideBBox
.X
- aWindowBox
.Width
/2.0);
346 catch (RuntimeException
&)
353 PresenterSlideSorter::~PresenterSlideSorter()
357 void SAL_CALL
PresenterSlideSorter::disposing()
359 mxComponentContext
= nullptr;
363 if (mpVerticalScrollBar
.is())
365 Reference
<lang::XComponent
> xComponent (
366 static_cast<XWeak
*>(mpVerticalScrollBar
.get()), UNO_QUERY
);
367 mpVerticalScrollBar
= nullptr;
369 xComponent
->dispose();
371 if (mpCloseButton
.is())
373 Reference
<lang::XComponent
> xComponent (
374 static_cast<XWeak
*>(mpCloseButton
.get()), UNO_QUERY
);
375 mpCloseButton
= nullptr;
377 xComponent
->dispose();
382 Reference
<lang::XComponent
> xComponent (mxCanvas
, UNO_QUERY
);
384 xComponent
->removeEventListener(static_cast<awt::XWindowListener
*>(this));
387 mpPresenterController
= nullptr;
388 mxSlideShowController
= nullptr;
390 mpMouseOverManager
.reset();
392 if (mxPreviewCache
.is())
394 mxPreviewCache
->removePreviewCreationNotifyListener(this);
396 Reference
<XComponent
> xComponent (mxPreviewCache
, UNO_QUERY
);
397 mxPreviewCache
= nullptr;
399 xComponent
->dispose();
404 mxWindow
->removeWindowListener(this);
405 mxWindow
->removePaintListener(this);
406 mxWindow
->removeMouseListener(this);
407 mxWindow
->removeMouseMotionListener(this);
411 //----- lang::XEventListener --------------------------------------------------
413 void SAL_CALL
PresenterSlideSorter::disposing (const lang::EventObject
& rEventObject
)
415 if (rEventObject
.Source
== mxWindow
)
420 else if (rEventObject
.Source
== mxPreviewCache
)
422 mxPreviewCache
= nullptr;
425 else if (rEventObject
.Source
== mxCanvas
)
428 mbIsLayoutPending
= true;
430 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
434 //----- XWindowListener -------------------------------------------------------
436 void SAL_CALL
PresenterSlideSorter::windowResized (const awt::WindowEvent
&)
439 mbIsLayoutPending
= true;
440 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
443 void SAL_CALL
PresenterSlideSorter::windowMoved (const awt::WindowEvent
&)
448 void SAL_CALL
PresenterSlideSorter::windowShown (const lang::EventObject
&)
451 mbIsLayoutPending
= true;
452 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
455 void SAL_CALL
PresenterSlideSorter::windowHidden (const lang::EventObject
&)
460 //----- XPaintListener --------------------------------------------------------
462 void SAL_CALL
PresenterSlideSorter::windowPaint (const css::awt::PaintEvent
& rEvent
)
464 // Deactivated views must not be painted.
465 if ( ! mbIsPresenterViewActive
)
468 Paint(rEvent
.UpdateRect
);
470 Reference
<rendering::XSpriteCanvas
> xSpriteCanvas (mxCanvas
, UNO_QUERY
);
471 if (xSpriteCanvas
.is())
472 xSpriteCanvas
->updateScreen(false);
475 //----- XMouseListener --------------------------------------------------------
477 void SAL_CALL
PresenterSlideSorter::mousePressed (const css::awt::MouseEvent
& rEvent
)
479 css::awt::MouseEvent rTemp
=rEvent
;
480 /// check whether RTL interface or not
481 if(AllSettings::GetLayoutRTL()){
482 awt::Rectangle aBox
= mxWindow
->getPosSize();
483 rTemp
.X
=aBox
.Width
-rEvent
.X
;
485 const geometry::RealPoint2D
aPosition(rTemp
.X
, rEvent
.Y
);
486 mnSlideIndexMousePressed
= mpLayout
->GetSlideIndexForPosition(aPosition
);
489 void SAL_CALL
PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent
& rEvent
)
491 css::awt::MouseEvent rTemp
=rEvent
;
492 /// check whether RTL interface or not
493 if(AllSettings::GetLayoutRTL()){
494 awt::Rectangle aBox
= mxWindow
->getPosSize();
495 rTemp
.X
=aBox
.Width
-rEvent
.X
;
497 const geometry::RealPoint2D
aPosition(rTemp
.X
, rEvent
.Y
);
498 const sal_Int32
nSlideIndex (mpLayout
->GetSlideIndexForPosition(aPosition
));
500 if (nSlideIndex
!= mnSlideIndexMousePressed
|| mnSlideIndexMousePressed
< 0)
503 switch (rEvent
.ClickCount
)
507 GotoSlide(nSlideIndex
);
511 OSL_ASSERT(mpPresenterController
);
512 OSL_ASSERT(mpPresenterController
->GetWindowManager());
513 mpPresenterController
->GetWindowManager()->SetSlideSorterState(false);
514 GotoSlide(nSlideIndex
);
519 void SAL_CALL
PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent
&) {}
521 void SAL_CALL
PresenterSlideSorter::mouseExited (const css::awt::MouseEvent
&)
523 mnSlideIndexMousePressed
= -1;
524 if (mpMouseOverManager
!= nullptr)
525 mpMouseOverManager
->SetSlide(mnSlideIndexMousePressed
, awt::Rectangle(0,0,0,0));
528 //----- XMouseMotionListener --------------------------------------------------
530 void SAL_CALL
PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent
& rEvent
)
532 if (mpMouseOverManager
== nullptr)
535 css::awt::MouseEvent rTemp
=rEvent
;
536 /// check whether RTL interface or not
537 if(AllSettings::GetLayoutRTL()){
538 awt::Rectangle aBox
= mxWindow
->getPosSize();
539 rTemp
.X
=aBox
.Width
-rEvent
.X
;
541 const geometry::RealPoint2D
aPosition(rTemp
.X
, rEvent
.Y
);
542 sal_Int32
nSlideIndex (mpLayout
->GetSlideIndexForPosition(aPosition
));
546 mnSlideIndexMousePressed
= -1;
547 mpMouseOverManager
->SetSlide(nSlideIndex
, awt::Rectangle(0,0,0,0));
551 mpMouseOverManager
->SetSlide(
553 mpLayout
->GetBoundingBox(nSlideIndex
));
557 void SAL_CALL
PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent
&) {}
559 //----- XResourceId -----------------------------------------------------------
561 Reference
<XResourceId
> SAL_CALL
PresenterSlideSorter::getResourceId()
567 sal_Bool SAL_CALL
PresenterSlideSorter::isAnchorOnly()
572 //----- XPropertyChangeListener -----------------------------------------------
574 void SAL_CALL
PresenterSlideSorter::propertyChange (
575 const css::beans::PropertyChangeEvent
&)
578 //----- XSlidePreviewCacheListener --------------------------------------------
580 void SAL_CALL
PresenterSlideSorter::notifyPreviewCreation (
581 sal_Int32 nSlideIndex
)
583 OSL_ASSERT(mpLayout
!= nullptr);
585 awt::Rectangle
aBBox (mpLayout
->GetBoundingBox(nSlideIndex
));
586 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
, aBBox
, true);
589 //----- XDrawView -------------------------------------------------------------
591 void SAL_CALL
PresenterSlideSorter::setCurrentPage (const Reference
<drawing::XDrawPage
>&)
594 ::osl::MutexGuard
aGuard (::osl::Mutex::getGlobalMutex());
596 if (!mxSlideShowController
.is())
599 const sal_Int32
nNewCurrentSlideIndex (mxSlideShowController
->getCurrentSlideIndex());
600 if (nNewCurrentSlideIndex
== mnCurrentSlideIndex
)
603 mnCurrentSlideIndex
= nNewCurrentSlideIndex
;
605 // Request a repaint of the previous current slide to hide its
606 // current slide indicator.
607 mpPresenterController
->GetPaintManager()->Invalidate(
609 maCurrentSlideFrameBoundingBox
);
611 // Request a repaint of the new current slide to show its
612 // current slide indicator.
613 maCurrentSlideFrameBoundingBox
= mpCurrentSlideFrameRenderer
->GetBoundingBox(
614 mpLayout
->GetBoundingBox(mnCurrentSlideIndex
));
615 mpPresenterController
->GetPaintManager()->Invalidate(
617 maCurrentSlideFrameBoundingBox
);
620 Reference
<drawing::XDrawPage
> SAL_CALL
PresenterSlideSorter::getCurrentPage()
627 void PresenterSlideSorter::UpdateLayout()
629 if ( ! mxWindow
.is())
632 mbIsLayoutPending
= false;
634 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
635 sal_Int32
nLeftBorderWidth (aWindowBox
.X
);
638 PresenterPaneContainer::SharedPaneDescriptor
pPane (
639 mpPresenterController
->GetPaneContainer()->FindViewURL(
640 mxViewId
->getResourceURL()));
645 if ( ! pPane
->mxPane
.is())
648 Reference
<drawing::framework::XPaneBorderPainter
> xBorderPainter (
649 pPane
->mxPane
->GetPaneBorderPainter());
650 if ( ! xBorderPainter
.is())
652 xBorderPainter
->addBorder (
653 mxViewId
->getAnchor()->getResourceURL(),
654 awt::Rectangle(0, 0, aWindowBox
.Width
, aWindowBox
.Height
),
655 drawing::framework::BorderType_INNER_BORDER
);
659 // Place vertical separator.
660 mnSeparatorY
= aWindowBox
.Height
- mpCloseButton
->GetSize().Height
- gnVerticalButtonPadding
;
662 PlaceCloseButton(pPane
, aWindowBox
, nLeftBorderWidth
);
664 geometry::RealRectangle2D
aUpperBox(
667 aWindowBox
.Width
- 2*gnHorizontalBorder
,
668 mnSeparatorY
- gnVerticalGap
);
670 // Determine whether the scroll bar has to be displayed.
671 aUpperBox
= PlaceScrollBars(aUpperBox
);
673 mpLayout
->Update(aUpperBox
, GetSlideAspectRatio());
674 mpLayout
->SetupVisibleArea();
675 mpLayout
->UpdateScrollBars();
677 // Tell the preview cache about some of the values.
678 mxPreviewCache
->setPreviewSize(mpLayout
->maPreviewSize
);
679 mxPreviewCache
->setVisibleRange(
680 mpLayout
->GetFirstVisibleSlideIndex(),
681 mpLayout
->GetLastVisibleSlideIndex());
683 // Clear the frame polygon so that it is re-created on the next paint.
684 mxPreviewFrame
= nullptr;
687 geometry::RealRectangle2D
PresenterSlideSorter::PlaceScrollBars (
688 const geometry::RealRectangle2D
& rUpperBox
)
690 mpLayout
->Update(rUpperBox
, GetSlideAspectRatio());
691 bool bIsScrollBarNeeded (false);
692 Reference
<container::XIndexAccess
> xSlides (mxSlideShowController
, UNO_QUERY_THROW
);
693 bIsScrollBarNeeded
= mpLayout
->IsScrollBarNeeded(xSlides
->getCount());
694 if (mpVerticalScrollBar
)
696 if (bIsScrollBarNeeded
)
698 if(AllSettings::GetLayoutRTL())
700 mpVerticalScrollBar
->SetPosSize(geometry::RealRectangle2D(
703 rUpperBox
.X1
+ mpVerticalScrollBar
->GetSize(),
705 mpVerticalScrollBar
->SetVisible(true);
706 // Reduce area covered by the scroll bar from the available
708 return geometry::RealRectangle2D(
709 rUpperBox
.X1
+ gnHorizontalGap
+ mpVerticalScrollBar
->GetSize(),
716 // if it's not RTL place vertical scroll bar at right border.
717 mpVerticalScrollBar
->SetPosSize(geometry::RealRectangle2D(
718 rUpperBox
.X2
- mpVerticalScrollBar
->GetSize(),
722 mpVerticalScrollBar
->SetVisible(true);
723 // Reduce area covered by the scroll bar from the available
725 return geometry::RealRectangle2D(
728 rUpperBox
.X2
- mpVerticalScrollBar
->GetSize() - gnHorizontalGap
,
733 mpVerticalScrollBar
->SetVisible(false);
738 void PresenterSlideSorter::PlaceCloseButton (
739 const PresenterPaneContainer::SharedPaneDescriptor
& rpPane
,
740 const awt::Rectangle
& rCenterBox
,
741 const sal_Int32 nLeftBorderWidth
)
743 // Place button. When the callout is near the center then the button is
744 // centered over the callout. Otherwise it is centered with respect to
746 sal_Int32
nCloseButtonCenter (rCenterBox
.Width
/2);
747 if (rpPane
&& rpPane
->mxPane
.is())
749 const sal_Int32
nCalloutCenter (-nLeftBorderWidth
);
750 const sal_Int32
nDistanceFromWindowCenter (abs(nCalloutCenter
- rCenterBox
.Width
/2));
751 const sal_Int32
nButtonWidth (mpCloseButton
->GetSize().Width
);
752 const static sal_Int32
nMaxDistanceForCalloutCentering (nButtonWidth
* 2);
753 if (nDistanceFromWindowCenter
< nMaxDistanceForCalloutCentering
)
755 if (nCalloutCenter
< nButtonWidth
/2)
756 nCloseButtonCenter
= nButtonWidth
/2;
757 else if (nCalloutCenter
> rCenterBox
.Width
-nButtonWidth
/2)
758 nCloseButtonCenter
= rCenterBox
.Width
-nButtonWidth
/2;
760 nCloseButtonCenter
= nCalloutCenter
;
763 mpCloseButton
->SetCenter(geometry::RealPoint2D(
765 rCenterBox
.Height
- mpCloseButton
->GetSize().Height
/ 2));
768 void PresenterSlideSorter::ClearBackground (
769 const Reference
<rendering::XCanvas
>& rxCanvas
,
770 const awt::Rectangle
& rUpdateBox
)
772 OSL_ASSERT(rxCanvas
.is());
774 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
775 mpPresenterController
->GetCanvasHelper()->Paint(
776 mpPresenterController
->GetViewBackground(mxViewId
->getResourceURL()),
779 awt::Rectangle(0,0,aWindowBox
.Width
,aWindowBox
.Height
),
783 double PresenterSlideSorter::GetSlideAspectRatio() const
785 double nSlideAspectRatio (28.0/21.0);
789 Reference
<container::XIndexAccess
> xSlides(mxSlideShowController
, UNO_QUERY_THROW
);
790 if (mxSlideShowController
.is() && xSlides
->getCount()>0)
792 Reference
<beans::XPropertySet
> xProperties(xSlides
->getByIndex(0),UNO_QUERY_THROW
);
793 sal_Int32
nWidth (28000);
794 sal_Int32
nHeight (21000);
795 if ((xProperties
->getPropertyValue("Width") >>= nWidth
)
796 && (xProperties
->getPropertyValue("Height") >>= nHeight
)
799 nSlideAspectRatio
= double(nWidth
) / double(nHeight
);
803 catch (RuntimeException
&)
808 return nSlideAspectRatio
;
811 Reference
<rendering::XBitmap
> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex
)
813 if (nSlideIndex
< 0 || nSlideIndex
>=mpLayout
->mnSlideCount
)
815 else if (mxPane
.is())
816 return mxPreviewCache
->getSlidePreview(nSlideIndex
, mxPane
->getCanvas());
821 void PresenterSlideSorter::PaintPreview (
822 const Reference
<rendering::XCanvas
>& rxCanvas
,
823 const css::awt::Rectangle
& rUpdateBox
,
824 const sal_Int32 nSlideIndex
)
826 OSL_ASSERT(rxCanvas
.is());
828 geometry::IntegerSize2D
aSize (mpLayout
->maPreviewSize
);
830 if (PresenterGeometryHelper::AreRectanglesDisjoint(
832 mpLayout
->GetBoundingBox(nSlideIndex
)))
837 Reference
<rendering::XBitmap
> xPreview (GetPreview(nSlideIndex
));
838 bool isRTL
= AllSettings::GetLayoutRTL();
840 const geometry::RealPoint2D
aTopLeft (
841 mpLayout
->GetWindowPosition(
842 mpLayout
->GetPoint(nSlideIndex
, isRTL
?1:-1, -1)));
844 PresenterBitmapContainer
aContainer (
845 "PresenterScreenSettings/ScrollBar/Bitmaps",
846 std::shared_ptr
<PresenterBitmapContainer
>(),
849 Reference
<container::XIndexAccess
> xIndexAccess(mxSlideShowController
, UNO_QUERY
);
850 Reference
<drawing::XDrawPage
> xPage( xIndexAccess
->getByIndex(nSlideIndex
), UNO_QUERY
);
851 bool bTransition
= PresenterController::HasTransition(xPage
);
852 bool bCustomAnimation
= PresenterController::HasCustomAnimation(xPage
);
854 // Create clip rectangle as intersection of the current update area and
855 // the bounding box of all previews.
856 geometry::RealRectangle2D
aBoundingBox (mpLayout
->maBoundingBox
);
857 aBoundingBox
.Y2
+= 1;
858 const geometry::RealRectangle2D
aClipBox (
859 PresenterGeometryHelper::Intersection(
860 PresenterGeometryHelper::ConvertRectangle(rUpdateBox
),
862 Reference
<rendering::XPolyPolygon2D
> xClip (
863 PresenterGeometryHelper::CreatePolygon(aClipBox
, rxCanvas
->getDevice()));
865 const rendering::ViewState
aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip
);
867 rendering::RenderState
aRenderState (
868 geometry::AffineMatrix2D(
873 rendering::CompositeOperation::SOURCE
);
875 // Emphasize the current slide.
876 if (nSlideIndex
== mnCurrentSlideIndex
)
878 if (mpCurrentSlideFrameRenderer
!= nullptr)
880 const awt::Rectangle
aSlideBoundingBox(
881 sal::static_int_cast
<sal_Int32
>(0.5 + aTopLeft
.X
),
882 sal::static_int_cast
<sal_Int32
>(0.5 + aTopLeft
.Y
),
885 maCurrentSlideFrameBoundingBox
886 = mpCurrentSlideFrameRenderer
->GetBoundingBox(aSlideBoundingBox
);
887 mpCurrentSlideFrameRenderer
->PaintCurrentSlideFrame (
894 // Paint the preview.
897 aSize
= xPreview
->getSize();
898 if (aSize
.Width
> 0 && aSize
.Height
> 0)
900 rxCanvas
->drawBitmap(xPreview
, aViewState
, aRenderState
);
901 if( bCustomAnimation
)
903 const awt::Rectangle
aAnimationPreviewBox(aTopLeft
.X
+3, aTopLeft
.Y
+aSize
.Height
-40, 0, 0);
904 SharedBitmapDescriptor aAnimationDescriptor
= aContainer
.GetBitmap("Animation");
905 Reference
<rendering::XBitmap
> xAnimationIcon (aAnimationDescriptor
->GetNormalBitmap());
906 rendering::RenderState
aAnimationRenderState (
907 geometry::AffineMatrix2D(
908 1, 0, aAnimationPreviewBox
.X
,
909 0, 1, aAnimationPreviewBox
.Y
),
912 rendering::CompositeOperation::SOURCE
);
913 rxCanvas
->drawBitmap(xAnimationIcon
, aViewState
, aAnimationRenderState
);
917 const awt::Rectangle
aTransitionPreviewBox(aTopLeft
.X
+3, aTopLeft
.Y
+aSize
.Height
-20, 0, 0);
918 SharedBitmapDescriptor aTransitionDescriptor
= aContainer
.GetBitmap("Transition");
919 Reference
<rendering::XBitmap
> xTransitionIcon (aTransitionDescriptor
->GetNormalBitmap());
920 rendering::RenderState
aTransitionRenderState (
921 geometry::AffineMatrix2D(
922 1, 0, aTransitionPreviewBox
.X
,
923 0, 1, aTransitionPreviewBox
.Y
),
926 rendering::CompositeOperation::SOURCE
);
927 rxCanvas
->drawBitmap(xTransitionIcon
, aViewState
, aTransitionRenderState
);
932 // Create a polygon that is used to paint a frame around previews. Its
933 // coordinates are chosen in the local coordinate system of a preview.
934 if ( ! mxPreviewFrame
.is())
935 mxPreviewFrame
= PresenterGeometryHelper::CreatePolygon(
936 awt::Rectangle(-1, -1, aSize
.Width
+2, aSize
.Height
+2),
937 rxCanvas
->getDevice());
939 // Paint a border around the preview.
940 if (mxPreviewFrame
.is())
942 const util::Color
aFrameColor (0x00000000);
943 PresenterCanvasHelper::SetDeviceColor(aRenderState
, aFrameColor
);
944 rxCanvas
->drawPolyPolygon(mxPreviewFrame
, aViewState
, aRenderState
);
947 // Paint mouse over effect.
948 mpMouseOverManager
->Paint(nSlideIndex
, mxCanvas
, xClip
);
951 void PresenterSlideSorter::Paint (const awt::Rectangle
& rUpdateBox
)
953 const bool bCanvasChanged ( ! mxCanvas
.is());
954 if ( ! ProvideCanvas())
957 if (mpLayout
->mnRowCount
<=0 || mpLayout
->mnColumnCount
<=0)
959 OSL_ASSERT(mpLayout
->mnRowCount
>0 || mpLayout
->mnColumnCount
>0);
963 ClearBackground(mxCanvas
, rUpdateBox
);
965 // Give the canvas to the controls.
968 if (mpVerticalScrollBar
.is())
969 mpVerticalScrollBar
->SetCanvas(mxCanvas
);
970 if (mpCloseButton
.is())
971 mpCloseButton
->SetCanvas(mxCanvas
, mxWindow
);
974 // Now that the controls have a canvas we can do the layouting.
975 if (mbIsLayoutPending
)
978 // Paint the horizontal separator.
979 rendering::RenderState
aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0),
980 nullptr, Sequence
<double>(4), rendering::CompositeOperation::SOURCE
);
981 PresenterCanvasHelper::SetDeviceColor(aRenderState
, maSeparatorColor
);
983 geometry::RealPoint2D(0, mnSeparatorY
),
984 geometry::RealPoint2D(mxWindow
->getPosSize().Width
, mnSeparatorY
),
985 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
989 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
991 PresenterGeometryHelper::ConvertRectangle(mpLayout
->maBoundingBox
)))
993 mpLayout
->ForAllVisibleSlides(
994 [this, &rUpdateBox
] (sal_Int32
const nIndex
) {
995 return this->PaintPreview(this->mxCanvas
, rUpdateBox
, nIndex
);
999 Reference
<rendering::XSpriteCanvas
> xSpriteCanvas (mxCanvas
, UNO_QUERY
);
1000 if (xSpriteCanvas
.is())
1001 xSpriteCanvas
->updateScreen(false);
1004 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset
)
1006 if (mpLayout
->SetHorizontalOffset(nXOffset
))
1008 mxPreviewCache
->setVisibleRange(
1009 mpLayout
->GetFirstVisibleSlideIndex(),
1010 mpLayout
->GetLastVisibleSlideIndex());
1012 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
1016 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset
)
1018 if (mpLayout
->SetVerticalOffset(nYOffset
))
1020 mxPreviewCache
->setVisibleRange(
1021 mpLayout
->GetFirstVisibleSlideIndex(),
1022 mpLayout
->GetLastVisibleSlideIndex());
1024 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
1028 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex
)
1030 mxSlideShowController
->gotoSlideIndex(nSlideIndex
);
1033 bool PresenterSlideSorter::ProvideCanvas()
1035 if ( ! mxCanvas
.is())
1038 mxCanvas
= mxPane
->getCanvas();
1040 // Register as event listener so that we are informed when the
1041 // canvas is disposed (and we have to fetch another one).
1042 Reference
<lang::XComponent
> xComponent (mxCanvas
, UNO_QUERY
);
1043 if (xComponent
.is())
1044 xComponent
->addEventListener(static_cast<awt::XWindowListener
*>(this));
1046 mpCurrentSlideFrameRenderer
=
1047 std::make_shared
<CurrentSlideFrameRenderer
>(mxComponentContext
, mxCanvas
);
1049 return mxCanvas
.is();
1052 void PresenterSlideSorter::ThrowIfDisposed()
1054 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
1056 throw lang::DisposedException (
1057 "PresenterSlideSorter has been already disposed",
1058 static_cast<uno::XWeak
*>(this));
1062 //===== PresenterSlideSorter::Layout ==========================================
1064 PresenterSlideSorter::Layout::Layout (
1065 const ::rtl::Reference
<PresenterScrollBar
>& rpVerticalScrollBar
)
1068 mnHorizontalOffset(0),
1069 mnVerticalOffset(0),
1072 mnHorizontalBorder(0),
1073 mnVerticalBorder(0),
1077 mnFirstVisibleColumn(-1),
1078 mnLastVisibleColumn(-1),
1079 mnFirstVisibleRow(-1),
1080 mnLastVisibleRow(-1),
1081 mpVerticalScrollBar(rpVerticalScrollBar
)
1085 void PresenterSlideSorter::Layout::Update (
1086 const geometry::RealRectangle2D
& rBoundingBox
,
1087 const double nSlideAspectRatio
)
1089 maBoundingBox
= rBoundingBox
;
1091 mnHorizontalBorder
= gnHorizontalBorder
;
1092 mnVerticalBorder
= gnVerticalBorder
;
1094 const double nWidth (rBoundingBox
.X2
- rBoundingBox
.X1
- 2*mnHorizontalBorder
);
1095 const double nHeight (rBoundingBox
.Y2
- rBoundingBox
.Y1
- 2*mnVerticalBorder
);
1096 if (nWidth
<=0 || nHeight
<=0)
1099 double nPreviewWidth
;
1101 // Determine column count, preview width, and horizontal gap (borders
1102 // are half the gap). Try to use the preferred values. Try more to
1103 // stay in the valid intervals. This last constraint may be not
1104 // fulfilled in some cases.
1105 const double nElementWidth
= nWidth
/ gnPreferredColumnCount
;
1106 if (nElementWidth
< gnMinimalPreviewWidth
+ gnMinimalHorizontalPreviewGap
)
1108 // The preferred column count is too large.
1109 // Can we use the preferred preview width?
1110 if (nWidth
- gnMinimalHorizontalPreviewGap
>= gnPreferredPreviewWidth
)
1113 nPreviewWidth
= gnPreferredPreviewWidth
;
1114 mnColumnCount
= floor((nWidth
+gnPreferredHorizontalPreviewGap
)
1115 / (nPreviewWidth
+gnPreferredHorizontalPreviewGap
));
1116 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1120 // No. Set the column count to 1 and adapt preview width and
1123 mnHorizontalGap
= floor(gnMinimalHorizontalPreviewGap
);
1124 if (nWidth
- gnMinimalHorizontalPreviewGap
>= gnPreferredPreviewWidth
)
1125 nPreviewWidth
= nWidth
- gnMinimalHorizontalPreviewGap
;
1127 nPreviewWidth
= ::std::max(gnMinimalPreviewWidth
, nWidth
-mnHorizontalGap
);
1130 else if (nElementWidth
> gnMaximalPreviewWidth
+ gnMaximalHorizontalPreviewGap
)
1132 // The preferred column count is too small.
1133 nPreviewWidth
= gnPreferredPreviewWidth
;
1134 mnColumnCount
= floor((nWidth
+gnPreferredHorizontalPreviewGap
)
1135 / (nPreviewWidth
+gnPreferredHorizontalPreviewGap
));
1136 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1140 // The preferred column count is possible. Determine gap and
1142 mnColumnCount
= gnPreferredColumnCount
;
1143 if (nElementWidth
- gnPreferredPreviewWidth
< gnMinimalHorizontalPreviewGap
)
1145 // Use the minimal gap and adapt the preview width.
1146 mnHorizontalGap
= floor(gnMinimalHorizontalPreviewGap
);
1147 nPreviewWidth
= (nWidth
- mnColumnCount
*mnHorizontalGap
) / mnColumnCount
;
1149 else if (nElementWidth
- gnPreferredPreviewWidth
<= gnMaximalHorizontalPreviewGap
)
1151 // Use the maximal gap and adapt the preview width.
1152 mnHorizontalGap
= round(gnMaximalHorizontalPreviewGap
);
1153 nPreviewWidth
= (nWidth
- mnColumnCount
*mnHorizontalGap
) / mnColumnCount
;
1157 // Use the preferred preview width and adapt the gap.
1158 nPreviewWidth
= gnPreferredPreviewWidth
;
1159 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1163 // Now determine the row count, preview height, and vertical gap.
1164 const double nPreviewHeight
= nPreviewWidth
/ nSlideAspectRatio
;
1165 mnRowCount
= ::std::max(
1167 sal_Int32(ceil((nHeight
+gnPreferredVerticalPreviewGap
)
1168 / (nPreviewHeight
+ gnPreferredVerticalPreviewGap
))));
1169 mnVerticalGap
= round(gnPreferredVerticalPreviewGap
);
1171 maPreviewSize
= geometry::IntegerSize2D(floor(nPreviewWidth
), floor(nPreviewHeight
));
1173 // Reset the offset.
1174 mnVerticalOffset
= 0;
1175 mnHorizontalOffset
= round(-(nWidth
1176 - mnColumnCount
*maPreviewSize
.Width
1177 - (mnColumnCount
-1)*mnHorizontalGap
)
1181 void PresenterSlideSorter::Layout::SetupVisibleArea()
1183 geometry::RealPoint2D
aPoint (GetLocalPosition(
1184 geometry::RealPoint2D(maBoundingBox
.X1
, maBoundingBox
.Y1
)));
1185 mnFirstVisibleColumn
= 0;
1186 mnFirstVisibleRow
= ::std::max(sal_Int32(0), GetRow(aPoint
));
1188 aPoint
= GetLocalPosition(geometry::RealPoint2D( maBoundingBox
.X2
, maBoundingBox
.Y2
));
1189 mnLastVisibleColumn
= mnColumnCount
- 1;
1190 mnLastVisibleRow
= GetRow(aPoint
, true);
1193 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount
)
1195 geometry::RealPoint2D aBottomRight
= GetPoint(
1196 mnColumnCount
* (GetRow(nSlideCount
)+1) - 1, +1, +1);
1197 return aBottomRight
.X
> maBoundingBox
.X2
-maBoundingBox
.X1
1198 || aBottomRight
.Y
> maBoundingBox
.Y2
-maBoundingBox
.Y1
;
1201 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetLocalPosition(
1202 const geometry::RealPoint2D
& rWindowPoint
) const
1204 if(AllSettings::GetLayoutRTL())
1206 return css::geometry::RealPoint2D(
1207 -rWindowPoint
.X
+ maBoundingBox
.X2
+ mnHorizontalOffset
,
1208 rWindowPoint
.Y
- maBoundingBox
.Y1
+ mnVerticalOffset
);
1212 return css::geometry::RealPoint2D(
1213 rWindowPoint
.X
- maBoundingBox
.X1
+ mnHorizontalOffset
,
1214 rWindowPoint
.Y
- maBoundingBox
.Y1
+ mnVerticalOffset
);
1218 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetWindowPosition(
1219 const geometry::RealPoint2D
& rLocalPoint
) const
1221 if(AllSettings::GetLayoutRTL())
1223 return css::geometry::RealPoint2D(
1224 -rLocalPoint
.X
+ mnHorizontalOffset
+ maBoundingBox
.X2
,
1225 rLocalPoint
.Y
- mnVerticalOffset
+ maBoundingBox
.Y1
);
1229 return css::geometry::RealPoint2D(
1230 rLocalPoint
.X
- mnHorizontalOffset
+ maBoundingBox
.X1
,
1231 rLocalPoint
.Y
- mnVerticalOffset
+ maBoundingBox
.Y1
);
1235 sal_Int32
PresenterSlideSorter::Layout::GetColumn (
1236 const css::geometry::RealPoint2D
& rLocalPoint
) const
1238 const sal_Int32
nColumn(floor(
1239 (rLocalPoint
.X
+ mnHorizontalGap
/2.0) / (maPreviewSize
.Width
+mnHorizontalGap
)));
1240 if (nColumn
>=mnFirstVisibleColumn
&& nColumn
<=mnLastVisibleColumn
)
1248 sal_Int32
PresenterSlideSorter::Layout::GetRow (
1249 const css::geometry::RealPoint2D
& rLocalPoint
,
1250 const bool bReturnInvalidValue
) const
1252 const sal_Int32
nRow (floor(
1253 (rLocalPoint
.Y
+ mnVerticalGap
/2.0) / (maPreviewSize
.Height
+mnVerticalGap
)));
1254 if (bReturnInvalidValue
1255 || (nRow
>=mnFirstVisibleRow
&& nRow
<=mnLastVisibleRow
))
1263 sal_Int32
PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1264 const css::geometry::RealPoint2D
& rWindowPoint
) const
1266 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox
, rWindowPoint
))
1269 const css::geometry::RealPoint2D
aLocalPosition (GetLocalPosition(rWindowPoint
));
1270 const sal_Int32
nColumn (GetColumn(aLocalPosition
));
1271 const sal_Int32
nRow (GetRow(aLocalPosition
));
1273 if (nColumn
< 0 || nRow
< 0)
1277 sal_Int32
nIndex (GetIndex(nRow
, nColumn
));
1278 if (nIndex
>= mnSlideCount
)
1285 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetPoint (
1286 const sal_Int32 nSlideIndex
,
1287 const sal_Int32 nRelativeHorizontalPosition
,
1288 const sal_Int32 nRelativeVerticalPosition
) const
1290 sal_Int32
nColumn (GetColumn(nSlideIndex
));
1291 sal_Int32
nRow (GetRow(nSlideIndex
));
1293 geometry::RealPoint2D
aPosition (
1294 mnHorizontalBorder
+ nColumn
*(maPreviewSize
.Width
+mnHorizontalGap
),
1295 mnVerticalBorder
+ nRow
*(maPreviewSize
.Height
+mnVerticalGap
));
1297 if (nRelativeHorizontalPosition
>= 0)
1299 if (nRelativeHorizontalPosition
> 0)
1300 aPosition
.X
+= maPreviewSize
.Width
;
1302 aPosition
.X
+= maPreviewSize
.Width
/ 2.0;
1304 if (nRelativeVerticalPosition
>= 0)
1306 if (nRelativeVerticalPosition
> 0)
1307 aPosition
.Y
+= maPreviewSize
.Height
;
1309 aPosition
.Y
+= maPreviewSize
.Height
/ 2.0;
1315 awt::Rectangle
PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex
) const
1317 bool isRTL
= AllSettings::GetLayoutRTL();
1318 const geometry::RealPoint2D
aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex
, isRTL
?1:-1, -1)));
1319 return PresenterGeometryHelper::ConvertRectangle(
1320 geometry::RealRectangle2D(
1323 aWindowPosition
.X
+ maPreviewSize
.Width
,
1324 aWindowPosition
.Y
+ maPreviewSize
.Height
));
1327 void PresenterSlideSorter::Layout::ForAllVisibleSlides(
1328 const ::std::function
<void (sal_Int32
)>& rAction
)
1330 for (sal_Int32 nRow
=mnFirstVisibleRow
; nRow
<=mnLastVisibleRow
; ++nRow
)
1332 for (sal_Int32 nColumn
=mnFirstVisibleColumn
; nColumn
<=mnLastVisibleColumn
; ++nColumn
)
1334 const sal_Int32
nSlideIndex (GetIndex(nRow
, nColumn
));
1335 if (nSlideIndex
>= mnSlideCount
)
1337 rAction(nSlideIndex
);
1342 sal_Int32
PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex() const
1344 return GetIndex(mnFirstVisibleRow
, mnFirstVisibleColumn
);
1347 sal_Int32
PresenterSlideSorter::Layout::GetLastVisibleSlideIndex() const
1350 GetIndex(mnLastVisibleRow
, mnLastVisibleColumn
),
1354 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset
)
1356 if (mnHorizontalOffset
!= nOffset
)
1358 mnHorizontalOffset
= round(nOffset
);
1367 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset
)
1369 if (mnVerticalOffset
!= nOffset
)
1371 mnVerticalOffset
= round(nOffset
);
1380 void PresenterSlideSorter::Layout::UpdateScrollBars()
1382 sal_Int32 nTotalRowCount
= sal_Int32(ceil(double(mnSlideCount
) / double(mnColumnCount
)));
1384 if (mpVerticalScrollBar
)
1386 mpVerticalScrollBar
->SetTotalSize(
1387 nTotalRowCount
* maPreviewSize
.Height
1388 + (nTotalRowCount
-1) * mnVerticalGap
1390 mpVerticalScrollBar
->SetThumbPosition(mnVerticalOffset
, false);
1391 mpVerticalScrollBar
->SetThumbSize(maBoundingBox
.Y2
- maBoundingBox
.Y1
+ 1);
1392 mpVerticalScrollBar
->SetLineHeight(maPreviewSize
.Height
);
1395 // No place yet for the vertical scroll bar.
1398 sal_Int32
PresenterSlideSorter::Layout::GetIndex (
1399 const sal_Int32 nRow
,
1400 const sal_Int32 nColumn
) const
1402 return nRow
* mnColumnCount
+ nColumn
;
1405 sal_Int32
PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex
) const
1407 return nSlideIndex
/ mnColumnCount
;
1410 sal_Int32
PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex
) const
1412 return nSlideIndex
% mnColumnCount
;
1415 //===== PresenterSlideSorter::MouseOverManager ================================
1417 PresenterSlideSorter::MouseOverManager::MouseOverManager (
1418 const Reference
<container::XIndexAccess
>& rxSlides
,
1419 const std::shared_ptr
<PresenterTheme
>& rpTheme
,
1420 const Reference
<awt::XWindow
>& rxInvalidateTarget
,
1421 const std::shared_ptr
<PresenterPaintManager
>& rpPaintManager
)
1424 mpLeftLabelBitmap(),
1425 mpCenterLabelBitmap(),
1426 mpRightLabelBitmap(),
1429 maSlideBoundingBox(),
1430 mxInvalidateTarget(rxInvalidateTarget
),
1431 mpPaintManager(rpPaintManager
)
1433 if (rpTheme
!= nullptr)
1435 std::shared_ptr
<PresenterBitmapContainer
> pBitmaps (rpTheme
->GetBitmapContainer());
1436 if (pBitmaps
!= nullptr)
1438 mpLeftLabelBitmap
= pBitmaps
->GetBitmap("LabelLeft");
1439 mpCenterLabelBitmap
= pBitmaps
->GetBitmap("LabelCenter");
1440 mpRightLabelBitmap
= pBitmaps
->GetBitmap("LabelRight");
1443 mpFont
= rpTheme
->GetFont("SlideSorterLabelFont");
1447 void PresenterSlideSorter::MouseOverManager::Paint (
1448 const sal_Int32 nSlideIndex
,
1449 const Reference
<rendering::XCanvas
>& rxCanvas
,
1450 const Reference
<rendering::XPolyPolygon2D
>& rxClip
)
1452 if (nSlideIndex
!= mnSlideIndex
)
1455 if (mxCanvas
!= rxCanvas
)
1456 SetCanvas(rxCanvas
);
1457 if (rxCanvas
== nullptr)
1460 if ( ! mxBitmap
.is())
1461 mxBitmap
= CreateBitmap(msText
, maSlideBoundingBox
.Width
);
1465 geometry::IntegerSize2D
aSize (mxBitmap
->getSize());
1466 const double nXOffset (maSlideBoundingBox
.X
1467 + (maSlideBoundingBox
.Width
- aSize
.Width
) / 2.0);
1468 const double nYOffset (maSlideBoundingBox
.Y
1469 + (maSlideBoundingBox
.Height
- aSize
.Height
) / 2.0);
1470 rxCanvas
->drawBitmap(
1472 rendering::ViewState(
1473 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1475 rendering::RenderState(
1476 geometry::AffineMatrix2D(1,0,nXOffset
, 0,1,nYOffset
),
1478 Sequence
<double>(4),
1479 rendering::CompositeOperation::SOURCE
));
1482 void PresenterSlideSorter::MouseOverManager::SetCanvas (
1483 const Reference
<rendering::XCanvas
>& rxCanvas
)
1485 mxCanvas
= rxCanvas
;
1487 mpFont
->PrepareFont(mxCanvas
);
1490 void PresenterSlideSorter::MouseOverManager::SetSlide (
1491 const sal_Int32 nSlideIndex
,
1492 const awt::Rectangle
& rBox
)
1494 if (mnSlideIndex
== nSlideIndex
)
1500 maSlideBoundingBox
= rBox
;
1501 mnSlideIndex
= nSlideIndex
;
1503 if (nSlideIndex
>= 0)
1509 Reference
<beans::XPropertySet
> xSlideProperties(mxSlides
->getByIndex(nSlideIndex
), UNO_QUERY
);
1510 if (xSlideProperties
.is())
1511 xSlideProperties
->getPropertyValue("LinkDisplayName") >>= msText
;
1513 if (msText
.isEmpty())
1514 msText
= "Slide " + OUString::number(nSlideIndex
+ 1);
1526 Reference
<rendering::XBitmap
> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1527 const OUString
& rsText
,
1528 const sal_Int32 nMaximalWidth
) const
1530 if ( ! mxCanvas
.is())
1533 if (!mpFont
|| !mpFont
->mxFont
.is())
1536 // Long text has to be shortened.
1537 const OUString
sText (GetFittingText(rsText
, nMaximalWidth
1538 - 2*gnHorizontalLabelBorder
1539 - 2*gnHorizontalLabelPadding
));
1541 // Determine the size of the label. Its height is defined by the
1542 // bitmaps that are used to paints its background. The width is defined
1544 geometry::IntegerSize2D
aLabelSize (CalculateLabelSize(sText
));
1546 // Create a new bitmap that will contain the complete label.
1547 Reference
<rendering::XBitmap
> xBitmap (
1548 mxCanvas
->getDevice()->createCompatibleAlphaBitmap(aLabelSize
));
1550 if ( ! xBitmap
.is())
1553 Reference
<rendering::XBitmapCanvas
> xBitmapCanvas (xBitmap
, UNO_QUERY
);
1554 if ( ! xBitmapCanvas
.is())
1557 // Paint the background.
1558 PaintButtonBackground(xBitmapCanvas
, aLabelSize
);
1561 if (!sText
.isEmpty())
1564 const rendering::StringContext
aContext (sText
, 0, sText
.getLength());
1565 const Reference
<rendering::XTextLayout
> xLayout (mpFont
->mxFont
->createTextLayout(
1566 aContext
, rendering::TextDirection::WEAK_LEFT_TO_RIGHT
,0));
1567 const geometry::RealRectangle2D
aTextBBox (xLayout
->queryTextBounds());
1569 const double nXOffset
= (aLabelSize
.Width
- aTextBBox
.X2
+ aTextBBox
.X1
) / 2;
1570 const double nYOffset
= aLabelSize
.Height
1571 - (aLabelSize
.Height
- aTextBBox
.Y2
+ aTextBBox
.Y1
)/2 - aTextBBox
.Y2
;
1573 const rendering::ViewState
aViewState(
1574 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1577 rendering::RenderState
aRenderState (
1578 geometry::AffineMatrix2D(1,0,nXOffset
, 0,1,nYOffset
),
1580 Sequence
<double>(4),
1581 rendering::CompositeOperation::SOURCE
);
1582 PresenterCanvasHelper::SetDeviceColor(aRenderState
, mpFont
->mnColor
);
1584 xBitmapCanvas
->drawTextLayout (
1593 OUString
PresenterSlideSorter::MouseOverManager::GetFittingText (
1594 const OUString
& rsText
,
1595 const double nMaximalWidth
) const
1597 const double nTextWidth (
1598 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, rsText
).Width
);
1599 if (nTextWidth
> nMaximalWidth
)
1601 // Text is too wide. Shorten it by removing characters from the end
1602 // and replacing them by ellipses.
1604 // Guess a start value of the final string length.
1605 double nBestWidth (0);
1606 OUString sBestCandidate
;
1607 sal_Int32
nLength (round(rsText
.getLength() * nMaximalWidth
/ nTextWidth
));
1608 static const OUStringLiteral
sEllipses (u
"...");
1611 const OUString
sCandidate (rsText
.subView(0,nLength
) + sEllipses
);
1612 const double nWidth (
1613 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, sCandidate
).Width
);
1614 if (nWidth
> nMaximalWidth
)
1616 // Candidate still too wide, shorten it.
1621 else if (nWidth
< nMaximalWidth
)
1623 // Candidate short enough.
1624 if (nWidth
> nBestWidth
)
1626 // Best length so far.
1627 sBestCandidate
= sCandidate
;
1628 nBestWidth
= nWidth
;
1630 if (nLength
>= rsText
.getLength())
1638 // Candidate is exactly as long as it may be. Use it
1639 // without looking any further.
1640 sBestCandidate
= sCandidate
;
1644 return sBestCandidate
;
1650 geometry::IntegerSize2D
PresenterSlideSorter::MouseOverManager::CalculateLabelSize (
1651 const OUString
& rsText
) const
1653 // Height is specified by the label bitmaps.
1654 sal_Int32
nHeight (32);
1655 if (mpCenterLabelBitmap
)
1657 Reference
<rendering::XBitmap
> xBitmap (mpCenterLabelBitmap
->GetNormalBitmap());
1659 nHeight
= xBitmap
->getSize().Height
;
1662 // Width is specified by text width and maximal width.
1663 const geometry::RealSize2D
aTextSize (
1664 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, rsText
));
1666 const sal_Int32
nWidth (round(aTextSize
.Width
+ 2*gnHorizontalLabelPadding
));
1668 return geometry::IntegerSize2D(nWidth
, nHeight
);
1671 void PresenterSlideSorter::MouseOverManager::PaintButtonBackground (
1672 const Reference
<rendering::XCanvas
>& rxCanvas
,
1673 const geometry::IntegerSize2D
& rSize
) const
1675 // Get the bitmaps for painting the label background.
1676 Reference
<rendering::XBitmap
> xLeftLabelBitmap
;
1677 if (mpLeftLabelBitmap
)
1678 xLeftLabelBitmap
= mpLeftLabelBitmap
->GetNormalBitmap();
1680 Reference
<rendering::XBitmap
> xCenterLabelBitmap
;
1681 if (mpCenterLabelBitmap
)
1682 xCenterLabelBitmap
= mpCenterLabelBitmap
->GetNormalBitmap();
1684 Reference
<rendering::XBitmap
> xRightLabelBitmap
;
1685 if (mpRightLabelBitmap
)
1686 xRightLabelBitmap
= mpRightLabelBitmap
->GetNormalBitmap();
1688 PresenterUIPainter::PaintHorizontalBitmapComposite (
1690 awt::Rectangle(0,0, rSize
.Width
,rSize
.Height
),
1691 awt::Rectangle(0,0, rSize
.Width
,rSize
.Height
),
1697 void PresenterSlideSorter::MouseOverManager::Invalidate()
1699 if (mpPaintManager
!= nullptr)
1700 mpPaintManager
->Invalidate(mxInvalidateTarget
, maSlideBoundingBox
, true);
1703 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
1705 PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer (
1706 const css::uno::Reference
<css::uno::XComponentContext
>& rxContext
,
1707 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
)
1718 mnRightFrameSize(0),
1719 mnBottomFrameSize(0)
1721 PresenterConfigurationAccess
aConfiguration (
1723 "/org.openoffice.Office.PresenterScreen/",
1724 PresenterConfigurationAccess::READ_ONLY
);
1725 Reference
<container::XHierarchicalNameAccess
> xBitmaps (
1726 aConfiguration
.GetConfigurationNode(
1727 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1729 if ( ! xBitmaps
.is())
1732 PresenterBitmapContainer
aContainer (
1733 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1734 std::shared_ptr
<PresenterBitmapContainer
>(),
1738 mpTopLeft
= aContainer
.GetBitmap("TopLeft");
1739 mpTop
= aContainer
.GetBitmap("Top");
1740 mpTopRight
= aContainer
.GetBitmap("TopRight");
1741 mpLeft
= aContainer
.GetBitmap("Left");
1742 mpRight
= aContainer
.GetBitmap("Right");
1743 mpBottomLeft
= aContainer
.GetBitmap("BottomLeft");
1744 mpBottom
= aContainer
.GetBitmap("Bottom");
1745 mpBottomRight
= aContainer
.GetBitmap("BottomRight");
1747 // Determine size of frame.
1749 mnTopFrameSize
= mpTop
->mnHeight
;
1751 mnLeftFrameSize
= mpLeft
->mnWidth
;
1753 mnRightFrameSize
= mpRight
->mnWidth
;
1755 mnBottomFrameSize
= mpBottom
->mnHeight
;
1759 mnTopFrameSize
= ::std::max(mnTopFrameSize
, mpTopLeft
->mnHeight
);
1760 mnLeftFrameSize
= ::std::max(mnLeftFrameSize
, mpTopLeft
->mnWidth
);
1764 mnTopFrameSize
= ::std::max(mnTopFrameSize
, mpTopRight
->mnHeight
);
1765 mnRightFrameSize
= ::std::max(mnRightFrameSize
, mpTopRight
->mnWidth
);
1769 mnLeftFrameSize
= ::std::max(mnLeftFrameSize
, mpBottomLeft
->mnWidth
);
1770 mnBottomFrameSize
= ::std::max(mnBottomFrameSize
, mpBottomLeft
->mnHeight
);
1774 mnRightFrameSize
= ::std::max(mnRightFrameSize
, mpBottomRight
->mnWidth
);
1775 mnBottomFrameSize
= ::std::max(mnBottomFrameSize
, mpBottomRight
->mnHeight
);
1779 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame (
1780 const awt::Rectangle
& rSlideBoundingBox
,
1781 const Reference
<rendering::XCanvas
>& rxCanvas
,
1782 const geometry::RealRectangle2D
& rClipBox
)
1784 if ( ! rxCanvas
.is())
1787 const Reference
<rendering::XPolyPolygon2D
> xClip (
1788 PresenterGeometryHelper::CreatePolygon(rClipBox
, rxCanvas
->getDevice()));
1793 mpTop
->GetNormalBitmap(),
1796 rSlideBoundingBox
.X
,
1797 rSlideBoundingBox
.Y
- mpTop
->mnHeight
,
1798 rSlideBoundingBox
.Width
,
1804 mpLeft
->GetNormalBitmap(),
1807 rSlideBoundingBox
.X
- mpLeft
->mnWidth
,
1808 rSlideBoundingBox
.Y
,
1810 rSlideBoundingBox
.Height
);
1815 mpRight
->GetNormalBitmap(),
1818 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1819 rSlideBoundingBox
.Y
,
1821 rSlideBoundingBox
.Height
);
1826 mpBottom
->GetNormalBitmap(),
1829 rSlideBoundingBox
.X
,
1830 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
,
1831 rSlideBoundingBox
.Width
,
1832 mpBottom
->mnHeight
);
1837 mpTopLeft
->GetNormalBitmap(),
1840 rSlideBoundingBox
.X
- mpTopLeft
->mnWidth
,
1841 rSlideBoundingBox
.Y
- mpTopLeft
->mnHeight
);
1846 mpTopRight
->GetNormalBitmap(),
1849 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1850 rSlideBoundingBox
.Y
- mpTopLeft
->mnHeight
);
1855 mpBottomLeft
->GetNormalBitmap(),
1858 rSlideBoundingBox
.X
- mpBottomLeft
->mnWidth
,
1859 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
);
1864 mpBottomRight
->GetNormalBitmap(),
1867 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1868 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
);
1872 awt::Rectangle
PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox (
1873 const awt::Rectangle
& rSlideBoundingBox
)
1875 return awt::Rectangle(
1876 rSlideBoundingBox
.X
- mnLeftFrameSize
,
1877 rSlideBoundingBox
.Y
- mnTopFrameSize
,
1878 rSlideBoundingBox
.Width
+ mnLeftFrameSize
+ mnRightFrameSize
,
1879 rSlideBoundingBox
.Height
+ mnTopFrameSize
+ mnBottomFrameSize
);
1882 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapOnce(
1883 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
1884 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
1885 const Reference
<rendering::XPolyPolygon2D
>& rxClip
,
1889 OSL_ASSERT(rxCanvas
.is());
1890 if ( ! rxBitmap
.is())
1893 const rendering::ViewState
aViewState(
1894 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1897 const rendering::RenderState
aRenderState (
1898 geometry::AffineMatrix2D(
1902 Sequence
<double>(4),
1903 rendering::CompositeOperation::SOURCE
);
1905 rxCanvas
->drawBitmap(
1911 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled(
1912 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
1913 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
1914 const geometry::RealRectangle2D
& rClipBox
,
1917 const double nWidth
,
1918 const double nHeight
)
1920 OSL_ASSERT(rxCanvas
.is());
1921 if ( ! rxBitmap
.is())
1924 geometry::IntegerSize2D
aSize (rxBitmap
->getSize());
1926 const rendering::ViewState
aViewState(
1927 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1928 PresenterGeometryHelper::CreatePolygon(
1929 PresenterGeometryHelper::Intersection(
1931 geometry::RealRectangle2D(nX0
,nY0
,nX0
+nWidth
,nY0
+nHeight
)),
1932 rxCanvas
->getDevice()));
1934 rendering::RenderState
aRenderState (
1935 geometry::AffineMatrix2D(
1939 Sequence
<double>(4),
1940 rendering::CompositeOperation::SOURCE
);
1942 const double nX1
= nX0
+ nWidth
;
1943 const double nY1
= nY0
+ nHeight
;
1944 for (double nY
=nY0
; nY
<nY1
; nY
+=aSize
.Height
)
1945 for (double nX
=nX0
; nX
<nX1
; nX
+=aSize
.Width
)
1947 aRenderState
.AffineTransform
.m02
= nX
;
1948 aRenderState
.AffineTransform
.m12
= nY
;
1949 rxCanvas
->drawBitmap(
1956 } // end of namespace ::sdext::presenter
1958 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */