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 <comphelper/anytostring.hxx>
22 #include <cppuhelper/exc_hlp.hxx>
24 #include <com/sun/star/awt/MouseButton.hpp>
25 #include <com/sun/star/awt/MouseEvent.hpp>
27 #include <basegfx/point/b2dpoint.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <cppcanvas/basegfxfactory.hxx>
31 #include <activity.hxx>
32 #include <slideshowcontext.hxx>
33 #include "userpaintoverlay.hxx"
34 #include <mouseeventhandler.hxx>
35 #include <eventmultiplexer.hxx>
36 #include <screenupdater.hxx>
37 #include <vieweventhandler.hxx>
40 #include <cursormanager.hxx>
42 using namespace ::com::sun::star
;
48 class PaintOverlayHandler
: public MouseEventHandler
,
49 public ViewEventHandler
,
50 public UserPaintEventHandler
53 PaintOverlayHandler( const RGBColor
& rStrokeColor
,
55 ScreenUpdater
& rScreenUpdater
,
56 const UnoViewContainer
& rViews
,
58 const PolyPolygonVector
& rPolygons
,
60 mrScreenUpdater( rScreenUpdater
),
62 maPolygons( rPolygons
),
63 maStrokeColor( rStrokeColor
),
64 mnStrokeWidth( nStrokeWidth
),
67 mbIsLastPointValid( false ),
68 mbIsLastMouseDownPosValid( false ),
69 //handle the "remove all ink from slide" mode of erasing
70 mbIsEraseAllModeActivated( false ),
71 //handle the "remove stroke by stroke" mode of erasing
72 mbIsEraseModeActivated( false ),
77 for( const auto& rView
: rViews
)
88 // ViewEventHandler methods
89 virtual void viewAdded( const UnoViewSharedPtr
& rView
) override
91 maViews
.push_back( rView
);
94 virtual void viewRemoved( const UnoViewSharedPtr
& rView
) override
96 maViews
.erase( ::std::remove( maViews
.begin(),
101 virtual void viewChanged( const UnoViewSharedPtr
& /*rView*/ ) override
103 // TODO(F2): for persistent drawings, need to store
104 // polygon and repaint here.
107 virtual void viewsChanged() override
109 // TODO(F2): for persistent drawings, need to store
110 // polygon and repaint here.
113 bool colorChanged( RGBColor
const& rUserColor
) override
115 mbIsLastPointValid
= false;
117 maStrokeColor
= rUserColor
;
118 mbIsEraseModeActivated
= false;
122 bool widthChanged( double nUserStrokeWidth
) override
124 mnStrokeWidth
= nUserStrokeWidth
;
125 mbIsEraseModeActivated
= false;
129 void repaintWithoutPolygons()
131 // must get access to the instance to erase all polygon
132 for( UnoViewVector::iterator aIter
=maViews
.begin(), aEnd
=maViews
.end();
136 // fully clear view content to background color
137 //(*aIter)->getCanvas()->clear();
139 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
140 SlideBitmapSharedPtr
pBitmap( mrSlide
.getCurrentSlideBitmap( *aIter
) );
141 ::cppcanvas::CanvasSharedPtr
pCanvas( (*aIter
)->getCanvas() );
143 const ::basegfx::B2DHomMatrix
aViewTransform( (*aIter
)->getTransformation() );
144 const ::basegfx::B2DPoint
aOutPosPixel( aViewTransform
* ::basegfx::B2DPoint() );
146 // setup a canvas with device coordinate space, the slide
147 // bitmap already has the correct dimension.
148 ::cppcanvas::CanvasSharedPtr
pDevicePixelCanvas( pCanvas
->clone() );
150 pDevicePixelCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
152 // render at given output position
153 pBitmap
->move( aOutPosPixel
);
155 // clear clip (might have been changed, e.g. from comb
157 pBitmap
->clip( ::basegfx::B2DPolyPolygon() );
158 pBitmap
->draw( pDevicePixelCanvas
);
160 mrScreenUpdater
.notifyUpdate(*aIter
,true);
164 bool eraseAllInkChanged( bool bEraseAllInk
) override
166 mbIsEraseAllModeActivated
= bEraseAllInk
;
167 // if the erase all mode is activated it will remove all ink from slide,
168 // therefore destroy all the polygons stored
169 if(mbIsEraseAllModeActivated
)
171 // The Erase Mode should be deactivated
172 mbIsEraseModeActivated
= false;
173 repaintWithoutPolygons();
176 mbIsEraseAllModeActivated
=false;
180 bool eraseInkWidthChanged( sal_Int32 rEraseInkSize
) override
183 mnSize
=rEraseInkSize
;
184 // Changed to mode Erase
185 mbIsEraseModeActivated
= true;
189 bool switchPenMode() override
191 mbIsLastPointValid
= false;
193 mbIsEraseModeActivated
= false;
197 bool switchEraserMode() override
199 mbIsLastPointValid
= false;
201 mbIsEraseModeActivated
= true;
205 bool disable() override
207 mbIsLastPointValid
= false;
208 mbIsLastMouseDownPosValid
= false;
213 //Draw all registered polygons.
216 for( PolyPolygonVector::iterator aIter
=maPolygons
.begin(), aEnd
=maPolygons
.end();
222 // screen update necessary to show painting
223 mrScreenUpdater
.notifyUpdate();
226 //Retrieve all registered polygons.
227 const PolyPolygonVector
& getPolygons()
232 // MouseEventHandler methods
233 virtual bool handleMousePressed( const awt::MouseEvent
& e
) override
238 if (e
.Buttons
== awt::MouseButton::RIGHT
)
240 mbIsLastPointValid
= false;
244 if (e
.Buttons
!= awt::MouseButton::LEFT
)
247 maLastMouseDownPos
.setX( e
.X
);
248 maLastMouseDownPos
.setY( e
.Y
);
249 mbIsLastMouseDownPosValid
= true;
251 // eat mouse click (though we don't process it
252 // _directly_, it enables the drag mode
256 virtual bool handleMouseReleased( const awt::MouseEvent
& e
) override
261 if (e
.Buttons
== awt::MouseButton::RIGHT
)
263 mbIsLastPointValid
= false;
267 if (e
.Buttons
!= awt::MouseButton::LEFT
)
270 // check, whether up- and down press are on exactly
271 // the same pixel. If that's the case, ignore the
272 // click, and pass on the event to low-prio
273 // handlers. This effectively permits effect
274 // advancements via clicks also when user paint is
276 if( mbIsLastMouseDownPosValid
&&
277 ::basegfx::B2DPoint( e
.X
,
278 e
.Y
) == maLastMouseDownPos
)
280 mbIsLastMouseDownPosValid
= false;
284 // invalidate, next downpress will have to start a new
286 mbIsLastPointValid
= false;
288 // eat mouse click (though we don't process it
289 // _directly_, it enables the drag mode
293 virtual bool handleMouseDragged( const awt::MouseEvent
& e
) override
298 if (e
.Buttons
== awt::MouseButton::RIGHT
)
300 mbIsLastPointValid
= false;
304 if(mbIsEraseModeActivated
)
306 //define the last point as an object
307 //we suppose that there's no way this point could be valid
308 ::basegfx::B2DPolygon aPoly
;
310 maLastPoint
.setX( e
.X
-mnSize
);
311 maLastPoint
.setY( e
.Y
-mnSize
);
313 aPoly
.append( maLastPoint
);
315 maLastPoint
.setX( e
.X
-mnSize
);
316 maLastPoint
.setY( e
.Y
+mnSize
);
318 aPoly
.append( maLastPoint
);
319 maLastPoint
.setX( e
.X
+mnSize
);
320 maLastPoint
.setY( e
.Y
+mnSize
);
322 aPoly
.append( maLastPoint
);
323 maLastPoint
.setX( e
.X
+mnSize
);
324 maLastPoint
.setY( e
.Y
-mnSize
);
326 aPoly
.append( maLastPoint
);
327 maLastPoint
.setX( e
.X
-mnSize
);
328 maLastPoint
.setY( e
.Y
-mnSize
);
330 aPoly
.append( maLastPoint
);
332 //now we have defined a Polygon that is closed
334 //The point is to redraw the LastPoint the way it was originally on the bitmap,
336 for( UnoViewVector::iterator aIter
=maViews
.begin(), aEnd
=maViews
.end();
341 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
342 SlideBitmapSharedPtr
pBitmap( mrSlide
.getCurrentSlideBitmap( *aIter
) );
343 ::cppcanvas::CanvasSharedPtr
pCanvas( (*aIter
)->getCanvas() );
345 ::basegfx::B2DHomMatrix
aViewTransform( (*aIter
)->getTransformation() );
346 const ::basegfx::B2DPoint
aOutPosPixel( aViewTransform
* ::basegfx::B2DPoint() );
348 // setup a canvas with device coordinate space, the slide
349 // bitmap already has the correct dimension.
350 ::cppcanvas::CanvasSharedPtr
pDevicePixelCanvas( pCanvas
->clone() );
352 pDevicePixelCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
354 // render at given output position
355 pBitmap
->move( aOutPosPixel
);
357 ::basegfx::B2DPolyPolygon aPolyPoly
=::basegfx::B2DPolyPolygon(aPoly
);
358 aViewTransform
.translate(-aOutPosPixel
.getX(), -aOutPosPixel
.getY());
359 aPolyPoly
.transform(aViewTransform
);
360 // set clip so that we just redraw a part of the canvas
361 pBitmap
->clip(aPolyPoly
);
362 pBitmap
->draw( pDevicePixelCanvas
);
364 mrScreenUpdater
.notifyUpdate(*aIter
,true);
370 if( !mbIsLastPointValid
)
372 mbIsLastPointValid
= true;
373 maLastPoint
.setX( e
.X
);
374 maLastPoint
.setY( e
.Y
);
378 ::basegfx::B2DPolygon aPoly
;
379 aPoly
.append( maLastPoint
);
381 maLastPoint
.setX( e
.X
);
382 maLastPoint
.setY( e
.Y
);
384 aPoly
.append( maLastPoint
);
386 // paint to all views
387 for( UnoViewVector::iterator aIter
=maViews
.begin(), aEnd
=maViews
.end();
391 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
392 ::cppcanvas::BaseGfxFactory::createPolyPolygon( (*aIter
)->getCanvas(),
397 pPolyPoly
->setStrokeWidth(mnStrokeWidth
);
398 pPolyPoly
->setRGBALineColor( maStrokeColor
.getIntegerColor() );
400 maPolygons
.push_back(pPolyPoly
);
404 // screen update necessary to show painting
405 mrScreenUpdater
.notifyUpdate();
408 // mouse events captured
412 virtual bool handleMouseMoved( const awt::MouseEvent
& /*e*/ ) override
415 return false; // did not handle the event
419 ScreenUpdater
& mrScreenUpdater
;
420 UnoViewVector maViews
;
421 PolyPolygonVector maPolygons
;
422 RGBColor maStrokeColor
;
423 double mnStrokeWidth
;
424 basegfx::B2DPoint maLastPoint
;
425 basegfx::B2DPoint maLastMouseDownPos
;
426 bool mbIsLastPointValid
;
427 bool mbIsLastMouseDownPosValid
;
428 // added bool for erasing purpose :
429 bool mbIsEraseAllModeActivated
;
430 bool mbIsEraseModeActivated
;
436 UserPaintOverlaySharedPtr
UserPaintOverlay::create( const RGBColor
& rStrokeColor
,
438 const SlideShowContext
& rContext
,
439 const PolyPolygonVector
& rPolygons
,
442 UserPaintOverlaySharedPtr
pRet( new UserPaintOverlay( rStrokeColor
,
451 UserPaintOverlay::UserPaintOverlay( const RGBColor
& rStrokeColor
,
453 const SlideShowContext
& rContext
,
454 const PolyPolygonVector
& rPolygons
,
456 mpHandler( new PaintOverlayHandler( rStrokeColor
,
458 rContext
.mrScreenUpdater
,
459 rContext
.mrViewContainer
,
460 //adding a link to Slide
461 dynamic_cast<Slide
&>(rContext
.mrCursorManager
),
462 rPolygons
, bActive
)),
463 mrMultiplexer( rContext
.mrEventMultiplexer
)
465 mrMultiplexer
.addClickHandler( mpHandler
, 3.0 );
466 mrMultiplexer
.addMouseMoveHandler( mpHandler
, 3.0 );
467 mrMultiplexer
.addViewHandler( mpHandler
);
468 mrMultiplexer
.addUserPaintHandler(mpHandler
);
471 PolyPolygonVector
UserPaintOverlay::getPolygons()
473 return mpHandler
->getPolygons();
476 void UserPaintOverlay::drawPolygons()
478 mpHandler
->drawPolygons();
481 UserPaintOverlay::~UserPaintOverlay()
485 mrMultiplexer
.removeMouseMoveHandler( mpHandler
);
486 mrMultiplexer
.removeClickHandler( mpHandler
);
487 mrMultiplexer
.removeViewHandler( mpHandler
);
488 mpHandler
->dispose();
490 catch (const uno::Exception
& e
)
492 SAL_WARN("slideshow", e
);
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */