update credits
[LibreOffice.git] / sdext / source / presenter / PresenterSlideSorter.cxx
blobc06c0dfd79ec348a5f0bc5eb9bc56e726bd42b61
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
36 #include <algorithm>
37 #include <math.h>
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::drawing::framework;
43 namespace {
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 {
66 namespace {
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
75 public:
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;
115 private:
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
127 public:
128 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;
136 void Paint (
137 const sal_Int32 nSlideIndex,
138 const Reference<rendering::XCanvas>& rxCanvas,
139 const Reference<rendering::XPolyPolygon2D>& rxClip);
141 void SetSlide (
142 const sal_Int32 nSlideIndex,
143 const awt::Rectangle& rBox);
145 private:
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;
154 OUString msText;
155 Reference<rendering::XBitmap> mxBitmap;
156 Reference<awt::XWindow> mxInvalidateTarget;
157 std::shared_ptr<PresenterPaintManager> mpPaintManager;
159 void SetCanvas (
160 const Reference<rendering::XCanvas>& rxCanvas);
161 /** Create a bitmap that shows the given text and is not wider than the
162 given maximal width.
164 Reference<rendering::XBitmap> CreateBitmap (
165 const OUString& rsText,
166 const sal_Int32 nMaximalWidth) const;
167 void Invalidate();
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
180 public:
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);
195 private:
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,
213 const double nX,
214 const double nY);
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,
219 const double nX,
220 const double nY,
221 const double nWidth,
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),
234 mxViewId(rxViewId),
235 mxPane(),
236 mxCanvas(),
237 mxWindow(),
238 mpPresenterController(rpPresenterController),
239 mxSlideShowController(mpPresenterController->GetSlideShowController()),
240 mxPreviewCache(),
241 mbIsLayoutPending(true),
242 mpLayout(),
243 mpVerticalScrollBar(),
244 mpCloseButton(),
245 mpMouseOverManager(),
246 mnSlideIndexMousePressed(-1),
247 mnCurrentSlideIndex(-1),
248 mnSeparatorY(0),
249 maSeparatorColor(0x00ffffff),
250 maCurrentSlideFrameBoundingBox(),
251 mpCurrentSlideFrameRenderer(),
252 mxPreviewFrame()
254 if ( ! rxContext.is()
255 || ! rxViewId.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(
290 rxContext,
291 mxWindow,
292 mpPresenterController->GetPaintManager(),
293 [this] (double const offset) { return this->SetVerticalOffset(offset); }));
295 mpCloseButton = PresenterButton::Create(
296 rxContext,
297 mpPresenterController,
298 mpPresenterController->GetTheme(),
299 mxWindow,
300 mxCanvas,
301 "SlideSorterCloser");
303 if (mpPresenterController->GetTheme() != nullptr)
305 PresenterTheme::SharedFontDescriptor pFont (
306 mpPresenterController->GetTheme()->GetFont("ButtonFont"));
307 if (pFont)
308 maSeparatorColor = pFont->mnColor;
311 // Create the layout.
312 mpLayout = std::make_shared<Layout>(mpVerticalScrollBar);
314 // Create the preview cache.
315 mxPreviewCache.set(
316 xFactory->createInstanceWithContext(
317 "com.sun.star.drawing.PresenterPreviewCache",
318 mxComponentContext),
319 UNO_QUERY_THROW);
320 Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY);
321 mxPreviewCache->setDocumentSlides(xSlides, rxController->getModel());
322 mxPreviewCache->addPreviewCreationNotifyListener(this);
323 if (xSlides.is())
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(),
332 mxWindow,
333 mpPresenterController->GetPaintManager()));
335 // Listen for changes of the current slide.
336 Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW);
337 xControllerProperties->addPropertyChangeListener(
338 "CurrentPage",
339 this);
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&)
348 disposing();
349 throw;
353 PresenterSlideSorter::~PresenterSlideSorter()
357 void SAL_CALL PresenterSlideSorter::disposing()
359 mxComponentContext = nullptr;
360 mxViewId = nullptr;
361 mxPane = nullptr;
363 if (mpVerticalScrollBar.is())
365 Reference<lang::XComponent> xComponent (
366 static_cast<XWeak*>(mpVerticalScrollBar.get()), UNO_QUERY);
367 mpVerticalScrollBar = nullptr;
368 if (xComponent.is())
369 xComponent->dispose();
371 if (mpCloseButton.is())
373 Reference<lang::XComponent> xComponent (
374 static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
375 mpCloseButton = nullptr;
376 if (xComponent.is())
377 xComponent->dispose();
380 if (mxCanvas.is())
382 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
383 if (xComponent.is())
384 xComponent->removeEventListener(static_cast<awt::XWindowListener*>(this));
385 mxCanvas = nullptr;
387 mpPresenterController = nullptr;
388 mxSlideShowController = nullptr;
389 mpLayout.reset();
390 mpMouseOverManager.reset();
392 if (mxPreviewCache.is())
394 mxPreviewCache->removePreviewCreationNotifyListener(this);
396 Reference<XComponent> xComponent (mxPreviewCache, UNO_QUERY);
397 mxPreviewCache = nullptr;
398 if (xComponent.is())
399 xComponent->dispose();
402 if (mxWindow.is())
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)
417 mxWindow = nullptr;
418 dispose();
420 else if (rEventObject.Source == mxPreviewCache)
422 mxPreviewCache = nullptr;
423 dispose();
425 else if (rEventObject.Source == mxCanvas)
427 mxCanvas = nullptr;
428 mbIsLayoutPending = true;
430 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
434 //----- XWindowListener -------------------------------------------------------
436 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent&)
438 ThrowIfDisposed();
439 mbIsLayoutPending = true;
440 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
443 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent&)
445 ThrowIfDisposed();
448 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject&)
450 ThrowIfDisposed();
451 mbIsLayoutPending = true;
452 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
455 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject&)
457 ThrowIfDisposed();
460 //----- XPaintListener --------------------------------------------------------
462 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
464 // Deactivated views must not be painted.
465 if ( ! mbIsPresenterViewActive)
466 return;
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)
501 return;
503 switch (rEvent.ClickCount)
505 case 1:
506 default:
507 GotoSlide(nSlideIndex);
508 break;
510 case 2:
511 OSL_ASSERT(mpPresenterController);
512 OSL_ASSERT(mpPresenterController->GetWindowManager());
513 mpPresenterController->GetWindowManager()->SetSlideSorterState(false);
514 GotoSlide(nSlideIndex);
515 break;
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)
533 return;
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));
544 if (nSlideIndex < 0)
546 mnSlideIndexMousePressed = -1;
547 mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
549 else
551 mpMouseOverManager->SetSlide(
552 nSlideIndex,
553 mpLayout->GetBoundingBox(nSlideIndex));
557 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent&) {}
559 //----- XResourceId -----------------------------------------------------------
561 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId()
563 ThrowIfDisposed();
564 return mxViewId;
567 sal_Bool SAL_CALL PresenterSlideSorter::isAnchorOnly()
569 return false;
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>&)
593 ThrowIfDisposed();
594 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
596 if (!mxSlideShowController.is())
597 return;
599 const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
600 if (nNewCurrentSlideIndex == mnCurrentSlideIndex)
601 return;
603 mnCurrentSlideIndex = nNewCurrentSlideIndex;
605 // Request a repaint of the previous current slide to hide its
606 // current slide indicator.
607 mpPresenterController->GetPaintManager()->Invalidate(
608 mxWindow,
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(
616 mxWindow,
617 maCurrentSlideFrameBoundingBox);
620 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage()
622 ThrowIfDisposed();
623 return nullptr;
627 void PresenterSlideSorter::UpdateLayout()
629 if ( ! mxWindow.is())
630 return;
632 mbIsLayoutPending = false;
634 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
635 sal_Int32 nLeftBorderWidth (aWindowBox.X);
637 // Get border width.
638 PresenterPaneContainer::SharedPaneDescriptor pPane (
639 mpPresenterController->GetPaneContainer()->FindViewURL(
640 mxViewId->getResourceURL()));
643 if (!pPane)
644 break;
645 if ( ! pPane->mxPane.is())
646 break;
648 Reference<drawing::framework::XPaneBorderPainter> xBorderPainter (
649 pPane->mxPane->GetPaneBorderPainter());
650 if ( ! xBorderPainter.is())
651 break;
652 xBorderPainter->addBorder (
653 mxViewId->getAnchor()->getResourceURL(),
654 awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height),
655 drawing::framework::BorderType_INNER_BORDER);
657 while(false);
659 // Place vertical separator.
660 mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
662 PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
664 geometry::RealRectangle2D aUpperBox(
665 gnHorizontalBorder,
666 gnVerticalBorder,
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(
701 rUpperBox.X1,
702 rUpperBox.Y1,
703 rUpperBox.X1 + mpVerticalScrollBar->GetSize(),
704 rUpperBox.Y2));
705 mpVerticalScrollBar->SetVisible(true);
706 // Reduce area covered by the scroll bar from the available
707 // space.
708 return geometry::RealRectangle2D(
709 rUpperBox.X1 + gnHorizontalGap + mpVerticalScrollBar->GetSize(),
710 rUpperBox.Y1,
711 rUpperBox.X2,
712 rUpperBox.Y2);
714 else
716 // if it's not RTL place vertical scroll bar at right border.
717 mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
718 rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
719 rUpperBox.Y1,
720 rUpperBox.X2,
721 rUpperBox.Y2));
722 mpVerticalScrollBar->SetVisible(true);
723 // Reduce area covered by the scroll bar from the available
724 // space.
725 return geometry::RealRectangle2D(
726 rUpperBox.X1,
727 rUpperBox.Y1,
728 rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
729 rUpperBox.Y2);
732 else
733 mpVerticalScrollBar->SetVisible(false);
735 return rUpperBox;
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
745 // the whole window.
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;
759 else
760 nCloseButtonCenter = nCalloutCenter;
763 mpCloseButton->SetCenter(geometry::RealPoint2D(
764 nCloseButtonCenter,
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()),
777 rxCanvas,
778 rUpdateBox,
779 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
780 awt::Rectangle());
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)
797 && nHeight > 0)
799 nSlideAspectRatio = double(nWidth) / double(nHeight);
803 catch (RuntimeException&)
805 OSL_ASSERT(false);
808 return nSlideAspectRatio;
811 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
813 if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount)
814 return nullptr;
815 else if (mxPane.is())
816 return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas());
817 else
818 return nullptr;
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(
831 rUpdateBox,
832 mpLayout->GetBoundingBox(nSlideIndex)))
834 return;
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>(),
847 mxComponentContext,
848 rxCanvas);
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),
861 aBoundingBox));
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(
869 1, 0, aTopLeft.X,
870 0, 1, aTopLeft.Y),
871 nullptr,
872 Sequence<double>(4),
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),
883 aSize.Width,
884 aSize.Height);
885 maCurrentSlideFrameBoundingBox
886 = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
887 mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
888 aSlideBoundingBox,
889 mxCanvas,
890 aClipBox);
894 // Paint the preview.
895 if (xPreview.is())
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),
910 nullptr,
911 Sequence<double>(4),
912 rendering::CompositeOperation::SOURCE);
913 rxCanvas->drawBitmap(xAnimationIcon, aViewState, aAnimationRenderState);
915 if( bTransition )
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),
924 nullptr,
925 Sequence<double>(4),
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())
955 return;
957 if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
959 OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
960 return;
963 ClearBackground(mxCanvas, rUpdateBox);
965 // Give the canvas to the controls.
966 if (bCanvasChanged)
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)
976 UpdateLayout();
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);
982 mxCanvas->drawLine(
983 geometry::RealPoint2D(0, mnSeparatorY),
984 geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY),
985 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
986 aRenderState);
988 // Paint the slides.
989 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
990 rUpdateBox,
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())
1037 if (mxPane.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)
1066 : maBoundingBox(),
1067 maPreviewSize(),
1068 mnHorizontalOffset(0),
1069 mnVerticalOffset(0),
1070 mnHorizontalGap(0),
1071 mnVerticalGap(0),
1072 mnHorizontalBorder(0),
1073 mnVerticalBorder(0),
1074 mnRowCount(1),
1075 mnColumnCount(1),
1076 mnSlideCount(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)
1097 return;
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)
1112 // Yes.
1113 nPreviewWidth = gnPreferredPreviewWidth;
1114 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1115 / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1116 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1118 else
1120 // No. Set the column count to 1 and adapt preview width and
1121 // gap.
1122 mnColumnCount = 1;
1123 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1124 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1125 nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap;
1126 else
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);
1138 else
1140 // The preferred column count is possible. Determine gap and
1141 // preview width.
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;
1155 else
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(
1166 sal_Int32(1),
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)
1178 / 2);
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);
1210 else
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);
1227 else
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)
1242 return nColumn;
1244 else
1245 return -1;
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))
1257 return nRow;
1259 else
1260 return -1;
1263 sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1264 const css::geometry::RealPoint2D& rWindowPoint) const
1266 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1267 return -1;
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)
1274 return -1;
1275 else
1277 sal_Int32 nIndex (GetIndex(nRow, nColumn));
1278 if (nIndex >= mnSlideCount)
1279 return -1;
1280 else
1281 return nIndex;
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;
1301 else
1302 aPosition.X += maPreviewSize.Width / 2.0;
1304 if (nRelativeVerticalPosition >= 0)
1306 if (nRelativeVerticalPosition > 0)
1307 aPosition.Y += maPreviewSize.Height;
1308 else
1309 aPosition.Y += maPreviewSize.Height / 2.0;
1312 return aPosition;
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(
1321 aWindowPosition.X,
1322 aWindowPosition.Y,
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)
1336 return;
1337 rAction(nSlideIndex);
1342 sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex() const
1344 return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1347 sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex() const
1349 return ::std::min(
1350 GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1351 mnSlideCount);
1354 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset)
1356 if (mnHorizontalOffset != nOffset)
1358 mnHorizontalOffset = round(nOffset);
1359 SetupVisibleArea();
1360 UpdateScrollBars();
1361 return true;
1363 else
1364 return false;
1367 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset)
1369 if (mnVerticalOffset != nOffset)
1371 mnVerticalOffset = round(nOffset);
1372 SetupVisibleArea();
1373 UpdateScrollBars();
1374 return true;
1376 else
1377 return false;
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
1389 + 2*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)
1422 : mxCanvas(),
1423 mxSlides(rxSlides),
1424 mpLeftLabelBitmap(),
1425 mpCenterLabelBitmap(),
1426 mpRightLabelBitmap(),
1427 mpFont(),
1428 mnSlideIndex(-1),
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)
1453 return;
1455 if (mxCanvas != rxCanvas)
1456 SetCanvas(rxCanvas);
1457 if (rxCanvas == nullptr)
1458 return;
1460 if ( ! mxBitmap.is())
1461 mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1462 if (!mxBitmap.is())
1463 return;
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(
1471 mxBitmap,
1472 rendering::ViewState(
1473 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1474 rxClip),
1475 rendering::RenderState(
1476 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1477 nullptr,
1478 Sequence<double>(4),
1479 rendering::CompositeOperation::SOURCE));
1482 void PresenterSlideSorter::MouseOverManager::SetCanvas (
1483 const Reference<rendering::XCanvas>& rxCanvas)
1485 mxCanvas = rxCanvas;
1486 if (mpFont)
1487 mpFont->PrepareFont(mxCanvas);
1490 void PresenterSlideSorter::MouseOverManager::SetSlide (
1491 const sal_Int32 nSlideIndex,
1492 const awt::Rectangle& rBox)
1494 if (mnSlideIndex == nSlideIndex)
1495 return;
1497 mnSlideIndex = -1;
1498 Invalidate();
1500 maSlideBoundingBox = rBox;
1501 mnSlideIndex = nSlideIndex;
1503 if (nSlideIndex >= 0)
1505 if (mxSlides)
1507 msText.clear();
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);
1517 else
1519 msText.clear();
1521 mxBitmap = nullptr;
1523 Invalidate();
1526 Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1527 const OUString& rsText,
1528 const sal_Int32 nMaximalWidth) const
1530 if ( ! mxCanvas.is())
1531 return nullptr;
1533 if (!mpFont || !mpFont->mxFont.is())
1534 return nullptr;
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
1543 // by the text.
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())
1551 return nullptr;
1553 Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1554 if ( ! xBitmapCanvas.is())
1555 return nullptr;
1557 // Paint the background.
1558 PaintButtonBackground(xBitmapCanvas, aLabelSize);
1560 // Paint the text.
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),
1575 nullptr);
1577 rendering::RenderState aRenderState (
1578 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1579 nullptr,
1580 Sequence<double>(4),
1581 rendering::CompositeOperation::SOURCE);
1582 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1584 xBitmapCanvas->drawTextLayout (
1585 xLayout,
1586 aViewState,
1587 aRenderState);
1590 return xBitmap;
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"...");
1609 while (true)
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.
1617 nLength -= 1;
1618 if (nLength <= 0)
1619 break;
1621 else if (nWidth < nMaximalWidth)
1623 // Candidate short enough.
1624 if (nWidth > nBestWidth)
1626 // Best length so far.
1627 sBestCandidate = sCandidate;
1628 nBestWidth = nWidth;
1629 nLength += 1;
1630 if (nLength >= rsText.getLength())
1631 break;
1633 else
1634 break;
1636 else
1638 // Candidate is exactly as long as it may be. Use it
1639 // without looking any further.
1640 sBestCandidate = sCandidate;
1641 break;
1644 return sBestCandidate;
1646 else
1647 return rsText;
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());
1658 if (xBitmap.is())
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 (
1689 rxCanvas,
1690 awt::Rectangle(0,0, rSize.Width,rSize.Height),
1691 awt::Rectangle(0,0, rSize.Width,rSize.Height),
1692 xLeftLabelBitmap,
1693 xCenterLabelBitmap,
1694 xRightLabelBitmap);
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)
1708 : mpTopLeft(),
1709 mpTop(),
1710 mpTopRight(),
1711 mpLeft(),
1712 mpRight(),
1713 mpBottomLeft(),
1714 mpBottom(),
1715 mpBottomRight(),
1716 mnTopFrameSize(0),
1717 mnLeftFrameSize(0),
1718 mnRightFrameSize(0),
1719 mnBottomFrameSize(0)
1721 PresenterConfigurationAccess aConfiguration (
1722 rxContext,
1723 "/org.openoffice.Office.PresenterScreen/",
1724 PresenterConfigurationAccess::READ_ONLY);
1725 Reference<container::XHierarchicalNameAccess> xBitmaps (
1726 aConfiguration.GetConfigurationNode(
1727 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1728 UNO_QUERY);
1729 if ( ! xBitmaps.is())
1730 return;
1732 PresenterBitmapContainer aContainer (
1733 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1734 std::shared_ptr<PresenterBitmapContainer>(),
1735 rxContext,
1736 rxCanvas);
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.
1748 if (mpTop)
1749 mnTopFrameSize = mpTop->mnHeight;
1750 if (mpLeft)
1751 mnLeftFrameSize = mpLeft->mnWidth;
1752 if (mpRight)
1753 mnRightFrameSize = mpRight->mnWidth;
1754 if (mpBottom)
1755 mnBottomFrameSize = mpBottom->mnHeight;
1757 if (mpTopLeft)
1759 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight);
1760 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth);
1762 if (mpTopRight)
1764 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight);
1765 mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth);
1767 if (mpBottomLeft)
1769 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth);
1770 mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight);
1772 if (mpBottomRight)
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())
1785 return;
1787 const Reference<rendering::XPolyPolygon2D> xClip (
1788 PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
1790 if (mpTop)
1792 PaintBitmapTiled(
1793 mpTop->GetNormalBitmap(),
1794 rxCanvas,
1795 rClipBox,
1796 rSlideBoundingBox.X,
1797 rSlideBoundingBox.Y - mpTop->mnHeight,
1798 rSlideBoundingBox.Width,
1799 mpTop->mnHeight);
1801 if (mpLeft)
1803 PaintBitmapTiled(
1804 mpLeft->GetNormalBitmap(),
1805 rxCanvas,
1806 rClipBox,
1807 rSlideBoundingBox.X - mpLeft->mnWidth,
1808 rSlideBoundingBox.Y,
1809 mpLeft->mnWidth,
1810 rSlideBoundingBox.Height);
1812 if (mpRight)
1814 PaintBitmapTiled(
1815 mpRight->GetNormalBitmap(),
1816 rxCanvas,
1817 rClipBox,
1818 rSlideBoundingBox.X + rSlideBoundingBox.Width,
1819 rSlideBoundingBox.Y,
1820 mpRight->mnWidth,
1821 rSlideBoundingBox.Height);
1823 if (mpBottom)
1825 PaintBitmapTiled(
1826 mpBottom->GetNormalBitmap(),
1827 rxCanvas,
1828 rClipBox,
1829 rSlideBoundingBox.X,
1830 rSlideBoundingBox.Y + rSlideBoundingBox.Height,
1831 rSlideBoundingBox.Width,
1832 mpBottom->mnHeight);
1834 if (mpTopLeft)
1836 PaintBitmapOnce(
1837 mpTopLeft->GetNormalBitmap(),
1838 rxCanvas,
1839 xClip,
1840 rSlideBoundingBox.X - mpTopLeft->mnWidth,
1841 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1843 if (mpTopRight)
1845 PaintBitmapOnce(
1846 mpTopRight->GetNormalBitmap(),
1847 rxCanvas,
1848 xClip,
1849 rSlideBoundingBox.X + rSlideBoundingBox.Width,
1850 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1852 if (mpBottomLeft)
1854 PaintBitmapOnce(
1855 mpBottomLeft->GetNormalBitmap(),
1856 rxCanvas,
1857 xClip,
1858 rSlideBoundingBox.X - mpBottomLeft->mnWidth,
1859 rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1861 if (mpBottomRight)
1863 PaintBitmapOnce(
1864 mpBottomRight->GetNormalBitmap(),
1865 rxCanvas,
1866 xClip,
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,
1886 const double nX,
1887 const double nY)
1889 OSL_ASSERT(rxCanvas.is());
1890 if ( ! rxBitmap.is())
1891 return;
1893 const rendering::ViewState aViewState(
1894 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1895 rxClip);
1897 const rendering::RenderState aRenderState (
1898 geometry::AffineMatrix2D(
1899 1, 0, nX,
1900 0, 1, nY),
1901 nullptr,
1902 Sequence<double>(4),
1903 rendering::CompositeOperation::SOURCE);
1905 rxCanvas->drawBitmap(
1906 rxBitmap,
1907 aViewState,
1908 aRenderState);
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,
1915 const double nX0,
1916 const double nY0,
1917 const double nWidth,
1918 const double nHeight)
1920 OSL_ASSERT(rxCanvas.is());
1921 if ( ! rxBitmap.is())
1922 return;
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(
1930 rClipBox,
1931 geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
1932 rxCanvas->getDevice()));
1934 rendering::RenderState aRenderState (
1935 geometry::AffineMatrix2D(
1936 1, 0, nX0,
1937 0, 1, nY0),
1938 nullptr,
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(
1950 rxBitmap,
1951 aViewState,
1952 aRenderState);
1956 } // end of namespace ::sdext::presenter
1958 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */