LibreOffice Module sdext (master)  1
PresenterSlideSorter.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/settings.hxx>
21 
22 #include "PresenterSlideSorter.hxx"
23 #include "PresenterButton.hxx"
27 #include "PresenterPaneBase.hxx"
28 #include "PresenterScrollBar.hxx"
29 #include "PresenterUIPainter.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>
38 
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::drawing::framework;
42 
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);
48 
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);
57 
58  const static sal_Int32 gnHorizontalLabelBorder (3);
59  const static sal_Int32 gnHorizontalLabelPadding (5);
60 
61  const static sal_Int32 gnVerticalButtonPadding (gnVerticalGap);
62 }
63 
64 namespace sdext::presenter {
65 
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); }
69 }
70 
71 //===== PresenterSlideSorter::Layout ==========================================
72 
74 {
75 public:
76  explicit Layout (const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar);
77 
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);
98 
99  css::geometry::RealRectangle2D maBoundingBox;
100  css::geometry::IntegerSize2D maPreviewSize;
102  sal_Int32 mnVerticalOffset;
103  sal_Int32 mnHorizontalGap;
104  sal_Int32 mnVerticalGap;
106  sal_Int32 mnVerticalBorder;
107  sal_Int32 mnRowCount;
108  sal_Int32 mnColumnCount;
109  sal_Int32 mnSlideCount;
112  sal_Int32 mnFirstVisibleRow;
113  sal_Int32 mnLastVisibleRow;
114 
115 private:
117 
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;
121 };
122 
123 //==== PresenterSlideSorter::MouseOverManager =================================
124 
126 {
127 public:
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;
135 
136  void Paint (
137  const sal_Int32 nSlideIndex,
138  const Reference<rendering::XCanvas>& rxCanvas,
139  const Reference<rendering::XPolyPolygon2D>& rxClip);
140 
141  void SetSlide (
142  const sal_Int32 nSlideIndex,
143  const awt::Rectangle& rBox);
144 
145 private:
146  Reference<rendering::XCanvas> mxCanvas;
147  const Reference<container::XIndexAccess> mxSlides;
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;
158 
159  void SetCanvas (
160  const Reference<rendering::XCanvas>& rxCanvas);
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;
174 };
175 
176 //==== PresenterSlideSorter::CurrentSlideFrameRenderer ========================
177 
179 {
180 public:
182  const css::uno::Reference<css::uno::XComponentContext>& rxContext,
183  const css::uno::Reference<css::rendering::XCanvas>& rxCanvas);
184 
186  const awt::Rectangle& rSlideBoundingBox,
187  const Reference<rendering::XCanvas>& rxCanvas,
188  const geometry::RealRectangle2D& rClipBox);
189 
192  awt::Rectangle GetBoundingBox (
193  const awt::Rectangle& rSlideBoundingBox);
194 
195 private:
204  sal_Int32 mnTopFrameSize;
205  sal_Int32 mnLeftFrameSize;
206  sal_Int32 mnRightFrameSize;
207  sal_Int32 mnBottomFrameSize;
208 
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);
223 };
224 
225 //===== PresenterSlideSorter ==================================================
226 
228  const Reference<uno::XComponentContext>& rxContext,
229  const Reference<XResourceId>& rxViewId,
230  const Reference<frame::XController>& rxController,
231  const ::rtl::Reference<PresenterController>& rpPresenterController)
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()
253 {
254  if ( ! rxContext.is()
255  || ! rxViewId.is()
256  || ! rxController.is()
257  || rpPresenterController.get()==nullptr)
258  {
259  throw lang::IllegalArgumentException();
260  }
261 
262  if ( ! mxSlideShowController.is())
263  throw RuntimeException();
264 
265  try
266  {
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);
273 
274  mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
275  mxWindow = mxPane->getWindow();
276 
277  // Add window listener.
278  mxWindow->addWindowListener(this);
279  mxWindow->addPaintListener(this);
280  mxWindow->addMouseListener(this);
281  mxWindow->addMouseMotionListener(this);
282  mxWindow->setVisible(true);
283 
284  // Remember the current slide.
285  mnCurrentSlideIndex = mxSlideShowController->getCurrentSlideIndex();
286 
287  // Create the scroll bar.
290  rxContext,
291  mxWindow,
292  mpPresenterController->GetPaintManager(),
293  [this] (double const offset) { return this->SetVerticalOffset(offset); }));
294 
296  rxContext,
298  mpPresenterController->GetTheme(),
299  mxWindow,
300  mxCanvas,
301  "SlideSorterCloser");
302 
303  if (mpPresenterController->GetTheme() != nullptr)
304  {
306  mpPresenterController->GetTheme()->GetFont("ButtonFont"));
307  if (pFont.get() != nullptr)
308  maSeparatorColor = pFont->mnColor;
309  }
310 
311  // Create the layout.
312  mpLayout = std::make_shared<Layout>(mpVerticalScrollBar);
313 
314  // Create the preview cache.
315  mxPreviewCache.set(
316  xFactory->createInstanceWithContext(
317  "com.sun.star.drawing.PresenterPreviewCache",
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())
324  {
325  mpLayout->mnSlideCount = xSlides->getCount();
326  }
327 
328  // Create the mouse over manager.
330  Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY),
331  mpPresenterController->GetTheme(),
332  mxWindow,
333  mpPresenterController->GetPaintManager()));
334 
335  // Listen for changes of the current slide.
336  Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW);
337  xControllerProperties->addPropertyChangeListener(
338  "CurrentPage",
339  this);
340 
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);
345  }
346  catch (RuntimeException&)
347  {
348  disposing();
349  throw;
350  }
351 }
352 
354 {
355 }
356 
358 {
359  mxComponentContext = nullptr;
360  mxViewId = nullptr;
361  mxPane = nullptr;
362 
363  if (mpVerticalScrollBar.is())
364  {
366  static_cast<XWeak*>(mpVerticalScrollBar.get()), UNO_QUERY);
367  mpVerticalScrollBar = nullptr;
368  if (xComponent.is())
369  xComponent->dispose();
370  }
371  if (mpCloseButton.is())
372  {
374  static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
375  mpCloseButton = nullptr;
376  if (xComponent.is())
377  xComponent->dispose();
378  }
379 
380  if (mxCanvas.is())
381  {
383  if (xComponent.is())
384  xComponent->removeEventListener(static_cast<awt::XWindowListener*>(this));
385  mxCanvas = nullptr;
386  }
387  mpPresenterController = nullptr;
388  mxSlideShowController = nullptr;
389  mpLayout.reset();
390  mpMouseOverManager.reset();
391 
392  if (mxPreviewCache.is())
393  {
394  mxPreviewCache->removePreviewCreationNotifyListener(this);
395 
396  Reference<XComponent> xComponent (mxPreviewCache, UNO_QUERY);
397  mxPreviewCache = nullptr;
398  if (xComponent.is())
399  xComponent->dispose();
400  }
401 
402  if (mxWindow.is())
403  {
404  mxWindow->removeWindowListener(this);
405  mxWindow->removePaintListener(this);
406  mxWindow->removeMouseListener(this);
407  mxWindow->removeMouseMotionListener(this);
408  }
409 }
410 
411 //----- lang::XEventListener --------------------------------------------------
412 
413 void SAL_CALL PresenterSlideSorter::disposing (const lang::EventObject& rEventObject)
414 {
415  if (rEventObject.Source == mxWindow)
416  {
417  mxWindow = nullptr;
418  dispose();
419  }
420  else if (rEventObject.Source == mxPreviewCache)
421  {
422  mxPreviewCache = nullptr;
423  dispose();
424  }
425  else if (rEventObject.Source == mxCanvas)
426  {
427  mxCanvas = nullptr;
428  mbIsLayoutPending = true;
429 
430  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
431  }
432 }
433 
434 //----- XWindowListener -------------------------------------------------------
435 
436 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent&)
437 {
438  ThrowIfDisposed();
439  mbIsLayoutPending = true;
440  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
441 }
442 
443 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent&)
444 {
445  ThrowIfDisposed();
446 }
447 
448 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject&)
449 {
450  ThrowIfDisposed();
451  mbIsLayoutPending = true;
452  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
453 }
454 
455 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject&)
456 {
457  ThrowIfDisposed();
458 }
459 
460 //----- XPaintListener --------------------------------------------------------
461 
462 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
463 {
464  // Deactivated views must not be painted.
466  return;
467 
468  Paint(rEvent.UpdateRect);
469 
470  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
471  if (xSpriteCanvas.is())
472  xSpriteCanvas->updateScreen(false);
473 }
474 
475 //----- XMouseListener --------------------------------------------------------
476 
477 void SAL_CALL PresenterSlideSorter::mousePressed (const css::awt::MouseEvent& rEvent)
478 {
479  css::awt::MouseEvent rTemp =rEvent;
482  awt::Rectangle aBox = mxWindow->getPosSize();
483  rTemp.X=aBox.Width-rEvent.X;
484  }
485  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
486  mnSlideIndexMousePressed = mpLayout->GetSlideIndexForPosition(aPosition);
487 }
488 
489 void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& rEvent)
490 {
491  css::awt::MouseEvent rTemp =rEvent;
494  awt::Rectangle aBox = mxWindow->getPosSize();
495  rTemp.X=aBox.Width-rEvent.X;
496  }
497  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
498  const sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
499 
500  if (!(nSlideIndex == mnSlideIndexMousePressed && mnSlideIndexMousePressed >= 0))
501  return;
502 
503  switch (rEvent.ClickCount)
504  {
505  case 1:
506  default:
507  GotoSlide(nSlideIndex);
508  break;
509 
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;
516  }
517 }
518 
519 void SAL_CALL PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent&) {}
520 
521 void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent&)
522 {
524  if (mpMouseOverManager != nullptr)
525  mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0));
526 }
527 
528 //----- XMouseMotionListener --------------------------------------------------
529 
530 void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEvent)
531 {
532  if (mpMouseOverManager == nullptr)
533  return;
534 
535  css::awt::MouseEvent rTemp =rEvent;
538  awt::Rectangle aBox = mxWindow->getPosSize();
539  rTemp.X=aBox.Width-rEvent.X;
540  }
541  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
542  sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
543 
544  if (nSlideIndex < 0)
546 
547  if (nSlideIndex < 0)
548  {
549  mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
550  }
551  else
552  {
553  mpMouseOverManager->SetSlide(
554  nSlideIndex,
555  mpLayout->GetBoundingBox(nSlideIndex));
556  }
557 }
558 
559 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent&) {}
560 
561 //----- XResourceId -----------------------------------------------------------
562 
563 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId()
564 {
565  ThrowIfDisposed();
566  return mxViewId;
567 }
568 
570 {
571  return false;
572 }
573 
574 //----- XPropertyChangeListener -----------------------------------------------
575 
577  const css::beans::PropertyChangeEvent&)
578 {}
579 
580 //----- XSlidePreviewCacheListener --------------------------------------------
581 
583  sal_Int32 nSlideIndex)
584 {
585  OSL_ASSERT(mpLayout != nullptr);
586 
587  awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex));
588  mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true);
589 }
590 
591 //----- XDrawView -------------------------------------------------------------
592 
594 {
595  ThrowIfDisposed();
596  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
597 
598  if (!mxSlideShowController.is())
599  return;
600 
601  const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
602  if (nNewCurrentSlideIndex == mnCurrentSlideIndex)
603  return;
604 
605  mnCurrentSlideIndex = nNewCurrentSlideIndex;
606 
607  // Request a repaint of the previous current slide to hide its
608  // current slide indicator.
609  mpPresenterController->GetPaintManager()->Invalidate(
610  mxWindow,
612 
613  // Request a repaint of the new current slide to show its
614  // current slide indicator.
616  mpLayout->GetBoundingBox(mnCurrentSlideIndex));
617  mpPresenterController->GetPaintManager()->Invalidate(
618  mxWindow,
620 }
621 
623 {
624  ThrowIfDisposed();
625  return nullptr;
626 }
627 
628 
630 {
631  if ( ! mxWindow.is())
632  return;
633 
634  mbIsLayoutPending = false;
635 
636  const awt::Rectangle aWindowBox (mxWindow->getPosSize());
637  sal_Int32 nLeftBorderWidth (aWindowBox.X);
638 
639  // Get border width.
641  mpPresenterController->GetPaneContainer()->FindViewURL(
642  mxViewId->getResourceURL()));
643  do
644  {
645  if (pPane.get() == nullptr)
646  break;
647  if ( ! pPane->mxPane.is())
648  break;
649 
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);
658  }
659  while(false);
660 
661  // Place vertical separator.
662  mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
663 
664  PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
665 
666  geometry::RealRectangle2D aUpperBox(
669  aWindowBox.Width - 2*gnHorizontalBorder,
670  mnSeparatorY - gnVerticalGap);
671 
672  // Determine whether the scroll bar has to be displayed.
673  aUpperBox = PlaceScrollBars(aUpperBox);
674 
675  mpLayout->Update(aUpperBox, GetSlideAspectRatio());
676  mpLayout->SetupVisibleArea();
677  mpLayout->UpdateScrollBars();
678 
679  // Tell the preview cache about some of the values.
680  mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize);
681  mxPreviewCache->setVisibleRange(
682  mpLayout->GetFirstVisibleSlideIndex(),
683  mpLayout->GetLastVisibleSlideIndex());
684 
685  // Clear the frame polygon so that it is re-created on the next paint.
686  mxPreviewFrame = nullptr;
687 }
688 
689 geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars (
690  const geometry::RealRectangle2D& rUpperBox)
691 {
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)
697  {
698  if (bIsScrollBarNeeded)
699  {
701  {
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);
715  }
716  else
717  {
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);
732  }
733  }
734  else
735  mpVerticalScrollBar->SetVisible(false);
736  }
737  return rUpperBox;
738 }
739 
742  const awt::Rectangle& rCenterBox,
743  const sal_Int32 nLeftBorderWidth)
744 {
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())
750  {
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)
756  {
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;
763  }
764  }
765  mpCloseButton->SetCenter(geometry::RealPoint2D(
766  nCloseButtonCenter,
767  rCenterBox.Height - mpCloseButton->GetSize().Height/ 2));
768 }
769 
771  const Reference<rendering::XCanvas>& rxCanvas,
772  const awt::Rectangle& rUpdateBox)
773 {
774  OSL_ASSERT(rxCanvas.is());
775 
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());
783 }
784 
786 {
787  double nSlideAspectRatio (28.0/21.0);
788 
789  try
790  {
791  Reference<container::XIndexAccess> xSlides(mxSlideShowController, UNO_QUERY_THROW);
792  if (mxSlideShowController.is() && xSlides->getCount()>0)
793  {
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)
800  {
801  nSlideAspectRatio = double(nWidth) / double(nHeight);
802  }
803  }
804  }
805  catch (RuntimeException&)
806  {
807  OSL_ASSERT(false);
808  }
809 
810  return nSlideAspectRatio;
811 }
812 
813 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
814 {
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;
821 }
822 
824  const Reference<rendering::XCanvas>& rxCanvas,
825  const css::awt::Rectangle& rUpdateBox,
826  const sal_Int32 nSlideIndex)
827 {
828  OSL_ASSERT(rxCanvas.is());
829 
830  geometry::IntegerSize2D aSize (mpLayout->maPreviewSize);
831 
833  rUpdateBox,
834  mpLayout->GetBoundingBox(nSlideIndex)))
835  {
836  return;
837  }
838 
839  Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex));
840  bool isRTL = AllSettings::GetLayoutRTL();
841 
842  const geometry::RealPoint2D aTopLeft (
843  mpLayout->GetWindowPosition(
844  mpLayout->GetPoint(nSlideIndex, isRTL?1:-1, -1)));
845 
846  PresenterBitmapContainer aContainer (
847  "PresenterScreenSettings/ScrollBar/Bitmaps",
848  std::shared_ptr<PresenterBitmapContainer>(),
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);
855 
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 (
863  aBoundingBox));
864  Reference<rendering::XPolyPolygon2D> xClip (
865  PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice()));
866 
867  const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip);
868 
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);
876 
877  // Emphasize the current slide.
878  if (nSlideIndex == mnCurrentSlideIndex)
879  {
880  if (mpCurrentSlideFrameRenderer != nullptr)
881  {
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);
888  = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
889  mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
890  aSlideBoundingBox,
891  mxCanvas,
892  aClipBox);
893  }
894  }
895 
896  // Paint the preview.
897  if (xPreview.is())
898  {
899  aSize = xPreview->getSize();
900  if (aSize.Width > 0 && aSize.Height > 0)
901  {
902  rxCanvas->drawBitmap(xPreview, aViewState, aRenderState);
903  if( bCustomAnimation )
904  {
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);
916  }
917  if( bTransition )
918  {
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);
930  }
931  }
932  }
933 
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())
938  awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2),
939  rxCanvas->getDevice());
940 
941  // Paint a border around the preview.
942  if (mxPreviewFrame.is())
943  {
944  const util::Color aFrameColor (0x00000000);
945  PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor);
946  rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState);
947  }
948 
949  // Paint mouse over effect.
950  mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip);
951 }
952 
953 void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox)
954 {
955  const bool bCanvasChanged ( ! mxCanvas.is());
956  if ( ! ProvideCanvas())
957  return;
958 
959  if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
960  {
961  OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
962  return;
963  }
964 
965  ClearBackground(mxCanvas, rUpdateBox);
966 
967  // Give the canvas to the controls.
968  if (bCanvasChanged)
969  {
970  if (mpVerticalScrollBar.is())
971  mpVerticalScrollBar->SetCanvas(mxCanvas);
972  if (mpCloseButton.is())
973  mpCloseButton->SetCanvas(mxCanvas, mxWindow);
974  }
975 
976  // Now that the controls have a canvas we can do the layouting.
977  if (mbIsLayoutPending)
978  UpdateLayout();
979 
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);
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);
989 
990  // Paint the slides.
992  rUpdateBox,
994  {
995  mpLayout->ForAllVisibleSlides(
996  [this, &rUpdateBox] (sal_Int32 const nIndex) {
997  return this->PaintPreview(this->mxCanvas, rUpdateBox, nIndex);
998  });
999  }
1000 
1001  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
1002  if (xSpriteCanvas.is())
1003  xSpriteCanvas->updateScreen(false);
1004 }
1005 
1006 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset)
1007 {
1008  if (mpLayout->SetHorizontalOffset(nXOffset))
1009  {
1010  mxPreviewCache->setVisibleRange(
1011  mpLayout->GetFirstVisibleSlideIndex(),
1012  mpLayout->GetLastVisibleSlideIndex());
1013 
1014  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1015  }
1016 }
1017 
1018 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset)
1019 {
1020  if (mpLayout->SetVerticalOffset(nYOffset))
1021  {
1022  mxPreviewCache->setVisibleRange(
1023  mpLayout->GetFirstVisibleSlideIndex(),
1024  mpLayout->GetLastVisibleSlideIndex());
1025 
1026  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1027  }
1028 }
1029 
1030 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex)
1031 {
1032  mxSlideShowController->gotoSlideIndex(nSlideIndex);
1033 }
1034 
1036 {
1037  if ( ! mxCanvas.is())
1038  {
1039  if (mxPane.is())
1040  mxCanvas = mxPane->getCanvas();
1041 
1042  // Register as event listener so that we are informed when the
1043  // canvas is disposed (and we have to fetch another one).
1045  if (xComponent.is())
1046  xComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
1047 
1049  std::make_shared<CurrentSlideFrameRenderer>(mxComponentContext, mxCanvas);
1050  }
1051  return mxCanvas.is();
1052 }
1053 
1055 {
1056  if (rBHelper.bDisposed || rBHelper.bInDispose)
1057  {
1058  throw lang::DisposedException (
1059  "PresenterSlideSorter has been already disposed",
1060  static_cast<uno::XWeak*>(this));
1061  }
1062 }
1063 
1064 //===== PresenterSlideSorter::Layout ==========================================
1065 
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)
1084 {
1085 }
1086 
1088  const geometry::RealRectangle2D& rBoundingBox,
1089  const double nSlideAspectRatio)
1090 {
1091  maBoundingBox = rBoundingBox;
1092 
1093  mnHorizontalBorder = gnHorizontalBorder;
1094  mnVerticalBorder = gnVerticalBorder;
1095 
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;
1100 
1101  double nPreviewWidth;
1102 
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)
1109  {
1110  // The preferred column count is too large.
1111  // Can we use the preferred preview width?
1112  if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1113  {
1114  // Yes.
1115  nPreviewWidth = gnPreferredPreviewWidth;
1116  mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1117  / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1118  mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1119  }
1120  else
1121  {
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);
1130  }
1131  }
1132  else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap)
1133  {
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);
1139  }
1140  else
1141  {
1142  // The preferred column count is possible. Determine gap and
1143  // preview width.
1144  mnColumnCount = gnPreferredColumnCount;
1145  if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap)
1146  {
1147  // Use the minimal gap and adapt the preview width.
1148  mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1149  nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1150  }
1151  else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap)
1152  {
1153  // Use the maximal gap and adapt the preview width.
1154  mnHorizontalGap = round(gnMaximalHorizontalPreviewGap);
1155  nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1156  }
1157  else
1158  {
1159  // Use the preferred preview width and adapt the gap.
1160  nPreviewWidth = gnPreferredPreviewWidth;
1161  mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1162  }
1163  }
1164 
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);
1172 
1173  maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight));
1174 
1175  // Reset the offset.
1176  mnVerticalOffset = 0;
1177  mnHorizontalOffset = round(-(nWidth
1178  - mnColumnCount*maPreviewSize.Width
1179  - (mnColumnCount-1)*mnHorizontalGap)
1180  / 2);
1181 }
1182 
1184 {
1185  geometry::RealPoint2D aPoint (GetLocalPosition(
1186  geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1)));
1187  mnFirstVisibleColumn = 0;
1188  mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint));
1189 
1190  aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2));
1191  mnLastVisibleColumn = mnColumnCount - 1;
1192  mnLastVisibleRow = GetRow(aPoint, true);
1193 }
1194 
1195 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount)
1196 {
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;
1201 }
1202 
1204  const geometry::RealPoint2D& rWindowPoint) const
1205 {
1207  {
1208  return css::geometry::RealPoint2D(
1209  -rWindowPoint.X + maBoundingBox.X2 + mnHorizontalOffset,
1210  rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1211  }
1212  else
1213  {
1214  return css::geometry::RealPoint2D(
1215  rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset,
1216  rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1217  }
1218 }
1219 
1221  const geometry::RealPoint2D& rLocalPoint) const
1222 {
1224  {
1225  return css::geometry::RealPoint2D(
1226  -rLocalPoint.X + mnHorizontalOffset + maBoundingBox.X2,
1227  rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1228  }
1229  else
1230  {
1231  return css::geometry::RealPoint2D(
1232  rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1,
1233  rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1234  }
1235 }
1236 
1238  const css::geometry::RealPoint2D& rLocalPoint) const
1239 {
1240  const sal_Int32 nColumn(floor(
1241  (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap)));
1242  if (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn)
1243  {
1244  return nColumn;
1245  }
1246  else
1247  return -1;
1248 }
1249 
1251  const css::geometry::RealPoint2D& rLocalPoint,
1252  const bool bReturnInvalidValue) const
1253 {
1254  const sal_Int32 nRow (floor(
1255  (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap)));
1256  if (bReturnInvalidValue
1257  || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow))
1258  {
1259  return nRow;
1260  }
1261  else
1262  return -1;
1263 }
1264 
1266  const css::geometry::RealPoint2D& rWindowPoint) const
1267 {
1268  if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1269  return -1;
1270 
1271  const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint));
1272  const sal_Int32 nColumn (GetColumn(aLocalPosition));
1273  const sal_Int32 nRow (GetRow(aLocalPosition));
1274 
1275  if (nColumn < 0 || nRow < 0)
1276  return -1;
1277  else
1278  {
1279  sal_Int32 nIndex (GetIndex(nRow, nColumn));
1280  if (nIndex >= mnSlideCount)
1281  return -1;
1282  else
1283  return nIndex;
1284  }
1285 }
1286 
1288  const sal_Int32 nSlideIndex,
1289  const sal_Int32 nRelativeHorizontalPosition,
1290  const sal_Int32 nRelativeVerticalPosition) const
1291 {
1292  sal_Int32 nColumn (GetColumn(nSlideIndex));
1293  sal_Int32 nRow (GetRow(nSlideIndex));
1294 
1295  geometry::RealPoint2D aPosition (
1296  mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap),
1297  mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap));
1298 
1299  if (nRelativeHorizontalPosition >= 0)
1300  {
1301  if (nRelativeHorizontalPosition > 0)
1302  aPosition.X += maPreviewSize.Width;
1303  else
1304  aPosition.X += maPreviewSize.Width / 2.0;
1305  }
1306  if (nRelativeVerticalPosition >= 0)
1307  {
1308  if (nRelativeVerticalPosition > 0)
1309  aPosition.Y += maPreviewSize.Height;
1310  else
1311  aPosition.Y += maPreviewSize.Height / 2.0;
1312  }
1313 
1314  return aPosition;
1315 }
1316 
1317 awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const
1318 {
1319  bool isRTL = AllSettings::GetLayoutRTL();
1320  const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, isRTL?1:-1, -1)));
1322  geometry::RealRectangle2D(
1323  aWindowPosition.X,
1324  aWindowPosition.Y,
1325  aWindowPosition.X + maPreviewSize.Width,
1326  aWindowPosition.Y + maPreviewSize.Height));
1327 }
1328 
1330  const ::std::function<void (sal_Int32)>& rAction)
1331 {
1332  for (sal_Int32 nRow=mnFirstVisibleRow; nRow<=mnLastVisibleRow; ++nRow)
1333  {
1334  for (sal_Int32 nColumn=mnFirstVisibleColumn; nColumn<=mnLastVisibleColumn; ++nColumn)
1335  {
1336  const sal_Int32 nSlideIndex (GetIndex(nRow, nColumn));
1337  if (nSlideIndex >= mnSlideCount)
1338  return;
1339  rAction(nSlideIndex);
1340  }
1341  }
1342 }
1343 
1345 {
1346  return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1347 }
1348 
1350 {
1351  return ::std::min(
1352  GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1353  mnSlideCount);
1354 }
1355 
1357 {
1358  if (mnHorizontalOffset != nOffset)
1359  {
1360  mnHorizontalOffset = round(nOffset);
1361  SetupVisibleArea();
1362  UpdateScrollBars();
1363  return true;
1364  }
1365  else
1366  return false;
1367 }
1368 
1370 {
1371  if (mnVerticalOffset != nOffset)
1372  {
1373  mnVerticalOffset = round(nOffset);
1374  SetupVisibleArea();
1375  UpdateScrollBars();
1376  return true;
1377  }
1378  else
1379  return false;
1380 }
1381 
1383 {
1384  sal_Int32 nTotalRowCount = sal_Int32(ceil(double(mnSlideCount) / double(mnColumnCount)));
1385 
1386  if (mpVerticalScrollBar.get() != nullptr)
1387  {
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);
1395  }
1396 
1397  // No place yet for the vertical scroll bar.
1398 }
1399 
1401  const sal_Int32 nRow,
1402  const sal_Int32 nColumn) const
1403 {
1404  return nRow * mnColumnCount + nColumn;
1405 }
1406 
1407 sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const
1408 {
1409  return nSlideIndex / mnColumnCount;
1410 }
1411 
1412 sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const
1413 {
1414  return nSlideIndex % mnColumnCount;
1415 }
1416 
1417 //===== PresenterSlideSorter::MouseOverManager ================================
1418 
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)
1434 {
1435  if (rpTheme != nullptr)
1436  {
1437  std::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer());
1438  if (pBitmaps != nullptr)
1439  {
1440  mpLeftLabelBitmap = pBitmaps->GetBitmap("LabelLeft");
1441  mpCenterLabelBitmap = pBitmaps->GetBitmap("LabelCenter");
1442  mpRightLabelBitmap = pBitmaps->GetBitmap("LabelRight");
1443  }
1444 
1445  mpFont = rpTheme->GetFont("SlideSorterLabelFont");
1446  }
1447 }
1448 
1450  const sal_Int32 nSlideIndex,
1451  const Reference<rendering::XCanvas>& rxCanvas,
1452  const Reference<rendering::XPolyPolygon2D>& rxClip)
1453 {
1454  if (nSlideIndex != mnSlideIndex)
1455  return;
1456 
1457  if (mxCanvas != rxCanvas)
1458  SetCanvas(rxCanvas);
1459  if (rxCanvas == nullptr)
1460  return;
1461 
1462  if ( ! mxBitmap.is())
1463  mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1464  if (!mxBitmap.is())
1465  return;
1466 
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));
1482 }
1483 
1485  const Reference<rendering::XCanvas>& rxCanvas)
1486 {
1487  mxCanvas = rxCanvas;
1488  if (mpFont.get() != nullptr)
1489  mpFont->PrepareFont(mxCanvas);
1490 }
1491 
1493  const sal_Int32 nSlideIndex,
1494  const awt::Rectangle& rBox)
1495 {
1496  if (mnSlideIndex == nSlideIndex)
1497  return;
1498 
1499  mnSlideIndex = -1;
1500  Invalidate();
1501 
1502  maSlideBoundingBox = rBox;
1503  mnSlideIndex = nSlideIndex;
1504 
1505  if (nSlideIndex >= 0)
1506  {
1507  if (mxSlides.get() != nullptr)
1508  {
1509  msText.clear();
1510 
1511  Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
1512  if (xSlideProperties.is())
1513  xSlideProperties->getPropertyValue("LinkDisplayName") >>= msText;
1514 
1515  if (msText.isEmpty())
1516  msText = "Slide " + OUString::number(nSlideIndex + 1);
1517  }
1518  }
1519  else
1520  {
1521  msText.clear();
1522  }
1523  mxBitmap = nullptr;
1524 
1525  Invalidate();
1526 }
1527 
1529  const OUString& rsText,
1530  const sal_Int32 nMaximalWidth) const
1531 {
1532  if ( ! mxCanvas.is())
1533  return nullptr;
1534 
1535  if (mpFont.get()==nullptr || !mpFont->mxFont.is())
1536  return nullptr;
1537 
1538  // Long text has to be shortened.
1539  const OUString sText (GetFittingText(rsText, nMaximalWidth
1540  - 2*gnHorizontalLabelBorder
1541  - 2*gnHorizontalLabelPadding));
1542 
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));
1547 
1548  // Create a new bitmap that will contain the complete label.
1549  Reference<rendering::XBitmap> xBitmap (
1550  mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize));
1551 
1552  if ( ! xBitmap.is())
1553  return nullptr;
1554 
1555  Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1556  if ( ! xBitmapCanvas.is())
1557  return nullptr;
1558 
1559  // Paint the background.
1560  PaintButtonBackground(xBitmapCanvas, aLabelSize);
1561 
1562  // Paint the text.
1563  if (!sText.isEmpty())
1564  {
1565 
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());
1570 
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;
1574 
1575  const rendering::ViewState aViewState(
1576  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1577  nullptr);
1578 
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);
1585 
1586  xBitmapCanvas->drawTextLayout (
1587  xLayout,
1588  aViewState,
1589  aRenderState);
1590  }
1591 
1592  return xBitmap;
1593 }
1594 
1596  const OUString& rsText,
1597  const double nMaximalWidth) const
1598 {
1599  const double nTextWidth (
1600  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width);
1601  if (nTextWidth > nMaximalWidth)
1602  {
1603  // Text is too wide. Shorten it by removing characters from the end
1604  // and replacing them by ellipses.
1605 
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)
1612  {
1613  const OUString sCandidate (rsText.copy(0,nLength) + sEllipses);
1614  const double nWidth (
1615  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width);
1616  if (nWidth > nMaximalWidth)
1617  {
1618  // Candidate still too wide, shorten it.
1619  nLength -= 1;
1620  if (nLength <= 0)
1621  break;
1622  }
1623  else if (nWidth < nMaximalWidth)
1624  {
1625  // Candidate short enough.
1626  if (nWidth > nBestWidth)
1627  {
1628  // Best length so far.
1629  sBestCandidate = sCandidate;
1630  nBestWidth = nWidth;
1631  nLength += 1;
1632  if (nLength >= rsText.getLength())
1633  break;
1634  }
1635  else
1636  break;
1637  }
1638  else
1639  {
1640  // Candidate is exactly as long as it may be. Use it
1641  // without looking any further.
1642  sBestCandidate = sCandidate;
1643  break;
1644  }
1645  }
1646  return sBestCandidate;
1647  }
1648  else
1649  return rsText;
1650 }
1651 
1653  const OUString& rsText) const
1654 {
1655  // Height is specified by the label bitmaps.
1656  sal_Int32 nHeight (32);
1657  if (mpCenterLabelBitmap.get() != nullptr)
1658  {
1659  Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap());
1660  if (xBitmap.is())
1661  nHeight = xBitmap->getSize().Height;
1662  }
1663 
1664  // Width is specified by text width and maximal width.
1665  const geometry::RealSize2D aTextSize (
1666  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText));
1667 
1668  const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding));
1669 
1670  return geometry::IntegerSize2D(nWidth, nHeight);
1671 }
1672 
1674  const Reference<rendering::XCanvas>& rxCanvas,
1675  const geometry::IntegerSize2D& rSize) const
1676 {
1677  // Get the bitmaps for painting the label background.
1678  Reference<rendering::XBitmap> xLeftLabelBitmap;
1679  if (mpLeftLabelBitmap.get() != nullptr)
1680  xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap();
1681 
1682  Reference<rendering::XBitmap> xCenterLabelBitmap;
1683  if (mpCenterLabelBitmap.get() != nullptr)
1684  xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap();
1685 
1686  Reference<rendering::XBitmap> xRightLabelBitmap;
1687  if (mpRightLabelBitmap.get() != nullptr)
1688  xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap();
1689 
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);
1697 }
1698 
1700 {
1701  if (mpPaintManager != nullptr)
1702  mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true);
1703 }
1704 
1705 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
1706 
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)
1722 {
1723  PresenterConfigurationAccess aConfiguration (
1724  rxContext,
1725  "/org.openoffice.Office.PresenterScreen/",
1727  Reference<container::XHierarchicalNameAccess> xBitmaps (
1728  aConfiguration.GetConfigurationNode(
1729  "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1730  UNO_QUERY);
1731  if ( ! xBitmaps.is())
1732  return;
1733 
1734  PresenterBitmapContainer aContainer (
1735  "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1736  std::shared_ptr<PresenterBitmapContainer>(),
1737  rxContext,
1738  rxCanvas);
1739 
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");
1748 
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;
1758 
1759  if (mpTopLeft.get() != nullptr)
1760  {
1761  mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight);
1762  mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth);
1763  }
1764  if (mpTopRight.get() != nullptr)
1765  {
1766  mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight);
1767  mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth);
1768  }
1769  if (mpBottomLeft.get() != nullptr)
1770  {
1771  mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth);
1772  mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight);
1773  }
1774  if (mpBottomRight.get() != nullptr)
1775  {
1776  mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth);
1777  mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight);
1778  }
1779 }
1780 
1782  const awt::Rectangle& rSlideBoundingBox,
1783  const Reference<rendering::XCanvas>& rxCanvas,
1784  const geometry::RealRectangle2D& rClipBox)
1785 {
1786  if ( ! rxCanvas.is())
1787  return;
1788 
1789  const Reference<rendering::XPolyPolygon2D> xClip (
1790  PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
1791 
1792  if (mpTop.get() != nullptr)
1793  {
1794  PaintBitmapTiled(
1795  mpTop->GetNormalBitmap(),
1796  rxCanvas,
1797  rClipBox,
1798  rSlideBoundingBox.X,
1799  rSlideBoundingBox.Y - mpTop->mnHeight,
1800  rSlideBoundingBox.Width,
1801  mpTop->mnHeight);
1802  }
1803  if (mpLeft.get() != nullptr)
1804  {
1805  PaintBitmapTiled(
1806  mpLeft->GetNormalBitmap(),
1807  rxCanvas,
1808  rClipBox,
1809  rSlideBoundingBox.X - mpLeft->mnWidth,
1810  rSlideBoundingBox.Y,
1811  mpLeft->mnWidth,
1812  rSlideBoundingBox.Height);
1813  }
1814  if (mpRight.get() != nullptr)
1815  {
1816  PaintBitmapTiled(
1817  mpRight->GetNormalBitmap(),
1818  rxCanvas,
1819  rClipBox,
1820  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1821  rSlideBoundingBox.Y,
1822  mpRight->mnWidth,
1823  rSlideBoundingBox.Height);
1824  }
1825  if (mpBottom.get() != nullptr)
1826  {
1827  PaintBitmapTiled(
1828  mpBottom->GetNormalBitmap(),
1829  rxCanvas,
1830  rClipBox,
1831  rSlideBoundingBox.X,
1832  rSlideBoundingBox.Y + rSlideBoundingBox.Height,
1833  rSlideBoundingBox.Width,
1834  mpBottom->mnHeight);
1835  }
1836  if (mpTopLeft.get() != nullptr)
1837  {
1838  PaintBitmapOnce(
1839  mpTopLeft->GetNormalBitmap(),
1840  rxCanvas,
1841  xClip,
1842  rSlideBoundingBox.X - mpTopLeft->mnWidth,
1843  rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1844  }
1845  if (mpTopRight.get() != nullptr)
1846  {
1847  PaintBitmapOnce(
1848  mpTopRight->GetNormalBitmap(),
1849  rxCanvas,
1850  xClip,
1851  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1852  rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1853  }
1854  if (mpBottomLeft.get() != nullptr)
1855  {
1856  PaintBitmapOnce(
1857  mpBottomLeft->GetNormalBitmap(),
1858  rxCanvas,
1859  xClip,
1860  rSlideBoundingBox.X - mpBottomLeft->mnWidth,
1861  rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1862  }
1863  if (mpBottomRight.get() != nullptr)
1864  {
1865  PaintBitmapOnce(
1866  mpBottomRight->GetNormalBitmap(),
1867  rxCanvas,
1868  xClip,
1869  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1870  rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1871  }
1872 }
1873 
1875  const awt::Rectangle& rSlideBoundingBox)
1876 {
1877  return awt::Rectangle(
1878  rSlideBoundingBox.X - mnLeftFrameSize,
1879  rSlideBoundingBox.Y - mnTopFrameSize,
1880  rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize,
1881  rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize);
1882 }
1883 
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)
1890 {
1891  OSL_ASSERT(rxCanvas.is());
1892  if ( ! rxBitmap.is())
1893  return;
1894 
1895  const rendering::ViewState aViewState(
1896  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1897  rxClip);
1898 
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);
1906 
1907  rxCanvas->drawBitmap(
1908  rxBitmap,
1909  aViewState,
1910  aRenderState);
1911 }
1912 
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)
1921 {
1922  OSL_ASSERT(rxCanvas.is());
1923  if ( ! rxBitmap.is())
1924  return;
1925 
1926  geometry::IntegerSize2D aSize (rxBitmap->getSize());
1927 
1928  const rendering::ViewState aViewState(
1929  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1932  rClipBox,
1933  geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
1934  rxCanvas->getDevice()));
1935 
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);
1943 
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)
1948  {
1949  aRenderState.AffineTransform.m02 = nX;
1950  aRenderState.AffineTransform.m12 = nY;
1951  rxCanvas->drawBitmap(
1952  rxBitmap,
1953  aViewState,
1954  aRenderState);
1955  }
1956 }
1957 
1958 } // end of namespace ::sdext::presenter
1959 
1960 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< PresenterPaintManager > mpPaintManager
Reference< rendering::XCanvas > mxCanvas
geometry::IntegerSize2D CalculateLabelSize(const OUString &rsText) const
sal_Int32 GetIndex(const sal_Int32 nRow, const sal_Int32 nColumn) const
SharedBitmapDescriptor mpBottomRight
static const double gnHorizontalBorder(15)
virtual void SAL_CALL mouseEntered(const css::awt::MouseEvent &rEvent) override
std::shared_ptr< FontDescriptor > SharedFontDescriptor
sal_Int32 nIndex
void PaintPreview(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::awt::Rectangle &rUpdateBox, const sal_Int32 nSlideIndex)
virtual void SAL_CALL windowHidden(const css::lang::EventObject &rEvent) override
Reference< rendering::XBitmap > CreateBitmap(const OUString &rsText, const sal_Int32 nMaximalWidth) const
Create a bitmap that shows the given text and is not wider than the given maximal width...
css::uno::Reference< css::drawing::framework::XResourceId > mxViewId
osl::Mutex m_aMutex
static bool AreRectanglesDisjoint(const css::awt::Rectangle &rBox1, const css::awt::Rectangle &rBox2)
static void PaintBitmapTiled(const css::uno::Reference< css::rendering::XBitmap > &rxBitmap, const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const geometry::RealRectangle2D &rClipBox, const double nX, const double nY, const double nWidth, const double nHeight)
CurrentSlideFrameRenderer(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::rendering::XCanvas > &rxCanvas)
virtual sal_Bool SAL_CALL isAnchorOnly() override
virtual void SAL_CALL mousePressed(const css::awt::MouseEvent &rEvent) override
virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getCurrentPage() override
css::uno::Reference< css::drawing::XSlidePreviewCache > mxPreviewCache
css::uno::Reference< css::rendering::XBitmap > GetPreview(const sal_Int32 nSlideIndex)
static bool HasCustomAnimation(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
sal_Int32 GetRow(const geometry::RealPoint2D &rLocalPoint, const bool bReturnInvalidValue=false) const
virtual void SAL_CALL mouseReleased(const css::awt::MouseEvent &rEvent) override
static void PaintBitmapOnce(const css::uno::Reference< css::rendering::XBitmap > &rxBitmap, const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const Reference< rendering::XPolyPolygon2D > &rxClip, const double nX, const double nY)
SharedBitmapDescriptor mpBottomLeft
::rtl::Reference< PresenterScrollBar > mpVerticalScrollBar
void Update(const geometry::RealRectangle2D &rBoundingBox, const double nSlideAspectRatio)
css::awt::Rectangle GetBoundingBox(const sal_Int32 nSlideIndex) const
std::shared_ptr< PresenterBitmapContainer::BitmapDescriptor > SharedBitmapDescriptor
SharedBitmapDescriptor mpTopLeft
SharedBitmapDescriptor mpLeft
void PaintCurrentSlideFrame(const awt::Rectangle &rSlideBoundingBox, const Reference< rendering::XCanvas > &rxCanvas, const geometry::RealRectangle2D &rClipBox)
void SetCanvas(const Reference< rendering::XCanvas > &rxCanvas)
::rtl::Reference< PresenterController > mpPresenterController
SharedBitmapDescriptor mpTopRight
This class gives access to the configuration.
sal_Int32 GetSlideIndexForPosition(const css::geometry::RealPoint2D &rPoint) const
virtual void SAL_CALL windowResized(const css::awt::WindowEvent &rEvent) override
virtual void SAL_CALL notifyPreviewCreation(sal_Int32 nSlideIndex) override
static void PaintHorizontalBitmapComposite(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::awt::Rectangle &rRepaintBox, const css::awt::Rectangle &rBoundingBox, const css::uno::Reference< css::rendering::XBitmap > &rxLeftBitmap, const css::uno::Reference< css::rendering::XBitmap > &rxRepeatableCenterBitmap, const css::uno::Reference< css::rendering::XBitmap > &rxRightBitmap)
MouseOverManager(const Reference< container::XIndexAccess > &rxSlides, const std::shared_ptr< PresenterTheme > &rpTheme, const Reference< awt::XWindow > &rxInvalidateTarget, const std::shared_ptr< PresenterPaintManager > &rpPaintManager)
if(nullptr==pCandidateA||nullptr==pCandidateB)
css::uno::Reference< css::lang::XComponent > xComponent
void Paint(const sal_Int32 nSlideIndex, const Reference< rendering::XCanvas > &rxCanvas, const Reference< rendering::XPolyPolygon2D > &rxClip)
static const double gnVerticalBorder(5)
virtual void SAL_CALL mouseExited(const css::awt::MouseEvent &rEvent) override
css::uno::Reference< css::drawing::framework::XPane > mxPane
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
bool IsScrollBarNeeded(const sal_Int32 nSlideCount)
::rtl::Reference< PresenterScrollBar > mpVerticalScrollBar
css::uno::Reference< css::awt::XWindow > mxWindow
void PlaceCloseButton(const PresenterPaneContainer::SharedPaneDescriptor &rpPane, const css::awt::Rectangle &rCenterBox, const sal_Int32 nLeftFrameWidth)
css::uno::Reference< css::presentation::XSlideShowController > GetSlideShowController(const css::uno::Reference< css::frame::XController > &rxController)
Return the slide show controller of a running presentation that has the same document as the given fr...
css::uno::Any GetConfigurationNode(const OUString &rsPathToNode)
Return a configuration node below the root of the called object.
unsigned char sal_Bool
virtual void SAL_CALL disposing() override
geometry::RealPoint2D GetWindowPosition(const geometry::RealPoint2D &rLocalPoint) const
static bool GetLayoutRTL()
VclPtr< VirtualDevice > mxBitmap
void GotoSlide(const sal_Int32 nSlideIndex)
void ForAllVisibleSlides(const ::std::function< void(sal_Int32)> &rAction)
css::uno::Reference< css::presentation::XSlideShowController > mxSlideShowController
void SetSlide(const sal_Int32 nSlideIndex, const awt::Rectangle &rBox)
std::shared_ptr< BitmapDescriptor > GetBitmap(const OUString &rsName) const
Return the bitmap set that is associated with the given name.
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
virtual css::uno::Reference< css::drawing::framework::XResourceId > SAL_CALL getResourceId() override
css::geometry::RealPoint2D GetPoint(const sal_Int32 nSlideIndex, const sal_Int32 nRelativeHorizontalPosition, const sal_Int32 nRelativeVerticalPosition) const
static css::awt::Rectangle ConvertRectangle(const css::geometry::RealRectangle2D &rBox)
Return the bounding box with integer coordinates of the given rectangle.
static css::uno::Reference< css::rendering::XPolyPolygon2D > CreatePolygon(const css::awt::Rectangle &rBox, const css::uno::Reference< css::rendering::XGraphicDevice > &rxDevice)
void ClearBackground(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::awt::Rectangle &rRedrawArea)
Layout(const ::rtl::Reference< PresenterScrollBar > &rpVerticalScrollBar)
css::uno::Reference< css::rendering::XCanvas > mxCanvas
css::uno::Reference< css::rendering::XPolyPolygon2D > mxPreviewFrame
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &rEvent) override
std::shared_ptr< CurrentSlideFrameRenderer > mpCurrentSlideFrameRenderer
void Paint(const css::awt::Rectangle &rUpdateBox)
static css::awt::Rectangle Intersection(const css::awt::Rectangle &rBox1, const css::awt::Rectangle &rBox2)
virtual void SAL_CALL windowPaint(const css::awt::PaintEvent &rEvent) override
PresenterTheme::SharedFontDescriptor mpFont
rtl::Reference< PresenterController > mpPresenterController
css::geometry::RealRectangle2D PlaceScrollBars(const css::geometry::RealRectangle2D &rUpperBox)
const OUString msText
virtual void SAL_CALL setCurrentPage(const css::uno::Reference< css::drawing::XDrawPage > &rxSlide) override
virtual void SAL_CALL mouseDragged(const css::awt::MouseEvent &rEvent) override
static void SetDeviceColor(css::rendering::RenderState &rRenderState, const css::util::Color aColor)
std::shared_ptr< PaneDescriptor > SharedPaneDescriptor
MouseOverManager & operator=(const MouseOverManager &)=delete
cppu::WeakComponentImplHelper< css::drawing::framework::XView, css::awt::XWindowListener, css::awt::XPaintListener, css::beans::XPropertyChangeListener, css::drawing::XSlidePreviewCacheListener, css::awt::XMouseListener, css::awt::XMouseMotionListener, css::drawing::XDrawView > PresenterSlideSorterInterfaceBase
static css::geometry::RealSize2D GetTextSize(const css::uno::Reference< css::rendering::XCanvasFont > &rxFont, const OUString &rsText)
PresenterSlideSorter(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::drawing::framework::XResourceId > &rxViewId, const css::uno::Reference< css::frame::XController > &rxController, const ::rtl::Reference< PresenterController > &rpPresenterController)
OUString GetFittingText(const OUString &rsText, const double nMaximalWidth) const
::rtl::Reference< PresenterButton > mpCloseButton
void PaintButtonBackground(const Reference< rendering::XCanvas > &rxCanvas, const geometry::IntegerSize2D &rSize) const
double mnVerticalOffset
awt::Rectangle GetBoundingBox(const awt::Rectangle &rSlideBoundingBox)
Enlarge the given rectangle to include the current slide indicator.
Reference< XSingleServiceFactory > xFactory
SharedBitmapDescriptor mpRight
sal_Int32 nLength
static bool IsInside(const css::geometry::RealRectangle2D &rBox, const css::geometry::RealPoint2D &rPoint)
void dispose()
static::rtl::Reference< PresenterButton > Create(const css::uno::Reference< css::uno::XComponentContext > &rxComponentContext, const ::rtl::Reference< PresenterController > &rpPresenterController, const std::shared_ptr< PresenterTheme > &rpTheme, const css::uno::Reference< css::awt::XWindow > &rxParentWindow, const css::uno::Reference< css::rendering::XCanvas > &rxParentCanvas, const OUString &rsConfigurationName)
const long nButtonWidth
geometry::RealPoint2D GetLocalPosition(const geometry::RealPoint2D &rWindowPoint) const
sal_Int32 GetColumn(const geometry::RealPoint2D &rLocalPoint) const
SharedBitmapDescriptor mpBottom
static bool HasTransition(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
virtual void SAL_CALL mouseMoved(const css::awt::MouseEvent &rEvent) override
virtual void SAL_CALL windowShown(const css::lang::EventObject &rEvent) override
SharedBitmapDescriptor mpTop
const Reference< container::XIndexAccess > mxSlides
void SetHorizontalOffset(const double nXOffset)
virtual void SAL_CALL windowMoved(const css::awt::WindowEvent &rEvent) override
Manage a set of bitmap groups as they are used for buttons: three bitmaps, one for the normal state...
std::unique_ptr< MouseOverManager > mpMouseOverManager