vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / presenter / PresenterSlideSorter.cxx
blob82c9bf8dbf81dc506cded425acf4a09f7f4b78ba
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 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 {
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.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(
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.get() != nullptr)
308 maSeparatorColor = pFont->mnColor;
311 // Create the layout.
312 mpLayout.reset(new 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.get()!=nullptr);
512 OSL_ASSERT(mpPresenterController->GetWindowManager().get()!=nullptr);
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)
545 mnSlideIndexMousePressed = -1;
547 if (nSlideIndex < 0)
549 mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
551 else
553 mpMouseOverManager->SetSlide(
554 nSlideIndex,
555 mpLayout->GetBoundingBox(nSlideIndex));
559 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent&) {}
561 //----- XResourceId -----------------------------------------------------------
563 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId()
565 ThrowIfDisposed();
566 return mxViewId;
569 sal_Bool SAL_CALL PresenterSlideSorter::isAnchorOnly()
571 return false;
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>&)
595 ThrowIfDisposed();
596 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
598 if (!mxSlideShowController.is())
599 return;
601 const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
602 if (nNewCurrentSlideIndex == mnCurrentSlideIndex)
603 return;
605 mnCurrentSlideIndex = nNewCurrentSlideIndex;
607 // Request a repaint of the previous current slide to hide its
608 // current slide indicator.
609 mpPresenterController->GetPaintManager()->Invalidate(
610 mxWindow,
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(
618 mxWindow,
619 maCurrentSlideFrameBoundingBox);
622 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage()
624 ThrowIfDisposed();
625 return nullptr;
629 void PresenterSlideSorter::UpdateLayout()
631 if ( ! mxWindow.is())
632 return;
634 mbIsLayoutPending = false;
636 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
637 sal_Int32 nLeftBorderWidth (aWindowBox.X);
639 // Get border width.
640 PresenterPaneContainer::SharedPaneDescriptor pPane (
641 mpPresenterController->GetPaneContainer()->FindViewURL(
642 mxViewId->getResourceURL()));
645 if (pPane.get() == nullptr)
646 break;
647 if ( ! pPane->mxPane.is())
648 break;
650 Reference<drawing::framework::XPaneBorderPainter> xBorderPainter (
651 pPane->mxPane->GetPaneBorderPainter());
652 if ( ! xBorderPainter.is())
653 break;
654 xBorderPainter->addBorder (
655 mxViewId->getAnchor()->getResourceURL(),
656 awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height),
657 drawing::framework::BorderType_INNER_BORDER);
659 while(false);
661 // Place vertical separator.
662 mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
664 PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
666 geometry::RealRectangle2D aUpperBox(
667 gnHorizontalBorder,
668 gnVerticalBorder,
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(
703 rUpperBox.X1,
704 rUpperBox.Y1,
705 rUpperBox.X1 + mpVerticalScrollBar->GetSize(),
706 rUpperBox.Y2));
707 mpVerticalScrollBar->SetVisible(true);
708 // Reduce area covered by the scroll bar from the available
709 // space.
710 return geometry::RealRectangle2D(
711 rUpperBox.X1 + gnHorizontalGap + mpVerticalScrollBar->GetSize(),
712 rUpperBox.Y1,
713 rUpperBox.X2,
714 rUpperBox.Y2);
716 else
718 // if it's not RTL place vertical scroll bar at right border.
719 mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
720 rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
721 rUpperBox.Y1,
722 rUpperBox.X2,
723 rUpperBox.Y2));
724 mpVerticalScrollBar->SetVisible(true);
725 // Reduce area covered by the scroll bar from the available
726 // space.
727 return geometry::RealRectangle2D(
728 rUpperBox.X1,
729 rUpperBox.Y1,
730 rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
731 rUpperBox.Y2);
734 else
735 mpVerticalScrollBar->SetVisible(false);
737 return rUpperBox;
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
747 // the whole window.
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;
761 else
762 nCloseButtonCenter = nCalloutCenter;
765 mpCloseButton->SetCenter(geometry::RealPoint2D(
766 nCloseButtonCenter,
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()),
779 rxCanvas,
780 rUpdateBox,
781 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
782 awt::Rectangle());
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)
799 && nHeight > 0)
801 nSlideAspectRatio = double(nWidth) / double(nHeight);
805 catch (RuntimeException&)
807 OSL_ASSERT(false);
810 return nSlideAspectRatio;
813 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
815 if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount)
816 return nullptr;
817 else if (mxPane.is())
818 return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas());
819 else
820 return nullptr;
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(
833 rUpdateBox,
834 mpLayout->GetBoundingBox(nSlideIndex)))
836 return;
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>(),
849 mxComponentContext,
850 rxCanvas);
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),
863 aBoundingBox));
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(
871 1, 0, aTopLeft.X,
872 0, 1, aTopLeft.Y),
873 nullptr,
874 Sequence<double>(4),
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),
885 aSize.Width,
886 aSize.Height);
887 maCurrentSlideFrameBoundingBox
888 = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
889 mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
890 aSlideBoundingBox,
891 mxCanvas,
892 aClipBox);
896 // Paint the preview.
897 if (xPreview.is())
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),
912 nullptr,
913 Sequence<double>(4),
914 rendering::CompositeOperation::SOURCE);
915 rxCanvas->drawBitmap(xAnimationIcon, aViewState, aAnimationRenderState);
917 if( bTransition )
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),
926 nullptr,
927 Sequence<double>(4),
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())
957 return;
959 if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
961 OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
962 return;
965 ClearBackground(mxCanvas, rUpdateBox);
967 // Give the canvas to the controls.
968 if (bCanvasChanged)
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)
978 UpdateLayout();
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);
984 mxCanvas->drawLine(
985 geometry::RealPoint2D(0, mnSeparatorY),
986 geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY),
987 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
988 aRenderState);
990 // Paint the slides.
991 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
992 rUpdateBox,
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())
1039 if (mxPane.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)
1068 : maBoundingBox(),
1069 maPreviewSize(),
1070 mnHorizontalOffset(0),
1071 mnVerticalOffset(0),
1072 mnHorizontalGap(0),
1073 mnVerticalGap(0),
1074 mnHorizontalBorder(0),
1075 mnVerticalBorder(0),
1076 mnRowCount(1),
1077 mnColumnCount(1),
1078 mnSlideCount(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)
1099 return;
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)
1114 // Yes.
1115 nPreviewWidth = gnPreferredPreviewWidth;
1116 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1117 / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1118 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1120 else
1122 // No. Set the column count to 1 and adapt preview width and
1123 // gap.
1124 mnColumnCount = 1;
1125 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1126 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1127 nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap;
1128 else
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);
1140 else
1142 // The preferred column count is possible. Determine gap and
1143 // preview width.
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;
1157 else
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(
1168 sal_Int32(1),
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)
1180 / 2);
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);
1212 else
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);
1229 else
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)
1244 return nColumn;
1246 else
1247 return -1;
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))
1259 return nRow;
1261 else
1262 return -1;
1265 sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1266 const css::geometry::RealPoint2D& rWindowPoint) const
1268 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1269 return -1;
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)
1276 return -1;
1277 else
1279 sal_Int32 nIndex (GetIndex(nRow, nColumn));
1280 if (nIndex >= mnSlideCount)
1281 return -1;
1282 else
1283 return nIndex;
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;
1303 else
1304 aPosition.X += maPreviewSize.Width / 2.0;
1306 if (nRelativeVerticalPosition >= 0)
1308 if (nRelativeVerticalPosition > 0)
1309 aPosition.Y += maPreviewSize.Height;
1310 else
1311 aPosition.Y += maPreviewSize.Height / 2.0;
1314 return aPosition;
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(
1323 aWindowPosition.X,
1324 aWindowPosition.Y,
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)
1338 return;
1339 rAction(nSlideIndex);
1344 sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex() const
1346 return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1349 sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex() const
1351 return ::std::min(
1352 GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1353 mnSlideCount);
1356 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset)
1358 if (mnHorizontalOffset != nOffset)
1360 mnHorizontalOffset = round(nOffset);
1361 SetupVisibleArea();
1362 UpdateScrollBars();
1363 return true;
1365 else
1366 return false;
1369 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset)
1371 if (mnVerticalOffset != nOffset)
1373 mnVerticalOffset = round(nOffset);
1374 SetupVisibleArea();
1375 UpdateScrollBars();
1376 return true;
1378 else
1379 return false;
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
1391 + 2*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)
1424 : mxCanvas(),
1425 mxSlides(rxSlides),
1426 mpLeftLabelBitmap(),
1427 mpCenterLabelBitmap(),
1428 mpRightLabelBitmap(),
1429 mpFont(),
1430 mnSlideIndex(-1),
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)
1455 return;
1457 if (mxCanvas != rxCanvas)
1458 SetCanvas(rxCanvas);
1459 if (rxCanvas == nullptr)
1460 return;
1462 if ( ! mxBitmap.is())
1463 mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1464 if (!mxBitmap.is())
1465 return;
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(
1473 mxBitmap,
1474 rendering::ViewState(
1475 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1476 rxClip),
1477 rendering::RenderState(
1478 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1479 nullptr,
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)
1497 return;
1499 mnSlideIndex = -1;
1500 Invalidate();
1502 maSlideBoundingBox = rBox;
1503 mnSlideIndex = nSlideIndex;
1505 if (nSlideIndex >= 0)
1507 if (mxSlides.get() != nullptr)
1509 msText.clear();
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);
1519 else
1521 msText.clear();
1523 mxBitmap = nullptr;
1525 Invalidate();
1528 Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1529 const OUString& rsText,
1530 const sal_Int32 nMaximalWidth) const
1532 if ( ! mxCanvas.is())
1533 return nullptr;
1535 if (mpFont.get()==nullptr || !mpFont->mxFont.is())
1536 return nullptr;
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
1545 // by the text.
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())
1553 return nullptr;
1555 Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1556 if ( ! xBitmapCanvas.is())
1557 return nullptr;
1559 // Paint the background.
1560 PaintButtonBackground(xBitmapCanvas, aLabelSize);
1562 // Paint the text.
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),
1577 nullptr);
1579 rendering::RenderState aRenderState (
1580 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1581 nullptr,
1582 Sequence<double>(4),
1583 rendering::CompositeOperation::SOURCE);
1584 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1586 xBitmapCanvas->drawTextLayout (
1587 xLayout,
1588 aViewState,
1589 aRenderState);
1592 return xBitmap;
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 ("...");
1611 while (true)
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.
1619 nLength -= 1;
1620 if (nLength <= 0)
1621 break;
1623 else if (nWidth < nMaximalWidth)
1625 // Candidate short enough.
1626 if (nWidth > nBestWidth)
1628 // Best length so far.
1629 sBestCandidate = sCandidate;
1630 nBestWidth = nWidth;
1631 nLength += 1;
1632 if (nLength >= rsText.getLength())
1633 break;
1635 else
1636 break;
1638 else
1640 // Candidate is exactly as long as it may be. Use it
1641 // without looking any further.
1642 sBestCandidate = sCandidate;
1643 break;
1646 return sBestCandidate;
1648 else
1649 return rsText;
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());
1660 if (xBitmap.is())
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 (
1691 rxCanvas,
1692 awt::Rectangle(0,0, rSize.Width,rSize.Height),
1693 awt::Rectangle(0,0, rSize.Width,rSize.Height),
1694 xLeftLabelBitmap,
1695 xCenterLabelBitmap,
1696 xRightLabelBitmap);
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)
1710 : mpTopLeft(),
1711 mpTop(),
1712 mpTopRight(),
1713 mpLeft(),
1714 mpRight(),
1715 mpBottomLeft(),
1716 mpBottom(),
1717 mpBottomRight(),
1718 mnTopFrameSize(0),
1719 mnLeftFrameSize(0),
1720 mnRightFrameSize(0),
1721 mnBottomFrameSize(0)
1723 PresenterConfigurationAccess aConfiguration (
1724 rxContext,
1725 "/org.openoffice.Office.PresenterScreen/",
1726 PresenterConfigurationAccess::READ_ONLY);
1727 Reference<container::XHierarchicalNameAccess> xBitmaps (
1728 aConfiguration.GetConfigurationNode(
1729 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1730 UNO_QUERY);
1731 if ( ! xBitmaps.is())
1732 return;
1734 PresenterBitmapContainer aContainer (
1735 "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1736 std::shared_ptr<PresenterBitmapContainer>(),
1737 rxContext,
1738 rxCanvas);
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())
1787 return;
1789 const Reference<rendering::XPolyPolygon2D> xClip (
1790 PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
1792 if (mpTop.get() != nullptr)
1794 PaintBitmapTiled(
1795 mpTop->GetNormalBitmap(),
1796 rxCanvas,
1797 rClipBox,
1798 rSlideBoundingBox.X,
1799 rSlideBoundingBox.Y - mpTop->mnHeight,
1800 rSlideBoundingBox.Width,
1801 mpTop->mnHeight);
1803 if (mpLeft.get() != nullptr)
1805 PaintBitmapTiled(
1806 mpLeft->GetNormalBitmap(),
1807 rxCanvas,
1808 rClipBox,
1809 rSlideBoundingBox.X - mpLeft->mnWidth,
1810 rSlideBoundingBox.Y,
1811 mpLeft->mnWidth,
1812 rSlideBoundingBox.Height);
1814 if (mpRight.get() != nullptr)
1816 PaintBitmapTiled(
1817 mpRight->GetNormalBitmap(),
1818 rxCanvas,
1819 rClipBox,
1820 rSlideBoundingBox.X + rSlideBoundingBox.Width,
1821 rSlideBoundingBox.Y,
1822 mpRight->mnWidth,
1823 rSlideBoundingBox.Height);
1825 if (mpBottom.get() != nullptr)
1827 PaintBitmapTiled(
1828 mpBottom->GetNormalBitmap(),
1829 rxCanvas,
1830 rClipBox,
1831 rSlideBoundingBox.X,
1832 rSlideBoundingBox.Y + rSlideBoundingBox.Height,
1833 rSlideBoundingBox.Width,
1834 mpBottom->mnHeight);
1836 if (mpTopLeft.get() != nullptr)
1838 PaintBitmapOnce(
1839 mpTopLeft->GetNormalBitmap(),
1840 rxCanvas,
1841 xClip,
1842 rSlideBoundingBox.X - mpTopLeft->mnWidth,
1843 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1845 if (mpTopRight.get() != nullptr)
1847 PaintBitmapOnce(
1848 mpTopRight->GetNormalBitmap(),
1849 rxCanvas,
1850 xClip,
1851 rSlideBoundingBox.X + rSlideBoundingBox.Width,
1852 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1854 if (mpBottomLeft.get() != nullptr)
1856 PaintBitmapOnce(
1857 mpBottomLeft->GetNormalBitmap(),
1858 rxCanvas,
1859 xClip,
1860 rSlideBoundingBox.X - mpBottomLeft->mnWidth,
1861 rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1863 if (mpBottomRight.get() != nullptr)
1865 PaintBitmapOnce(
1866 mpBottomRight->GetNormalBitmap(),
1867 rxCanvas,
1868 xClip,
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,
1888 const double nX,
1889 const double nY)
1891 OSL_ASSERT(rxCanvas.is());
1892 if ( ! rxBitmap.is())
1893 return;
1895 const rendering::ViewState aViewState(
1896 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1897 rxClip);
1899 const rendering::RenderState aRenderState (
1900 geometry::AffineMatrix2D(
1901 1, 0, nX,
1902 0, 1, nY),
1903 nullptr,
1904 Sequence<double>(4),
1905 rendering::CompositeOperation::SOURCE);
1907 rxCanvas->drawBitmap(
1908 rxBitmap,
1909 aViewState,
1910 aRenderState);
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,
1917 const double nX0,
1918 const double nY0,
1919 const double nWidth,
1920 const double nHeight)
1922 OSL_ASSERT(rxCanvas.is());
1923 if ( ! rxBitmap.is())
1924 return;
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(
1932 rClipBox,
1933 geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
1934 rxCanvas->getDevice()));
1936 rendering::RenderState aRenderState (
1937 geometry::AffineMatrix2D(
1938 1, 0, nX0,
1939 0, 1, nY0),
1940 nullptr,
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(
1952 rxBitmap,
1953 aViewState,
1954 aRenderState);
1958 } } // end of namespace ::sdext::presenter
1960 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */