diff options
Diffstat (limited to 'slideshow/source/engine/slide/userpaintoverlay.cxx')
-rw-r--r-- | slideshow/source/engine/slide/userpaintoverlay.cxx | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/slideshow/source/engine/slide/userpaintoverlay.cxx b/slideshow/source/engine/slide/userpaintoverlay.cxx new file mode 100644 index 000000000000..8d9fad06a3e3 --- /dev/null +++ b/slideshow/source/engine/slide/userpaintoverlay.cxx @@ -0,0 +1,504 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_slideshow.hxx" + +#include <canvas/debug.hxx> + +#include <comphelper/anytostring.hxx> +#include <cppuhelper/exc_hlp.hxx> + +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/presentation/XSlideShowView.hpp> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <cppcanvas/basegfxfactory.hxx> + +#include "activity.hxx" +#include "activitiesqueue.hxx" +#include "slideshowcontext.hxx" +#include "userpaintoverlay.hxx" +#include "mouseeventhandler.hxx" +#include "eventmultiplexer.hxx" +#include "screenupdater.hxx" +#include "vieweventhandler.hxx" + +#include <boost/bind.hpp> +#include <boost/noncopyable.hpp> +#include "slide.hxx" +#include "cursormanager.hxx" + +using namespace ::com::sun::star; + +namespace slideshow +{ + namespace internal + { + class PaintOverlayHandler : public MouseEventHandler, + public ViewEventHandler, + public UserPaintEventHandler + { + public: + PaintOverlayHandler( const RGBColor& rStrokeColor, + double nStrokeWidth, + ActivitiesQueue& rActivitiesQueue, + ScreenUpdater& rScreenUpdater, + const UnoViewContainer& rViews, + Slide& rSlide, + const PolyPolygonVector& rPolygons ) : + mrActivitiesQueue( rActivitiesQueue ), + mrScreenUpdater( rScreenUpdater ), + maViews(), + maPolygons( rPolygons ), + maStrokeColor( rStrokeColor ), + mnStrokeWidth( nStrokeWidth ), + maLastPoint(), + maLastMouseDownPos(), + mbIsLastPointValid( false ), + mbIsLastMouseDownPosValid( false ), + //handle the "remove all ink from slide" mode of erasing + mbIsEraseAllModeActivated( false ), + //handle the "remove stroke by stroke" mode of erasing + mbIsEraseModeActivated( false ), + mrSlide(rSlide), + mnSize(100) + { + std::for_each( rViews.begin(), + rViews.end(), + boost::bind( &PaintOverlayHandler::viewAdded, + this, + _1 )); + drawPolygons(); + } + + virtual void dispose() + { + maViews.clear(); + } + + // ViewEventHandler methods + virtual void viewAdded( const UnoViewSharedPtr& rView ) + { + maViews.push_back( rView ); + } + + virtual void viewRemoved( const UnoViewSharedPtr& rView ) + { + maViews.erase( ::std::remove( maViews.begin(), + maViews.end(), + rView ) ); + } + + virtual void viewChanged( const UnoViewSharedPtr& /*rView*/ ) + { + // TODO(F2): for persistent drawings, need to store + // polygon and repaint here. + } + + virtual void viewsChanged() + { + // TODO(F2): for persistent drawings, need to store + // polygon and repaint here. + } + + bool colorChanged( RGBColor const& rUserColor ) + { + this->maStrokeColor = rUserColor; + this->mbIsEraseModeActivated = false; + return true; + } + + bool widthChanged( double nUserStrokeWidth ) + { + this->mnStrokeWidth = nUserStrokeWidth; + mbIsEraseModeActivated = false; + return true; + } + + bool eraseAllInkChanged( bool const& rEraseAllInk ) + { + this->mbIsEraseAllModeActivated= rEraseAllInk; + // if the erase all mode is activated it will remove all ink from slide, + // therefor destroy all the polygons stored + if(mbIsEraseAllModeActivated) + { + // The Erase Mode should be desactivated + mbIsEraseModeActivated = false; + // must get access to the instance to erase all polygon + for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end(); + aIter!=aEnd; + ++aIter ) + { + // fully clear view content to background color + (*aIter)->getCanvas()->clear(); + + //get via SlideImpl instance the bitmap of the slide unmodified to redraw it + SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) ); + ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() ); + + const ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() ); + const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() ); + + // setup a canvas with device coordinate space, the slide + // bitmap already has the correct dimension. + ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() ); + + pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() ); + + // render at given output position + pBitmap->move( aOutPosPixel ); + + // clear clip (might have been changed, e.g. from comb + // transition) + pBitmap->clip( ::basegfx::B2DPolyPolygon() ); + pBitmap->draw( pDevicePixelCanvas ); + + mrScreenUpdater.notifyUpdate(*aIter,true); + } + maPolygons.clear(); + } + mbIsEraseAllModeActivated=false; + return true; + } + + bool eraseInkWidthChanged( sal_Int32 rEraseInkSize ) + { + // Change the size + this->mnSize=rEraseInkSize; + // Changed to mode Erase + this->mbIsEraseModeActivated = true; + return true; + } + + bool switchPenMode() + { + this->mbIsEraseModeActivated = false; + return true; + } + + bool switchEraserMode() + { + this->mbIsEraseModeActivated = true; + return true; + } + + bool disable() + { + return true; + } + + //Draw all registered polygons. + void drawPolygons() + { + for( PolyPolygonVector::iterator aIter=maPolygons.begin(), aEnd=maPolygons.end(); + aIter!=aEnd; + ++aIter ) + { + (*aIter)->draw(); + } + // screen update necessary to show painting + mrScreenUpdater.notifyUpdate(); + } + + //Retrieve all registered polygons. + PolyPolygonVector getPolygons() + { + return maPolygons; + } + + // MouseEventHandler methods + virtual bool handleMousePressed( const awt::MouseEvent& e ) + { + if (e.Buttons == awt::MouseButton::RIGHT) + { + mbIsLastPointValid = false; + return false; + } + + if (e.Buttons != awt::MouseButton::LEFT) + return false; + + maLastMouseDownPos.setX( e.X ); + maLastMouseDownPos.setY( e.Y ); + mbIsLastMouseDownPosValid = true; + + // eat mouse click (though we don't process it + // _directly_, it enables the drag mode + return true; + } + + virtual bool handleMouseReleased( const awt::MouseEvent& e ) + { + if (e.Buttons == awt::MouseButton::RIGHT) + { + mbIsLastPointValid = false; + return false; + } + + if (e.Buttons != awt::MouseButton::LEFT) + return false; + + // check, whether up- and down press are on exactly + // the same pixel. If that's the case, ignore the + // click, and pass on the event to low-prio + // handlers. This effectively permits effect + // advancements via clicks also when user paint is + // enabled. + if( mbIsLastMouseDownPosValid && + ::basegfx::B2DPoint( e.X, + e.Y ) == maLastMouseDownPos ) + { + mbIsLastMouseDownPosValid = false; + return false; + } + + // invalidate, next downpress will have to start a new + // polygon. + mbIsLastPointValid = false; + + // eat mouse click (though we don't process it + // _directly_, it enables the drag mode + return true; + } + + virtual bool handleMouseEntered( const awt::MouseEvent& e ) + { + mbIsLastPointValid = true; + maLastPoint.setX( e.X ); + maLastPoint.setY( e.Y ); + + return true; + } + + virtual bool handleMouseExited( const awt::MouseEvent& ) + { + mbIsLastPointValid = false; + mbIsLastMouseDownPosValid = false; + + return true; + } + + virtual bool handleMouseDragged( const awt::MouseEvent& e ) + { + if(mbIsEraseModeActivated) + { + //define the last point as an object + //we suppose that there's no way this point could be valid + ::basegfx::B2DPolygon aPoly; + + maLastPoint.setX( e.X-mnSize ); + maLastPoint.setY( e.Y-mnSize ); + + aPoly.append( maLastPoint ); + + maLastPoint.setX( e.X-mnSize ); + maLastPoint.setY( e.Y+mnSize ); + + aPoly.append( maLastPoint ); + maLastPoint.setX( e.X+mnSize ); + maLastPoint.setY( e.Y+mnSize ); + + aPoly.append( maLastPoint ); + maLastPoint.setX( e.X+mnSize ); + maLastPoint.setY( e.Y-mnSize ); + + aPoly.append( maLastPoint ); + maLastPoint.setX( e.X-mnSize ); + maLastPoint.setY( e.Y-mnSize ); + + aPoly.append( maLastPoint ); + + //now we have defined a Polygon that is closed + + //The point is to redraw the LastPoint the way it was originally on the bitmap, + //of the slide + for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end(); + aIter!=aEnd; + ++aIter ) + { + + //get via SlideImpl instance the bitmap of the slide unmodified to redraw it + SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) ); + ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() ); + + ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() ); + const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() ); + + // setup a canvas with device coordinate space, the slide + // bitmap already has the correct dimension. + ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() ); + + pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() ); + + // render at given output position + pBitmap->move( aOutPosPixel ); + + ::basegfx::B2DPolyPolygon aPolyPoly=::basegfx::B2DPolyPolygon(aPoly); + aViewTransform.translate(-aOutPosPixel.getX(), -aOutPosPixel.getY()); + aPolyPoly.transform(aViewTransform); + // set clip so that we just redraw a part of the canvas + pBitmap->clip(aPolyPoly); + pBitmap->draw( pDevicePixelCanvas ); + + mrScreenUpdater.notifyUpdate(*aIter,true); + } + + } + else + { + if( !mbIsLastPointValid ) + { + mbIsLastPointValid = true; + maLastPoint.setX( e.X ); + maLastPoint.setY( e.Y ); + } + else + { + ::basegfx::B2DPolygon aPoly; + aPoly.append( maLastPoint ); + + maLastPoint.setX( e.X ); + maLastPoint.setY( e.Y ); + + aPoly.append( maLastPoint ); + + // paint to all views + for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end(); + aIter!=aEnd; + ++aIter ) + { + ::cppcanvas::PolyPolygonSharedPtr pPolyPoly( + ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( (*aIter)->getCanvas(), + aPoly ) ); + + if( pPolyPoly ) + { + pPolyPoly->setStrokeWidth(mnStrokeWidth); + pPolyPoly->setRGBALineColor( maStrokeColor.getIntegerColor() ); + pPolyPoly->draw(); + maPolygons.push_back(pPolyPoly); + } + } + + // screen update necessary to show painting + mrScreenUpdater.notifyUpdate(); + } + } + // mouse events captured + return true; + } + + virtual bool handleMouseMoved( const awt::MouseEvent& /*e*/ ) + { + // not used here + return false; // did not handle the event + } + + + + private: + ActivitiesQueue& mrActivitiesQueue; + ScreenUpdater& mrScreenUpdater; + UnoViewVector maViews; + PolyPolygonVector maPolygons; + RGBColor maStrokeColor; + double mnStrokeWidth; + basegfx::B2DPoint maLastPoint; + basegfx::B2DPoint maLastMouseDownPos; + bool mbIsLastPointValid; + bool mbIsLastMouseDownPosValid; + // added bool for erasing purpose : + bool mbIsEraseAllModeActivated; + bool mbIsEraseModeActivated; + Slide& mrSlide; + sal_Int32 mnSize; + }; + + UserPaintOverlaySharedPtr UserPaintOverlay::create( const RGBColor& rStrokeColor, + double nStrokeWidth, + const SlideShowContext& rContext, + const PolyPolygonVector& rPolygons ) + { + UserPaintOverlaySharedPtr pRet( new UserPaintOverlay( rStrokeColor, + nStrokeWidth, + rContext, + rPolygons )); + + return pRet; + } + + UserPaintOverlay::UserPaintOverlay( const RGBColor& rStrokeColor, + double nStrokeWidth, + const SlideShowContext& rContext, + const PolyPolygonVector& rPolygons ) : + mpHandler( new PaintOverlayHandler( rStrokeColor, + nStrokeWidth, + rContext.mrActivitiesQueue, + rContext.mrScreenUpdater, + rContext.mrViewContainer, + //adding a link to Slide + dynamic_cast<Slide&>(rContext.mrCursorManager), + rPolygons )), + mrMultiplexer( rContext.mrEventMultiplexer ) + { + mrMultiplexer.addClickHandler( mpHandler, 3.0 ); + mrMultiplexer.addMouseMoveHandler( mpHandler, 3.0 ); + mrMultiplexer.addViewHandler( mpHandler ); + mrMultiplexer.addUserPaintHandler(mpHandler); + } + + PolyPolygonVector UserPaintOverlay::getPolygons() + { + return mpHandler->getPolygons(); + } + + void UserPaintOverlay::drawPolygons() + { + mpHandler->drawPolygons(); + } + + UserPaintOverlay::~UserPaintOverlay() + { + try + { + mrMultiplexer.removeMouseMoveHandler( mpHandler ); + mrMultiplexer.removeClickHandler( mpHandler ); + mrMultiplexer.removeViewHandler( mpHandler ); + mpHandler->dispose(); + } + catch (uno::Exception &) + { + OSL_ENSURE( false, rtl::OUStringToOString( + comphelper::anyToString( + cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + } +} |