bump product version to 5.0.4.1
[LibreOffice.git] / slideshow / source / engine / slide / userpaintoverlay.cxx
blobcdab35a9a91907754b636328905bf1271ec47085
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <canvas/debug.hxx>
23 #include <comphelper/anytostring.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
26 #include <com/sun/star/awt/MouseButton.hpp>
27 #include <com/sun/star/presentation/XSlideShowView.hpp>
29 #include <basegfx/point/b2dpoint.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
31 #include <cppcanvas/basegfxfactory.hxx>
33 #include "activity.hxx"
34 #include "slideshowcontext.hxx"
35 #include "userpaintoverlay.hxx"
36 #include "mouseeventhandler.hxx"
37 #include "eventmultiplexer.hxx"
38 #include "screenupdater.hxx"
39 #include "vieweventhandler.hxx"
41 #include <boost/bind.hpp>
42 #include <boost/noncopyable.hpp>
43 #include "slide.hxx"
44 #include "cursormanager.hxx"
46 using namespace ::com::sun::star;
48 namespace slideshow
50 namespace internal
52 class PaintOverlayHandler : public MouseEventHandler,
53 public ViewEventHandler,
54 public UserPaintEventHandler
56 public:
57 PaintOverlayHandler( const RGBColor& rStrokeColor,
58 double nStrokeWidth,
59 ScreenUpdater& rScreenUpdater,
60 const UnoViewContainer& rViews,
61 Slide& rSlide,
62 const PolyPolygonVector& rPolygons,
63 bool bActive ) :
64 mrScreenUpdater( rScreenUpdater ),
65 maViews(),
66 maPolygons( rPolygons ),
67 maStrokeColor( rStrokeColor ),
68 mnStrokeWidth( nStrokeWidth ),
69 maLastPoint(),
70 maLastMouseDownPos(),
71 mbIsLastPointValid( false ),
72 mbIsLastMouseDownPosValid( false ),
73 //handle the "remove all ink from slide" mode of erasing
74 mbIsEraseAllModeActivated( false ),
75 //handle the "remove stroke by stroke" mode of erasing
76 mbIsEraseModeActivated( false ),
77 mrSlide(rSlide),
78 mnSize(100),
79 mbActive( bActive )
81 std::for_each( rViews.begin(),
82 rViews.end(),
83 boost::bind( &PaintOverlayHandler::viewAdded,
84 this,
85 _1 ));
86 drawPolygons();
89 void dispose()
91 maViews.clear();
94 // ViewEventHandler methods
95 virtual void viewAdded( const UnoViewSharedPtr& rView ) SAL_OVERRIDE
97 maViews.push_back( rView );
100 virtual void viewRemoved( const UnoViewSharedPtr& rView ) SAL_OVERRIDE
102 maViews.erase( ::std::remove( maViews.begin(),
103 maViews.end(),
104 rView ) );
107 virtual void viewChanged( const UnoViewSharedPtr& /*rView*/ ) SAL_OVERRIDE
109 // TODO(F2): for persistent drawings, need to store
110 // polygon and repaint here.
113 virtual void viewsChanged() SAL_OVERRIDE
115 // TODO(F2): for persistent drawings, need to store
116 // polygon and repaint here.
119 bool colorChanged( RGBColor const& rUserColor ) SAL_OVERRIDE
121 mbIsLastPointValid = false;
122 mbActive = true;
123 this->maStrokeColor = rUserColor;
124 this->mbIsEraseModeActivated = false;
125 return true;
128 bool widthChanged( double nUserStrokeWidth ) SAL_OVERRIDE
130 this->mnStrokeWidth = nUserStrokeWidth;
131 mbIsEraseModeActivated = false;
132 return true;
135 void repaintWithoutPolygons()
137 // must get access to the instance to erase all polygon
138 for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
139 aIter!=aEnd;
140 ++aIter )
142 // fully clear view content to background color
143 //(*aIter)->getCanvas()->clear();
145 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
146 SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) );
147 ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() );
149 const ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() );
150 const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
152 // setup a canvas with device coordinate space, the slide
153 // bitmap already has the correct dimension.
154 ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
156 pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
158 // render at given output position
159 pBitmap->move( aOutPosPixel );
161 // clear clip (might have been changed, e.g. from comb
162 // transition)
163 pBitmap->clip( ::basegfx::B2DPolyPolygon() );
164 pBitmap->draw( pDevicePixelCanvas );
166 mrScreenUpdater.notifyUpdate(*aIter,true);
170 bool eraseAllInkChanged( bool const& rEraseAllInk ) SAL_OVERRIDE
172 this->mbIsEraseAllModeActivated= rEraseAllInk;
173 // if the erase all mode is activated it will remove all ink from slide,
174 // therefore destroy all the polygons stored
175 if(mbIsEraseAllModeActivated)
177 // The Erase Mode should be desactivated
178 mbIsEraseModeActivated = false;
179 repaintWithoutPolygons();
180 maPolygons.clear();
182 mbIsEraseAllModeActivated=false;
183 return true;
186 bool eraseInkWidthChanged( sal_Int32 rEraseInkSize ) SAL_OVERRIDE
188 // Change the size
189 this->mnSize=rEraseInkSize;
190 // Changed to mode Erase
191 this->mbIsEraseModeActivated = true;
192 return true;
195 bool switchPenMode() SAL_OVERRIDE
197 mbIsLastPointValid = false;
198 mbActive = true;
199 this->mbIsEraseModeActivated = false;
200 return true;
203 bool switchEraserMode() SAL_OVERRIDE
205 mbIsLastPointValid = false;
206 mbActive = true;
207 this->mbIsEraseModeActivated = true;
208 return true;
211 bool disable() SAL_OVERRIDE
213 mbIsLastPointValid = false;
214 mbIsLastMouseDownPosValid = false;
215 mbActive = false;
216 return true;
219 //Draw all registered polygons.
220 void drawPolygons()
222 for( PolyPolygonVector::iterator aIter=maPolygons.begin(), aEnd=maPolygons.end();
223 aIter!=aEnd;
224 ++aIter )
226 (*aIter)->draw();
228 // screen update necessary to show painting
229 mrScreenUpdater.notifyUpdate();
232 //Retrieve all registered polygons.
233 PolyPolygonVector getPolygons()
235 return maPolygons;
238 // MouseEventHandler methods
239 virtual bool handleMousePressed( const awt::MouseEvent& e ) SAL_OVERRIDE
241 if( !mbActive )
242 return false;
244 if (e.Buttons == awt::MouseButton::RIGHT)
246 mbIsLastPointValid = false;
247 return false;
250 if (e.Buttons != awt::MouseButton::LEFT)
251 return false;
253 maLastMouseDownPos.setX( e.X );
254 maLastMouseDownPos.setY( e.Y );
255 mbIsLastMouseDownPosValid = true;
257 // eat mouse click (though we don't process it
258 // _directly_, it enables the drag mode
259 return true;
262 virtual bool handleMouseReleased( const awt::MouseEvent& e ) SAL_OVERRIDE
264 if( !mbActive )
265 return false;
267 if (e.Buttons == awt::MouseButton::RIGHT)
269 mbIsLastPointValid = false;
270 return false;
273 if (e.Buttons != awt::MouseButton::LEFT)
274 return false;
276 // check, whether up- and down press are on exactly
277 // the same pixel. If that's the case, ignore the
278 // click, and pass on the event to low-prio
279 // handlers. This effectively permits effect
280 // advancements via clicks also when user paint is
281 // enabled.
282 if( mbIsLastMouseDownPosValid &&
283 ::basegfx::B2DPoint( e.X,
284 e.Y ) == maLastMouseDownPos )
286 mbIsLastMouseDownPosValid = false;
287 return false;
290 // invalidate, next downpress will have to start a new
291 // polygon.
292 mbIsLastPointValid = false;
294 // eat mouse click (though we don't process it
295 // _directly_, it enables the drag mode
296 return true;
299 virtual bool handleMouseEntered( const awt::MouseEvent& e ) SAL_OVERRIDE
301 if( !mbActive )
302 return false;
304 mbIsLastPointValid = true;
305 maLastPoint.setX( e.X );
306 maLastPoint.setY( e.Y );
308 return true;
311 virtual bool handleMouseExited( const awt::MouseEvent& ) SAL_OVERRIDE
313 if( !mbActive )
314 return false;
316 mbIsLastPointValid = false;
317 mbIsLastMouseDownPosValid = false;
319 return true;
322 virtual bool handleMouseDragged( const awt::MouseEvent& e ) SAL_OVERRIDE
324 if( !mbActive )
325 return false;
327 if (e.Buttons == awt::MouseButton::RIGHT)
329 mbIsLastPointValid = false;
330 return false;
333 if(mbIsEraseModeActivated)
335 //define the last point as an object
336 //we suppose that there's no way this point could be valid
337 ::basegfx::B2DPolygon aPoly;
339 maLastPoint.setX( e.X-mnSize );
340 maLastPoint.setY( e.Y-mnSize );
342 aPoly.append( maLastPoint );
344 maLastPoint.setX( e.X-mnSize );
345 maLastPoint.setY( e.Y+mnSize );
347 aPoly.append( maLastPoint );
348 maLastPoint.setX( e.X+mnSize );
349 maLastPoint.setY( e.Y+mnSize );
351 aPoly.append( maLastPoint );
352 maLastPoint.setX( e.X+mnSize );
353 maLastPoint.setY( e.Y-mnSize );
355 aPoly.append( maLastPoint );
356 maLastPoint.setX( e.X-mnSize );
357 maLastPoint.setY( e.Y-mnSize );
359 aPoly.append( maLastPoint );
361 //now we have defined a Polygon that is closed
363 //The point is to redraw the LastPoint the way it was originally on the bitmap,
364 //of the slide
365 for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
366 aIter!=aEnd;
367 ++aIter )
370 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
371 SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( (*aIter) ) );
372 ::cppcanvas::CanvasSharedPtr pCanvas( (*aIter)->getCanvas() );
374 ::basegfx::B2DHomMatrix aViewTransform( (*aIter)->getTransformation() );
375 const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
377 // setup a canvas with device coordinate space, the slide
378 // bitmap already has the correct dimension.
379 ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
381 pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
383 // render at given output position
384 pBitmap->move( aOutPosPixel );
386 ::basegfx::B2DPolyPolygon aPolyPoly=::basegfx::B2DPolyPolygon(aPoly);
387 aViewTransform.translate(-aOutPosPixel.getX(), -aOutPosPixel.getY());
388 aPolyPoly.transform(aViewTransform);
389 // set clip so that we just redraw a part of the canvas
390 pBitmap->clip(aPolyPoly);
391 pBitmap->draw( pDevicePixelCanvas );
393 mrScreenUpdater.notifyUpdate(*aIter,true);
397 else
399 if( !mbIsLastPointValid )
401 mbIsLastPointValid = true;
402 maLastPoint.setX( e.X );
403 maLastPoint.setY( e.Y );
405 else
407 ::basegfx::B2DPolygon aPoly;
408 aPoly.append( maLastPoint );
410 maLastPoint.setX( e.X );
411 maLastPoint.setY( e.Y );
413 aPoly.append( maLastPoint );
415 // paint to all views
416 for( UnoViewVector::iterator aIter=maViews.begin(), aEnd=maViews.end();
417 aIter!=aEnd;
418 ++aIter )
420 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
421 ::cppcanvas::BaseGfxFactory::createPolyPolygon( (*aIter)->getCanvas(),
422 aPoly ) );
424 if( pPolyPoly )
426 pPolyPoly->setStrokeWidth(mnStrokeWidth);
427 pPolyPoly->setRGBALineColor( maStrokeColor.getIntegerColor() );
428 pPolyPoly->draw();
429 maPolygons.push_back(pPolyPoly);
433 // screen update necessary to show painting
434 mrScreenUpdater.notifyUpdate();
437 // mouse events captured
438 return true;
441 virtual bool handleMouseMoved( const awt::MouseEvent& /*e*/ ) SAL_OVERRIDE
443 // not used here
444 return false; // did not handle the event
447 private:
448 ScreenUpdater& mrScreenUpdater;
449 UnoViewVector maViews;
450 PolyPolygonVector maPolygons;
451 RGBColor maStrokeColor;
452 double mnStrokeWidth;
453 basegfx::B2DPoint maLastPoint;
454 basegfx::B2DPoint maLastMouseDownPos;
455 bool mbIsLastPointValid;
456 bool mbIsLastMouseDownPosValid;
457 // added bool for erasing purpose :
458 bool mbIsEraseAllModeActivated;
459 bool mbIsEraseModeActivated;
460 Slide& mrSlide;
461 sal_Int32 mnSize;
462 bool mbActive;
465 UserPaintOverlaySharedPtr UserPaintOverlay::create( const RGBColor& rStrokeColor,
466 double nStrokeWidth,
467 const SlideShowContext& rContext,
468 const PolyPolygonVector& rPolygons,
469 bool bActive )
471 UserPaintOverlaySharedPtr pRet( new UserPaintOverlay( rStrokeColor,
472 nStrokeWidth,
473 rContext,
474 rPolygons,
475 bActive));
477 return pRet;
480 UserPaintOverlay::UserPaintOverlay( const RGBColor& rStrokeColor,
481 double nStrokeWidth,
482 const SlideShowContext& rContext,
483 const PolyPolygonVector& rPolygons,
484 bool bActive ) :
485 mpHandler( new PaintOverlayHandler( rStrokeColor,
486 nStrokeWidth,
487 rContext.mrScreenUpdater,
488 rContext.mrViewContainer,
489 //adding a link to Slide
490 dynamic_cast<Slide&>(rContext.mrCursorManager),
491 rPolygons, bActive )),
492 mrMultiplexer( rContext.mrEventMultiplexer )
494 mrMultiplexer.addClickHandler( mpHandler, 3.0 );
495 mrMultiplexer.addMouseMoveHandler( mpHandler, 3.0 );
496 mrMultiplexer.addViewHandler( mpHandler );
497 mrMultiplexer.addUserPaintHandler(mpHandler);
500 PolyPolygonVector UserPaintOverlay::getPolygons()
502 return mpHandler->getPolygons();
505 void UserPaintOverlay::drawPolygons()
507 mpHandler->drawPolygons();
510 UserPaintOverlay::~UserPaintOverlay()
514 mrMultiplexer.removeMouseMoveHandler( mpHandler );
515 mrMultiplexer.removeClickHandler( mpHandler );
516 mrMultiplexer.removeViewHandler( mpHandler );
517 mpHandler->dispose();
519 catch (uno::Exception &)
521 OSL_FAIL( OUStringToOString(
522 comphelper::anyToString(
523 cppu::getCaughtException() ),
524 RTL_TEXTENCODING_UTF8 ).getStr() );
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */