1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
44 #include "cursormanager.hxx"
46 using namespace ::com::sun::star
;
52 class PaintOverlayHandler
: public MouseEventHandler
,
53 public ViewEventHandler
,
54 public UserPaintEventHandler
57 PaintOverlayHandler( const RGBColor
& rStrokeColor
,
59 ScreenUpdater
& rScreenUpdater
,
60 const UnoViewContainer
& rViews
,
62 const PolyPolygonVector
& rPolygons
,
64 mrScreenUpdater( rScreenUpdater
),
66 maPolygons( rPolygons
),
67 maStrokeColor( rStrokeColor
),
68 mnStrokeWidth( nStrokeWidth
),
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 ),
81 std::for_each( rViews
.begin(),
83 boost::bind( &PaintOverlayHandler::viewAdded
,
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(),
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;
123 this->maStrokeColor
= rUserColor
;
124 this->mbIsEraseModeActivated
= false;
128 bool widthChanged( double nUserStrokeWidth
) SAL_OVERRIDE
130 this->mnStrokeWidth
= nUserStrokeWidth
;
131 mbIsEraseModeActivated
= false;
135 void repaintWithoutPolygons()
137 // must get access to the instance to erase all polygon
138 for( UnoViewVector::iterator aIter
=maViews
.begin(), aEnd
=maViews
.end();
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
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();
182 mbIsEraseAllModeActivated
=false;
186 bool eraseInkWidthChanged( sal_Int32 rEraseInkSize
) SAL_OVERRIDE
189 this->mnSize
=rEraseInkSize
;
190 // Changed to mode Erase
191 this->mbIsEraseModeActivated
= true;
195 bool switchPenMode() SAL_OVERRIDE
197 mbIsLastPointValid
= false;
199 this->mbIsEraseModeActivated
= false;
203 bool switchEraserMode() SAL_OVERRIDE
205 mbIsLastPointValid
= false;
207 this->mbIsEraseModeActivated
= true;
211 bool disable() SAL_OVERRIDE
213 mbIsLastPointValid
= false;
214 mbIsLastMouseDownPosValid
= false;
219 //Draw all registered polygons.
222 for( PolyPolygonVector::iterator aIter
=maPolygons
.begin(), aEnd
=maPolygons
.end();
228 // screen update necessary to show painting
229 mrScreenUpdater
.notifyUpdate();
232 //Retrieve all registered polygons.
233 PolyPolygonVector
getPolygons()
238 // MouseEventHandler methods
239 virtual bool handleMousePressed( const awt::MouseEvent
& e
) SAL_OVERRIDE
244 if (e
.Buttons
== awt::MouseButton::RIGHT
)
246 mbIsLastPointValid
= false;
250 if (e
.Buttons
!= awt::MouseButton::LEFT
)
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
262 virtual bool handleMouseReleased( const awt::MouseEvent
& e
) SAL_OVERRIDE
267 if (e
.Buttons
== awt::MouseButton::RIGHT
)
269 mbIsLastPointValid
= false;
273 if (e
.Buttons
!= awt::MouseButton::LEFT
)
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
282 if( mbIsLastMouseDownPosValid
&&
283 ::basegfx::B2DPoint( e
.X
,
284 e
.Y
) == maLastMouseDownPos
)
286 mbIsLastMouseDownPosValid
= false;
290 // invalidate, next downpress will have to start a new
292 mbIsLastPointValid
= false;
294 // eat mouse click (though we don't process it
295 // _directly_, it enables the drag mode
299 virtual bool handleMouseEntered( const awt::MouseEvent
& e
) SAL_OVERRIDE
304 mbIsLastPointValid
= true;
305 maLastPoint
.setX( e
.X
);
306 maLastPoint
.setY( e
.Y
);
311 virtual bool handleMouseExited( const awt::MouseEvent
& ) SAL_OVERRIDE
316 mbIsLastPointValid
= false;
317 mbIsLastMouseDownPosValid
= false;
322 virtual bool handleMouseDragged( const awt::MouseEvent
& e
) SAL_OVERRIDE
327 if (e
.Buttons
== awt::MouseButton::RIGHT
)
329 mbIsLastPointValid
= 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,
365 for( UnoViewVector::iterator aIter
=maViews
.begin(), aEnd
=maViews
.end();
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);
399 if( !mbIsLastPointValid
)
401 mbIsLastPointValid
= true;
402 maLastPoint
.setX( e
.X
);
403 maLastPoint
.setY( e
.Y
);
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();
420 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
421 ::cppcanvas::BaseGfxFactory::createPolyPolygon( (*aIter
)->getCanvas(),
426 pPolyPoly
->setStrokeWidth(mnStrokeWidth
);
427 pPolyPoly
->setRGBALineColor( maStrokeColor
.getIntegerColor() );
429 maPolygons
.push_back(pPolyPoly
);
433 // screen update necessary to show painting
434 mrScreenUpdater
.notifyUpdate();
437 // mouse events captured
441 virtual bool handleMouseMoved( const awt::MouseEvent
& /*e*/ ) SAL_OVERRIDE
444 return false; // did not handle the event
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
;
465 UserPaintOverlaySharedPtr
UserPaintOverlay::create( const RGBColor
& rStrokeColor
,
467 const SlideShowContext
& rContext
,
468 const PolyPolygonVector
& rPolygons
,
471 UserPaintOverlaySharedPtr
pRet( new UserPaintOverlay( rStrokeColor
,
480 UserPaintOverlay::UserPaintOverlay( const RGBColor
& rStrokeColor
,
482 const SlideShowContext
& rContext
,
483 const PolyPolygonVector
& rPolygons
,
485 mpHandler( new PaintOverlayHandler( rStrokeColor
,
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: */