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 static sal_Int32
gnVerticalGap (10);
45 const static sal_Int32
gnVerticalBorder (10);
46 const static sal_Int32
gnHorizontalGap (10);
47 const static sal_Int32
gnHorizontalBorder (10);
49 const static double gnMinimalPreviewWidth (200);
50 const static double gnPreferredPreviewWidth (300);
51 const static double gnMaximalPreviewWidth (400);
52 const static sal_Int32
gnPreferredColumnCount (6);
53 const static double gnMinimalHorizontalPreviewGap(15);
54 const static double gnPreferredHorizontalPreviewGap(25);
55 const static double gnMaximalHorizontalPreviewGap(50);
56 const static double gnPreferredVerticalPreviewGap(25);
58 const static sal_Int32
gnHorizontalLabelBorder (3);
59 const static sal_Int32
gnHorizontalLabelPadding (5);
61 const static sal_Int32
gnVerticalButtonPadding (gnVerticalGap
);
64 namespace sdext
{ namespace 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
.get()==nullptr)
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"));
307 if (pFont
.get() != nullptr)
308 maSeparatorColor
= pFont
->mnColor
;
311 // Create the layout.
312 mpLayout
.reset(new 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
.get()!=nullptr);
512 OSL_ASSERT(mpPresenterController
->GetWindowManager().get()!=nullptr);
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
));
545 mnSlideIndexMousePressed
= -1;
549 mpMouseOverManager
->SetSlide(nSlideIndex
, awt::Rectangle(0,0,0,0));
553 mpMouseOverManager
->SetSlide(
555 mpLayout
->GetBoundingBox(nSlideIndex
));
559 void SAL_CALL
PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent
&) {}
561 //----- XResourceId -----------------------------------------------------------
563 Reference
<XResourceId
> SAL_CALL
PresenterSlideSorter::getResourceId()
569 sal_Bool SAL_CALL
PresenterSlideSorter::isAnchorOnly()
574 //----- XPropertyChangeListener -----------------------------------------------
576 void SAL_CALL
PresenterSlideSorter::propertyChange (
577 const css::beans::PropertyChangeEvent
&)
580 //----- XSlidePreviewCacheListener --------------------------------------------
582 void SAL_CALL
PresenterSlideSorter::notifyPreviewCreation (
583 sal_Int32 nSlideIndex
)
585 OSL_ASSERT(mpLayout
!= nullptr);
587 awt::Rectangle
aBBox (mpLayout
->GetBoundingBox(nSlideIndex
));
588 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
, aBBox
, true);
591 //----- XDrawView -------------------------------------------------------------
593 void SAL_CALL
PresenterSlideSorter::setCurrentPage (const Reference
<drawing::XDrawPage
>&)
596 ::osl::MutexGuard
aGuard (::osl::Mutex::getGlobalMutex());
598 if (!mxSlideShowController
.is())
601 const sal_Int32
nNewCurrentSlideIndex (mxSlideShowController
->getCurrentSlideIndex());
602 if (nNewCurrentSlideIndex
== mnCurrentSlideIndex
)
605 mnCurrentSlideIndex
= nNewCurrentSlideIndex
;
607 // Request a repaint of the previous current slide to hide its
608 // current slide indicator.
609 mpPresenterController
->GetPaintManager()->Invalidate(
611 maCurrentSlideFrameBoundingBox
);
613 // Request a repaint of the new current slide to show its
614 // current slide indicator.
615 maCurrentSlideFrameBoundingBox
= mpCurrentSlideFrameRenderer
->GetBoundingBox(
616 mpLayout
->GetBoundingBox(mnCurrentSlideIndex
));
617 mpPresenterController
->GetPaintManager()->Invalidate(
619 maCurrentSlideFrameBoundingBox
);
622 Reference
<drawing::XDrawPage
> SAL_CALL
PresenterSlideSorter::getCurrentPage()
629 void PresenterSlideSorter::UpdateLayout()
631 if ( ! mxWindow
.is())
634 mbIsLayoutPending
= false;
636 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
637 sal_Int32
nLeftBorderWidth (aWindowBox
.X
);
640 PresenterPaneContainer::SharedPaneDescriptor
pPane (
641 mpPresenterController
->GetPaneContainer()->FindViewURL(
642 mxViewId
->getResourceURL()));
645 if (pPane
.get() == nullptr)
647 if ( ! pPane
->mxPane
.is())
650 Reference
<drawing::framework::XPaneBorderPainter
> xBorderPainter (
651 pPane
->mxPane
->GetPaneBorderPainter());
652 if ( ! xBorderPainter
.is())
654 xBorderPainter
->addBorder (
655 mxViewId
->getAnchor()->getResourceURL(),
656 awt::Rectangle(0, 0, aWindowBox
.Width
, aWindowBox
.Height
),
657 drawing::framework::BorderType_INNER_BORDER
);
661 // Place vertical separator.
662 mnSeparatorY
= aWindowBox
.Height
- mpCloseButton
->GetSize().Height
- gnVerticalButtonPadding
;
664 PlaceCloseButton(pPane
, aWindowBox
, nLeftBorderWidth
);
666 geometry::RealRectangle2D
aUpperBox(
669 aWindowBox
.Width
- 2*gnHorizontalBorder
,
670 mnSeparatorY
- gnVerticalGap
);
672 // Determine whether the scroll bar has to be displayed.
673 aUpperBox
= PlaceScrollBars(aUpperBox
);
675 mpLayout
->Update(aUpperBox
, GetSlideAspectRatio());
676 mpLayout
->SetupVisibleArea();
677 mpLayout
->UpdateScrollBars();
679 // Tell the preview cache about some of the values.
680 mxPreviewCache
->setPreviewSize(mpLayout
->maPreviewSize
);
681 mxPreviewCache
->setVisibleRange(
682 mpLayout
->GetFirstVisibleSlideIndex(),
683 mpLayout
->GetLastVisibleSlideIndex());
685 // Clear the frame polygon so that it is re-created on the next paint.
686 mxPreviewFrame
= nullptr;
689 geometry::RealRectangle2D
PresenterSlideSorter::PlaceScrollBars (
690 const geometry::RealRectangle2D
& rUpperBox
)
692 mpLayout
->Update(rUpperBox
, GetSlideAspectRatio());
693 bool bIsScrollBarNeeded (false);
694 Reference
<container::XIndexAccess
> xSlides (mxSlideShowController
, UNO_QUERY_THROW
);
695 bIsScrollBarNeeded
= mpLayout
->IsScrollBarNeeded(xSlides
->getCount());
696 if (mpVerticalScrollBar
.get() != nullptr)
698 if (bIsScrollBarNeeded
)
700 if(AllSettings::GetLayoutRTL())
702 mpVerticalScrollBar
->SetPosSize(geometry::RealRectangle2D(
705 rUpperBox
.X1
+ mpVerticalScrollBar
->GetSize(),
707 mpVerticalScrollBar
->SetVisible(true);
708 // Reduce area covered by the scroll bar from the available
710 return geometry::RealRectangle2D(
711 rUpperBox
.X1
+ gnHorizontalGap
+ mpVerticalScrollBar
->GetSize(),
718 // if it's not RTL place vertical scroll bar at right border.
719 mpVerticalScrollBar
->SetPosSize(geometry::RealRectangle2D(
720 rUpperBox
.X2
- mpVerticalScrollBar
->GetSize(),
724 mpVerticalScrollBar
->SetVisible(true);
725 // Reduce area covered by the scroll bar from the available
727 return geometry::RealRectangle2D(
730 rUpperBox
.X2
- mpVerticalScrollBar
->GetSize() - gnHorizontalGap
,
735 mpVerticalScrollBar
->SetVisible(false);
740 void PresenterSlideSorter::PlaceCloseButton (
741 const PresenterPaneContainer::SharedPaneDescriptor
& rpPane
,
742 const awt::Rectangle
& rCenterBox
,
743 const sal_Int32 nLeftBorderWidth
)
745 // Place button. When the callout is near the center then the button is
746 // centered over the callout. Otherwise it is centered with respect to
748 sal_Int32
nCloseButtonCenter (rCenterBox
.Width
/2);
749 if (rpPane
.get() != nullptr && rpPane
->mxPane
.is())
751 const sal_Int32
nCalloutCenter (-nLeftBorderWidth
);
752 const sal_Int32
nDistanceFromWindowCenter (abs(nCalloutCenter
- rCenterBox
.Width
/2));
753 const sal_Int32
nButtonWidth (mpCloseButton
->GetSize().Width
);
754 const static sal_Int32
nMaxDistanceForCalloutCentering (nButtonWidth
* 2);
755 if (nDistanceFromWindowCenter
< nMaxDistanceForCalloutCentering
)
757 if (nCalloutCenter
< nButtonWidth
/2)
758 nCloseButtonCenter
= nButtonWidth
/2;
759 else if (nCalloutCenter
> rCenterBox
.Width
-nButtonWidth
/2)
760 nCloseButtonCenter
= rCenterBox
.Width
-nButtonWidth
/2;
762 nCloseButtonCenter
= nCalloutCenter
;
765 mpCloseButton
->SetCenter(geometry::RealPoint2D(
767 rCenterBox
.Height
- mpCloseButton
->GetSize().Height
/ 2));
770 void PresenterSlideSorter::ClearBackground (
771 const Reference
<rendering::XCanvas
>& rxCanvas
,
772 const awt::Rectangle
& rUpdateBox
)
774 OSL_ASSERT(rxCanvas
.is());
776 const awt::Rectangle
aWindowBox (mxWindow
->getPosSize());
777 mpPresenterController
->GetCanvasHelper()->Paint(
778 mpPresenterController
->GetViewBackground(mxViewId
->getResourceURL()),
781 awt::Rectangle(0,0,aWindowBox
.Width
,aWindowBox
.Height
),
785 double PresenterSlideSorter::GetSlideAspectRatio() const
787 double nSlideAspectRatio (28.0/21.0);
791 Reference
<container::XIndexAccess
> xSlides(mxSlideShowController
, UNO_QUERY_THROW
);
792 if (mxSlideShowController
.is() && xSlides
->getCount()>0)
794 Reference
<beans::XPropertySet
> xProperties(xSlides
->getByIndex(0),UNO_QUERY_THROW
);
795 sal_Int32
nWidth (28000);
796 sal_Int32
nHeight (21000);
797 if ((xProperties
->getPropertyValue("Width") >>= nWidth
)
798 && (xProperties
->getPropertyValue("Height") >>= nHeight
)
801 nSlideAspectRatio
= double(nWidth
) / double(nHeight
);
805 catch (RuntimeException
&)
810 return nSlideAspectRatio
;
813 Reference
<rendering::XBitmap
> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex
)
815 if (nSlideIndex
< 0 || nSlideIndex
>=mpLayout
->mnSlideCount
)
817 else if (mxPane
.is())
818 return mxPreviewCache
->getSlidePreview(nSlideIndex
, mxPane
->getCanvas());
823 void PresenterSlideSorter::PaintPreview (
824 const Reference
<rendering::XCanvas
>& rxCanvas
,
825 const css::awt::Rectangle
& rUpdateBox
,
826 const sal_Int32 nSlideIndex
)
828 OSL_ASSERT(rxCanvas
.is());
830 geometry::IntegerSize2D
aSize (mpLayout
->maPreviewSize
);
832 if (PresenterGeometryHelper::AreRectanglesDisjoint(
834 mpLayout
->GetBoundingBox(nSlideIndex
)))
839 Reference
<rendering::XBitmap
> xPreview (GetPreview(nSlideIndex
));
840 bool isRTL
= AllSettings::GetLayoutRTL();
842 const geometry::RealPoint2D
aTopLeft (
843 mpLayout
->GetWindowPosition(
844 mpLayout
->GetPoint(nSlideIndex
, isRTL
?1:-1, -1)));
846 PresenterBitmapContainer
aContainer (
847 "PresenterScreenSettings/ScrollBar/Bitmaps",
848 std::shared_ptr
<PresenterBitmapContainer
>(),
851 Reference
<container::XIndexAccess
> xIndexAccess(mxSlideShowController
, UNO_QUERY
);
852 Reference
<drawing::XDrawPage
> xPage( xIndexAccess
->getByIndex(nSlideIndex
), UNO_QUERY
);
853 bool bTransition
= PresenterController::HasTransition(xPage
);
854 bool bCustomAnimation
= PresenterController::HasCustomAnimation(xPage
);
856 // Create clip rectangle as intersection of the current update area and
857 // the bounding box of all previews.
858 geometry::RealRectangle2D
aBoundingBox (mpLayout
->maBoundingBox
);
859 aBoundingBox
.Y2
+= 1;
860 const geometry::RealRectangle2D
aClipBox (
861 PresenterGeometryHelper::Intersection(
862 PresenterGeometryHelper::ConvertRectangle(rUpdateBox
),
864 Reference
<rendering::XPolyPolygon2D
> xClip (
865 PresenterGeometryHelper::CreatePolygon(aClipBox
, rxCanvas
->getDevice()));
867 const rendering::ViewState
aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip
);
869 rendering::RenderState
aRenderState (
870 geometry::AffineMatrix2D(
875 rendering::CompositeOperation::SOURCE
);
877 // Emphasize the current slide.
878 if (nSlideIndex
== mnCurrentSlideIndex
)
880 if (mpCurrentSlideFrameRenderer
!= nullptr)
882 const awt::Rectangle
aSlideBoundingBox(
883 sal::static_int_cast
<sal_Int32
>(0.5 + aTopLeft
.X
),
884 sal::static_int_cast
<sal_Int32
>(0.5 + aTopLeft
.Y
),
887 maCurrentSlideFrameBoundingBox
888 = mpCurrentSlideFrameRenderer
->GetBoundingBox(aSlideBoundingBox
);
889 mpCurrentSlideFrameRenderer
->PaintCurrentSlideFrame (
896 // Paint the preview.
899 aSize
= xPreview
->getSize();
900 if (aSize
.Width
> 0 && aSize
.Height
> 0)
902 rxCanvas
->drawBitmap(xPreview
, aViewState
, aRenderState
);
903 if( bCustomAnimation
)
905 const awt::Rectangle
aAnimationPreviewBox(aTopLeft
.X
+3, aTopLeft
.Y
+aSize
.Height
-40, 0, 0);
906 SharedBitmapDescriptor aAnimationDescriptor
= aContainer
.GetBitmap("Animation");
907 Reference
<rendering::XBitmap
> xAnimationIcon (aAnimationDescriptor
->GetNormalBitmap());
908 rendering::RenderState
aAnimationRenderState (
909 geometry::AffineMatrix2D(
910 1, 0, aAnimationPreviewBox
.X
,
911 0, 1, aAnimationPreviewBox
.Y
),
914 rendering::CompositeOperation::SOURCE
);
915 rxCanvas
->drawBitmap(xAnimationIcon
, aViewState
, aAnimationRenderState
);
919 const awt::Rectangle
aTransitionPreviewBox(aTopLeft
.X
+3, aTopLeft
.Y
+aSize
.Height
-20, 0, 0);
920 SharedBitmapDescriptor aTransitionDescriptor
= aContainer
.GetBitmap("Transition");
921 Reference
<rendering::XBitmap
> xTransitionIcon (aTransitionDescriptor
->GetNormalBitmap());
922 rendering::RenderState
aTransitionRenderState (
923 geometry::AffineMatrix2D(
924 1, 0, aTransitionPreviewBox
.X
,
925 0, 1, aTransitionPreviewBox
.Y
),
928 rendering::CompositeOperation::SOURCE
);
929 rxCanvas
->drawBitmap(xTransitionIcon
, aViewState
, aTransitionRenderState
);
934 // Create a polygon that is used to paint a frame around previews. Its
935 // coordinates are chosen in the local coordinate system of a preview.
936 if ( ! mxPreviewFrame
.is())
937 mxPreviewFrame
= PresenterGeometryHelper::CreatePolygon(
938 awt::Rectangle(-1, -1, aSize
.Width
+2, aSize
.Height
+2),
939 rxCanvas
->getDevice());
941 // Paint a border around the preview.
942 if (mxPreviewFrame
.is())
944 const util::Color
aFrameColor (0x00000000);
945 PresenterCanvasHelper::SetDeviceColor(aRenderState
, aFrameColor
);
946 rxCanvas
->drawPolyPolygon(mxPreviewFrame
, aViewState
, aRenderState
);
949 // Paint mouse over effect.
950 mpMouseOverManager
->Paint(nSlideIndex
, mxCanvas
, xClip
);
953 void PresenterSlideSorter::Paint (const awt::Rectangle
& rUpdateBox
)
955 const bool bCanvasChanged ( ! mxCanvas
.is());
956 if ( ! ProvideCanvas())
959 if (mpLayout
->mnRowCount
<=0 || mpLayout
->mnColumnCount
<=0)
961 OSL_ASSERT(mpLayout
->mnRowCount
>0 || mpLayout
->mnColumnCount
>0);
965 ClearBackground(mxCanvas
, rUpdateBox
);
967 // Give the canvas to the controls.
970 if (mpVerticalScrollBar
.is())
971 mpVerticalScrollBar
->SetCanvas(mxCanvas
);
972 if (mpCloseButton
.is())
973 mpCloseButton
->SetCanvas(mxCanvas
, mxWindow
);
976 // Now that the controls have a canvas we can do the layouting.
977 if (mbIsLayoutPending
)
980 // Paint the horizontal separator.
981 rendering::RenderState
aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0),
982 nullptr, Sequence
<double>(4), rendering::CompositeOperation::SOURCE
);
983 PresenterCanvasHelper::SetDeviceColor(aRenderState
, maSeparatorColor
);
985 geometry::RealPoint2D(0, mnSeparatorY
),
986 geometry::RealPoint2D(mxWindow
->getPosSize().Width
, mnSeparatorY
),
987 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
991 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
993 PresenterGeometryHelper::ConvertRectangle(mpLayout
->maBoundingBox
)))
995 mpLayout
->ForAllVisibleSlides(
996 [this, &rUpdateBox
] (sal_Int32
const nIndex
) {
997 return this->PaintPreview(this->mxCanvas
, rUpdateBox
, nIndex
);
1001 Reference
<rendering::XSpriteCanvas
> xSpriteCanvas (mxCanvas
, UNO_QUERY
);
1002 if (xSpriteCanvas
.is())
1003 xSpriteCanvas
->updateScreen(false);
1006 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset
)
1008 if (mpLayout
->SetHorizontalOffset(nXOffset
))
1010 mxPreviewCache
->setVisibleRange(
1011 mpLayout
->GetFirstVisibleSlideIndex(),
1012 mpLayout
->GetLastVisibleSlideIndex());
1014 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
1018 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset
)
1020 if (mpLayout
->SetVerticalOffset(nYOffset
))
1022 mxPreviewCache
->setVisibleRange(
1023 mpLayout
->GetFirstVisibleSlideIndex(),
1024 mpLayout
->GetLastVisibleSlideIndex());
1026 mpPresenterController
->GetPaintManager()->Invalidate(mxWindow
);
1030 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex
)
1032 mxSlideShowController
->gotoSlideIndex(nSlideIndex
);
1035 bool PresenterSlideSorter::ProvideCanvas()
1037 if ( ! mxCanvas
.is())
1040 mxCanvas
= mxPane
->getCanvas();
1042 // Register as event listener so that we are informed when the
1043 // canvas is disposed (and we have to fetch another one).
1044 Reference
<lang::XComponent
> xComponent (mxCanvas
, UNO_QUERY
);
1045 if (xComponent
.is())
1046 xComponent
->addEventListener(static_cast<awt::XWindowListener
*>(this));
1048 mpCurrentSlideFrameRenderer
.reset(
1049 new CurrentSlideFrameRenderer(mxComponentContext
, mxCanvas
));
1051 return mxCanvas
.is();
1054 void PresenterSlideSorter::ThrowIfDisposed()
1056 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
)
1058 throw lang::DisposedException (
1059 "PresenterSlideSorter has been already disposed",
1060 static_cast<uno::XWeak
*>(this));
1064 //===== PresenterSlideSorter::Layout ==========================================
1066 PresenterSlideSorter::Layout::Layout (
1067 const ::rtl::Reference
<PresenterScrollBar
>& rpVerticalScrollBar
)
1070 mnHorizontalOffset(0),
1071 mnVerticalOffset(0),
1074 mnHorizontalBorder(0),
1075 mnVerticalBorder(0),
1079 mnFirstVisibleColumn(-1),
1080 mnLastVisibleColumn(-1),
1081 mnFirstVisibleRow(-1),
1082 mnLastVisibleRow(-1),
1083 mpVerticalScrollBar(rpVerticalScrollBar
)
1087 void PresenterSlideSorter::Layout::Update (
1088 const geometry::RealRectangle2D
& rBoundingBox
,
1089 const double nSlideAspectRatio
)
1091 maBoundingBox
= rBoundingBox
;
1093 mnHorizontalBorder
= gnHorizontalBorder
;
1094 mnVerticalBorder
= gnVerticalBorder
;
1096 const double nWidth (rBoundingBox
.X2
- rBoundingBox
.X1
- 2*mnHorizontalBorder
);
1097 const double nHeight (rBoundingBox
.Y2
- rBoundingBox
.Y1
- 2*mnVerticalBorder
);
1098 if (nWidth
<=0 || nHeight
<=0)
1101 double nPreviewWidth
;
1103 // Determine column count, preview width, and horizontal gap (borders
1104 // are half the gap). Try to use the preferred values. Try more to
1105 // stay in the valid intervals. This last constraint may be not
1106 // fulfilled in some cases.
1107 const double nElementWidth
= nWidth
/ gnPreferredColumnCount
;
1108 if (nElementWidth
< gnMinimalPreviewWidth
+ gnMinimalHorizontalPreviewGap
)
1110 // The preferred column count is too large.
1111 // Can we use the preferred preview width?
1112 if (nWidth
- gnMinimalHorizontalPreviewGap
>= gnPreferredPreviewWidth
)
1115 nPreviewWidth
= gnPreferredPreviewWidth
;
1116 mnColumnCount
= floor((nWidth
+gnPreferredHorizontalPreviewGap
)
1117 / (nPreviewWidth
+gnPreferredHorizontalPreviewGap
));
1118 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1122 // No. Set the column count to 1 and adapt preview width and
1125 mnHorizontalGap
= floor(gnMinimalHorizontalPreviewGap
);
1126 if (nWidth
- gnMinimalHorizontalPreviewGap
>= gnPreferredPreviewWidth
)
1127 nPreviewWidth
= nWidth
- gnMinimalHorizontalPreviewGap
;
1129 nPreviewWidth
= ::std::max(gnMinimalPreviewWidth
, nWidth
-mnHorizontalGap
);
1132 else if (nElementWidth
> gnMaximalPreviewWidth
+ gnMaximalHorizontalPreviewGap
)
1134 // The preferred column count is too small.
1135 nPreviewWidth
= gnPreferredPreviewWidth
;
1136 mnColumnCount
= floor((nWidth
+gnPreferredHorizontalPreviewGap
)
1137 / (nPreviewWidth
+gnPreferredHorizontalPreviewGap
));
1138 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1142 // The preferred column count is possible. Determine gap and
1144 mnColumnCount
= gnPreferredColumnCount
;
1145 if (nElementWidth
- gnPreferredPreviewWidth
< gnMinimalHorizontalPreviewGap
)
1147 // Use the minimal gap and adapt the preview width.
1148 mnHorizontalGap
= floor(gnMinimalHorizontalPreviewGap
);
1149 nPreviewWidth
= (nWidth
- mnColumnCount
*mnHorizontalGap
) / mnColumnCount
;
1151 else if (nElementWidth
- gnPreferredPreviewWidth
<= gnMaximalHorizontalPreviewGap
)
1153 // Use the maximal gap and adapt the preview width.
1154 mnHorizontalGap
= round(gnMaximalHorizontalPreviewGap
);
1155 nPreviewWidth
= (nWidth
- mnColumnCount
*mnHorizontalGap
) / mnColumnCount
;
1159 // Use the preferred preview width and adapt the gap.
1160 nPreviewWidth
= gnPreferredPreviewWidth
;
1161 mnHorizontalGap
= round((nWidth
- mnColumnCount
*nPreviewWidth
) / mnColumnCount
);
1165 // Now determine the row count, preview height, and vertical gap.
1166 const double nPreviewHeight
= nPreviewWidth
/ nSlideAspectRatio
;
1167 mnRowCount
= ::std::max(
1169 sal_Int32(ceil((nHeight
+gnPreferredVerticalPreviewGap
)
1170 / (nPreviewHeight
+ gnPreferredVerticalPreviewGap
))));
1171 mnVerticalGap
= round(gnPreferredVerticalPreviewGap
);
1173 maPreviewSize
= geometry::IntegerSize2D(floor(nPreviewWidth
), floor(nPreviewHeight
));
1175 // Reset the offset.
1176 mnVerticalOffset
= 0;
1177 mnHorizontalOffset
= round(-(nWidth
1178 - mnColumnCount
*maPreviewSize
.Width
1179 - (mnColumnCount
-1)*mnHorizontalGap
)
1183 void PresenterSlideSorter::Layout::SetupVisibleArea()
1185 geometry::RealPoint2D
aPoint (GetLocalPosition(
1186 geometry::RealPoint2D(maBoundingBox
.X1
, maBoundingBox
.Y1
)));
1187 mnFirstVisibleColumn
= 0;
1188 mnFirstVisibleRow
= ::std::max(sal_Int32(0), GetRow(aPoint
));
1190 aPoint
= GetLocalPosition(geometry::RealPoint2D( maBoundingBox
.X2
, maBoundingBox
.Y2
));
1191 mnLastVisibleColumn
= mnColumnCount
- 1;
1192 mnLastVisibleRow
= GetRow(aPoint
, true);
1195 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount
)
1197 geometry::RealPoint2D aBottomRight
= GetPoint(
1198 mnColumnCount
* (GetRow(nSlideCount
)+1) - 1, +1, +1);
1199 return aBottomRight
.X
> maBoundingBox
.X2
-maBoundingBox
.X1
1200 || aBottomRight
.Y
> maBoundingBox
.Y2
-maBoundingBox
.Y1
;
1203 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetLocalPosition(
1204 const geometry::RealPoint2D
& rWindowPoint
) const
1206 if(AllSettings::GetLayoutRTL())
1208 return css::geometry::RealPoint2D(
1209 -rWindowPoint
.X
+ maBoundingBox
.X2
+ mnHorizontalOffset
,
1210 rWindowPoint
.Y
- maBoundingBox
.Y1
+ mnVerticalOffset
);
1214 return css::geometry::RealPoint2D(
1215 rWindowPoint
.X
- maBoundingBox
.X1
+ mnHorizontalOffset
,
1216 rWindowPoint
.Y
- maBoundingBox
.Y1
+ mnVerticalOffset
);
1220 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetWindowPosition(
1221 const geometry::RealPoint2D
& rLocalPoint
) const
1223 if(AllSettings::GetLayoutRTL())
1225 return css::geometry::RealPoint2D(
1226 -rLocalPoint
.X
+ mnHorizontalOffset
+ maBoundingBox
.X2
,
1227 rLocalPoint
.Y
- mnVerticalOffset
+ maBoundingBox
.Y1
);
1231 return css::geometry::RealPoint2D(
1232 rLocalPoint
.X
- mnHorizontalOffset
+ maBoundingBox
.X1
,
1233 rLocalPoint
.Y
- mnVerticalOffset
+ maBoundingBox
.Y1
);
1237 sal_Int32
PresenterSlideSorter::Layout::GetColumn (
1238 const css::geometry::RealPoint2D
& rLocalPoint
) const
1240 const sal_Int32
nColumn(floor(
1241 (rLocalPoint
.X
+ mnHorizontalGap
/2.0) / (maPreviewSize
.Width
+mnHorizontalGap
)));
1242 if (nColumn
>=mnFirstVisibleColumn
&& nColumn
<=mnLastVisibleColumn
)
1250 sal_Int32
PresenterSlideSorter::Layout::GetRow (
1251 const css::geometry::RealPoint2D
& rLocalPoint
,
1252 const bool bReturnInvalidValue
) const
1254 const sal_Int32
nRow (floor(
1255 (rLocalPoint
.Y
+ mnVerticalGap
/2.0) / (maPreviewSize
.Height
+mnVerticalGap
)));
1256 if (bReturnInvalidValue
1257 || (nRow
>=mnFirstVisibleRow
&& nRow
<=mnLastVisibleRow
))
1265 sal_Int32
PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1266 const css::geometry::RealPoint2D
& rWindowPoint
) const
1268 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox
, rWindowPoint
))
1271 const css::geometry::RealPoint2D
aLocalPosition (GetLocalPosition(rWindowPoint
));
1272 const sal_Int32
nColumn (GetColumn(aLocalPosition
));
1273 const sal_Int32
nRow (GetRow(aLocalPosition
));
1275 if (nColumn
< 0 || nRow
< 0)
1279 sal_Int32
nIndex (GetIndex(nRow
, nColumn
));
1280 if (nIndex
>= mnSlideCount
)
1287 geometry::RealPoint2D
PresenterSlideSorter::Layout::GetPoint (
1288 const sal_Int32 nSlideIndex
,
1289 const sal_Int32 nRelativeHorizontalPosition
,
1290 const sal_Int32 nRelativeVerticalPosition
) const
1292 sal_Int32
nColumn (GetColumn(nSlideIndex
));
1293 sal_Int32
nRow (GetRow(nSlideIndex
));
1295 geometry::RealPoint2D
aPosition (
1296 mnHorizontalBorder
+ nColumn
*(maPreviewSize
.Width
+mnHorizontalGap
),
1297 mnVerticalBorder
+ nRow
*(maPreviewSize
.Height
+mnVerticalGap
));
1299 if (nRelativeHorizontalPosition
>= 0)
1301 if (nRelativeHorizontalPosition
> 0)
1302 aPosition
.X
+= maPreviewSize
.Width
;
1304 aPosition
.X
+= maPreviewSize
.Width
/ 2.0;
1306 if (nRelativeVerticalPosition
>= 0)
1308 if (nRelativeVerticalPosition
> 0)
1309 aPosition
.Y
+= maPreviewSize
.Height
;
1311 aPosition
.Y
+= maPreviewSize
.Height
/ 2.0;
1317 awt::Rectangle
PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex
) const
1319 bool isRTL
= AllSettings::GetLayoutRTL();
1320 const geometry::RealPoint2D
aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex
, isRTL
?1:-1, -1)));
1321 return PresenterGeometryHelper::ConvertRectangle(
1322 geometry::RealRectangle2D(
1325 aWindowPosition
.X
+ maPreviewSize
.Width
,
1326 aWindowPosition
.Y
+ maPreviewSize
.Height
));
1329 void PresenterSlideSorter::Layout::ForAllVisibleSlides(
1330 const ::std::function
<void (sal_Int32
)>& rAction
)
1332 for (sal_Int32 nRow
=mnFirstVisibleRow
; nRow
<=mnLastVisibleRow
; ++nRow
)
1334 for (sal_Int32 nColumn
=mnFirstVisibleColumn
; nColumn
<=mnLastVisibleColumn
; ++nColumn
)
1336 const sal_Int32
nSlideIndex (GetIndex(nRow
, nColumn
));
1337 if (nSlideIndex
>= mnSlideCount
)
1339 rAction(nSlideIndex
);
1344 sal_Int32
PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex() const
1346 return GetIndex(mnFirstVisibleRow
, mnFirstVisibleColumn
);
1349 sal_Int32
PresenterSlideSorter::Layout::GetLastVisibleSlideIndex() const
1352 GetIndex(mnLastVisibleRow
, mnLastVisibleColumn
),
1356 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset
)
1358 if (mnHorizontalOffset
!= nOffset
)
1360 mnHorizontalOffset
= round(nOffset
);
1369 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset
)
1371 if (mnVerticalOffset
!= nOffset
)
1373 mnVerticalOffset
= round(nOffset
);
1382 void PresenterSlideSorter::Layout::UpdateScrollBars()
1384 sal_Int32 nTotalRowCount
= sal_Int32(ceil(double(mnSlideCount
) / double(mnColumnCount
)));
1386 if (mpVerticalScrollBar
.get() != nullptr)
1388 mpVerticalScrollBar
->SetTotalSize(
1389 nTotalRowCount
* maPreviewSize
.Height
1390 + (nTotalRowCount
-1) * mnVerticalGap
1392 mpVerticalScrollBar
->SetThumbPosition(mnVerticalOffset
, false);
1393 mpVerticalScrollBar
->SetThumbSize(maBoundingBox
.Y2
- maBoundingBox
.Y1
+ 1);
1394 mpVerticalScrollBar
->SetLineHeight(maPreviewSize
.Height
);
1397 // No place yet for the vertical scroll bar.
1400 sal_Int32
PresenterSlideSorter::Layout::GetIndex (
1401 const sal_Int32 nRow
,
1402 const sal_Int32 nColumn
) const
1404 return nRow
* mnColumnCount
+ nColumn
;
1407 sal_Int32
PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex
) const
1409 return nSlideIndex
/ mnColumnCount
;
1412 sal_Int32
PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex
) const
1414 return nSlideIndex
% mnColumnCount
;
1417 //===== PresenterSlideSorter::MouseOverManager ================================
1419 PresenterSlideSorter::MouseOverManager::MouseOverManager (
1420 const Reference
<container::XIndexAccess
>& rxSlides
,
1421 const std::shared_ptr
<PresenterTheme
>& rpTheme
,
1422 const Reference
<awt::XWindow
>& rxInvalidateTarget
,
1423 const std::shared_ptr
<PresenterPaintManager
>& rpPaintManager
)
1426 mpLeftLabelBitmap(),
1427 mpCenterLabelBitmap(),
1428 mpRightLabelBitmap(),
1431 maSlideBoundingBox(),
1432 mxInvalidateTarget(rxInvalidateTarget
),
1433 mpPaintManager(rpPaintManager
)
1435 if (rpTheme
!= nullptr)
1437 std::shared_ptr
<PresenterBitmapContainer
> pBitmaps (rpTheme
->GetBitmapContainer());
1438 if (pBitmaps
!= nullptr)
1440 mpLeftLabelBitmap
= pBitmaps
->GetBitmap("LabelLeft");
1441 mpCenterLabelBitmap
= pBitmaps
->GetBitmap("LabelCenter");
1442 mpRightLabelBitmap
= pBitmaps
->GetBitmap("LabelRight");
1445 mpFont
= rpTheme
->GetFont("SlideSorterLabelFont");
1449 void PresenterSlideSorter::MouseOverManager::Paint (
1450 const sal_Int32 nSlideIndex
,
1451 const Reference
<rendering::XCanvas
>& rxCanvas
,
1452 const Reference
<rendering::XPolyPolygon2D
>& rxClip
)
1454 if (nSlideIndex
!= mnSlideIndex
)
1457 if (mxCanvas
!= rxCanvas
)
1458 SetCanvas(rxCanvas
);
1459 if (rxCanvas
== nullptr)
1462 if ( ! mxBitmap
.is())
1463 mxBitmap
= CreateBitmap(msText
, maSlideBoundingBox
.Width
);
1467 geometry::IntegerSize2D
aSize (mxBitmap
->getSize());
1468 const double nXOffset (maSlideBoundingBox
.X
1469 + (maSlideBoundingBox
.Width
- aSize
.Width
) / 2.0);
1470 const double nYOffset (maSlideBoundingBox
.Y
1471 + (maSlideBoundingBox
.Height
- aSize
.Height
) / 2.0);
1472 rxCanvas
->drawBitmap(
1474 rendering::ViewState(
1475 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1477 rendering::RenderState(
1478 geometry::AffineMatrix2D(1,0,nXOffset
, 0,1,nYOffset
),
1480 Sequence
<double>(4),
1481 rendering::CompositeOperation::SOURCE
));
1484 void PresenterSlideSorter::MouseOverManager::SetCanvas (
1485 const Reference
<rendering::XCanvas
>& rxCanvas
)
1487 mxCanvas
= rxCanvas
;
1488 if (mpFont
.get() != nullptr)
1489 mpFont
->PrepareFont(mxCanvas
);
1492 void PresenterSlideSorter::MouseOverManager::SetSlide (
1493 const sal_Int32 nSlideIndex
,
1494 const awt::Rectangle
& rBox
)
1496 if (mnSlideIndex
== nSlideIndex
)
1502 maSlideBoundingBox
= rBox
;
1503 mnSlideIndex
= nSlideIndex
;
1505 if (nSlideIndex
>= 0)
1507 if (mxSlides
.get() != nullptr)
1511 Reference
<beans::XPropertySet
> xSlideProperties(mxSlides
->getByIndex(nSlideIndex
), UNO_QUERY
);
1512 if (xSlideProperties
.is())
1513 xSlideProperties
->getPropertyValue("LinkDisplayName") >>= msText
;
1515 if (msText
.isEmpty())
1516 msText
= "Slide " + OUString::number(nSlideIndex
+ 1);
1528 Reference
<rendering::XBitmap
> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1529 const OUString
& rsText
,
1530 const sal_Int32 nMaximalWidth
) const
1532 if ( ! mxCanvas
.is())
1535 if (mpFont
.get()==nullptr || !mpFont
->mxFont
.is())
1538 // Long text has to be shortened.
1539 const OUString
sText (GetFittingText(rsText
, nMaximalWidth
1540 - 2*gnHorizontalLabelBorder
1541 - 2*gnHorizontalLabelPadding
));
1543 // Determine the size of the label. Its height is defined by the
1544 // bitmaps that are used to paints its background. The width is defined
1546 geometry::IntegerSize2D
aLabelSize (CalculateLabelSize(sText
));
1548 // Create a new bitmap that will contain the complete label.
1549 Reference
<rendering::XBitmap
> xBitmap (
1550 mxCanvas
->getDevice()->createCompatibleAlphaBitmap(aLabelSize
));
1552 if ( ! xBitmap
.is())
1555 Reference
<rendering::XBitmapCanvas
> xBitmapCanvas (xBitmap
, UNO_QUERY
);
1556 if ( ! xBitmapCanvas
.is())
1559 // Paint the background.
1560 PaintButtonBackground(xBitmapCanvas
, aLabelSize
);
1563 if (!sText
.isEmpty())
1566 const rendering::StringContext
aContext (sText
, 0, sText
.getLength());
1567 const Reference
<rendering::XTextLayout
> xLayout (mpFont
->mxFont
->createTextLayout(
1568 aContext
, rendering::TextDirection::WEAK_LEFT_TO_RIGHT
,0));
1569 const geometry::RealRectangle2D
aTextBBox (xLayout
->queryTextBounds());
1571 const double nXOffset
= (aLabelSize
.Width
- aTextBBox
.X2
+ aTextBBox
.X1
) / 2;
1572 const double nYOffset
= aLabelSize
.Height
1573 - (aLabelSize
.Height
- aTextBBox
.Y2
+ aTextBBox
.Y1
)/2 - aTextBBox
.Y2
;
1575 const rendering::ViewState
aViewState(
1576 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1579 rendering::RenderState
aRenderState (
1580 geometry::AffineMatrix2D(1,0,nXOffset
, 0,1,nYOffset
),
1582 Sequence
<double>(4),
1583 rendering::CompositeOperation::SOURCE
);
1584 PresenterCanvasHelper::SetDeviceColor(aRenderState
, mpFont
->mnColor
);
1586 xBitmapCanvas
->drawTextLayout (
1595 OUString
PresenterSlideSorter::MouseOverManager::GetFittingText (
1596 const OUString
& rsText
,
1597 const double nMaximalWidth
) const
1599 const double nTextWidth (
1600 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, rsText
).Width
);
1601 if (nTextWidth
> nMaximalWidth
)
1603 // Text is too wide. Shorten it by removing characters from the end
1604 // and replacing them by ellipses.
1606 // Guess a start value of the final string length.
1607 double nBestWidth (0);
1608 OUString sBestCandidate
;
1609 sal_Int32
nLength (round(rsText
.getLength() * nMaximalWidth
/ nTextWidth
));
1610 const OUString
sEllipses ("...");
1613 const OUString
sCandidate (rsText
.copy(0,nLength
) + sEllipses
);
1614 const double nWidth (
1615 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, sCandidate
).Width
);
1616 if (nWidth
> nMaximalWidth
)
1618 // Candidate still too wide, shorten it.
1623 else if (nWidth
< nMaximalWidth
)
1625 // Candidate short enough.
1626 if (nWidth
> nBestWidth
)
1628 // Best length so far.
1629 sBestCandidate
= sCandidate
;
1630 nBestWidth
= nWidth
;
1632 if (nLength
>= rsText
.getLength())
1640 // Candidate is exactly as long as it may be. Use it
1641 // without looking any further.
1642 sBestCandidate
= sCandidate
;
1646 return sBestCandidate
;
1652 geometry::IntegerSize2D
PresenterSlideSorter::MouseOverManager::CalculateLabelSize (
1653 const OUString
& rsText
) const
1655 // Height is specified by the label bitmaps.
1656 sal_Int32
nHeight (32);
1657 if (mpCenterLabelBitmap
.get() != nullptr)
1659 Reference
<rendering::XBitmap
> xBitmap (mpCenterLabelBitmap
->GetNormalBitmap());
1661 nHeight
= xBitmap
->getSize().Height
;
1664 // Width is specified by text width and maximal width.
1665 const geometry::RealSize2D
aTextSize (
1666 PresenterCanvasHelper::GetTextSize(mpFont
->mxFont
, rsText
));
1668 const sal_Int32
nWidth (round(aTextSize
.Width
+ 2*gnHorizontalLabelPadding
));
1670 return geometry::IntegerSize2D(nWidth
, nHeight
);
1673 void PresenterSlideSorter::MouseOverManager::PaintButtonBackground (
1674 const Reference
<rendering::XCanvas
>& rxCanvas
,
1675 const geometry::IntegerSize2D
& rSize
) const
1677 // Get the bitmaps for painting the label background.
1678 Reference
<rendering::XBitmap
> xLeftLabelBitmap
;
1679 if (mpLeftLabelBitmap
.get() != nullptr)
1680 xLeftLabelBitmap
= mpLeftLabelBitmap
->GetNormalBitmap();
1682 Reference
<rendering::XBitmap
> xCenterLabelBitmap
;
1683 if (mpCenterLabelBitmap
.get() != nullptr)
1684 xCenterLabelBitmap
= mpCenterLabelBitmap
->GetNormalBitmap();
1686 Reference
<rendering::XBitmap
> xRightLabelBitmap
;
1687 if (mpRightLabelBitmap
.get() != nullptr)
1688 xRightLabelBitmap
= mpRightLabelBitmap
->GetNormalBitmap();
1690 PresenterUIPainter::PaintHorizontalBitmapComposite (
1692 awt::Rectangle(0,0, rSize
.Width
,rSize
.Height
),
1693 awt::Rectangle(0,0, rSize
.Width
,rSize
.Height
),
1699 void PresenterSlideSorter::MouseOverManager::Invalidate()
1701 if (mpPaintManager
!= nullptr)
1702 mpPaintManager
->Invalidate(mxInvalidateTarget
, maSlideBoundingBox
, true);
1705 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
1707 PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer (
1708 const css::uno::Reference
<css::uno::XComponentContext
>& rxContext
,
1709 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
)
1720 mnRightFrameSize(0),
1721 mnBottomFrameSize(0)
1723 PresenterConfigurationAccess
aConfiguration (
1725 "/org.openoffice.Office.PresenterScreen/",
1726 PresenterConfigurationAccess::READ_ONLY
);
1727 Reference
<container::XHierarchicalNameAccess
> xBitmaps (
1728 aConfiguration
.GetConfigurationNode(
1729 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1731 if ( ! xBitmaps
.is())
1734 PresenterBitmapContainer
aContainer (
1735 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1736 std::shared_ptr
<PresenterBitmapContainer
>(),
1740 mpTopLeft
= aContainer
.GetBitmap("TopLeft");
1741 mpTop
= aContainer
.GetBitmap("Top");
1742 mpTopRight
= aContainer
.GetBitmap("TopRight");
1743 mpLeft
= aContainer
.GetBitmap("Left");
1744 mpRight
= aContainer
.GetBitmap("Right");
1745 mpBottomLeft
= aContainer
.GetBitmap("BottomLeft");
1746 mpBottom
= aContainer
.GetBitmap("Bottom");
1747 mpBottomRight
= aContainer
.GetBitmap("BottomRight");
1749 // Determine size of frame.
1750 if (mpTop
.get() != nullptr)
1751 mnTopFrameSize
= mpTop
->mnHeight
;
1752 if (mpLeft
.get() != nullptr)
1753 mnLeftFrameSize
= mpLeft
->mnWidth
;
1754 if (mpRight
.get() != nullptr)
1755 mnRightFrameSize
= mpRight
->mnWidth
;
1756 if (mpBottom
.get() != nullptr)
1757 mnBottomFrameSize
= mpBottom
->mnHeight
;
1759 if (mpTopLeft
.get() != nullptr)
1761 mnTopFrameSize
= ::std::max(mnTopFrameSize
, mpTopLeft
->mnHeight
);
1762 mnLeftFrameSize
= ::std::max(mnLeftFrameSize
, mpTopLeft
->mnWidth
);
1764 if (mpTopRight
.get() != nullptr)
1766 mnTopFrameSize
= ::std::max(mnTopFrameSize
, mpTopRight
->mnHeight
);
1767 mnRightFrameSize
= ::std::max(mnRightFrameSize
, mpTopRight
->mnWidth
);
1769 if (mpBottomLeft
.get() != nullptr)
1771 mnLeftFrameSize
= ::std::max(mnLeftFrameSize
, mpBottomLeft
->mnWidth
);
1772 mnBottomFrameSize
= ::std::max(mnBottomFrameSize
, mpBottomLeft
->mnHeight
);
1774 if (mpBottomRight
.get() != nullptr)
1776 mnRightFrameSize
= ::std::max(mnRightFrameSize
, mpBottomRight
->mnWidth
);
1777 mnBottomFrameSize
= ::std::max(mnBottomFrameSize
, mpBottomRight
->mnHeight
);
1781 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame (
1782 const awt::Rectangle
& rSlideBoundingBox
,
1783 const Reference
<rendering::XCanvas
>& rxCanvas
,
1784 const geometry::RealRectangle2D
& rClipBox
)
1786 if ( ! rxCanvas
.is())
1789 const Reference
<rendering::XPolyPolygon2D
> xClip (
1790 PresenterGeometryHelper::CreatePolygon(rClipBox
, rxCanvas
->getDevice()));
1792 if (mpTop
.get() != nullptr)
1795 mpTop
->GetNormalBitmap(),
1798 rSlideBoundingBox
.X
,
1799 rSlideBoundingBox
.Y
- mpTop
->mnHeight
,
1800 rSlideBoundingBox
.Width
,
1803 if (mpLeft
.get() != nullptr)
1806 mpLeft
->GetNormalBitmap(),
1809 rSlideBoundingBox
.X
- mpLeft
->mnWidth
,
1810 rSlideBoundingBox
.Y
,
1812 rSlideBoundingBox
.Height
);
1814 if (mpRight
.get() != nullptr)
1817 mpRight
->GetNormalBitmap(),
1820 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1821 rSlideBoundingBox
.Y
,
1823 rSlideBoundingBox
.Height
);
1825 if (mpBottom
.get() != nullptr)
1828 mpBottom
->GetNormalBitmap(),
1831 rSlideBoundingBox
.X
,
1832 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
,
1833 rSlideBoundingBox
.Width
,
1834 mpBottom
->mnHeight
);
1836 if (mpTopLeft
.get() != nullptr)
1839 mpTopLeft
->GetNormalBitmap(),
1842 rSlideBoundingBox
.X
- mpTopLeft
->mnWidth
,
1843 rSlideBoundingBox
.Y
- mpTopLeft
->mnHeight
);
1845 if (mpTopRight
.get() != nullptr)
1848 mpTopRight
->GetNormalBitmap(),
1851 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1852 rSlideBoundingBox
.Y
- mpTopLeft
->mnHeight
);
1854 if (mpBottomLeft
.get() != nullptr)
1857 mpBottomLeft
->GetNormalBitmap(),
1860 rSlideBoundingBox
.X
- mpBottomLeft
->mnWidth
,
1861 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
);
1863 if (mpBottomRight
.get() != nullptr)
1866 mpBottomRight
->GetNormalBitmap(),
1869 rSlideBoundingBox
.X
+ rSlideBoundingBox
.Width
,
1870 rSlideBoundingBox
.Y
+ rSlideBoundingBox
.Height
);
1874 awt::Rectangle
PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox (
1875 const awt::Rectangle
& rSlideBoundingBox
)
1877 return awt::Rectangle(
1878 rSlideBoundingBox
.X
- mnLeftFrameSize
,
1879 rSlideBoundingBox
.Y
- mnTopFrameSize
,
1880 rSlideBoundingBox
.Width
+ mnLeftFrameSize
+ mnRightFrameSize
,
1881 rSlideBoundingBox
.Height
+ mnTopFrameSize
+ mnBottomFrameSize
);
1884 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapOnce(
1885 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
1886 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
1887 const Reference
<rendering::XPolyPolygon2D
>& rxClip
,
1891 OSL_ASSERT(rxCanvas
.is());
1892 if ( ! rxBitmap
.is())
1895 const rendering::ViewState
aViewState(
1896 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1899 const rendering::RenderState
aRenderState (
1900 geometry::AffineMatrix2D(
1904 Sequence
<double>(4),
1905 rendering::CompositeOperation::SOURCE
);
1907 rxCanvas
->drawBitmap(
1913 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled(
1914 const css::uno::Reference
<css::rendering::XBitmap
>& rxBitmap
,
1915 const css::uno::Reference
<css::rendering::XCanvas
>& rxCanvas
,
1916 const geometry::RealRectangle2D
& rClipBox
,
1919 const double nWidth
,
1920 const double nHeight
)
1922 OSL_ASSERT(rxCanvas
.is());
1923 if ( ! rxBitmap
.is())
1926 geometry::IntegerSize2D
aSize (rxBitmap
->getSize());
1928 const rendering::ViewState
aViewState(
1929 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1930 PresenterGeometryHelper::CreatePolygon(
1931 PresenterGeometryHelper::Intersection(
1933 geometry::RealRectangle2D(nX0
,nY0
,nX0
+nWidth
,nY0
+nHeight
)),
1934 rxCanvas
->getDevice()));
1936 rendering::RenderState
aRenderState (
1937 geometry::AffineMatrix2D(
1941 Sequence
<double>(4),
1942 rendering::CompositeOperation::SOURCE
);
1944 const double nX1
= nX0
+ nWidth
;
1945 const double nY1
= nY0
+ nHeight
;
1946 for (double nY
=nY0
; nY
<nY1
; nY
+=aSize
.Height
)
1947 for (double nX
=nX0
; nX
<nX1
; nX
+=aSize
.Width
)
1949 aRenderState
.AffineTransform
.m02
= nX
;
1950 aRenderState
.AffineTransform
.m12
= nY
;
1951 rxCanvas
->drawBitmap(
1958 } } // end of namespace ::sdext::presenter
1960 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */