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 sal_Int32 gnVerticalGap (10);
45  const sal_Int32 gnVerticalBorder (10);
46  const sal_Int32 gnHorizontalGap (10);
47  const sal_Int32 gnHorizontalBorder (10);
48 
49  const double gnMinimalPreviewWidth (200);
50  const double gnPreferredPreviewWidth (300);
51  const double gnMaximalPreviewWidth (400);
52  const sal_Int32 gnPreferredColumnCount (6);
53  const double gnMinimalHorizontalPreviewGap(15);
54  const double gnPreferredHorizontalPreviewGap(25);
55  const double gnMaximalHorizontalPreviewGap(50);
56  const double gnPreferredVerticalPreviewGap(25);
57 
58  const sal_Int32 gnHorizontalLabelBorder (3);
59  const sal_Int32 gnHorizontalLabelPadding (5);
60 
61  const 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  mpPresenterController(rpPresenterController),
236  mxSlideShowController(mpPresenterController->GetSlideShowController()),
237  mbIsLayoutPending(true),
238  mnSlideIndexMousePressed(-1),
239  mnCurrentSlideIndex(-1),
240  mnSeparatorY(0),
241  maSeparatorColor(0x00ffffff)
242 {
243  if ( ! rxContext.is()
244  || ! rxViewId.is()
245  || ! rxController.is()
246  || ! rpPresenterController)
247  {
248  throw lang::IllegalArgumentException();
249  }
250 
251  if ( ! mxSlideShowController.is())
252  throw RuntimeException();
253 
254  try
255  {
256  // Get pane and window.
257  Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
258  Reference<XConfigurationController> xCC (
259  xCM->getConfigurationController(), UNO_SET_THROW);
260  Reference<lang::XMultiComponentFactory> xFactory (
261  mxComponentContext->getServiceManager(), UNO_SET_THROW);
262 
263  mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
264  mxWindow = mxPane->getWindow();
265 
266  // Add window listener.
267  mxWindow->addWindowListener(this);
268  mxWindow->addPaintListener(this);
269  mxWindow->addMouseListener(this);
270  mxWindow->addMouseMotionListener(this);
271  mxWindow->setVisible(true);
272 
273  // Remember the current slide.
274  mnCurrentSlideIndex = mxSlideShowController->getCurrentSlideIndex();
275 
276  // Create the scroll bar.
279  rxContext,
280  mxWindow,
281  mpPresenterController->GetPaintManager(),
282  [this] (double const offset) { return this->SetVerticalOffset(offset); }));
283 
285  rxContext,
287  mpPresenterController->GetTheme(),
288  mxWindow,
289  mxCanvas,
290  "SlideSorterCloser");
291 
292  if (mpPresenterController->GetTheme() != nullptr)
293  {
295  mpPresenterController->GetTheme()->GetFont("ButtonFont"));
296  if (pFont)
297  maSeparatorColor = pFont->mnColor;
298  }
299 
300  // Create the layout.
301  mpLayout = std::make_shared<Layout>(mpVerticalScrollBar);
302 
303  // Create the preview cache.
304  mxPreviewCache.set(
305  xFactory->createInstanceWithContext(
306  "com.sun.star.drawing.PresenterPreviewCache",
308  UNO_QUERY_THROW);
309  Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY);
310  mxPreviewCache->setDocumentSlides(xSlides, rxController->getModel());
311  mxPreviewCache->addPreviewCreationNotifyListener(this);
312  if (xSlides.is())
313  {
314  mpLayout->mnSlideCount = xSlides->getCount();
315  }
316 
317  // Create the mouse over manager.
319  Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY),
320  mpPresenterController->GetTheme(),
321  mxWindow,
322  mpPresenterController->GetPaintManager()));
323 
324  // Listen for changes of the current slide.
325  Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW);
326  xControllerProperties->addPropertyChangeListener(
327  "CurrentPage",
328  this);
329 
330  // Move the current slide in the center of the window.
331  const awt::Rectangle aCurrentSlideBBox (mpLayout->GetBoundingBox(mnCurrentSlideIndex));
332  const awt::Rectangle aWindowBox (mxWindow->getPosSize());
333  SetHorizontalOffset(aCurrentSlideBBox.X - aWindowBox.Width/2.0);
334  }
335  catch (RuntimeException&)
336  {
337  disposing();
338  throw;
339  }
340 }
341 
343 {
344 }
345 
347 {
348  mxComponentContext = nullptr;
349  mxViewId = nullptr;
350  mxPane = nullptr;
351 
352  if (mpVerticalScrollBar.is())
353  {
355  mpVerticalScrollBar = nullptr;
356  if (xComponent.is())
357  xComponent->dispose();
358  }
359  if (mpCloseButton.is())
360  {
362  mpCloseButton = nullptr;
363  if (xComponent.is())
364  xComponent->dispose();
365  }
366 
367  if (mxCanvas.is())
368  {
369  Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
370  if (xComponent.is())
371  xComponent->removeEventListener(static_cast<awt::XWindowListener*>(this));
372  mxCanvas = nullptr;
373  }
374  mpPresenterController = nullptr;
375  mxSlideShowController = nullptr;
376  mpLayout.reset();
377  mpMouseOverManager.reset();
378 
379  if (mxPreviewCache.is())
380  {
381  mxPreviewCache->removePreviewCreationNotifyListener(this);
382 
383  Reference<XComponent> xComponent (mxPreviewCache, UNO_QUERY);
384  mxPreviewCache = nullptr;
385  if (xComponent.is())
386  xComponent->dispose();
387  }
388 
389  if (mxWindow.is())
390  {
391  mxWindow->removeWindowListener(this);
392  mxWindow->removePaintListener(this);
393  mxWindow->removeMouseListener(this);
394  mxWindow->removeMouseMotionListener(this);
395  }
396 }
397 
398 //----- lang::XEventListener --------------------------------------------------
399 
400 void SAL_CALL PresenterSlideSorter::disposing (const lang::EventObject& rEventObject)
401 {
402  if (rEventObject.Source == mxWindow)
403  {
404  mxWindow = nullptr;
405  dispose();
406  }
407  else if (rEventObject.Source == mxPreviewCache)
408  {
409  mxPreviewCache = nullptr;
410  dispose();
411  }
412  else if (rEventObject.Source == mxCanvas)
413  {
414  mxCanvas = nullptr;
415  mbIsLayoutPending = true;
416 
417  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
418  }
419 }
420 
421 //----- XWindowListener -------------------------------------------------------
422 
423 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent&)
424 {
425  ThrowIfDisposed();
426  mbIsLayoutPending = true;
427  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
428 }
429 
430 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent&)
431 {
432  ThrowIfDisposed();
433 }
434 
435 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject&)
436 {
437  ThrowIfDisposed();
438  mbIsLayoutPending = true;
439  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
440 }
441 
442 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject&)
443 {
444  ThrowIfDisposed();
445 }
446 
447 //----- XPaintListener --------------------------------------------------------
448 
449 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
450 {
451  // Deactivated views must not be painted.
453  return;
454 
455  Paint(rEvent.UpdateRect);
456 
457  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
458  if (xSpriteCanvas.is())
459  xSpriteCanvas->updateScreen(false);
460 }
461 
462 //----- XMouseListener --------------------------------------------------------
463 
464 void SAL_CALL PresenterSlideSorter::mousePressed (const css::awt::MouseEvent& rEvent)
465 {
466  css::awt::MouseEvent rTemp =rEvent;
469  awt::Rectangle aBox = mxWindow->getPosSize();
470  rTemp.X=aBox.Width-rEvent.X;
471  }
472  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
473  mnSlideIndexMousePressed = mpLayout->GetSlideIndexForPosition(aPosition);
474 }
475 
476 void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& rEvent)
477 {
478  css::awt::MouseEvent rTemp =rEvent;
481  awt::Rectangle aBox = mxWindow->getPosSize();
482  rTemp.X=aBox.Width-rEvent.X;
483  }
484  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
485  const sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
486 
487  if (nSlideIndex != mnSlideIndexMousePressed || mnSlideIndexMousePressed < 0)
488  return;
489 
490  switch (rEvent.ClickCount)
491  {
492  case 1:
493  default:
494  GotoSlide(nSlideIndex);
495  break;
496 
497  case 2:
498  OSL_ASSERT(mpPresenterController);
499  OSL_ASSERT(mpPresenterController->GetWindowManager());
500  mpPresenterController->GetWindowManager()->SetSlideSorterState(false);
501  GotoSlide(nSlideIndex);
502  break;
503  }
504 }
505 
506 void SAL_CALL PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent&) {}
507 
508 void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent&)
509 {
511  if (mpMouseOverManager != nullptr)
512  mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0));
513 }
514 
515 //----- XMouseMotionListener --------------------------------------------------
516 
517 void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEvent)
518 {
519  if (mpMouseOverManager == nullptr)
520  return;
521 
522  css::awt::MouseEvent rTemp =rEvent;
525  awt::Rectangle aBox = mxWindow->getPosSize();
526  rTemp.X=aBox.Width-rEvent.X;
527  }
528  const geometry::RealPoint2D aPosition(rTemp.X, rEvent.Y);
529  sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
530 
531  if (nSlideIndex < 0)
532  {
534  mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
535  }
536  else
537  {
538  mpMouseOverManager->SetSlide(
539  nSlideIndex,
540  mpLayout->GetBoundingBox(nSlideIndex));
541  }
542 }
543 
544 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent&) {}
545 
546 //----- XResourceId -----------------------------------------------------------
547 
548 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId()
549 {
550  ThrowIfDisposed();
551  return mxViewId;
552 }
553 
555 {
556  return false;
557 }
558 
559 //----- XPropertyChangeListener -----------------------------------------------
560 
562  const css::beans::PropertyChangeEvent&)
563 {}
564 
565 //----- XSlidePreviewCacheListener --------------------------------------------
566 
568  sal_Int32 nSlideIndex)
569 {
570  OSL_ASSERT(mpLayout != nullptr);
571 
572  awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex));
573  mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true);
574 }
575 
576 //----- XDrawView -------------------------------------------------------------
577 
579 {
580  ThrowIfDisposed();
581  ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
582 
583  if (!mxSlideShowController.is())
584  return;
585 
586  const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
587  if (nNewCurrentSlideIndex == mnCurrentSlideIndex)
588  return;
589 
590  mnCurrentSlideIndex = nNewCurrentSlideIndex;
591 
592  // Request a repaint of the previous current slide to hide its
593  // current slide indicator.
594  mpPresenterController->GetPaintManager()->Invalidate(
595  mxWindow,
597 
598  // Request a repaint of the new current slide to show its
599  // current slide indicator.
601  mpLayout->GetBoundingBox(mnCurrentSlideIndex));
602  mpPresenterController->GetPaintManager()->Invalidate(
603  mxWindow,
605 }
606 
608 {
609  ThrowIfDisposed();
610  return nullptr;
611 }
612 
613 
615 {
616  if ( ! mxWindow.is())
617  return;
618 
619  mbIsLayoutPending = false;
620 
621  const awt::Rectangle aWindowBox (mxWindow->getPosSize());
622  sal_Int32 nLeftBorderWidth (aWindowBox.X);
623 
624  // Get border width.
626  mpPresenterController->GetPaneContainer()->FindViewURL(
627  mxViewId->getResourceURL()));
628  do
629  {
630  if (!pPane)
631  break;
632  if ( ! pPane->mxPane.is())
633  break;
634 
635  Reference<drawing::framework::XPaneBorderPainter> xBorderPainter (
636  pPane->mxPane->GetPaneBorderPainter());
637  if ( ! xBorderPainter.is())
638  break;
639  xBorderPainter->addBorder (
640  mxViewId->getAnchor()->getResourceURL(),
641  awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height),
642  drawing::framework::BorderType_INNER_BORDER);
643  }
644  while(false);
645 
646  // Place vertical separator.
647  mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
648 
649  PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
650 
651  geometry::RealRectangle2D aUpperBox(
654  aWindowBox.Width - 2*gnHorizontalBorder,
655  mnSeparatorY - gnVerticalGap);
656 
657  // Determine whether the scroll bar has to be displayed.
658  aUpperBox = PlaceScrollBars(aUpperBox);
659 
660  mpLayout->Update(aUpperBox, GetSlideAspectRatio());
661  mpLayout->SetupVisibleArea();
662  mpLayout->UpdateScrollBars();
663 
664  // Tell the preview cache about some of the values.
665  mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize);
666  mxPreviewCache->setVisibleRange(
667  mpLayout->GetFirstVisibleSlideIndex(),
668  mpLayout->GetLastVisibleSlideIndex());
669 
670  // Clear the frame polygon so that it is re-created on the next paint.
671  mxPreviewFrame = nullptr;
672 }
673 
674 geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars (
675  const geometry::RealRectangle2D& rUpperBox)
676 {
677  mpLayout->Update(rUpperBox, GetSlideAspectRatio());
678  bool bIsScrollBarNeeded (false);
679  Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW);
680  bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount());
682  {
683  if (bIsScrollBarNeeded)
684  {
686  {
687  mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
688  rUpperBox.X1,
689  rUpperBox.Y1,
690  rUpperBox.X1 + mpVerticalScrollBar->GetSize(),
691  rUpperBox.Y2));
692  mpVerticalScrollBar->SetVisible(true);
693  // Reduce area covered by the scroll bar from the available
694  // space.
695  return geometry::RealRectangle2D(
696  rUpperBox.X1 + gnHorizontalGap + mpVerticalScrollBar->GetSize(),
697  rUpperBox.Y1,
698  rUpperBox.X2,
699  rUpperBox.Y2);
700  }
701  else
702  {
703  // if it's not RTL place vertical scroll bar at right border.
704  mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
705  rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
706  rUpperBox.Y1,
707  rUpperBox.X2,
708  rUpperBox.Y2));
709  mpVerticalScrollBar->SetVisible(true);
710  // Reduce area covered by the scroll bar from the available
711  // space.
712  return geometry::RealRectangle2D(
713  rUpperBox.X1,
714  rUpperBox.Y1,
715  rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
716  rUpperBox.Y2);
717  }
718  }
719  else
720  mpVerticalScrollBar->SetVisible(false);
721  }
722  return rUpperBox;
723 }
724 
727  const awt::Rectangle& rCenterBox,
728  const sal_Int32 nLeftBorderWidth)
729 {
730  // Place button. When the callout is near the center then the button is
731  // centered over the callout. Otherwise it is centered with respect to
732  // the whole window.
733  sal_Int32 nCloseButtonCenter (rCenterBox.Width/2);
734  if (rpPane && rpPane->mxPane.is())
735  {
736  const sal_Int32 nCalloutCenter (-nLeftBorderWidth);
737  const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2));
738  const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width);
739  const static sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2);
740  if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering)
741  {
742  if (nCalloutCenter < nButtonWidth/2)
743  nCloseButtonCenter = nButtonWidth/2;
744  else if (nCalloutCenter > rCenterBox.Width-nButtonWidth/2)
745  nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2;
746  else
747  nCloseButtonCenter = nCalloutCenter;
748  }
749  }
750  mpCloseButton->SetCenter(geometry::RealPoint2D(
751  nCloseButtonCenter,
752  rCenterBox.Height - mpCloseButton->GetSize().Height/ 2));
753 }
754 
756  const Reference<rendering::XCanvas>& rxCanvas,
757  const awt::Rectangle& rUpdateBox)
758 {
759  OSL_ASSERT(rxCanvas.is());
760 
761  const awt::Rectangle aWindowBox (mxWindow->getPosSize());
762  mpPresenterController->GetCanvasHelper()->Paint(
763  mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
764  rxCanvas,
765  rUpdateBox,
766  awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
767  awt::Rectangle());
768 }
769 
771 {
772  double nSlideAspectRatio (28.0/21.0);
773 
774  try
775  {
776  Reference<container::XIndexAccess> xSlides(mxSlideShowController, UNO_QUERY_THROW);
777  if (mxSlideShowController.is() && xSlides->getCount()>0)
778  {
779  Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
780  sal_Int32 nWidth (28000);
781  sal_Int32 nHeight (21000);
782  if ((xProperties->getPropertyValue("Width") >>= nWidth)
783  && (xProperties->getPropertyValue("Height") >>= nHeight)
784  && nHeight > 0)
785  {
786  nSlideAspectRatio = double(nWidth) / double(nHeight);
787  }
788  }
789  }
790  catch (RuntimeException&)
791  {
792  OSL_ASSERT(false);
793  }
794 
795  return nSlideAspectRatio;
796 }
797 
798 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
799 {
800  if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount)
801  return nullptr;
802  else if (mxPane.is())
803  return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas());
804  else
805  return nullptr;
806 }
807 
809  const Reference<rendering::XCanvas>& rxCanvas,
810  const css::awt::Rectangle& rUpdateBox,
811  const sal_Int32 nSlideIndex)
812 {
813  OSL_ASSERT(rxCanvas.is());
814 
815  geometry::IntegerSize2D aSize (mpLayout->maPreviewSize);
816 
818  rUpdateBox,
819  mpLayout->GetBoundingBox(nSlideIndex)))
820  {
821  return;
822  }
823 
824  Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex));
825  bool isRTL = AllSettings::GetLayoutRTL();
826 
827  const geometry::RealPoint2D aTopLeft (
828  mpLayout->GetWindowPosition(
829  mpLayout->GetPoint(nSlideIndex, isRTL?1:-1, -1)));
830 
831  PresenterBitmapContainer aContainer (
832  "PresenterScreenSettings/ScrollBar/Bitmaps",
833  std::shared_ptr<PresenterBitmapContainer>(),
835  rxCanvas);
836  Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
837  Reference<drawing::XDrawPage> xPage( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
838  bool bTransition = PresenterController::HasTransition(xPage);
839  bool bCustomAnimation = PresenterController::HasCustomAnimation(xPage);
840 
841  // Create clip rectangle as intersection of the current update area and
842  // the bounding box of all previews.
843  geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox);
844  aBoundingBox.Y2 += 1;
845  const geometry::RealRectangle2D aClipBox (
848  aBoundingBox));
849  Reference<rendering::XPolyPolygon2D> xClip (
850  PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice()));
851 
852  const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip);
853 
854  rendering::RenderState aRenderState (
855  geometry::AffineMatrix2D(
856  1, 0, aTopLeft.X,
857  0, 1, aTopLeft.Y),
858  nullptr,
859  Sequence<double>(4),
860  rendering::CompositeOperation::SOURCE);
861 
862  // Emphasize the current slide.
863  if (nSlideIndex == mnCurrentSlideIndex)
864  {
865  if (mpCurrentSlideFrameRenderer != nullptr)
866  {
867  const awt::Rectangle aSlideBoundingBox(
868  sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.X),
869  sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.Y),
870  aSize.Width,
871  aSize.Height);
873  = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
874  mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
875  aSlideBoundingBox,
876  mxCanvas,
877  aClipBox);
878  }
879  }
880 
881  // Paint the preview.
882  if (xPreview.is())
883  {
884  aSize = xPreview->getSize();
885  if (aSize.Width > 0 && aSize.Height > 0)
886  {
887  rxCanvas->drawBitmap(xPreview, aViewState, aRenderState);
888  if( bCustomAnimation )
889  {
890  const awt::Rectangle aAnimationPreviewBox(aTopLeft.X+3, aTopLeft.Y+aSize.Height-40, 0, 0);
891  SharedBitmapDescriptor aAnimationDescriptor = aContainer.GetBitmap("Animation");
892  Reference<rendering::XBitmap> xAnimationIcon (aAnimationDescriptor->GetNormalBitmap());
893  rendering::RenderState aAnimationRenderState (
894  geometry::AffineMatrix2D(
895  1, 0, aAnimationPreviewBox.X,
896  0, 1, aAnimationPreviewBox.Y),
897  nullptr,
898  Sequence<double>(4),
899  rendering::CompositeOperation::SOURCE);
900  rxCanvas->drawBitmap(xAnimationIcon, aViewState, aAnimationRenderState);
901  }
902  if( bTransition )
903  {
904  const awt::Rectangle aTransitionPreviewBox(aTopLeft.X+3, aTopLeft.Y+aSize.Height-20, 0, 0);
905  SharedBitmapDescriptor aTransitionDescriptor = aContainer.GetBitmap("Transition");
906  Reference<rendering::XBitmap> xTransitionIcon (aTransitionDescriptor->GetNormalBitmap());
907  rendering::RenderState aTransitionRenderState (
908  geometry::AffineMatrix2D(
909  1, 0, aTransitionPreviewBox.X,
910  0, 1, aTransitionPreviewBox.Y),
911  nullptr,
912  Sequence<double>(4),
913  rendering::CompositeOperation::SOURCE);
914  rxCanvas->drawBitmap(xTransitionIcon, aViewState, aTransitionRenderState);
915  }
916  }
917  }
918 
919  // Create a polygon that is used to paint a frame around previews. Its
920  // coordinates are chosen in the local coordinate system of a preview.
921  if ( ! mxPreviewFrame.is())
923  awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2),
924  rxCanvas->getDevice());
925 
926  // Paint a border around the preview.
927  if (mxPreviewFrame.is())
928  {
929  const util::Color aFrameColor (0x00000000);
930  PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor);
931  rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState);
932  }
933 
934  // Paint mouse over effect.
935  mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip);
936 }
937 
938 void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox)
939 {
940  const bool bCanvasChanged ( ! mxCanvas.is());
941  if ( ! ProvideCanvas())
942  return;
943 
944  if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
945  {
946  OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
947  return;
948  }
949 
950  ClearBackground(mxCanvas, rUpdateBox);
951 
952  // Give the canvas to the controls.
953  if (bCanvasChanged)
954  {
955  if (mpVerticalScrollBar.is())
956  mpVerticalScrollBar->SetCanvas(mxCanvas);
957  if (mpCloseButton.is())
958  mpCloseButton->SetCanvas(mxCanvas, mxWindow);
959  }
960 
961  // Now that the controls have a canvas we can do the layouting.
962  if (mbIsLayoutPending)
963  UpdateLayout();
964 
965  // Paint the horizontal separator.
966  rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0),
967  nullptr, Sequence<double>(4), rendering::CompositeOperation::SOURCE);
969  mxCanvas->drawLine(
970  geometry::RealPoint2D(0, mnSeparatorY),
971  geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY),
972  rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
973  aRenderState);
974 
975  // Paint the slides.
977  rUpdateBox,
979  {
980  mpLayout->ForAllVisibleSlides(
981  [this, &rUpdateBox] (sal_Int32 const nIndex) {
982  return this->PaintPreview(this->mxCanvas, rUpdateBox, nIndex);
983  });
984  }
985 
986  Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
987  if (xSpriteCanvas.is())
988  xSpriteCanvas->updateScreen(false);
989 }
990 
991 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset)
992 {
993  if (mpLayout->SetHorizontalOffset(nXOffset))
994  {
995  mxPreviewCache->setVisibleRange(
996  mpLayout->GetFirstVisibleSlideIndex(),
997  mpLayout->GetLastVisibleSlideIndex());
998 
999  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1000  }
1001 }
1002 
1003 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset)
1004 {
1005  if (mpLayout->SetVerticalOffset(nYOffset))
1006  {
1007  mxPreviewCache->setVisibleRange(
1008  mpLayout->GetFirstVisibleSlideIndex(),
1009  mpLayout->GetLastVisibleSlideIndex());
1010 
1011  mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1012  }
1013 }
1014 
1015 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex)
1016 {
1017  mxSlideShowController->gotoSlideIndex(nSlideIndex);
1018 }
1019 
1021 {
1022  if ( ! mxCanvas.is())
1023  {
1024  if (mxPane.is())
1025  mxCanvas = mxPane->getCanvas();
1026 
1027  // Register as event listener so that we are informed when the
1028  // canvas is disposed (and we have to fetch another one).
1029  Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
1030  if (xComponent.is())
1031  xComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
1032 
1034  std::make_shared<CurrentSlideFrameRenderer>(mxComponentContext, mxCanvas);
1035  }
1036  return mxCanvas.is();
1037 }
1038 
1040 {
1041  if (rBHelper.bDisposed || rBHelper.bInDispose)
1042  {
1043  throw lang::DisposedException (
1044  "PresenterSlideSorter has been already disposed",
1045  static_cast<uno::XWeak*>(this));
1046  }
1047 }
1048 
1049 //===== PresenterSlideSorter::Layout ==========================================
1050 
1052  const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar)
1053  : mnHorizontalOffset(0),
1054  mnVerticalOffset(0),
1055  mnHorizontalGap(0),
1056  mnVerticalGap(0),
1057  mnHorizontalBorder(0),
1058  mnVerticalBorder(0),
1059  mnRowCount(1),
1060  mnColumnCount(1),
1061  mnSlideCount(0),
1062  mnFirstVisibleColumn(-1),
1063  mnLastVisibleColumn(-1),
1064  mnFirstVisibleRow(-1),
1065  mnLastVisibleRow(-1),
1066  mpVerticalScrollBar(rpVerticalScrollBar)
1067 {
1068 }
1069 
1071  const geometry::RealRectangle2D& rBoundingBox,
1072  const double nSlideAspectRatio)
1073 {
1074  maBoundingBox = rBoundingBox;
1075 
1076  mnHorizontalBorder = gnHorizontalBorder;
1077  mnVerticalBorder = gnVerticalBorder;
1078 
1079  const double nWidth (rBoundingBox.X2 - rBoundingBox.X1 - 2*mnHorizontalBorder);
1080  const double nHeight (rBoundingBox.Y2 - rBoundingBox.Y1 - 2*mnVerticalBorder);
1081  if (nWidth<=0 || nHeight<=0)
1082  return;
1083 
1084  double nPreviewWidth;
1085 
1086  // Determine column count, preview width, and horizontal gap (borders
1087  // are half the gap). Try to use the preferred values. Try more to
1088  // stay in the valid intervals. This last constraint may be not
1089  // fulfilled in some cases.
1090  const double nElementWidth = nWidth / gnPreferredColumnCount;
1091  if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap)
1092  {
1093  // The preferred column count is too large.
1094  // Can we use the preferred preview width?
1095  if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1096  {
1097  // Yes.
1098  nPreviewWidth = gnPreferredPreviewWidth;
1099  mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1100  / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1101  mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1102  }
1103  else
1104  {
1105  // No. Set the column count to 1 and adapt preview width and
1106  // gap.
1107  mnColumnCount = 1;
1108  mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1109  if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1110  nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap;
1111  else
1112  nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap);
1113  }
1114  }
1115  else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap)
1116  {
1117  // The preferred column count is too small.
1118  nPreviewWidth = gnPreferredPreviewWidth;
1119  mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1120  / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1121  mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1122  }
1123  else
1124  {
1125  // The preferred column count is possible. Determine gap and
1126  // preview width.
1127  mnColumnCount = gnPreferredColumnCount;
1128  if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap)
1129  {
1130  // Use the minimal gap and adapt the preview width.
1131  mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1132  nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1133  }
1134  else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap)
1135  {
1136  // Use the maximal gap and adapt the preview width.
1137  mnHorizontalGap = round(gnMaximalHorizontalPreviewGap);
1138  nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1139  }
1140  else
1141  {
1142  // Use the preferred preview width and adapt the gap.
1143  nPreviewWidth = gnPreferredPreviewWidth;
1144  mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1145  }
1146  }
1147 
1148  // Now determine the row count, preview height, and vertical gap.
1149  const double nPreviewHeight = nPreviewWidth / nSlideAspectRatio;
1150  mnRowCount = ::std::max(
1151  sal_Int32(1),
1152  sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap)
1153  / (nPreviewHeight + gnPreferredVerticalPreviewGap))));
1154  mnVerticalGap = round(gnPreferredVerticalPreviewGap);
1155 
1156  maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight));
1157 
1158  // Reset the offset.
1159  mnVerticalOffset = 0;
1160  mnHorizontalOffset = round(-(nWidth
1161  - mnColumnCount*maPreviewSize.Width
1162  - (mnColumnCount-1)*mnHorizontalGap)
1163  / 2);
1164 }
1165 
1167 {
1168  geometry::RealPoint2D aPoint (GetLocalPosition(
1169  geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1)));
1170  mnFirstVisibleColumn = 0;
1171  mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint));
1172 
1173  aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2));
1174  mnLastVisibleColumn = mnColumnCount - 1;
1175  mnLastVisibleRow = GetRow(aPoint, true);
1176 }
1177 
1178 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount)
1179 {
1180  geometry::RealPoint2D aBottomRight = GetPoint(
1181  mnColumnCount * (GetRow(nSlideCount)+1) - 1, +1, +1);
1182  return aBottomRight.X > maBoundingBox.X2-maBoundingBox.X1
1183  || aBottomRight.Y > maBoundingBox.Y2-maBoundingBox.Y1;
1184 }
1185 
1187  const geometry::RealPoint2D& rWindowPoint) const
1188 {
1190  {
1191  return css::geometry::RealPoint2D(
1192  -rWindowPoint.X + maBoundingBox.X2 + mnHorizontalOffset,
1193  rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1194  }
1195  else
1196  {
1197  return css::geometry::RealPoint2D(
1198  rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset,
1199  rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1200  }
1201 }
1202 
1204  const geometry::RealPoint2D& rLocalPoint) const
1205 {
1207  {
1208  return css::geometry::RealPoint2D(
1209  -rLocalPoint.X + mnHorizontalOffset + maBoundingBox.X2,
1210  rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1211  }
1212  else
1213  {
1214  return css::geometry::RealPoint2D(
1215  rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1,
1216  rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1217  }
1218 }
1219 
1221  const css::geometry::RealPoint2D& rLocalPoint) const
1222 {
1223  const sal_Int32 nColumn(floor(
1224  (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap)));
1225  if (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn)
1226  {
1227  return nColumn;
1228  }
1229  else
1230  return -1;
1231 }
1232 
1234  const css::geometry::RealPoint2D& rLocalPoint,
1235  const bool bReturnInvalidValue) const
1236 {
1237  const sal_Int32 nRow (floor(
1238  (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap)));
1239  if (bReturnInvalidValue
1240  || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow))
1241  {
1242  return nRow;
1243  }
1244  else
1245  return -1;
1246 }
1247 
1249  const css::geometry::RealPoint2D& rWindowPoint) const
1250 {
1251  if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1252  return -1;
1253 
1254  const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint));
1255  const sal_Int32 nColumn (GetColumn(aLocalPosition));
1256  const sal_Int32 nRow (GetRow(aLocalPosition));
1257 
1258  if (nColumn < 0 || nRow < 0)
1259  return -1;
1260  else
1261  {
1262  sal_Int32 nIndex (GetIndex(nRow, nColumn));
1263  if (nIndex >= mnSlideCount)
1264  return -1;
1265  else
1266  return nIndex;
1267  }
1268 }
1269 
1271  const sal_Int32 nSlideIndex,
1272  const sal_Int32 nRelativeHorizontalPosition,
1273  const sal_Int32 nRelativeVerticalPosition) const
1274 {
1275  sal_Int32 nColumn (GetColumn(nSlideIndex));
1276  sal_Int32 nRow (GetRow(nSlideIndex));
1277 
1278  geometry::RealPoint2D aPosition (
1279  mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap),
1280  mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap));
1281 
1282  if (nRelativeHorizontalPosition >= 0)
1283  {
1284  if (nRelativeHorizontalPosition > 0)
1285  aPosition.X += maPreviewSize.Width;
1286  else
1287  aPosition.X += maPreviewSize.Width / 2.0;
1288  }
1289  if (nRelativeVerticalPosition >= 0)
1290  {
1291  if (nRelativeVerticalPosition > 0)
1292  aPosition.Y += maPreviewSize.Height;
1293  else
1294  aPosition.Y += maPreviewSize.Height / 2.0;
1295  }
1296 
1297  return aPosition;
1298 }
1299 
1300 awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const
1301 {
1302  bool isRTL = AllSettings::GetLayoutRTL();
1303  const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, isRTL?1:-1, -1)));
1305  geometry::RealRectangle2D(
1306  aWindowPosition.X,
1307  aWindowPosition.Y,
1308  aWindowPosition.X + maPreviewSize.Width,
1309  aWindowPosition.Y + maPreviewSize.Height));
1310 }
1311 
1313  const ::std::function<void (sal_Int32)>& rAction)
1314 {
1315  for (sal_Int32 nRow=mnFirstVisibleRow; nRow<=mnLastVisibleRow; ++nRow)
1316  {
1317  for (sal_Int32 nColumn=mnFirstVisibleColumn; nColumn<=mnLastVisibleColumn; ++nColumn)
1318  {
1319  const sal_Int32 nSlideIndex (GetIndex(nRow, nColumn));
1320  if (nSlideIndex >= mnSlideCount)
1321  return;
1322  rAction(nSlideIndex);
1323  }
1324  }
1325 }
1326 
1328 {
1329  return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1330 }
1331 
1333 {
1334  return ::std::min(
1335  GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1336  mnSlideCount);
1337 }
1338 
1340 {
1341  if (mnHorizontalOffset != nOffset)
1342  {
1343  mnHorizontalOffset = round(nOffset);
1344  SetupVisibleArea();
1345  UpdateScrollBars();
1346  return true;
1347  }
1348  else
1349  return false;
1350 }
1351 
1353 {
1354  if (mnVerticalOffset != nOffset)
1355  {
1356  mnVerticalOffset = round(nOffset);
1357  SetupVisibleArea();
1358  UpdateScrollBars();
1359  return true;
1360  }
1361  else
1362  return false;
1363 }
1364 
1366 {
1367  sal_Int32 nTotalRowCount = sal_Int32(ceil(double(mnSlideCount) / double(mnColumnCount)));
1368 
1369  if (mpVerticalScrollBar)
1370  {
1371  mpVerticalScrollBar->SetTotalSize(
1372  nTotalRowCount * maPreviewSize.Height
1373  + (nTotalRowCount-1) * mnVerticalGap
1374  + 2*mnVerticalGap);
1375  mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset, false);
1376  mpVerticalScrollBar->SetThumbSize(maBoundingBox.Y2 - maBoundingBox.Y1 + 1);
1377  mpVerticalScrollBar->SetLineHeight(maPreviewSize.Height);
1378  }
1379 
1380  // No place yet for the vertical scroll bar.
1381 }
1382 
1384  const sal_Int32 nRow,
1385  const sal_Int32 nColumn) const
1386 {
1387  return nRow * mnColumnCount + nColumn;
1388 }
1389 
1390 sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const
1391 {
1392  return nSlideIndex / mnColumnCount;
1393 }
1394 
1395 sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const
1396 {
1397  return nSlideIndex % mnColumnCount;
1398 }
1399 
1400 //===== PresenterSlideSorter::MouseOverManager ================================
1401 
1403  const Reference<container::XIndexAccess>& rxSlides,
1404  const std::shared_ptr<PresenterTheme>& rpTheme,
1405  const Reference<awt::XWindow>& rxInvalidateTarget,
1406  const std::shared_ptr<PresenterPaintManager>& rpPaintManager)
1407  : mxSlides(rxSlides),
1408  mnSlideIndex(-1),
1409  mxInvalidateTarget(rxInvalidateTarget),
1410  mpPaintManager(rpPaintManager)
1411 {
1412  if (rpTheme != nullptr)
1413  {
1414  std::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer());
1415  if (pBitmaps != nullptr)
1416  {
1417  mpLeftLabelBitmap = pBitmaps->GetBitmap("LabelLeft");
1418  mpCenterLabelBitmap = pBitmaps->GetBitmap("LabelCenter");
1419  mpRightLabelBitmap = pBitmaps->GetBitmap("LabelRight");
1420  }
1421 
1422  mpFont = rpTheme->GetFont("SlideSorterLabelFont");
1423  }
1424 }
1425 
1427  const sal_Int32 nSlideIndex,
1428  const Reference<rendering::XCanvas>& rxCanvas,
1429  const Reference<rendering::XPolyPolygon2D>& rxClip)
1430 {
1431  if (nSlideIndex != mnSlideIndex)
1432  return;
1433 
1434  if (mxCanvas != rxCanvas)
1435  SetCanvas(rxCanvas);
1436  if (rxCanvas == nullptr)
1437  return;
1438 
1439  if ( ! mxBitmap.is())
1440  mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1441  if (!mxBitmap.is())
1442  return;
1443 
1444  geometry::IntegerSize2D aSize (mxBitmap->getSize());
1445  const double nXOffset (maSlideBoundingBox.X
1446  + (maSlideBoundingBox.Width - aSize.Width) / 2.0);
1447  const double nYOffset (maSlideBoundingBox.Y
1448  + (maSlideBoundingBox.Height - aSize.Height) / 2.0);
1449  rxCanvas->drawBitmap(
1450  mxBitmap,
1451  rendering::ViewState(
1452  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1453  rxClip),
1454  rendering::RenderState(
1455  geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1456  nullptr,
1457  Sequence<double>(4),
1458  rendering::CompositeOperation::SOURCE));
1459 }
1460 
1462  const Reference<rendering::XCanvas>& rxCanvas)
1463 {
1464  mxCanvas = rxCanvas;
1465  if (mpFont)
1466  mpFont->PrepareFont(mxCanvas);
1467 }
1468 
1470  const sal_Int32 nSlideIndex,
1471  const awt::Rectangle& rBox)
1472 {
1473  if (mnSlideIndex == nSlideIndex)
1474  return;
1475 
1476  mnSlideIndex = -1;
1477  Invalidate();
1478 
1479  maSlideBoundingBox = rBox;
1480  mnSlideIndex = nSlideIndex;
1481 
1482  if (nSlideIndex >= 0)
1483  {
1484  if (mxSlides)
1485  {
1486  msText.clear();
1487 
1488  Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
1489  if (xSlideProperties.is())
1490  xSlideProperties->getPropertyValue("LinkDisplayName") >>= msText;
1491 
1492  if (msText.isEmpty())
1493  msText = "Slide " + OUString::number(nSlideIndex + 1);
1494  }
1495  }
1496  else
1497  {
1498  msText.clear();
1499  }
1500  mxBitmap = nullptr;
1501 
1502  Invalidate();
1503 }
1504 
1506  const OUString& rsText,
1507  const sal_Int32 nMaximalWidth) const
1508 {
1509  if ( ! mxCanvas.is())
1510  return nullptr;
1511 
1512  if (!mpFont || !mpFont->mxFont.is())
1513  return nullptr;
1514 
1515  // Long text has to be shortened.
1516  const OUString sText (GetFittingText(rsText, nMaximalWidth
1517  - 2*gnHorizontalLabelBorder
1518  - 2*gnHorizontalLabelPadding));
1519 
1520  // Determine the size of the label. Its height is defined by the
1521  // bitmaps that are used to paints its background. The width is defined
1522  // by the text.
1523  geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText));
1524 
1525  // Create a new bitmap that will contain the complete label.
1526  Reference<rendering::XBitmap> xBitmap (
1527  mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize));
1528 
1529  if ( ! xBitmap.is())
1530  return nullptr;
1531 
1532  Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1533  if ( ! xBitmapCanvas.is())
1534  return nullptr;
1535 
1536  // Paint the background.
1537  PaintButtonBackground(xBitmapCanvas, aLabelSize);
1538 
1539  // Paint the text.
1540  if (!sText.isEmpty())
1541  {
1542 
1543  const rendering::StringContext aContext (sText, 0, sText.getLength());
1544  const Reference<rendering::XTextLayout> xLayout (mpFont->mxFont->createTextLayout(
1545  aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
1546  const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
1547 
1548  const double nXOffset = (aLabelSize.Width - aTextBBox.X2 + aTextBBox.X1) / 2;
1549  const double nYOffset = aLabelSize.Height
1550  - (aLabelSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y2;
1551 
1552  const rendering::ViewState aViewState(
1553  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1554  nullptr);
1555 
1556  rendering::RenderState aRenderState (
1557  geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1558  nullptr,
1559  Sequence<double>(4),
1560  rendering::CompositeOperation::SOURCE);
1561  PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1562 
1563  xBitmapCanvas->drawTextLayout (
1564  xLayout,
1565  aViewState,
1566  aRenderState);
1567  }
1568 
1569  return xBitmap;
1570 }
1571 
1573  const OUString& rsText,
1574  const double nMaximalWidth) const
1575 {
1576  const double nTextWidth (
1577  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width);
1578  if (nTextWidth > nMaximalWidth)
1579  {
1580  // Text is too wide. Shorten it by removing characters from the end
1581  // and replacing them by ellipses.
1582 
1583  // Guess a start value of the final string length.
1584  double nBestWidth (0);
1585  OUString sBestCandidate;
1586  sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth));
1587  static const OUStringLiteral sEllipses (u"...");
1588  while (true)
1589  {
1590  const OUString sCandidate (rsText.subView(0,nLength) + sEllipses);
1591  const double nWidth (
1592  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width);
1593  if (nWidth > nMaximalWidth)
1594  {
1595  // Candidate still too wide, shorten it.
1596  nLength -= 1;
1597  if (nLength <= 0)
1598  break;
1599  }
1600  else if (nWidth < nMaximalWidth)
1601  {
1602  // Candidate short enough.
1603  if (nWidth > nBestWidth)
1604  {
1605  // Best length so far.
1606  sBestCandidate = sCandidate;
1607  nBestWidth = nWidth;
1608  nLength += 1;
1609  if (nLength >= rsText.getLength())
1610  break;
1611  }
1612  else
1613  break;
1614  }
1615  else
1616  {
1617  // Candidate is exactly as long as it may be. Use it
1618  // without looking any further.
1619  sBestCandidate = sCandidate;
1620  break;
1621  }
1622  }
1623  return sBestCandidate;
1624  }
1625  else
1626  return rsText;
1627 }
1628 
1630  const OUString& rsText) const
1631 {
1632  // Height is specified by the label bitmaps.
1633  sal_Int32 nHeight (32);
1634  if (mpCenterLabelBitmap)
1635  {
1636  Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap());
1637  if (xBitmap.is())
1638  nHeight = xBitmap->getSize().Height;
1639  }
1640 
1641  // Width is specified by text width and maximal width.
1642  const geometry::RealSize2D aTextSize (
1643  PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText));
1644 
1645  const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding));
1646 
1647  return geometry::IntegerSize2D(nWidth, nHeight);
1648 }
1649 
1651  const Reference<rendering::XCanvas>& rxCanvas,
1652  const geometry::IntegerSize2D& rSize) const
1653 {
1654  // Get the bitmaps for painting the label background.
1655  Reference<rendering::XBitmap> xLeftLabelBitmap;
1656  if (mpLeftLabelBitmap)
1657  xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap();
1658 
1659  Reference<rendering::XBitmap> xCenterLabelBitmap;
1660  if (mpCenterLabelBitmap)
1661  xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap();
1662 
1663  Reference<rendering::XBitmap> xRightLabelBitmap;
1664  if (mpRightLabelBitmap)
1665  xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap();
1666 
1668  rxCanvas,
1669  awt::Rectangle(0,0, rSize.Width,rSize.Height),
1670  awt::Rectangle(0,0, rSize.Width,rSize.Height),
1671  xLeftLabelBitmap,
1672  xCenterLabelBitmap,
1673  xRightLabelBitmap);
1674 }
1675 
1677 {
1678  if (mpPaintManager != nullptr)
1679  mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true);
1680 }
1681 
1682 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
1683 
1685  const css::uno::Reference<css::uno::XComponentContext>& rxContext,
1686  const css::uno::Reference<css::rendering::XCanvas>& rxCanvas)
1687  : mnTopFrameSize(0),
1688  mnLeftFrameSize(0),
1689  mnRightFrameSize(0),
1690  mnBottomFrameSize(0)
1691 {
1692  PresenterConfigurationAccess aConfiguration (
1693  rxContext,
1694  "/org.openoffice.Office.PresenterScreen/",
1696  Reference<container::XHierarchicalNameAccess> xBitmaps (
1697  aConfiguration.GetConfigurationNode(
1698  "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
1699  UNO_QUERY);
1700  if ( ! xBitmaps.is())
1701  return;
1702 
1703  PresenterBitmapContainer aContainer (
1704  "PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps",
1705  std::shared_ptr<PresenterBitmapContainer>(),
1706  rxContext,
1707  rxCanvas);
1708 
1709  mpTopLeft = aContainer.GetBitmap("TopLeft");
1710  mpTop = aContainer.GetBitmap("Top");
1711  mpTopRight = aContainer.GetBitmap("TopRight");
1712  mpLeft = aContainer.GetBitmap("Left");
1713  mpRight = aContainer.GetBitmap("Right");
1714  mpBottomLeft = aContainer.GetBitmap("BottomLeft");
1715  mpBottom = aContainer.GetBitmap("Bottom");
1716  mpBottomRight = aContainer.GetBitmap("BottomRight");
1717 
1718  // Determine size of frame.
1719  if (mpTop)
1720  mnTopFrameSize = mpTop->mnHeight;
1721  if (mpLeft)
1722  mnLeftFrameSize = mpLeft->mnWidth;
1723  if (mpRight)
1724  mnRightFrameSize = mpRight->mnWidth;
1725  if (mpBottom)
1726  mnBottomFrameSize = mpBottom->mnHeight;
1727 
1728  if (mpTopLeft)
1729  {
1730  mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight);
1731  mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth);
1732  }
1733  if (mpTopRight)
1734  {
1735  mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight);
1736  mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth);
1737  }
1738  if (mpBottomLeft)
1739  {
1740  mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth);
1741  mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight);
1742  }
1743  if (mpBottomRight)
1744  {
1745  mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth);
1746  mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight);
1747  }
1748 }
1749 
1751  const awt::Rectangle& rSlideBoundingBox,
1752  const Reference<rendering::XCanvas>& rxCanvas,
1753  const geometry::RealRectangle2D& rClipBox)
1754 {
1755  if ( ! rxCanvas.is())
1756  return;
1757 
1758  const Reference<rendering::XPolyPolygon2D> xClip (
1759  PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
1760 
1761  if (mpTop)
1762  {
1763  PaintBitmapTiled(
1764  mpTop->GetNormalBitmap(),
1765  rxCanvas,
1766  rClipBox,
1767  rSlideBoundingBox.X,
1768  rSlideBoundingBox.Y - mpTop->mnHeight,
1769  rSlideBoundingBox.Width,
1770  mpTop->mnHeight);
1771  }
1772  if (mpLeft)
1773  {
1774  PaintBitmapTiled(
1775  mpLeft->GetNormalBitmap(),
1776  rxCanvas,
1777  rClipBox,
1778  rSlideBoundingBox.X - mpLeft->mnWidth,
1779  rSlideBoundingBox.Y,
1780  mpLeft->mnWidth,
1781  rSlideBoundingBox.Height);
1782  }
1783  if (mpRight)
1784  {
1785  PaintBitmapTiled(
1786  mpRight->GetNormalBitmap(),
1787  rxCanvas,
1788  rClipBox,
1789  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1790  rSlideBoundingBox.Y,
1791  mpRight->mnWidth,
1792  rSlideBoundingBox.Height);
1793  }
1794  if (mpBottom)
1795  {
1796  PaintBitmapTiled(
1797  mpBottom->GetNormalBitmap(),
1798  rxCanvas,
1799  rClipBox,
1800  rSlideBoundingBox.X,
1801  rSlideBoundingBox.Y + rSlideBoundingBox.Height,
1802  rSlideBoundingBox.Width,
1803  mpBottom->mnHeight);
1804  }
1805  if (mpTopLeft)
1806  {
1807  PaintBitmapOnce(
1808  mpTopLeft->GetNormalBitmap(),
1809  rxCanvas,
1810  xClip,
1811  rSlideBoundingBox.X - mpTopLeft->mnWidth,
1812  rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1813  }
1814  if (mpTopRight)
1815  {
1816  PaintBitmapOnce(
1817  mpTopRight->GetNormalBitmap(),
1818  rxCanvas,
1819  xClip,
1820  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1821  rSlideBoundingBox.Y - mpTopLeft->mnHeight);
1822  }
1823  if (mpBottomLeft)
1824  {
1825  PaintBitmapOnce(
1826  mpBottomLeft->GetNormalBitmap(),
1827  rxCanvas,
1828  xClip,
1829  rSlideBoundingBox.X - mpBottomLeft->mnWidth,
1830  rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1831  }
1832  if (mpBottomRight)
1833  {
1834  PaintBitmapOnce(
1835  mpBottomRight->GetNormalBitmap(),
1836  rxCanvas,
1837  xClip,
1838  rSlideBoundingBox.X + rSlideBoundingBox.Width,
1839  rSlideBoundingBox.Y + rSlideBoundingBox.Height);
1840  }
1841 }
1842 
1844  const awt::Rectangle& rSlideBoundingBox)
1845 {
1846  return awt::Rectangle(
1847  rSlideBoundingBox.X - mnLeftFrameSize,
1848  rSlideBoundingBox.Y - mnTopFrameSize,
1849  rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize,
1850  rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize);
1851 }
1852 
1854  const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
1855  const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
1856  const Reference<rendering::XPolyPolygon2D>& rxClip,
1857  const double nX,
1858  const double nY)
1859 {
1860  OSL_ASSERT(rxCanvas.is());
1861  if ( ! rxBitmap.is())
1862  return;
1863 
1864  const rendering::ViewState aViewState(
1865  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1866  rxClip);
1867 
1868  const rendering::RenderState aRenderState (
1869  geometry::AffineMatrix2D(
1870  1, 0, nX,
1871  0, 1, nY),
1872  nullptr,
1873  Sequence<double>(4),
1874  rendering::CompositeOperation::SOURCE);
1875 
1876  rxCanvas->drawBitmap(
1877  rxBitmap,
1878  aViewState,
1879  aRenderState);
1880 }
1881 
1883  const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
1884  const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
1885  const geometry::RealRectangle2D& rClipBox,
1886  const double nX0,
1887  const double nY0,
1888  const double nWidth,
1889  const double nHeight)
1890 {
1891  OSL_ASSERT(rxCanvas.is());
1892  if ( ! rxBitmap.is())
1893  return;
1894 
1895  geometry::IntegerSize2D aSize (rxBitmap->getSize());
1896 
1897  const rendering::ViewState aViewState(
1898  geometry::AffineMatrix2D(1,0,0, 0,1,0),
1901  rClipBox,
1902  geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
1903  rxCanvas->getDevice()));
1904 
1905  rendering::RenderState aRenderState (
1906  geometry::AffineMatrix2D(
1907  1, 0, nX0,
1908  0, 1, nY0),
1909  nullptr,
1910  Sequence<double>(4),
1911  rendering::CompositeOperation::SOURCE);
1912 
1913  const double nX1 = nX0 + nWidth;
1914  const double nY1 = nY0 + nHeight;
1915  for (double nY=nY0; nY<nY1; nY+=aSize.Height)
1916  for (double nX=nX0; nX<nX1; nX+=aSize.Width)
1917  {
1918  aRenderState.AffineTransform.m02 = nX;
1919  aRenderState.AffineTransform.m12 = nY;
1920  rxCanvas->drawBitmap(
1921  rxBitmap,
1922  aViewState,
1923  aRenderState);
1924  }
1925 }
1926 
1927 } // end of namespace ::sdext::presenter
1928 
1929 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< PresenterPaintManager > mpPaintManager
geometry::IntegerSize2D CalculateLabelSize(const OUString &rsText) const
sal_Int32 GetIndex(const sal_Int32 nRow, const sal_Int32 nColumn) const
SharedBitmapDescriptor mpBottomRight
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
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
std::mutex m_aMutex
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)
void Paint(const sal_Int32 nSlideIndex, const Reference< rendering::XCanvas > &rxCanvas, const Reference< rendering::XPolyPolygon2D > &rxClip)
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.
float u
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
const double gnHorizontalBorder(15)
::rtl::Reference< PresenterButton > mpCloseButton
const tools::Long nButtonWidth
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
Degree100 abs(Degree100 x)
sal_Int32 nLength
static bool IsInside(const css::geometry::RealRectangle2D &rBox, const css::geometry::RealPoint2D &rPoint)
void dispose()
const double gnVerticalBorder(5)
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)
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