diff options
author | Vladimir Glazounov <vg@openoffice.org> | 2008-05-13 13:37:48 +0000 |
---|---|---|
committer | Vladimir Glazounov <vg@openoffice.org> | 2008-05-13 13:37:48 +0000 |
commit | d3ff78188fd08422586e7a884a31e185ecdde34c (patch) | |
tree | 3ceacf4d572e802b80e624ea7b44d3c650acb243 /sdext/source/presenter/PresenterSlideSorter.cxx | |
parent | 43a71a2d078a69927db8b492066cc6e176c84f45 (diff) |
INTEGRATION: CWS presenterscreen (1.2.4); FILE MERGED
2008/04/28 14:46:33 af 1.2.4.5: #i18486# Fixed GetColumn() and GetRow() for when offsets are not zero.
2008/04/22 13:05:58 af 1.2.4.4: #i18486# Made extension identifier platform specific.
2008/04/22 08:28:04 af 1.2.4.3: RESYNC: (1.2-1.3); FILE MERGED
2008/04/16 16:59:13 af 1.2.4.2: #i18486# Fixed some Linux build problems.
2008/04/16 16:05:13 af 1.2.4.1: #i18486# Added close button. Changed mouse over effect.
Diffstat (limited to 'sdext/source/presenter/PresenterSlideSorter.cxx')
-rw-r--r-- | sdext/source/presenter/PresenterSlideSorter.cxx | 1826 |
1 files changed, 1327 insertions, 499 deletions
diff --git a/sdext/source/presenter/PresenterSlideSorter.cxx b/sdext/source/presenter/PresenterSlideSorter.cxx index c71c6fa89b6e..aec508f99b8c 100644 --- a/sdext/source/presenter/PresenterSlideSorter.cxx +++ b/sdext/source/presenter/PresenterSlideSorter.cxx @@ -8,7 +8,7 @@ * * $RCSfile: PresenterSlideSorter.cxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * * This file is part of OpenOffice.org. * @@ -30,14 +30,20 @@ ************************************************************************/ #include "PresenterSlideSorter.hxx" +#include "PresenterButton.hxx" +#include "PresenterCanvasHelper.hxx" +#include "PresenterComponent.hxx" #include "PresenterGeometryHelper.hxx" #include "PresenterHelper.hxx" +#include "PresenterPaintManager.hxx" +#include "PresenterPaneBase.hxx" #include "PresenterScrollBar.hxx" +#include "PresenterUIPainter.hxx" #include "PresenterWindowManager.hxx" -#include <com/sun/star/awt/InvalidateStyle.hpp> #include <com/sun/star/awt/PosSize.hpp> #include <com/sun/star/awt/XWindowPeer.hpp> #include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> #include <com/sun/star/drawing/XSlideSorterBase.hpp> #include <com/sun/star/drawing/framework/XConfigurationController.hpp> #include <com/sun/star/drawing/framework/XControllerManager.hpp> @@ -54,8 +60,41 @@ using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing::framework; using ::rtl::OUString; +#define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) + +namespace { + const static sal_Int32 gnVerticalGap (10); + const static sal_Int32 gnVerticalBorder (10); + const static sal_Int32 gnHorizontalGap (10); + const static sal_Int32 gnHorizontalBorder (10); + + const static double gnMinimalPreviewWidth (200); + const static double gnPreferredPreviewWidth (300); + const static double gnMaximalPreviewWidth (400); + const static sal_Int32 gnPreferredColumnCount (6); + const static double gnMinimalHorizontalPreviewGap(15); + const static double gnPreferredHorizontalPreviewGap(25); + const static double gnMaximalHorizontalPreviewGap(50); + const static double gnMinimalVerticalPreviewGap(15); + const static double gnPreferredVerticalPreviewGap(25); + const static double gnMaximalVerticalPreviewGap(50); + + const static sal_Int32 gnHorizontalLabelBorder (3); + const static sal_Int32 gnHorizontalLabelPadding (5); + + const static sal_Int32 gnVerticalButtonPadding (gnVerticalGap); +} + namespace sdext { namespace presenter { +namespace { + sal_Int32 round (const double nValue) { return sal::static_int_cast<sal_Int32>(0.5 + nValue); } + sal_Int32 floor (const double nValue) { return sal::static_int_cast<sal_Int32>(nValue); } + double sqr (const double nValue) { return nValue*nValue; } +} + + + //===== PresenterSlideSorter::Layout ========================================== class PresenterSlideSorter::Layout @@ -67,32 +106,38 @@ public: const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar, const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar); - void Update (const awt::Rectangle& rWindowBox, const double nSlideAspectRatio); + void Update (const geometry::RealRectangle2D& rBoundingBox, const double nSlideAspectRatio); void SetupVisibleArea (void); - sal_Int32 GetSlideIndexForPosition (const css::geometry::RealPoint2D& rPoint); + void UpdateScrollBars (void); + bool IsScrollBarNeeded (const sal_Int32 nSlideCount); + geometry::RealPoint2D GetLocalPosition (const geometry::RealPoint2D& rWindowPoint) const; + geometry::RealPoint2D GetWindowPosition(const geometry::RealPoint2D& rLocalPoint) const; + sal_Int32 GetColumn (const geometry::RealPoint2D& rLocalPoint, + const bool bReturnInvalidValue = false) const; + sal_Int32 GetRow (const geometry::RealPoint2D& rLocalPoint, + const bool bReturnInvalidValue = false) const; + sal_Int32 GetSlideIndexForPosition (const css::geometry::RealPoint2D& rPoint) const; css::geometry::RealPoint2D GetPoint ( const sal_Int32 nSlideIndex, const sal_Int32 nRelativeHorizontalPosition, - const sal_Int32 nRelativeVerticalPosition); - enum DistanceType { Norm1, Norm2, XOnly, YOnly }; - double GetDistanceFromCenter ( - const css::geometry::RealPoint2D& rPoint, - const sal_Int32 nSlideIndex, - const DistanceType eDistanceType); - css::awt::Rectangle GetBoundingBox (const sal_Int32 nSlideIndex); + const sal_Int32 nRelativeVerticalPosition) const; + css::awt::Rectangle GetBoundingBox (const sal_Int32 nSlideIndex) const; + geometry::IntegerSize2D GetPreviewSize (void) const; void ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction); - sal_Int32 GetFirstVisibleSlideIndex (void); - sal_Int32 GetLastVisibleSlideIndex (void); + sal_Int32 GetFirstVisibleSlideIndex (void) const; + sal_Int32 GetLastVisibleSlideIndex (void) const; bool SetHorizontalOffset (const double nOffset); + bool SetVerticalOffset (const double nOffset); + Orientation GetOrientation (void) const; - css::geometry::RealRectangle2D maInnerBorder; - css::geometry::RealRectangle2D maOuterBorder; - css::geometry::RealRectangle2D maViewport; + css::geometry::RealRectangle2D maBoundingBox; css::geometry::IntegerSize2D maPreviewSize; - double mnHorizontalOffset; - double mnVerticalOffset; - double mnHorizontalGap; - double mnVerticalGap; + sal_Int32 mnHorizontalOffset; + sal_Int32 mnVerticalOffset; + sal_Int32 mnHorizontalGap; + sal_Int32 mnVerticalGap; + sal_Int32 mnHorizontalBorder; + sal_Int32 mnVerticalBorder; sal_Int32 mnRowCount; sal_Int32 mnColumnCount; sal_Int32 mnSlideCount; @@ -101,16 +146,15 @@ public: sal_Int32 mnLastVisibleColumn; sal_Int32 mnFirstVisibleRow; sal_Int32 mnLastVisibleRow; - double mnScrollBarHeight; private: Orientation meOrientation; ::rtl::Reference<PresenterScrollBar> mpHorizontalScrollBar; ::rtl::Reference<PresenterScrollBar> mpVerticalScrollBar; - void UpdateScrollBars (void); - sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn); - sal_Int32 GetRow (const sal_Int32 nSlideIndex); - sal_Int32 GetColumn (const sal_Int32 nSlideIndex); + + sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const; + sal_Int32 GetRow (const sal_Int32 nSlideIndex) const; + sal_Int32 GetColumn (const sal_Int32 nSlideIndex) const; }; @@ -118,58 +162,110 @@ private: //==== PresenterSlideSorter::MouseOverManager ================================= -namespace { - typedef cppu::WeakComponentImplHelper1< - css::drawing::XSlidePreviewCacheListener - > MouseOverManagerInterfaceBase; -} - class PresenterSlideSorter::MouseOverManager - : private ::cppu::BaseMutex, - public MouseOverManagerInterfaceBase + : ::boost::noncopyable { public: - const static double mnMinScale; - const static double mnMaxScale; - MouseOverManager ( - const Reference<XComponentContext>& rxContext, const Reference<container::XIndexAccess>& rxSlides, - const Reference<frame::XModel>& rxModel); + const ::boost::shared_ptr<PresenterTheme>& rpTheme, + const Reference<awt::XWindow>& rxInvalidateTarget, + const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager); ~MouseOverManager (void); - void SetCanvas ( - const Reference<rendering::XSpriteCanvas>& rxCanvas); + void Paint ( + const sal_Int32 nSlideIndex, + const Reference<rendering::XCanvas>& rxCanvas, + const Reference<rendering::XPolyPolygon2D>& rxClip); void SetSlide ( const sal_Int32 nSlideIndex, - const awt::Rectangle& rBox, - const double nDistance); + const awt::Rectangle& rBox); - void SetActiveState (const bool bIsActive); +private: + Reference<rendering::XCanvas> mxCanvas; + const Reference<container::XIndexAccess> mxSlides; + SharedBitmapDescriptor mpLeftLabelBitmap; + SharedBitmapDescriptor mpCenterLabelBitmap; + SharedBitmapDescriptor mpRightLabelBitmap; + PresenterTheme::SharedFontDescriptor mpFont; + sal_Int32 mnSlideIndex; + awt::Rectangle maSlideBoundingBox; + OUString msText; + Reference<rendering::XBitmap> mxBitmap; + Reference<awt::XWindow> mxInvalidateTarget; + ::boost::shared_ptr<PresenterPaintManager> mpPaintManager; - // XSlidePreviewCacheListener + void SetCanvas ( + const Reference<rendering::XCanvas>& rxCanvas); + /** Create a bitmap that shows the given text and is not wider than the + given maximal width. + */ + Reference<rendering::XBitmap> CreateBitmap ( + const OUString& rsText, + const sal_Int32 nMaximalWidth) const; + void Invalidate (void); + geometry::IntegerSize2D CalculateLabelSize ( + const OUString& rsText) const; + OUString GetFittingText (const OUString& rsText, const double nMaximalWidth) const; + void PaintButtonBackground ( + const Reference<rendering::XBitmapCanvas>& rxCanvas, + const geometry::IntegerSize2D& rSize) const; +}; + + + + +//==== PresenterSlideSorter::CurrentSlideFrameRenderer ======================== + +class PresenterSlideSorter::CurrentSlideFrameRenderer +{ +public: + CurrentSlideFrameRenderer ( + const css::uno::Reference<css::uno::XComponentContext>& rxContext, + const css::uno::Reference<css::rendering::XCanvas>& rxCanvas); + ~CurrentSlideFrameRenderer (void); - virtual void SAL_CALL notifyPreviewCreation ( - sal_Int32 nSlideIndex) - throw(css::uno::RuntimeException); + void PaintCurrentSlideFrame ( + const awt::Rectangle& rSlideBoundingBox, + const Reference<rendering::XCanvas>& rxCanvas, + const geometry::RealRectangle2D& rClipBox); + + /** Enlarge the given rectangle to include the current slide indicator. + */ + awt::Rectangle GetBoundingBox ( + const awt::Rectangle& rSlideBoundingBox); private: - Reference<rendering::XSpriteCanvas> mxCanvas; - Reference<drawing::XSlidePreviewCache> mxPreviewCache; - sal_Int32 mnSlideIndex; - awt::Rectangle maBoundingBox; - double mnDistance; - Reference<rendering::XCustomSprite> mxSprite; - geometry::RealSize2D maSpriteSize; - bool mbIsActive; - - void CreateSprite (const sal_Int32 nSlideIndex); - void DisposeSprite (void); + SharedBitmapDescriptor mpTopLeft; + SharedBitmapDescriptor mpTop; + SharedBitmapDescriptor mpTopRight; + SharedBitmapDescriptor mpLeft; + SharedBitmapDescriptor mpRight; + SharedBitmapDescriptor mpBottomLeft; + SharedBitmapDescriptor mpBottom; + SharedBitmapDescriptor mpBottomRight; + sal_Int32 mnTopFrameSize; + sal_Int32 mnLeftFrameSize; + sal_Int32 mnRightFrameSize; + sal_Int32 mnBottomFrameSize; + + 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); + 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); }; -const double PresenterSlideSorter::MouseOverManager::mnMinScale = 1.0; -const double PresenterSlideSorter::MouseOverManager::mnMaxScale = 2.0; @@ -190,11 +286,20 @@ PresenterSlideSorter::PresenterSlideSorter ( mxSlideShowController(mpPresenterController->GetSlideShowController()), mxPreviewCache(), mbIsPaintPending(true), + mbIsLayoutPending(true), mpLayout(), mpHorizontalScrollBar(), + mpVerticalScrollBar(), + mpCloseButton(), mpMouseOverManager(), mnSlideIndexMousePressed(-1), - mnCurrentSlideIndex(-1) + mnCurrentSlideIndex(-1), + mnSeparatorY(0), + maSeparatorColor(0x00ffffff), + maCloseButtonCenter(), + maCurrentSlideFrameBoundingBox(), + mpCurrentSlideFrameRenderer(), + mxPreviewFrame() { if ( ! rxContext.is() || ! rxViewId.is() @@ -226,21 +331,48 @@ PresenterSlideSorter::PresenterSlideSorter ( mxWindow->addMouseMotionListener(this); mxWindow->setVisible(sal_True); - // Create the scroll bar. - mpHorizontalScrollBar = ::rtl::Reference<PresenterScrollBar>( - new PresenterHorizontalScrollBar( - rxContext, - mxWindow, - ::boost::bind(&PresenterSlideSorter::SetHorizontalOffset,this,_1))); - // Remember the current slide. mnCurrentSlideIndex = mxSlideShowController->getCurrentSlideIndex(); + // Set the orientation. + const bool bIsVertical (true); + + // Create the scroll bar. + if (bIsVertical) + mpVerticalScrollBar = ::rtl::Reference<PresenterScrollBar>( + new PresenterVerticalScrollBar( + rxContext, + mxWindow, + mpPresenterController->GetPaintManager(), + ::boost::bind(&PresenterSlideSorter::SetVerticalOffset,this,_1))); + else + mpHorizontalScrollBar = ::rtl::Reference<PresenterScrollBar>( + new PresenterHorizontalScrollBar( + rxContext, + mxWindow, + mpPresenterController->GetPaintManager(), + ::boost::bind(&PresenterSlideSorter::SetHorizontalOffset,this,_1))); + mpCloseButton = PresenterButton::Create( + rxContext, + mpPresenterController, + mpPresenterController->GetTheme(), + mxWindow, + mxCanvas, + A2S("SlideSorterCloser")); + + if (mpPresenterController->GetTheme().get() != NULL) + { + PresenterTheme::SharedFontDescriptor pFont ( + mpPresenterController->GetTheme()->GetFont(A2S("ButtonFont"))); + if (pFont.get() != NULL) + maSeparatorColor = pFont->mnColor; + } + // Create the layout. mpLayout.reset(new Layout( - Layout::Horizontal, + Layout::Vertical, mpHorizontalScrollBar, - ::rtl::Reference<PresenterScrollBar>())); + mpVerticalScrollBar)); // Create the preview cache. mxPreviewCache = Reference<drawing::XSlidePreviewCache>( @@ -257,10 +389,11 @@ PresenterSlideSorter::PresenterSlideSorter ( } // Create the mouse over manager. - mpMouseOverManager = ::rtl::Reference<MouseOverManager>(new MouseOverManager( - mxComponentContext, + mpMouseOverManager.reset(new MouseOverManager( Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY), - rxController->getModel())); + mpPresenterController->GetTheme(), + mxWindow, + mpPresenterController->GetPaintManager())); // Listen for changes of the current slide. Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW); @@ -268,14 +401,10 @@ PresenterSlideSorter::PresenterSlideSorter ( OUString::createFromAscii("CurrentPage"), this); - UpdateLayout(); - // Move the current slide in the center of the window. const awt::Rectangle aCurrentSlideBBox (mpLayout->GetBoundingBox(mnCurrentSlideIndex)); const awt::Rectangle aWindowBox (mxWindow->getPosSize()); SetHorizontalOffset(aCurrentSlideBBox.X - aWindowBox.Width/2.0); - - Paint(); } catch (RuntimeException&) { @@ -299,6 +428,32 @@ void SAL_CALL PresenterSlideSorter::disposing (void) mxComponentContext = NULL; mxViewId = NULL; mxPane = NULL; + + if (mpVerticalScrollBar.is()) + { + Reference<lang::XComponent> xComponent ( + static_cast<XWeak*>(mpVerticalScrollBar.get()), UNO_QUERY); + mpVerticalScrollBar = NULL; + if (xComponent.is()) + xComponent->dispose(); + } + if (mpHorizontalScrollBar.is()) + { + Reference<lang::XComponent> xComponent ( + static_cast<XWeak*>(mpHorizontalScrollBar.get()), UNO_QUERY); + mpHorizontalScrollBar = NULL; + if (xComponent.is()) + xComponent->dispose(); + } + if (mpCloseButton.is()) + { + Reference<lang::XComponent> xComponent ( + static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY); + mpCloseButton = NULL; + if (xComponent.is()) + xComponent->dispose(); + } + if (mxCanvas.is()) { Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY); @@ -309,12 +464,7 @@ void SAL_CALL PresenterSlideSorter::disposing (void) mpPresenterController = NULL; mxSlideShowController = NULL; mpLayout.reset(); - mpHorizontalScrollBar = NULL; - if (mpMouseOverManager.is()) - { - mpMouseOverManager->dispose(); - mpMouseOverManager = NULL; - } + mpMouseOverManager.reset(); if (mxPreviewCache.is()) { @@ -340,14 +490,7 @@ void SAL_CALL PresenterSlideSorter::disposing (void) void PresenterSlideSorter::SetActiveState (const bool bIsActive) { - if (mxPreviewCache.is()) - if (bIsActive) - mxPreviewCache->resume(); - else - mxPreviewCache->pause(); - - if (mpMouseOverManager.get() != NULL) - mpMouseOverManager->SetActiveState(bIsActive); + (void)bIsActive; } @@ -371,15 +514,12 @@ void SAL_CALL PresenterSlideSorter::disposing (const lang::EventObject& rEventOb else if (rEventObject.Source == mxCanvas) { mxCanvas = NULL; - if (mpMouseOverManager.get() != NULL) - mpMouseOverManager->SetCanvas(NULL); if (mpHorizontalScrollBar.is()) mpHorizontalScrollBar->SetCanvas(NULL); + mbIsLayoutPending = true; mbIsPaintPending = true; - Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY); - if (xPeer.is()) - xPeer->invalidate(awt::InvalidateStyle::CHILDREN); + mpPresenterController->GetPaintManager()->Invalidate(mxWindow); } } @@ -393,9 +533,8 @@ void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent& rEven { (void)rEvent; ThrowIfDisposed(); - // The canvas should eventually be (or already has been) disposed by the - // pane. We listen for that and request a repaint when that happens. - mbIsPaintPending = true; + mbIsLayoutPending = true; + mpPresenterController->GetPaintManager()->Invalidate(mxWindow); } @@ -416,7 +555,8 @@ void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject& rEvent { (void)rEvent; ThrowIfDisposed(); - mbIsPaintPending = true; + mbIsLayoutPending = true; + mpPresenterController->GetPaintManager()->Invalidate(mxWindow); } @@ -439,20 +579,15 @@ void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEv { (void)rEvent; - if ( ! ProvideCanvas()) + // Deactivated views must not be painted. + if ( ! mbIsPresenterViewActive) return; - if (mbIsPaintPending) - { - UpdateLayout(); - Paint(); - } + Paint(rEvent.UpdateRect); - /* Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is()) xSpriteCanvas->updateScreen(sal_False); - */ } @@ -478,8 +613,20 @@ void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& r if (nSlideIndex == mnSlideIndexMousePressed && mnSlideIndexMousePressed >= 0) { - mpMouseOverManager->SetSlide(-1, awt::Rectangle(0,0,0,0), 0); - GotoSlide(nSlideIndex); + switch (rEvent.ClickCount) + { + case 1: + default: + GotoSlide(nSlideIndex); + break; + + case 2: + OSL_ASSERT(mpPresenterController.get()!=NULL); + OSL_ASSERT(mpPresenterController->GetWindowManager().get()!=NULL); + mpPresenterController->GetWindowManager()->SetSlideSorterState(false); + GotoSlide(nSlideIndex); + break; + } } } @@ -501,7 +648,7 @@ void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent& rEv (void)rEvent; mnSlideIndexMousePressed = -1; if (mpMouseOverManager.get() != NULL) - mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0), 0); + mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0)); } @@ -516,32 +663,19 @@ void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEve { const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y); sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition)); - double nDistanceFromCenter (2); - if (nSlideIndex >= 0) - { - const double nDistance (mpLayout->GetDistanceFromCenter(aPosition, nSlideIndex, - Layout::Norm1)); - if (nDistance < 1) - nDistanceFromCenter = nDistance; - else - nSlideIndex = -1; - } - else - { + if (nSlideIndex < 0) mnSlideIndexMousePressed = -1; - } if (nSlideIndex < 0) { - mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0), 0); + mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0)); } else { mpMouseOverManager->SetSlide( nSlideIndex, - mpLayout->GetBoundingBox(nSlideIndex), - nDistanceFromCenter); + mpLayout->GetBoundingBox(nSlideIndex)); } } } @@ -586,7 +720,6 @@ void SAL_CALL PresenterSlideSorter::propertyChange ( throw(css::uno::RuntimeException) { (void)rEvent; - // Close the slide sorter view. } @@ -598,7 +731,57 @@ void SAL_CALL PresenterSlideSorter::notifyPreviewCreation ( sal_Int32 nSlideIndex) throw(css::uno::RuntimeException) { - PaintPreview(nSlideIndex); + OSL_ASSERT(mpLayout.get()!=NULL); + + awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex)); + mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true); +} + + + + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL PresenterSlideSorter::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide) + throw (RuntimeException) +{ + (void)rxSlide; + + ThrowIfDisposed(); + ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); + + if (mxSlideShowController.is()) + { + const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex()); + if (nNewCurrentSlideIndex != mnCurrentSlideIndex) + { + mnCurrentSlideIndex = nNewCurrentSlideIndex; + + // Request a repaint of the previous current slide to hide its + // current slide indicator. + mpPresenterController->GetPaintManager()->Invalidate( + mxWindow, + maCurrentSlideFrameBoundingBox); + + // Request a repaint of the new current slide to show its + // current slide indicator. + maCurrentSlideFrameBoundingBox = mpCurrentSlideFrameRenderer->GetBoundingBox( + mpLayout->GetBoundingBox(mnCurrentSlideIndex)); + mpPresenterController->GetPaintManager()->Invalidate( + mxWindow, + maCurrentSlideFrameBoundingBox); + } + } +} + + + + +Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + return NULL; } @@ -611,15 +794,162 @@ void PresenterSlideSorter::UpdateLayout (void) if ( ! mxWindow.is()) return; - mpLayout->Update( - mxWindow->getPosSize(), - GetSlideAspectRatio()); + mbIsLayoutPending = false; + mbIsPaintPending = true; + + const awt::Rectangle aWindowBox (mxWindow->getPosSize()); + awt::Rectangle aCenterBox (aWindowBox); + sal_Int32 nLeftBorderWidth (aWindowBox.X); + + // Get border width. + PresenterPaneContainer::SharedPaneDescriptor pPane ( + mpPresenterController->GetPaneContainer()->FindViewURL( + mxViewId->getResourceURL())); + do + { + if (pPane.get() == NULL) + break; + if ( ! pPane->mxPane.is()) + break; + + Reference<drawing::framework::XPaneBorderPainter> xBorderPainter ( + pPane->mxPane->GetPaneBorderPainter()); + if ( ! xBorderPainter.is()) + break; + aCenterBox = xBorderPainter->addBorder ( + mxViewId->getAnchor()->getResourceURL(), + awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height), + drawing::framework::BorderType_INNER_BORDER); + } + while(false); + + // Place vertical separator. + mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding; + + PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth); + + geometry::RealRectangle2D aUpperBox( + gnHorizontalBorder, + gnVerticalBorder, + aWindowBox.Width - 2*gnHorizontalBorder, + mnSeparatorY - gnVerticalGap); + + // Determine whether the scroll bar has to be displayed. + aUpperBox = PlaceScrollBars(aUpperBox); + + mpLayout->Update(aUpperBox, GetSlideAspectRatio()); + mpLayout->SetupVisibleArea(); + mpLayout->UpdateScrollBars(); // Tell the preview cache about some of the values. mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize); mxPreviewCache->setVisibleRange( mpLayout->GetFirstVisibleSlideIndex(), mpLayout->GetLastVisibleSlideIndex()); + + // Clear the frame polygon so that it is re-created on the next paint. + mxPreviewFrame = NULL; +} + + + + +geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars ( + const geometry::RealRectangle2D& rUpperBox) +{ + mpLayout->Update(rUpperBox, GetSlideAspectRatio()); + bool bIsScrollBarNeeded (false); + Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW); + if (xSlides.is()) + bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount()); + + if (mpLayout->GetOrientation() == Layout::Vertical) + { + if (mpVerticalScrollBar.get() != NULL) + { + if (bIsScrollBarNeeded) + { + // Place vertical scroll bar at right border. + mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D( + rUpperBox.X2 - mpVerticalScrollBar->GetSize(), + rUpperBox.Y1, + rUpperBox.X2, + rUpperBox.Y2)); + mpVerticalScrollBar->SetVisible(true); + + // Reduce area covered by the scroll bar from the available + // space. + return geometry::RealRectangle2D( + rUpperBox.X1, + rUpperBox.Y1, + rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap, + rUpperBox.Y2); + } + else + mpVerticalScrollBar->SetVisible(false); + } + } + else + { + if (mpHorizontalScrollBar.get() != NULL) + { + if (bIsScrollBarNeeded) + { + // Place horixontal scroll bar at the bottom. + mpHorizontalScrollBar->SetPosSize(geometry::RealRectangle2D( + rUpperBox.X1, + rUpperBox.Y2 - mpHorizontalScrollBar->GetSize(), + rUpperBox.X2, + rUpperBox.Y2)); + mpHorizontalScrollBar->SetVisible(true); + + // Reduce area covered by the scroll bar from the available + // space. + return geometry::RealRectangle2D( + rUpperBox.X1, + rUpperBox.Y1, + rUpperBox.X2, + rUpperBox.Y2 - mpHorizontalScrollBar->GetSize() - gnVerticalGap); + } + else + mpHorizontalScrollBar->SetVisible(false); + } + } + + return rUpperBox; +} + + + + +void PresenterSlideSorter::PlaceCloseButton ( + const PresenterPaneContainer::SharedPaneDescriptor& rpPane, + const awt::Rectangle& rCenterBox, + const sal_Int32 nLeftBorderWidth) +{ + // Place button. When the callout is near the center then the button is + // centered over the callout. Otherwise it is centered with respect to + // the whole window. + sal_Int32 nCloseButtonCenter (rCenterBox.Width/2); + if (rpPane.get() != NULL && rpPane->mxPane.is()) + { + const sal_Int32 nCalloutCenter (rpPane->mxPane->GetCalloutAnchor().X - nLeftBorderWidth); + const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2)); + const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width); + const static sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2); + if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering) + { + if (nCalloutCenter < nButtonWidth/2) + nCloseButtonCenter = nButtonWidth/2; + else if (nCalloutCenter > rCenterBox.Width-nButtonWidth/2) + nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2; + else + nCloseButtonCenter = nCalloutCenter; + } + } + mpCloseButton->SetCenter(geometry::RealPoint2D( + nCloseButtonCenter, + rCenterBox.Height - mpCloseButton->GetSize().Height/ 2)); } @@ -631,30 +961,13 @@ void PresenterSlideSorter::ClearBackground ( { OSL_ASSERT(rxCanvas.is()); - util::Color aColor ( - mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL())); - Sequence<double> aBackgroundColor(3); - aBackgroundColor[0] = ((aColor >> 16) & 0x0ff) / 255.0; - aBackgroundColor[1] = ((aColor >> 8) & 0x0ff) / 255.0; - aBackgroundColor[2] = ((aColor >> 0) & 0x0ff) / 255.0; - - rendering::ViewState aViewState( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL); - - rendering::RenderState aRenderState ( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL, - aBackgroundColor, - rendering::CompositeOperation::SOURCE); - - Reference<rendering::XPolyPolygon2D> xPolygon ( - PresenterGeometryHelper::CreatePolygon(rUpdateBox, rxCanvas->getDevice())); - if (xPolygon.is()) - rxCanvas->fillPolyPolygon( - xPolygon, - aViewState, - aRenderState); + const awt::Rectangle aWindowBox (mxWindow->getPosSize()); + mpPresenterController->GetCanvasHelper()->Paint( + mpPresenterController->GetViewBackground(mxViewId->getResourceURL()), + rxCanvas, + rUpdateBox, + awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height), + awt::Rectangle()); } @@ -705,34 +1018,40 @@ Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 void PresenterSlideSorter::PaintPreview ( + const Reference<rendering::XCanvas>& rxCanvas, + const css::awt::Rectangle& rUpdateBox, const sal_Int32 nSlideIndex) { - if ( ! ProvideCanvas()) - return; + OSL_ASSERT(rxCanvas.is()); - const awt::Rectangle aWindowBox (mxWindow->getPosSize()); - PaintPreview(mxCanvas, nSlideIndex); + geometry::IntegerSize2D aSize (mpLayout->maPreviewSize); - Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); - if (xSpriteCanvas.is()) - xSpriteCanvas->updateScreen(sal_False); -} + if (PresenterGeometryHelper::AreRectanglesDisjoint( + rUpdateBox, + mpLayout->GetBoundingBox(nSlideIndex))) + { + return; + } + Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex)); + const geometry::RealPoint2D aTopLeft ( + mpLayout->GetWindowPosition( + mpLayout->GetPoint(nSlideIndex, -1, -1))); + // Create clip rectangle as intersection of the current update area and + // the bounding box of all previews. + geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox); + aBoundingBox.Y2 += 1; + const geometry::RealRectangle2D aClipBox ( + PresenterGeometryHelper::Intersection( + PresenterGeometryHelper::ConvertRectangle(rUpdateBox), + aBoundingBox)); + Reference<rendering::XPolyPolygon2D> xClip ( + PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice())); -void PresenterSlideSorter::PaintPreview ( - const Reference<rendering::XCanvas>& rxCanvas, - const sal_Int32 nSlideIndex) -{ - OSL_ASSERT(rxCanvas.is()); - - Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex)); + const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip); - const geometry::RealPoint2D aTopLeft (mpLayout->GetPoint(nSlideIndex, -1, -1)); - rendering::ViewState aViewState( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL); rendering::RenderState aRenderState ( geometry::AffineMatrix2D( @@ -742,28 +1061,27 @@ void PresenterSlideSorter::PaintPreview ( Sequence<double>(3), rendering::CompositeOperation::SOURCE); - geometry::IntegerSize2D aSize (mpLayout->maPreviewSize); + // Emphasize the current slide. if (nSlideIndex == mnCurrentSlideIndex) { - // Paint a frame around the slide preview that indicates that this - // is the current slide. - const double nFrameWidth (3); - const geometry::RealRectangle2D aBox (-nFrameWidth, -nFrameWidth, - aSize.Width+nFrameWidth, aSize.Height+nFrameWidth); - Reference<rendering::XPolyPolygon2D> xPolygon ( - PresenterGeometryHelper::CreatePolygon(aBox, rxCanvas->getDevice())); - if (xPolygon.is()) + if (mpCurrentSlideFrameRenderer.get() != NULL) { - const util::Color aColor ( - mpPresenterController->GetViewFontColor(mxViewId->getResourceURL())); - aRenderState.DeviceColor[0] = ((aColor >> 16) & 0x0ff) / 255.0; - aRenderState.DeviceColor[1] = ((aColor >> 8) & 0x0ff) / 255.0; - aRenderState.DeviceColor[2] = ((aColor >> 0) & 0x0ff) / 255.0; - rxCanvas->fillPolyPolygon(xPolygon, aViewState, aRenderState); + const awt::Rectangle aSlideBoundingBox( + sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.X), + sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.Y), + aSize.Width, + aSize.Height); + maCurrentSlideFrameBoundingBox + = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox); + mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame ( + aSlideBoundingBox, + mxCanvas, + aClipBox); } } + // Paint the preview. if (xPreview.is()) { aSize = xPreview->getSize(); @@ -773,26 +1091,32 @@ void PresenterSlideSorter::PaintPreview ( } } + // Create a polygon that is used to paint a frame around previews. Its + // coordinates are chosen in the local coordinate system of a preview. + if ( ! mxPreviewFrame.is()) + mxPreviewFrame = PresenterGeometryHelper::CreatePolygon( + awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2), + rxCanvas->getDevice()); + // Paint a border around the preview. - const geometry::RealRectangle2D aBox (0, 0, aSize.Width, aSize.Height); - Reference<rendering::XPolyPolygon2D> xPolygon ( - PresenterGeometryHelper::CreatePolygon(aBox, rxCanvas->getDevice())); - if (xPolygon.is()) + if (mxPreviewFrame.is()) { - const util::Color aColor ( - mpPresenterController->GetViewFontColor(mxViewId->getResourceURL())); - aRenderState.DeviceColor[0] = ((aColor >> 16) & 0x0ff) / 255.0; - aRenderState.DeviceColor[1] = ((aColor >> 8) & 0x0ff) / 255.0; - aRenderState.DeviceColor[2] = ((aColor >> 0) & 0x0ff) / 255.0; - rxCanvas->drawPolyPolygon(xPolygon, aViewState, aRenderState); + const geometry::RealRectangle2D aBox (0, 0, aSize.Width, aSize.Height); + const util::Color aFrameColor (0x00000000); + PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor); + rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState); } + + // Paint mouse over effect. + mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip); } -void PresenterSlideSorter::Paint (void) +void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox) { + const bool bCanvasChanged ( ! mxCanvas.is()); if ( ! ProvideCanvas()) return; @@ -804,19 +1128,41 @@ void PresenterSlideSorter::Paint (void) mbIsPaintPending = false; - const awt::Rectangle aWindowBox (mxWindow->getPosSize()); - ClearBackground(mxCanvas, awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height)); + ClearBackground(mxCanvas, rUpdateBox); - // Paint the horizontal scroll bar. - if (mpHorizontalScrollBar.is()) + // Give the canvas to the controls. + if (bCanvasChanged) { - mpHorizontalScrollBar->SetCanvas(mxCanvas); - mpHorizontalScrollBar->Paint(aWindowBox); + if (mpHorizontalScrollBar.is()) + mpHorizontalScrollBar->SetCanvas(mxCanvas); + if (mpVerticalScrollBar.is()) + mpVerticalScrollBar->SetCanvas(mxCanvas); + if (mpCloseButton.is()) + mpCloseButton->SetCanvas(mxCanvas, mxWindow); } + // Now that the controls have a canvas we can do the layouting. + if (mbIsLayoutPending) + UpdateLayout(); + + // Paint the horizontal separator. + rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0), + NULL, Sequence<double>(3), rendering::CompositeOperation::SOURCE); + PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor); + mxCanvas->drawLine( + geometry::RealPoint2D(0, mnSeparatorY), + geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY), + rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL), + aRenderState); + // Paint the slides. - mpLayout->ForAllVisibleSlides( - ::boost::bind(&PresenterSlideSorter::PaintPreview, this, mxCanvas, _1)); + if ( ! PresenterGeometryHelper::AreRectanglesDisjoint( + rUpdateBox, + PresenterGeometryHelper::ConvertRectangle(mpLayout->maBoundingBox))) + { + mpLayout->ForAllVisibleSlides( + ::boost::bind(&PresenterSlideSorter::PaintPreview, this, mxCanvas, rUpdateBox, _1)); + } Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is()) @@ -826,25 +1172,30 @@ void PresenterSlideSorter::Paint (void) -void PresenterSlideSorter::Invalidate (const awt::Rectangle& rBBox) +void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset) { - Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY); - if (xPeer.is()) - xPeer->invalidateRect(rBBox, awt::InvalidateStyle::UPDATE); + if (mpLayout->SetHorizontalOffset(nXOffset)) + { + mxPreviewCache->setVisibleRange( + mpLayout->GetFirstVisibleSlideIndex(), + mpLayout->GetLastVisibleSlideIndex()); + + mpPresenterController->GetPaintManager()->Invalidate(mxWindow); + } } -void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset) +void PresenterSlideSorter::SetVerticalOffset (const double nYOffset) { - if (mpLayout->SetHorizontalOffset(nXOffset)) + if (mpLayout->SetVerticalOffset(nYOffset)) { mxPreviewCache->setVisibleRange( mpLayout->GetFirstVisibleSlideIndex(), mpLayout->GetLastVisibleSlideIndex()); - Paint(); + mpPresenterController->GetPaintManager()->Invalidate(mxWindow); } } @@ -873,14 +1224,12 @@ bool PresenterSlideSorter::ProvideCanvas (void) if (xComponent.is()) xComponent->addEventListener(static_cast<awt::XWindowListener*>(this)); - // New canvas => new MouseOverManager. - if (mpMouseOverManager.get() != NULL) - mpMouseOverManager->SetCanvas( - Reference<rendering::XSpriteCanvas>(mxCanvas, UNO_QUERY)); - // Tell the scrollbar about the canvas. if (mpHorizontalScrollBar.is()) mpHorizontalScrollBar->SetCanvas(mxCanvas); + + mpCurrentSlideFrameRenderer.reset( + new CurrentSlideFrameRenderer(mxComponentContext, mxCanvas)); } return mxCanvas.is(); } @@ -888,6 +1237,13 @@ bool PresenterSlideSorter::ProvideCanvas (void) +void PresenterSlideSorter::Close (void) +{ +} + + + + void PresenterSlideSorter::ThrowIfDisposed (void) throw (lang::DisposedException) { @@ -909,14 +1265,14 @@ PresenterSlideSorter::Layout::Layout ( const Orientation eOrientation, const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar, const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar) - : maInnerBorder(), - maOuterBorder(), - maViewport(), + : maBoundingBox(), maPreviewSize(), mnHorizontalOffset(0), mnVerticalOffset(0), mnHorizontalGap(0), mnVerticalGap(0), + mnHorizontalBorder(0), + mnVerticalBorder(0), mnRowCount(1), mnColumnCount(1), mnSlideCount(0), @@ -925,7 +1281,6 @@ PresenterSlideSorter::Layout::Layout ( mnLastVisibleColumn(-1), mnFirstVisibleRow(-1), mnLastVisibleRow(-1), - mnScrollBarHeight(25), meOrientation(eOrientation), mpHorizontalScrollBar(rpHorizontalScrollBar), mpVerticalScrollBar(rpVerticalScrollBar) @@ -936,79 +1291,109 @@ PresenterSlideSorter::Layout::Layout ( void PresenterSlideSorter::Layout::Update ( - const awt::Rectangle& rWindowBox, + const geometry::RealRectangle2D& rBoundingBox, const double nSlideAspectRatio) { - if (rWindowBox.Width <= 0 || rWindowBox.Height <= 0) + maBoundingBox = rBoundingBox; + + mnHorizontalBorder = gnHorizontalBorder; + mnVerticalBorder = gnVerticalBorder; + + const double nWidth (rBoundingBox.X2 - rBoundingBox.X1 - 2*mnHorizontalBorder); + const double nHeight (rBoundingBox.Y2 - rBoundingBox.Y1 - 2*mnVerticalBorder); + if (nWidth<=0 || nHeight<=0) return; - const static sal_Int32 nFrameSize (10); - maInnerBorder = geometry::RealRectangle2D(nFrameSize,nFrameSize,nFrameSize,nFrameSize); - maOuterBorder = geometry::RealRectangle2D(50,50,50,50); - const static double nMinGap(15); - mnRowCount = 1; - mnColumnCount = 6; - - maViewport = geometry::RealRectangle2D( - maInnerBorder.X1 + maOuterBorder.X1, - maInnerBorder.Y1 + maInnerBorder.Y1, - rWindowBox.Width - maInnerBorder.X2 - maOuterBorder.X2, - rWindowBox.Height - maInnerBorder.Y2 - mnScrollBarHeight - maOuterBorder.Y2); - const double nAvailableWidth (maViewport.X2 - maViewport.X1); - const double nAvailableHeight (maViewport.Y2 - maViewport.Y1); - const double nMaxWidth (::std::max(nAvailableWidth / mnColumnCount - nMinGap, 50.0)); - const double nMaxHeight (::std::max(nAvailableHeight / mnRowCount - nMinGap, 30.0)); - - // Calculate the preview size. - if ((double(nMaxWidth) / double(nMaxHeight)) <= nSlideAspectRatio) - { - maPreviewSize.Width = sal_Int32(nMaxWidth); - maPreviewSize.Height = sal_Int32(nMaxWidth / nSlideAspectRatio); + double nPreviewWidth; + + // Determine column count, preview width, and horizontal gap (borders + // are half the gap). Try to use the preferred values. Try more to + // stay in the valid intervalls. This last constraint may be not + // fullfilled in some cases. + const double nElementWidth = nWidth / gnPreferredColumnCount; + if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap) + { + // The preferred column count is too large. + // Can we use the preferred preview width? + if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth) + { + // Yes. + nPreviewWidth = gnPreferredPreviewWidth; + mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap) + / (nPreviewWidth+gnPreferredHorizontalPreviewGap)); + mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); + } + else + { + // No. Set the column count to 1 and adapt preview width and + // gap. + mnColumnCount = 1; + mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap); + if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth) + nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap; + else + nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap); + } + } + else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap) + { + // The preferred column count is too small. + nPreviewWidth = gnPreferredPreviewWidth; + mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap) + / (nPreviewWidth+gnPreferredHorizontalPreviewGap)); + mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); } else { - maPreviewSize.Width = sal_Int32(nMaxHeight * nSlideAspectRatio); - maPreviewSize.Height = sal_Int32(nMaxHeight); + // The preferred column count is possible. Determine gap and + // preview width. + mnColumnCount = gnPreferredColumnCount; + if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap) + { + // Use the minimal gap and adapt the preview width. + mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap); + nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount; + } + else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap) + { + // Use the maximal gap and adapt the preview width. + mnHorizontalGap = round(gnMaximalHorizontalPreviewGap); + nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount; + } + else + { + // Use the preferred preview width and adapt the gap. + nPreviewWidth = gnPreferredPreviewWidth; + mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount); + } } - if (maPreviewSize.Width <= 0 || maPreviewSize.Height <= 0) - return; - // Calculate the numbers of visible rows and columns. - mnColumnCount = sal_Int32((nAvailableWidth+nMinGap) / (maPreviewSize.Width + nMinGap)); - if (mnColumnCount < 1) - mnColumnCount = 1; - mnRowCount = sal_Int32((nAvailableHeight+nMinGap) / (maPreviewSize.Height + nMinGap)); - if (mnRowCount < 1) - mnRowCount = 1; - - // Calculate the gaps between adjacent previews. - if (mnColumnCount >= 2) - mnHorizontalGap = (nAvailableWidth - mnColumnCount*maPreviewSize.Width) / (mnColumnCount-1); - else - mnHorizontalGap = 0; - if (mnRowCount >= 2) - mnVerticalGap = (nAvailableHeight - mnRowCount*maPreviewSize.Height) / (mnRowCount-1); - else - mnVerticalGap = 0; + // Now determine the row count, preview height, and vertical gap. + const double nPreviewHeight = nPreviewWidth / nSlideAspectRatio; + mnRowCount = ::std::max( + sal_Int32(1), + sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap) + / (nPreviewHeight + gnPreferredVerticalPreviewGap)))); + mnVerticalGap = round(gnPreferredVerticalPreviewGap); + + maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight)); // Reset the offset. if (meOrientation == Horizontal) { - mnVerticalOffset = -(nAvailableHeight + mnVerticalOffset = round(-(nHeight - mnRowCount*maPreviewSize.Height - (mnRowCount-1)*mnVerticalGap) - / 2; + / 2); mnHorizontalOffset = 0; } else { mnVerticalOffset = 0; - mnHorizontalOffset = -(nAvailableWidth - - mnColumnCount*maPreviewSize.Width - (mnColumnCount-1)*mnHorizontalGap) - / 2; + mnHorizontalOffset = round(-(nWidth + - mnColumnCount*maPreviewSize.Width + - (mnColumnCount-1)*mnHorizontalGap) + / 2); } - - SetupVisibleArea(); - UpdateScrollBars(); } @@ -1016,59 +1401,118 @@ void PresenterSlideSorter::Layout::Update ( void PresenterSlideSorter::Layout::SetupVisibleArea (void) { - geometry::RealPoint2D aPoint (0,0); + geometry::RealPoint2D aPoint (GetLocalPosition( + geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1))); if (meOrientation == Horizontal) { - mnFirstVisibleColumn = ::std::max( - sal_Int32(0), - sal_Int32((aPoint.X + mnHorizontalOffset + mnHorizontalGap) - / (maPreviewSize.Width+mnHorizontalGap))); + mnFirstVisibleColumn = ::std::max(sal_Int32(0), GetColumn(aPoint)); mnFirstVisibleRow = 0; } else { mnFirstVisibleColumn = 0; - mnFirstVisibleRow = ::std::max( - sal_Int32(0), - sal_Int32((aPoint.Y + mnVerticalOffset + mnVerticalGap) - / (maPreviewSize.Height+mnVerticalGap))); + mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint)); } - aPoint = geometry::RealPoint2D(maViewport.X2-maViewport.X1, maViewport.Y2-maViewport.Y1); + aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2)); if (meOrientation == Horizontal) { - mnLastVisibleColumn = sal_Int32((aPoint.X + mnHorizontalOffset) - / (maPreviewSize.Width+mnHorizontalGap)); + mnLastVisibleColumn = GetColumn(aPoint, true); mnLastVisibleRow = mnRowCount - 1; } else { mnLastVisibleColumn = mnColumnCount - 1; - mnLastVisibleRow = sal_Int32((aPoint.Y + mnVerticalOffset) - / (maPreviewSize.Height+mnVerticalGap)); + mnLastVisibleRow = GetRow(aPoint, true); } } -sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition ( - const css::geometry::RealPoint2D& rPoint) +bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount) { - if (rPoint.X < maViewport.X1 - || rPoint.X > maViewport.X2 - || rPoint.Y < maViewport.Y1 - || rPoint.Y > maViewport.Y2) + geometry::RealPoint2D aBottomRight; + if (GetOrientation() == Layout::Vertical) + aBottomRight = GetPoint( + mnColumnCount * (GetRow(nSlideCount)+1) - 1, +1, +1); + else + aBottomRight = GetPoint( + mnRowCount * (GetColumn(nSlideCount)+1) - 1, +1, +1); + return aBottomRight.X > maBoundingBox.X2-maBoundingBox.X1 + || aBottomRight.Y > maBoundingBox.Y2-maBoundingBox.Y1; +} + + + + +geometry::RealPoint2D PresenterSlideSorter::Layout::GetLocalPosition( + const geometry::RealPoint2D& rWindowPoint) const +{ + return css::geometry::RealPoint2D( + rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset, + rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset); +} + + + + +geometry::RealPoint2D PresenterSlideSorter::Layout::GetWindowPosition( + const geometry::RealPoint2D& rLocalPoint) const +{ + return css::geometry::RealPoint2D( + rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1, + rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1); +} + + + + +sal_Int32 PresenterSlideSorter::Layout::GetColumn ( + const css::geometry::RealPoint2D& rLocalPoint, + const bool bReturnInvalidValue) const +{ + const sal_Int32 nColumn(floor( + (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap))); + if (bReturnInvalidValue + || (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn)) { + return nColumn; + } + else return -1; +} + + + + +sal_Int32 PresenterSlideSorter::Layout::GetRow ( + const css::geometry::RealPoint2D& rLocalPoint, + const bool bReturnInvalidValue) const +{ + const sal_Int32 nRow (floor( + (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap))); + if (bReturnInvalidValue + || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow)) + { + return nRow; } + else + return -1; +} - const double nX (rPoint.X - maViewport.X1 + mnHorizontalOffset); - const double nY (rPoint.Y - maViewport.Y1 + mnVerticalOffset); - const sal_Int32 nColumn (sal_Int32( - (nX + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap))); - const sal_Int32 nRow (sal_Int32( - (nY + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap))); + + + +sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition ( + const css::geometry::RealPoint2D& rWindowPoint) const +{ + if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint)) + return -1; + + const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint)); + const sal_Int32 nColumn (GetColumn(aLocalPosition)); + const sal_Int32 nRow (GetRow(aLocalPosition)); if (nColumn < 0 || nRow < 0) return -1; @@ -1088,14 +1532,14 @@ sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition ( geometry::RealPoint2D PresenterSlideSorter::Layout::GetPoint ( const sal_Int32 nSlideIndex, const sal_Int32 nRelativeHorizontalPosition, - const sal_Int32 nRelativeVerticalPosition) + const sal_Int32 nRelativeVerticalPosition) const { sal_Int32 nColumn (GetColumn(nSlideIndex)); sal_Int32 nRow (GetRow(nSlideIndex)); - geometry::RealPoint2D aPosition( - maViewport.X1 + nColumn*(maPreviewSize.Width+mnHorizontalGap) - mnHorizontalOffset, - maViewport.Y1 + nRow*(maPreviewSize.Height+mnVerticalGap) - mnVerticalOffset); + geometry::RealPoint2D aPosition ( + mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap), + mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap)); if (nRelativeHorizontalPosition >= 0) if (nRelativeHorizontalPosition > 0) @@ -1112,47 +1556,25 @@ geometry::RealPoint2D PresenterSlideSorter::Layout::GetPoint ( } -namespace { double sqr (const double nValue) { return nValue*nValue; } } -double PresenterSlideSorter::Layout::GetDistanceFromCenter ( - const css::geometry::RealPoint2D& rPoint, - const sal_Int32 nSlideIndex, - const DistanceType eDistanceType) -{ - const geometry::RealPoint2D aCenter (GetPoint(nSlideIndex, 0,0)); - - switch (eDistanceType) - { - case Norm1: - default: - return ::std::max( - fabs(rPoint.X - aCenter.X) / maPreviewSize.Width * 2, - fabs(rPoint.Y - aCenter.Y) / maPreviewSize.Height * 2); - - case Norm2: - return sqrt( - sqr((rPoint.X - aCenter.X) / maPreviewSize.Width * 2) - + sqr((rPoint.Y - aCenter.Y) / maPreviewSize.Height * 2)); - case XOnly: - return fabs(rPoint.X - aCenter.X) / maPreviewSize.Width * 2; - - case YOnly: - return fabs(rPoint.Y - aCenter.Y) / maPreviewSize.Height * 2; - } +awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const +{ + const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, -1, -1))); + return PresenterGeometryHelper::ConvertRectangle( + geometry::RealRectangle2D( + aWindowPosition.X, + aWindowPosition.Y, + aWindowPosition.X + maPreviewSize.Width, + aWindowPosition.Y + maPreviewSize.Height)); } -awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) +geometry::IntegerSize2D PresenterSlideSorter::Layout::GetPreviewSize (void) const { - const geometry::RealPoint2D aPosition(GetPoint(nSlideIndex, 0, 0)); - return awt::Rectangle ( - sal_Int32(floor(aPosition.X)), - sal_Int32(floor(aPosition.Y)), - sal_Int32(ceil(aPosition.X + maPreviewSize.Width) - floor(aPosition.X)), - sal_Int32(ceil(aPosition.Y + maPreviewSize.Height) - floor(aPosition.Y))); + return maPreviewSize; } @@ -1175,7 +1597,7 @@ void PresenterSlideSorter::Layout::ForAllVisibleSlides (const ::boost::function< -sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) +sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) const { return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn); } @@ -1183,7 +1605,7 @@ sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) -sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex (void) +sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex (void) const { return ::std::min( GetIndex(mnLastVisibleRow, mnLastVisibleColumn), @@ -1197,7 +1619,7 @@ bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset) { if (mnHorizontalOffset != nOffset) { - mnHorizontalOffset = nOffset; + mnHorizontalOffset = round(nOffset); SetupVisibleArea(); UpdateScrollBars(); return true; @@ -1209,6 +1631,31 @@ bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset) +bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset) +{ + if (mnVerticalOffset != nOffset) + { + mnVerticalOffset = round(nOffset); + SetupVisibleArea(); + UpdateScrollBars(); + return true; + } + else + return false; +} + + + + +PresenterSlideSorter::Layout::Orientation + PresenterSlideSorter::Layout::GetOrientation (void) const +{ + return meOrientation; +} + + + + void PresenterSlideSorter::Layout::UpdateScrollBars (void) { sal_Int32 nTotalColumnCount (0); @@ -1227,30 +1674,23 @@ void PresenterSlideSorter::Layout::UpdateScrollBars (void) if (mpHorizontalScrollBar.get() != NULL) { mpHorizontalScrollBar->SetTotalSize( - nTotalColumnCount * maPreviewSize.Width + (nTotalColumnCount-1) * mnHorizontalGap); - mpHorizontalScrollBar->SetThumbPosition(mnHorizontalOffset); - mpHorizontalScrollBar->SetThumbSize( - mnColumnCount * (maPreviewSize.Width + mnHorizontalGap) - mnHorizontalGap); + nTotalColumnCount * maPreviewSize.Width + + (nTotalColumnCount-1) * mnHorizontalGap + + 2*mnHorizontalBorder); + mpHorizontalScrollBar->SetThumbPosition(mnHorizontalOffset, false); + mpHorizontalScrollBar->SetThumbSize(maBoundingBox.X2 - maBoundingBox.X1 + 1); } if (mpVerticalScrollBar.get() != NULL) { mpVerticalScrollBar->SetTotalSize( - nTotalRowCount * maPreviewSize.Height + (nTotalRowCount-1) * mnVerticalGap); - mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset); - mpVerticalScrollBar->SetThumbSize( - mnRowCount * (maPreviewSize.Height + mnVerticalGap) - mnVerticalGap); + nTotalRowCount * maPreviewSize.Height + + (nTotalRowCount-1) * mnVerticalGap + + 2*mnVerticalGap); + mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset, false); + mpVerticalScrollBar->SetThumbSize(maBoundingBox.Y2 - maBoundingBox.Y1 + 1); } - // Place the scroll bars. - if (mpHorizontalScrollBar.get() != NULL) - { - mpHorizontalScrollBar->SetPosSize(geometry::RealRectangle2D( - maViewport.X1, - maViewport.Y2 + maInnerBorder.Y2, - maViewport.X2, - maViewport.Y2 + maInnerBorder.Y2 + mnScrollBarHeight)); - } // No place yet for the vertical scroll bar. } @@ -1258,7 +1698,9 @@ void PresenterSlideSorter::Layout::UpdateScrollBars (void) -sal_Int32 PresenterSlideSorter::Layout::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) +sal_Int32 PresenterSlideSorter::Layout::GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const { if (meOrientation == Horizontal) return nColumn * mnRowCount + nRow; @@ -1269,7 +1711,7 @@ sal_Int32 PresenterSlideSorter::Layout::GetIndex (const sal_Int32 nRow, const sa -sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) +sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const { if (meOrientation == Horizontal) return nSlideIndex % mnRowCount; @@ -1280,7 +1722,7 @@ sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) -sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) +sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const { if (meOrientation == Horizontal) return nSlideIndex / mnRowCount; @@ -1294,29 +1736,32 @@ sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) //===== PresenterSlideSorter::MouseOverManager ================================ PresenterSlideSorter::MouseOverManager::MouseOverManager ( - const Reference<XComponentContext>& rxContext, const Reference<container::XIndexAccess>& rxSlides, - const Reference<frame::XModel>& rxModel) - : MouseOverManagerInterfaceBase(m_aMutex), - mxCanvas(), - mxPreviewCache(), + const ::boost::shared_ptr<PresenterTheme>& rpTheme, + const Reference<awt::XWindow>& rxInvalidateTarget, + const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager) + : mxCanvas(), + mxSlides(rxSlides), + mpLeftLabelBitmap(), + mpCenterLabelBitmap(), + mpRightLabelBitmap(), + mpFont(), mnSlideIndex(-1), - mnDistance(2), - mxSprite(NULL), - maSpriteSize(0,0), - mbIsActive(true) + maSlideBoundingBox(), + mxInvalidateTarget(rxInvalidateTarget), + mpPaintManager(rpPaintManager) { - Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager(), UNO_QUERY); - if (xFactory.is()) + if (rpTheme.get()!=NULL) { - // Create the preview cache. - mxPreviewCache = Reference<drawing::XSlidePreviewCache>( - xFactory->createInstanceWithContext( - OUString::createFromAscii("com.sun.star.drawing.PresenterPreviewCache"), - rxContext), - UNO_QUERY_THROW); - mxPreviewCache->setDocumentSlides(rxSlides, rxModel); - mxPreviewCache->addPreviewCreationNotifyListener(this); + ::boost::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer()); + if (pBitmaps.get() != NULL) + { + mpLeftLabelBitmap = pBitmaps->GetBitmap(A2S("LabelLeft")); + mpCenterLabelBitmap = pBitmaps->GetBitmap(A2S("LabelCenter")); + mpRightLabelBitmap = pBitmaps->GetBitmap(A2S("LabelRight")); + } + + mpFont = rpTheme->GetFont(A2S("SlideSorterLabelFont")); } } @@ -1325,29 +1770,43 @@ PresenterSlideSorter::MouseOverManager::MouseOverManager ( PresenterSlideSorter::MouseOverManager::~MouseOverManager (void) { - Reference<lang::XComponent> xComponent (mxPreviewCache, UNO_QUERY); - mxPreviewCache = NULL; - if (xComponent.is()) - xComponent->dispose(); - - DisposeSprite(); } -void PresenterSlideSorter::MouseOverManager::DisposeSprite (void) +void PresenterSlideSorter::MouseOverManager::Paint ( + const sal_Int32 nSlideIndex, + const Reference<rendering::XCanvas>& rxCanvas, + const Reference<rendering::XPolyPolygon2D>& rxClip) { - if (mxSprite.is()) - { - mxSprite->hide(); - if (mxCanvas.is()) - mxCanvas->updateScreen(sal_False); + if (nSlideIndex != mnSlideIndex) + return; - Reference<lang::XComponent> xComponent (mxSprite, UNO_QUERY); - mxSprite = NULL; - if (xComponent.is()) - xComponent->dispose(); + if (mxCanvas != rxCanvas) + SetCanvas(rxCanvas); + if (rxCanvas != NULL) + { + if ( ! mxBitmap.is()) + mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width); + if (mxBitmap.is()) + { + geometry::IntegerSize2D aSize (mxBitmap->getSize()); + const double nXOffset (maSlideBoundingBox.X + + (maSlideBoundingBox.Width - aSize.Width) / 2.0); + const double nYOffset (maSlideBoundingBox.Y + + (maSlideBoundingBox.Height - aSize.Height) / 2.0); + rxCanvas->drawBitmap( + mxBitmap, + rendering::ViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + rxClip), + rendering::RenderState( + geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset), + NULL, + Sequence<double>(3), + rendering::CompositeOperation::SOURCE)); + } } } @@ -1355,9 +1814,11 @@ void PresenterSlideSorter::MouseOverManager::DisposeSprite (void) void PresenterSlideSorter::MouseOverManager::SetCanvas ( - const Reference<rendering::XSpriteCanvas>& rxCanvas) + const Reference<rendering::XCanvas>& rxCanvas) { mxCanvas = rxCanvas; + if (mpFont.get() != NULL) + mpFont->PrepareFont(Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY)); } @@ -1365,140 +1826,507 @@ void PresenterSlideSorter::MouseOverManager::SetCanvas ( void PresenterSlideSorter::MouseOverManager::SetSlide ( const sal_Int32 nSlideIndex, - const awt::Rectangle& rBox, - const double nDistance) -{ - mnDistance = nDistance; - if ( ! mxSprite.is() - || nSlideIndex != mnSlideIndex - || rBox.X != maBoundingBox.X - || rBox.Y != maBoundingBox.Y) - { - DisposeSprite(); - mnSlideIndex = nSlideIndex; - maBoundingBox = rBox; - - if (mnSlideIndex < 0) - return; - - if ( ! mbIsActive) - return; - - CreateSprite(nSlideIndex); - if ( ! mxSprite.is()) - return; - - mxSprite->move( - geometry::RealPoint2D(maBoundingBox.X, maBoundingBox.Y), - rendering::ViewState( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL), - rendering::RenderState( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL, - Sequence<double>(3), - rendering::CompositeOperation::SOURCE) - ); - } - - if ( ! mxSprite.is()) + const awt::Rectangle& rBox) +{ + if (mnSlideIndex == nSlideIndex) return; - double nDownScale (maBoundingBox.Width / maSpriteSize.Width); - double nUpScale (1.0); - if (nDistance < 1.0) - if (nDistance < 0.8) - nUpScale = mnMaxScale; - else + mnSlideIndex = -1; + Invalidate(); + + maSlideBoundingBox = rBox; + mnSlideIndex = nSlideIndex; + + if (nSlideIndex >= 0) + { + if (mxSlides.get() != NULL) { - const double nWeight ((nDistance-0.8) / 0.2); - nUpScale = mnMinScale*nWeight + mnMaxScale*(1-nWeight); - } + msText = OUString(); - double nScale (nDownScale * nUpScale); - mxSprite->transform( - geometry::AffineMatrix2D( - nScale,0, - nScale*maSpriteSize.Width/2.0, - 0,nScale, - nScale*maSpriteSize.Height/2.0)); + Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY); + if (xSlideProperties.is()) + xSlideProperties->getPropertyValue(A2S("LinkDisplayName")) >>= msText; - mxCanvas->updateScreen(sal_False); + if (msText.getLength() == 0) + msText = A2S("Slide ") + OUString::valueOf(nSlideIndex + 1); + } + } + else + { + msText = OUString(); + } + mxBitmap = NULL; + + Invalidate(); } -void PresenterSlideSorter::MouseOverManager::SetActiveState (const bool bIsActive) +Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap ( + const OUString& rsText, + const sal_Int32 nMaximalWidth) const { - if (mbIsActive != bIsActive) + if ( ! mxCanvas.is()) + return NULL; + + if (mpFont.get()==NULL || !mpFont->mxFont.is()) + return NULL; + + // Long text has to be shortened. + const OUString sText (GetFittingText(rsText, nMaximalWidth + - 2*gnHorizontalLabelBorder + - 2*gnHorizontalLabelPadding)); + + // Determine the size of the label. Its height is defined by the + // bitmaps that are used to paints its background. The width is defined + // by the text. + geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText)); + + // Create a new bitmap that will contain the complete label. + Reference<rendering::XBitmap> xBitmap ( + mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize)); + + if ( ! xBitmap.is()) + return NULL; + + Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap->queryBitmapCanvas()); + if ( ! xBitmapCanvas.is()) + return NULL; + + // Paint the background. + PaintButtonBackground(xBitmapCanvas, aLabelSize); + + // Paint the text. + if (sText.getLength() > 0) { - mbIsActive = bIsActive; - if ( ! mbIsActive) - DisposeSprite(); - else if (mnSlideIndex >= 0) - SetSlide (mnSlideIndex, maBoundingBox, mnDistance); + + const rendering::StringContext aContext (sText, 0, sText.getLength()); + const Reference<rendering::XTextLayout> xLayout (mpFont->mxFont->createTextLayout( + aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0)); + const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds()); + + const double nXOffset = (aLabelSize.Width - aTextBBox.X2 + aTextBBox.X1) / 2; + const double nYOffset = aLabelSize.Height + - (aLabelSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y2; + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + NULL); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset), + NULL, + Sequence<double>(3), + rendering::CompositeOperation::SOURCE); + PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor); + + xBitmapCanvas->drawText( + aContext, + mpFont->mxFont, + aViewState, + aRenderState, + rendering::TextDirection::WEAK_LEFT_TO_RIGHT); } + + return xBitmap; } -void PresenterSlideSorter::MouseOverManager::CreateSprite (const sal_Int32 nSlideIndex) +OUString PresenterSlideSorter::MouseOverManager::GetFittingText ( + const OUString& rsText, + const double nMaximalWidth) const { - if ( ! mxPreviewCache.is()) - return; - maSpriteSize = geometry::RealSize2D(maBoundingBox.Width*2, maBoundingBox.Height*2); - mxPreviewCache->setPreviewSize(geometry::IntegerSize2D( - sal_Int32(maSpriteSize.Width), sal_Int32(maSpriteSize.Height))); - if (mxCanvas.is() && ! mxSprite.is()) + const double nTextWidth ( + PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width); + if (nTextWidth > nMaximalWidth) { - mxSprite = mxCanvas->createCustomSprite(maSpriteSize); - if (mxSprite.is()) + // Text is too wide. Shorten it by removing characters from the end + // and replacing them by ellipses. + + // Guess a start value of the final string length. + double nBestWidth (0); + OUString sBestCandidate; + sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth)); + const OUString sEllipses (A2S("...")); + while (true) { - mxSprite->setAlpha(1.0); - mxSprite->setPriority(+10); - mxSprite->show(); + const OUString sCandidate (rsText.copy(0,nLength) + sEllipses); + const double nWidth ( + PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width); + if (nWidth > nMaximalWidth) + { + // Candidate still too wide, shorten it. + nLength -= 1; + if (nLength <= 0) + break; + } + else if (nWidth < nMaximalWidth) + { + // Candidate short enough. + if (nWidth > nBestWidth) + { + // Best length so far. + sBestCandidate = sCandidate; + nBestWidth = nWidth; + nLength += 1; + if (nLength >= rsText.getLength()) + break; + } + else + break; + } + else + { + // Candidate is exactly as long as it may be. Use it + // without looking any further. + sBestCandidate = sCandidate; + break; + } } + return sBestCandidate; } - if (mxSprite.is()) - { - Reference<rendering::XCanvas> xSpriteCanvas (mxSprite->getContentCanvas()); - if (xSpriteCanvas.is()) - { - Reference<rendering::XBitmap> xBitmap ( - mxPreviewCache->getSlidePreview(nSlideIndex, xSpriteCanvas)); - if (xBitmap.is()) - { - rendering::ViewState aViewState( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL); + else + return rsText; +} - rendering::RenderState aRenderState ( - geometry::AffineMatrix2D(1,0,0, 0,1,0), - NULL, - Sequence<double>(3), - rendering::CompositeOperation::SOURCE); - xSpriteCanvas->drawBitmap(xBitmap, aViewState, aRenderState); - } - } + +geometry::IntegerSize2D PresenterSlideSorter::MouseOverManager::CalculateLabelSize ( + const OUString& rsText) const +{ + // Height is specified by the label bitmaps. + sal_Int32 nHeight (32); + if (mpCenterLabelBitmap.get() != NULL) + { + Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap()); + if (xBitmap.is()) + nHeight = xBitmap->getSize().Height; } + + // Width is specified by text width and maximal width. + const geometry::RealSize2D aTextSize ( + PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText)); + + const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding)); + + return geometry::IntegerSize2D(nWidth, nHeight); } -void SAL_CALL PresenterSlideSorter::MouseOverManager::notifyPreviewCreation ( - sal_Int32 nSlideIndex) - throw(css::uno::RuntimeException) +void PresenterSlideSorter::MouseOverManager::PaintButtonBackground ( + const Reference<rendering::XBitmapCanvas>& rxCanvas, + const geometry::IntegerSize2D& rSize) const { - if (nSlideIndex == mnSlideIndex) + // Get the bitmaps for painting the label background. + Reference<rendering::XBitmap> xLeftLabelBitmap; + if (mpLeftLabelBitmap.get() != NULL) + xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap(); + + Reference<rendering::XBitmap> xCenterLabelBitmap; + if (mpCenterLabelBitmap.get() != NULL) + xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap(); + + Reference<rendering::XBitmap> xRightLabelBitmap; + if (mpRightLabelBitmap.get() != NULL) + xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap(); + + PresenterUIPainter::PaintHorizontalBitmapComposite ( + Reference<rendering::XCanvas>(rxCanvas, UNO_QUERY), + awt::Rectangle(0,0, rSize.Width,rSize.Height), + awt::Rectangle(0,0, rSize.Width,rSize.Height), + xLeftLabelBitmap, + xCenterLabelBitmap, + xRightLabelBitmap); +} + + + + +void PresenterSlideSorter::MouseOverManager::Invalidate (void) +{ + if (mpPaintManager.get() != NULL) + mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true); +} + + + + +//===== PresenterSlideSorter::CurrentSlideFrameRenderer ======================= + +PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer ( + const css::uno::Reference<css::uno::XComponentContext>& rxContext, + const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) + : mpTopLeft(), + mpTop(), + mpTopRight(), + mpLeft(), + mpRight(), + mpBottomLeft(), + mpBottom(), + mpBottomRight(), + mnTopFrameSize(0), + mnLeftFrameSize(0), + mnRightFrameSize(0), + mnBottomFrameSize(0) +{ + PresenterConfigurationAccess aConfiguration ( + rxContext, + OUString::createFromAscii("/org.openoffice.Office.extension.PresenterScreen/"), + PresenterConfigurationAccess::READ_ONLY); + Reference<container::XHierarchicalNameAccess> xBitmaps ( + aConfiguration.GetConfigurationNode( + A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps")), + UNO_QUERY); + if ( ! xBitmaps.is()) + return; + + PresenterBitmapContainer aContainer ( + A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"), + ::boost::shared_ptr<PresenterBitmapContainer>(), + rxContext, + rxCanvas, + PresenterComponent::GetBasePath(rxContext)); + + mpTopLeft = aContainer.GetBitmap(A2S("TopLeft")); + mpTop = aContainer.GetBitmap(A2S("Top")); + mpTopRight = aContainer.GetBitmap(A2S("TopRight")); + mpLeft = aContainer.GetBitmap(A2S("Left")); + mpRight = aContainer.GetBitmap(A2S("Right")); + mpBottomLeft = aContainer.GetBitmap(A2S("BottomLeft")); + mpBottom = aContainer.GetBitmap(A2S("Bottom")); + mpBottomRight = aContainer.GetBitmap(A2S("BottomRight")); + + // Determine size of frame. + if (mpTop.get() != NULL) + mnTopFrameSize = mpTop->mnHeight; + if (mpLeft.get() != NULL) + mnLeftFrameSize = mpLeft->mnWidth; + if (mpRight.get() != NULL) + mnRightFrameSize = mpRight->mnWidth; + if (mpBottom.get() != NULL) + mnBottomFrameSize = mpBottom->mnHeight; + + if (mpTopLeft.get() != NULL) + { + mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight); + mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth); + } + if (mpTopRight.get() != NULL) + { + mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight); + mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth); + } + if (mpBottomLeft.get() != NULL) { - CreateSprite(mnSlideIndex); + mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth); + mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight); + } + if (mpBottomRight.get() != NULL) + { + mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth); + mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight); + } +} - Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY); - if (xSpriteCanvas.is()) - xSpriteCanvas->updateScreen(sal_False); + + + +PresenterSlideSorter::CurrentSlideFrameRenderer::~CurrentSlideFrameRenderer (void) +{ +} + + + + +void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame ( + const awt::Rectangle& rSlideBoundingBox, + const Reference<rendering::XCanvas>& rxCanvas, + const geometry::RealRectangle2D& rClipBox) +{ + if ( ! rxCanvas.is()) + return; + + const Reference<rendering::XPolyPolygon2D> xClip ( + PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice())); + + if (mpTop.get() != NULL) + { + PaintBitmapTiled( + mpTop->GetNormalBitmap(), + rxCanvas, + rClipBox, + rSlideBoundingBox.X, + rSlideBoundingBox.Y - mpTop->mnHeight, + rSlideBoundingBox.Width, + mpTop->mnHeight); + } + if (mpLeft.get() != NULL) + { + PaintBitmapTiled( + mpLeft->GetNormalBitmap(), + rxCanvas, + rClipBox, + rSlideBoundingBox.X - mpLeft->mnWidth, + rSlideBoundingBox.Y, + mpLeft->mnWidth, + rSlideBoundingBox.Height); + } + if (mpRight.get() != NULL) + { + PaintBitmapTiled( + mpRight->GetNormalBitmap(), + rxCanvas, + rClipBox, + rSlideBoundingBox.X + rSlideBoundingBox.Width, + rSlideBoundingBox.Y, + mpRight->mnWidth, + rSlideBoundingBox.Height); + } + if (mpBottom.get() != NULL) + { + PaintBitmapTiled( + mpBottom->GetNormalBitmap(), + rxCanvas, + rClipBox, + rSlideBoundingBox.X, + rSlideBoundingBox.Y + rSlideBoundingBox.Height, + rSlideBoundingBox.Width, + mpBottom->mnHeight); + } + if (mpTopLeft.get() != NULL) + { + PaintBitmapOnce( + mpTopLeft->GetNormalBitmap(), + rxCanvas, + xClip, + rSlideBoundingBox.X - mpTopLeft->mnWidth, + rSlideBoundingBox.Y - mpTopLeft->mnHeight); + } + if (mpTopRight.get() != NULL) + { + PaintBitmapOnce( + mpTopRight->GetNormalBitmap(), + rxCanvas, + xClip, + rSlideBoundingBox.X + rSlideBoundingBox.Width, + rSlideBoundingBox.Y - mpTopLeft->mnHeight); + } + if (mpBottomLeft.get() != NULL) + { + PaintBitmapOnce( + mpBottomLeft->GetNormalBitmap(), + rxCanvas, + xClip, + rSlideBoundingBox.X - mpBottomLeft->mnWidth, + rSlideBoundingBox.Y + rSlideBoundingBox.Height); + } + if (mpBottomRight.get() != NULL) + { + PaintBitmapOnce( + mpBottomRight->GetNormalBitmap(), + rxCanvas, + xClip, + rSlideBoundingBox.X + rSlideBoundingBox.Width, + rSlideBoundingBox.Y + rSlideBoundingBox.Height); } } + + + +awt::Rectangle PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox ( + const awt::Rectangle& rSlideBoundingBox) +{ + return awt::Rectangle( + rSlideBoundingBox.X - mnLeftFrameSize, + rSlideBoundingBox.Y - mnTopFrameSize, + rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize, + rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize); +} + + + + +void PresenterSlideSorter::CurrentSlideFrameRenderer::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) +{ + OSL_ASSERT(rxCanvas.is()); + if ( ! rxBitmap.is()) + return; + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + rxClip); + + const rendering::RenderState aRenderState ( + geometry::AffineMatrix2D( + 1, 0, nX, + 0, 1, nY), + NULL, + Sequence<double>(3), + rendering::CompositeOperation::SOURCE); + + rxCanvas->drawBitmap( + rxBitmap, + aViewState, + aRenderState); +} + + + + +void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled( + const css::uno::Reference<css::rendering::XBitmap>& rxBitmap, + const css::uno::Reference<css::rendering::XCanvas>& rxCanvas, + const geometry::RealRectangle2D& rClipBox, + const double nX0, + const double nY0, + const double nWidth, + const double nHeight) +{ + OSL_ASSERT(rxCanvas.is()); + if ( ! rxBitmap.is()) + return; + + geometry::IntegerSize2D aSize (rxBitmap->getSize()); + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + PresenterGeometryHelper::CreatePolygon( + PresenterGeometryHelper::Intersection( + rClipBox, + geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)), + rxCanvas->getDevice())); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D( + 1, 0, nX0, + 0, 1, nY0), + NULL, + Sequence<double>(3), + rendering::CompositeOperation::SOURCE); + + const double nX1 = nX0 + nWidth; + const double nY1 = nY0 + nHeight; + for (double nY=nY0; nY<nY1; nY+=aSize.Height) + for (double nX=nX0; nX<nX1; nX+=aSize.Width) + { + aRenderState.AffineTransform.m02 = nX; + aRenderState.AffineTransform.m12 = nY; + rxCanvas->drawBitmap( + rxBitmap, + aViewState, + aRenderState); + } +} + } } // end of namespace ::sdext::presenter |