/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: PresenterToolBar.cxx,v $ * * $Revision: 1.2 $ * * last change: $Author: kz $ $Date: 2008-04-03 16:06:28 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ #include "PresenterToolBar.hxx" #include "PresenterBitmapContainer.hxx" #include "PresenterGeometryHelper.hxx" //#include "PresenterHelper.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; 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 sal_Int32 gnButtonSize = 64; } namespace sdext { namespace presenter { //===== PresenterToolBar::Element ============================================= class PresenterToolBar::Element { public: explicit Element ( const Reference& rxWindowPeer); explicit Element ( const Reference& rxWindowPeer, const awt::Rectangle& rBoundingBox); virtual ~Element (void); virtual void SetCurrentSlide ( const Reference& rxCurrentSlide, const sal_Int32 nSlideCount); virtual void SetPosSize (const awt::Rectangle& rBox); virtual awt::Rectangle GetBoundingBox (void) const; virtual void Paint ( const Reference& rxCanvas, const rendering::ViewState& rViewState) = 0; virtual bool SetState (const bool bIsOver, const bool bIsPressed); virtual void Invalidate (void); virtual bool IsOutside (const awt::Rectangle& rBox); protected: Reference mxWindowPeer; awt::Rectangle maBoundingBox; }; //===== PresenterToolBar::Button ============================================== class Button : public PresenterToolBar::Element { public: typedef ::boost::function Callback; /** @param rxWindowPeer The window peer is used to invalidate the region of the button to enforce its repaint. */ Button ( const Reference& rxWindowPeer, const OUString& rsText, const PresenterBitmapContainer::BitmapSet& rIcons, const Callback& rCallback); virtual void Paint ( const Reference& rxCanvas, const rendering::ViewState& rViewState); virtual bool SetState (const bool bIsOver, const bool bIsPressed); private: OUString msText; bool mbIsOver; bool mbIsPressed; PresenterBitmapContainer::BitmapSet maIcons; bool mbIconLoadingFailed; Callback maCallback; }; //===== PresenterToolBar::Label =============================================== class Label : public PresenterToolBar::Element { public: Label ( const Reference& rxPeer, const util::Color& rFontColor, const rendering::FontRequest& rRequestedFontDescriptor); virtual void SetCurrentSlide ( const Reference& rxCurrentSlide, const sal_Int32 nSlideCount); void SetText (const OUString& rsText); virtual void Paint ( const Reference& rxCanvas, const rendering::ViewState& rViewState); private: OUString msText; Reference mxFont; util::Color maFontColor; rendering::FontRequest maRequestedFontDescriptor; }; //===== PresenterToolBar ====================================================== PresenterToolBar::PresenterToolBar ( const Reference& rxContext, const Reference& rxViewId, const Reference& rxController, const ::rtl::Reference& rpPresenterController) : PresenterToolBarInterfaceBase(m_aMutex), mxComponentContext(rxContext), mxPane(), mxViewId(rxViewId), mxCanvas(), maElementContainer(), mxWindow(), mxControl(), mxCurrentSlide(), mxSlideShowController(), mpPresenterController(rpPresenterController), msPreviousButtonBitmapURL(), msNextButtonBitmapURL(), mpIconContainer() { try { Reference xCM (rxController, UNO_QUERY_THROW); Reference xCC(xCM->getConfigurationController(),UNO_QUERY_THROW); mxPane = Reference(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW); mxWindow = mxPane->getWindow(); mxCanvas = mxPane->getCanvas(); mpIconContainer.reset(new PresenterBitmapContainer(rxContext, mxCanvas, A2S("PresenterScreenSettings/ToolBar/Bitmaps"))); CreateControls(); // Set background of tool bar. Reference xPeer (mxWindow, UNO_QUERY); if (xPeer.is()) { xPeer->setBackground( mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL())); } if (mxWindow.is()) { mxWindow->addWindowListener(this); mxWindow->addPaintListener(this); mxWindow->addMouseListener(this); mxWindow->addMouseMotionListener(this); xPeer = Reference(mxWindow, UNO_QUERY); if (xPeer.is()) xPeer->setBackground(util::Color(0xff000000)); mxWindow->setVisible(sal_True); } mxSlideShowController = rpPresenterController->GetSlideShowController(); UpdateSlideNumber(); Resize(); } catch (RuntimeException&) { mxViewId = NULL; maElementContainer.clear(); mxControl = NULL; throw; } } PresenterToolBar::~PresenterToolBar (void) { } void SAL_CALL PresenterToolBar::disposing (void) { if (mxWindow.is()) { mxWindow->removeWindowListener(this); mxWindow->removePaintListener(this); mxWindow->removeMouseListener(this); mxWindow->removeMouseMotionListener(this); mxWindow = NULL; } Reference xComponent (mxControl, UNO_QUERY); if (xComponent.is()) xComponent->dispose(); mxControl = NULL; maElementContainer.clear(); mxViewId = NULL; } //----- lang::XEventListener ------------------------------------------------- void SAL_CALL PresenterToolBar::disposing (const lang::EventObject& rEventObject) throw (RuntimeException) { if (rEventObject.Source == mxWindow) mxWindow = NULL; } //----- XWindowListener ------------------------------------------------------- void SAL_CALL PresenterToolBar::windowResized (const awt::WindowEvent& rEvent) throw (RuntimeException) { (void)rEvent; Resize(); } void SAL_CALL PresenterToolBar::windowMoved (const awt::WindowEvent& rEvent) throw (RuntimeException) { (void)rEvent; } void SAL_CALL PresenterToolBar::windowShown (const lang::EventObject& rEvent) throw (RuntimeException) { (void)rEvent; } void SAL_CALL PresenterToolBar::windowHidden (const lang::EventObject& rEvent) throw (RuntimeException) { (void)rEvent; } //----- XPaintListener -------------------------------------------------------- void SAL_CALL PresenterToolBar::windowPaint (const css::awt::PaintEvent& rEvent) throw (RuntimeException) { if ( ! mxCanvas.is()) return; const rendering::ViewState aViewState ( geometry::AffineMatrix2D(1,0,0, 0,1,0), PresenterGeometryHelper::CreatePolygon(rEvent.UpdateRect, mxCanvas->getDevice())); Clear(rEvent.UpdateRect, aViewState); Paint(rEvent.UpdateRect, aViewState); // Make the back buffer visible. Reference xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is()) xSpriteCanvas->updateScreen(sal_False); } //----- XMouseListener -------------------------------------------------------- void SAL_CALL PresenterToolBar::mousePressed (const css::awt::MouseEvent& rEvent) throw(css::uno::RuntimeException) { CheckMouseOver(rEvent, true, true); } void SAL_CALL PresenterToolBar::mouseReleased (const css::awt::MouseEvent& rEvent) throw(css::uno::RuntimeException) { CheckMouseOver(rEvent, true); } void SAL_CALL PresenterToolBar::mouseEntered (const css::awt::MouseEvent& rEvent) throw(css::uno::RuntimeException) { CheckMouseOver(rEvent, true); } void SAL_CALL PresenterToolBar::mouseExited (const css::awt::MouseEvent& rEvent) throw(css::uno::RuntimeException) { CheckMouseOver(rEvent, false); } //----- XMouseMotionListener -------------------------------------------------- void SAL_CALL PresenterToolBar::mouseMoved (const css::awt::MouseEvent& rEvent) throw (css::uno::RuntimeException) { ThrowIfDisposed(); CheckMouseOver(rEvent, true); } void SAL_CALL PresenterToolBar::mouseDragged (const css::awt::MouseEvent& rEvent) throw (css::uno::RuntimeException) { ThrowIfDisposed(); (void)rEvent; } //----- XResourceId ----------------------------------------------------------- Reference SAL_CALL PresenterToolBar::getResourceId (void) throw (RuntimeException) { return mxViewId; } sal_Bool SAL_CALL PresenterToolBar::isAnchorOnly (void) throw (RuntimeException) { return false; } //----- XDrawView ------------------------------------------------------------- void SAL_CALL PresenterToolBar::setCurrentPage (const Reference& rxSlide) throw (RuntimeException) { if (mxCurrentSlide != rxSlide) { mxCurrentSlide = rxSlide; UpdateSlideNumber(); } } Reference SAL_CALL PresenterToolBar::getCurrentPage (void) throw (RuntimeException) { return mxCurrentSlide; } //----------------------------------------------------------------------------- void PresenterToolBar::GotoPreviousSlide (void) { if (mxSlideShowController.is()) { mxSlideShowController->gotoPreviousSlide(); // Going to the previous slide does not trigger any event that would // cause an update of the presenter view. Therefore request an // update explicitly. if (mpPresenterController.is()) mpPresenterController->UpdateCurrentSlide(0); } } void PresenterToolBar::GotoNextEffect (void) { if (mxSlideShowController.is()) { mxSlideShowController->gotoNextEffect(); // When playing the next effect causes a change to the next slide // then events are sent that cause an update of the presenter view. } } void PresenterToolBar::GotoNextSlide (void) { if (mxSlideShowController.is()) { mxSlideShowController->gotoNextSlide(); // Going to the next slide does not trigger any event that would // cause an update of the presenter view. Therefore request an // update explicitly. if (mpPresenterController.is()) mpPresenterController->UpdateCurrentSlide(0); } } void PresenterToolBar::CreateControls (void) { if ( ! mxWindow.is()) return; // Expand the macro in the bitmap file names. Reference xInformationProvider ( mxComponentContext->getValueByName( A2S("/singletons/com.sun.star.deployment.PackageInformationProvider")), UNO_QUERY); Reference xPeer (mxWindow, UNO_QUERY); maElementContainer.push_back(boost::shared_ptr(new Button( xPeer, A2S("Back"), mpIconContainer->GetButtons(A2S("PreviousSlide")), ::boost::bind(&PresenterToolBar::GotoPreviousSlide,this)))); maElementContainer.push_back(boost::shared_ptr(new Label( xPeer, mpPresenterController->GetViewFontColor(mxViewId->getResourceURL()), mpPresenterController->GetViewFontRequest(mxViewId->getResourceURL())))); maElementContainer.push_back(boost::shared_ptr(new Button( xPeer, A2S("Next\nEffect"), mpIconContainer->GetButtons(A2S("NextEffect")), ::boost::bind(&PresenterToolBar::GotoNextEffect,this)))); maElementContainer.push_back(boost::shared_ptr(new Button( xPeer, A2S("Next\nSlide"), mpIconContainer->GetButtons(A2S("NextSlide")), ::boost::bind(&PresenterToolBar::GotoNextSlide,this)))); } void PresenterToolBar::Resize (void) { if (mxWindow.is()) { const awt::Rectangle aWindowBox (mxWindow->getPosSize()); if (mxControl.is()) mxControl->setPosSize(0,0, aWindowBox.Width, aWindowBox.Height, awt::PosSize::POSSIZE); // Calculate the summed width of all elements. sal_Int32 nTotalControlWidth (0); sal_Int32 nMaximalHeight (0); sal_Int32 nElementCount (0); ElementContainer::iterator iElement; for (iElement=maElementContainer.begin(); iElement!=maElementContainer.end(); ++iElement) { if (iElement->get() != NULL) { ++nElementCount; nTotalControlWidth += (*iElement)->GetBoundingBox().Width; const sal_Int32 nHeight ((*iElement)->GetBoundingBox().Height); if (nHeight > nMaximalHeight) nMaximalHeight = nHeight; } } // Calculate the gaps between elements. sal_Int32 nGapSize = (aWindowBox.Width - nTotalControlWidth) / 3; if (nGapSize > 10) nGapSize = 10; sal_Int32 nX = (aWindowBox.Width - (nTotalControlWidth + (nElementCount-1)*nGapSize)) / 2; sal_Int32 nY = (aWindowBox.Height - nMaximalHeight) / 2; // Place the elements. for (iElement=maElementContainer.begin(); iElement!=maElementContainer.end(); ++iElement) { if (iElement->get() != NULL) { const awt::Rectangle aBox ((*iElement)->GetBoundingBox()); (*iElement)->SetPosSize(awt::Rectangle(nX,nY, aBox.Width, aBox.Height)); nX += aBox.Width + nGapSize; } } // The whole window has to be repainted. Reference xPeer (mxWindow, UNO_QUERY); if (xPeer.is()) xPeer->invalidate(awt::InvalidateStyle::CHILDREN); } } void PresenterToolBar::Clear ( const awt::Rectangle& rUpdateBox, const rendering::ViewState& rViewState) { OSL_ASSERT(mxCanvas.is()); rendering::RenderState aRenderState( geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL, Sequence(3), rendering::CompositeOperation::SOURCE); const sal_Int32 nColor ( mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL())); aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0; aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >> 8) / 255.0; aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >> 0) / 255.0; Reference xRectangle ( PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice())); if (xRectangle.is()) mxCanvas->fillPolyPolygon(xRectangle, rViewState, aRenderState); } void PresenterToolBar::Paint ( const awt::Rectangle& rUpdateBox, const rendering::ViewState& rViewState) { OSL_ASSERT(mxCanvas.is()); ElementContainer::iterator iElement; for (iElement=maElementContainer.begin(); iElement!=maElementContainer.end(); ++iElement) { if (iElement->get() != NULL) { if ( ! (*iElement)->IsOutside(rUpdateBox)) (*iElement)->Paint(mxCanvas, rViewState); } } } void PresenterToolBar::UpdateSlideNumber (void) { if( mxSlideShowController.is() ) { ElementContainer::iterator iElement; for (iElement=maElementContainer.begin(); iElement!=maElementContainer.end(); ++iElement) { if (iElement->get() != NULL) (*iElement)->SetCurrentSlide(mxCurrentSlide, mxSlideShowController->getSlideCount()); } } // All elements may have to be repainted. Reference xPeer (mxWindow, UNO_QUERY); if (xPeer.is()) xPeer->invalidate(awt::InvalidateStyle::CHILDREN); } void PresenterToolBar::CheckMouseOver ( const css::awt::MouseEvent& rEvent, const bool bOverWindow, const bool bMouseDown) { ElementContainer::iterator iElement; for (iElement=maElementContainer.begin(); iElement!=maElementContainer.end(); ++iElement) { if (iElement->get() == NULL) continue; awt::Rectangle aBox ((*iElement)->GetBoundingBox()); const bool bIsOver = bOverWindow && aBox.X <= rEvent.X && aBox.Width+aBox.X-1 >= rEvent.X && aBox.Y <= rEvent.Y && aBox.Height+aBox.Y-1 >= rEvent.Y; (*iElement)->SetState( bIsOver, bIsOver && rEvent.Buttons!=0 && bMouseDown && rEvent.ClickCount>0); } } void PresenterToolBar::ThrowIfDisposed (void) const throw (::com::sun::star::lang::DisposedException) { if (rBHelper.bDisposed || rBHelper.bInDispose) { throw lang::DisposedException ( OUString(RTL_CONSTASCII_USTRINGPARAM( "PresenterToolBar has already been disposed")), const_cast(static_cast(this))); } } //===== PresenterToolBar::Element ============================================= PresenterToolBar::Element::Element (const Reference& rxWindowPeer) : mxWindowPeer(rxWindowPeer), maBoundingBox() { } PresenterToolBar::Element::Element ( const Reference& rxWindowPeer, const awt::Rectangle& rBoundingBox) : mxWindowPeer(rxWindowPeer), maBoundingBox(rBoundingBox) { } PresenterToolBar::Element::~Element (void) { } void PresenterToolBar::Element::SetCurrentSlide ( const Reference& rxCurrentSlide, const sal_Int32 nSlideCount) { (void)rxCurrentSlide; (void)nSlideCount; } void PresenterToolBar::Element::SetPosSize (const awt::Rectangle& rBox) { maBoundingBox = rBox; } awt::Rectangle PresenterToolBar::Element::GetBoundingBox (void) const { return maBoundingBox; } bool PresenterToolBar::Element::SetState ( const bool bIsOver, const bool bIsPressed) { (void)bIsOver; (void)bIsPressed; return false; } void PresenterToolBar::Element::Invalidate (void) { if (mxWindowPeer.is()) mxWindowPeer->invalidateRect(maBoundingBox, awt::InvalidateStyle::UPDATE); } bool PresenterToolBar::Element::IsOutside (const awt::Rectangle& rBox) { if (rBox.X >= maBoundingBox.X+maBoundingBox.Width) return true; else if (rBox.Y >= maBoundingBox.Y+maBoundingBox.Height) return true; else if (maBoundingBox.X >= rBox.X+rBox.Width) return true; else if (maBoundingBox.Y >= rBox.Y+rBox.Height) return true; else return false; } //===== PresenterToolBar::Button ============================================== Button::Button ( const Reference& rxWindowPeer, const OUString& rsText, const PresenterBitmapContainer::BitmapSet& rIcons, const Callback& rCallback) : Element(rxWindowPeer, awt::Rectangle(0,0,gnButtonSize,gnButtonSize)), msText(rsText), mbIsOver(false), mbIsPressed(false), maIcons(rIcons), mbIconLoadingFailed(false), maCallback(rCallback) { } void Button::Paint ( const Reference& rxCanvas, const rendering::ViewState& rViewState) { OSL_ASSERT(rxCanvas.is()); Reference xBitmap; if (mbIsPressed) xBitmap = maIcons.mxButtonDownIcon; else if (mbIsOver) xBitmap = maIcons.mxMouseOverIcon; else xBitmap = maIcons.mxNormalIcon; if (xBitmap.is()) { const rendering::RenderState aRenderState( geometry::AffineMatrix2D(1,0,maBoundingBox.X, 0,1,maBoundingBox.Y), NULL, Sequence(3), rendering::CompositeOperation::OVER); rxCanvas->drawBitmap(xBitmap, rViewState, aRenderState); } } bool Button::SetState ( const bool bIsOver, const bool bIsPressed) { bool bModified (mbIsOver != bIsOver || mbIsPressed != bIsPressed); bool bClicked (mbIsPressed && bIsOver && ! bIsPressed); mbIsOver = bIsOver; mbIsPressed = bIsPressed; if (bModified) Invalidate(); if (bClicked) maCallback(); return bModified; } //===== PresenterToolBar::Label =============================================== Label::Label ( const Reference& rxWindowPeer, const util::Color& rFontColor, const rendering::FontRequest& rFontDescriptor) : Element(rxWindowPeer, awt::Rectangle(0,0,100,gnButtonSize)), msText(), mxFont(), maFontColor(rFontColor), maRequestedFontDescriptor(rFontDescriptor) { maRequestedFontDescriptor.CellSize = gnButtonSize / 2; } void Label::SetCurrentSlide ( const Reference& rxCurrentSlide, const sal_Int32 nSlideCount) { try { Reference xSlideProperties (rxCurrentSlide, UNO_QUERY_THROW); const Any aSlideNumber (xSlideProperties->getPropertyValue( OUString::createFromAscii("Number"))); sal_Int32 nSlideNumber (0); if (aSlideNumber >>= nSlideNumber) { SetText( OUString::valueOf(nSlideNumber) + OUString::createFromAscii(" / ") + OUString::valueOf(nSlideCount)); } } catch (RuntimeException&) { } } void Label::SetText (const OUString& rsText) { msText = rsText; Invalidate(); } void Label::Paint ( const Reference& rxCanvas, const rendering::ViewState& rViewState) { OSL_ASSERT(rxCanvas.is()); if ( ! mxFont.is()) mxFont = rxCanvas->createFont( maRequestedFontDescriptor, Sequence(), geometry::Matrix2D(1,0,0,1)); if (mxFont.is()) { rendering::StringContext aContext (msText, 0, msText.getLength()); Reference xLayout ( mxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0)); geometry::RealRectangle2D aBox (xLayout->queryTextBounds()); const double nTextWidth = aBox.X2 - aBox.X1; const double nTextHeight = aBox.Y2 - aBox.Y1; const double nY = maBoundingBox.Y + (maBoundingBox.Height - nTextHeight)/2 + 3*nTextHeight/4; const double nX = maBoundingBox.X + (maBoundingBox.Width - nTextWidth)/2; rendering::RenderState aRenderState( geometry::AffineMatrix2D(1,0,nX, 0,1,nY), NULL, Sequence(3), rendering::CompositeOperation::SOURCE); aRenderState.DeviceColor[0] = ((maFontColor&0x00ff0000)>>16) / 255.0; aRenderState.DeviceColor[1] = ((maFontColor&0x0000ff00)>>8) / 255.0; aRenderState.DeviceColor[2] = (maFontColor&0x000000ff) / 255.0; rxCanvas->drawText( aContext, mxFont, rViewState, aRenderState, rendering::TextDirection::WEAK_LEFT_TO_RIGHT); } } } } // end of namespace ::sdext::presenter