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 <com/sun/star/awt/MouseButton.hpp>
22 #include <com/sun/star/awt/MouseEvent.hpp>
24 #include <basegfx/point/b2dpoint.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/matrix/b2dhommatrix.hxx>
27 #include <cppcanvas/basegfxfactory.hxx>
28 #include <comphelper/diagnose_ex.hxx>
30 #include <slideshowcontext.hxx>
31 #include "userpaintoverlay.hxx"
32 #include <mouseeventhandler.hxx>
33 #include <eventmultiplexer.hxx>
34 #include <screenupdater.hxx>
35 #include <vieweventhandler.hxx>
38 #include <cursormanager.hxx>
40 using namespace ::com::sun::star
;
42 namespace slideshow::internal
44 class PaintOverlayHandler
: public MouseEventHandler
,
45 public ViewEventHandler
,
46 public UserPaintEventHandler
49 PaintOverlayHandler( const RGBColor
& rStrokeColor
,
51 ScreenUpdater
& rScreenUpdater
,
52 const UnoViewContainer
& rViews
,
54 PolyPolygonVector
&& rPolygons
,
56 mrScreenUpdater( rScreenUpdater
),
58 maPolygons( std::move(rPolygons
) ),
59 maStrokeColor( rStrokeColor
),
60 mnStrokeWidth( nStrokeWidth
),
63 mbIsLastPointValid( false ),
64 mbIsLastMouseDownPosValid( false ),
65 //handle the "remove all ink from slide" mode of erasing
66 mbIsEraseAllModeActivated( false ),
67 //handle the "remove stroke by stroke" mode of erasing
68 mbIsEraseModeActivated( false ),
73 for( const auto& rView
: rViews
)
84 // ViewEventHandler methods
85 virtual void viewAdded( const UnoViewSharedPtr
& rView
) override
87 maViews
.push_back( rView
);
90 virtual void viewRemoved( const UnoViewSharedPtr
& rView
) override
92 maViews
.erase( ::std::remove( maViews
.begin(),
97 virtual void viewChanged( const UnoViewSharedPtr
& /*rView*/ ) override
99 // TODO(F2): for persistent drawings, need to store
100 // polygon and repaint here.
103 virtual void viewsChanged() override
105 // TODO(F2): for persistent drawings, need to store
106 // polygon and repaint here.
109 bool colorChanged( RGBColor
const& rUserColor
) override
111 mbIsLastPointValid
= false;
113 maStrokeColor
= rUserColor
;
114 mbIsEraseModeActivated
= false;
118 bool widthChanged( double nUserStrokeWidth
) override
120 mnStrokeWidth
= nUserStrokeWidth
;
121 mbIsEraseModeActivated
= false;
125 void repaintWithoutPolygons()
127 // must get access to the instance to erase all polygon
128 for( const auto& rxView
: maViews
)
130 // fully clear view content to background color
131 //rxView->getCanvas()->clear();
133 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
134 SlideBitmapSharedPtr
pBitmap( mrSlide
.getCurrentSlideBitmap( rxView
) );
135 ::cppcanvas::CanvasSharedPtr
pCanvas( rxView
->getCanvas() );
137 const ::basegfx::B2DHomMatrix
aViewTransform( rxView
->getTransformation() );
138 const ::basegfx::B2DPoint
aOutPosPixel( aViewTransform
* ::basegfx::B2DPoint() );
140 // setup a canvas with device coordinate space, the slide
141 // bitmap already has the correct dimension.
142 ::cppcanvas::CanvasSharedPtr
pDevicePixelCanvas( pCanvas
->clone() );
144 pDevicePixelCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
146 // render at given output position
147 pBitmap
->move( aOutPosPixel
);
149 // clear clip (might have been changed, e.g. from comb
151 pBitmap
->clip( ::basegfx::B2DPolyPolygon() );
152 pBitmap
->draw( pDevicePixelCanvas
);
154 mrScreenUpdater
.notifyUpdate(rxView
,true);
158 bool eraseAllInkChanged( bool bEraseAllInk
) override
160 mbIsEraseAllModeActivated
= bEraseAllInk
;
161 // if the erase all mode is activated it will remove all ink from slide,
162 // therefore destroy all the polygons stored
163 if(mbIsEraseAllModeActivated
)
165 // The Erase Mode should be deactivated
166 mbIsEraseModeActivated
= false;
167 repaintWithoutPolygons();
170 mbIsEraseAllModeActivated
=false;
174 bool eraseInkWidthChanged( sal_Int32 rEraseInkSize
) override
177 mnSize
=rEraseInkSize
;
178 // Changed to mode Erase
179 mbIsEraseModeActivated
= true;
183 bool switchPenMode() override
185 mbIsLastPointValid
= false;
187 mbIsEraseModeActivated
= false;
191 bool switchEraserMode() override
193 mbIsLastPointValid
= false;
195 mbIsEraseModeActivated
= true;
199 bool disable() override
201 mbIsLastPointValid
= false;
202 mbIsLastMouseDownPosValid
= false;
207 //Draw all registered polygons.
210 for( const auto& rxPolygon
: maPolygons
)
214 // screen update necessary to show painting
215 mrScreenUpdater
.notifyUpdate();
218 //Retrieve all registered polygons.
219 const PolyPolygonVector
& getPolygons() const
224 // MouseEventHandler methods
225 virtual bool handleMousePressed( const awt::MouseEvent
& e
) override
230 if (e
.Buttons
== awt::MouseButton::RIGHT
)
232 mbIsLastPointValid
= false;
236 if (e
.Buttons
!= awt::MouseButton::LEFT
)
239 maLastMouseDownPos
.setX( e
.X
);
240 maLastMouseDownPos
.setY( e
.Y
);
241 mbIsLastMouseDownPosValid
= true;
243 // eat mouse click (though we don't process it
244 // _directly_, it enables the drag mode
248 virtual bool handleMouseReleased( const awt::MouseEvent
& e
) override
253 if (e
.Buttons
== awt::MouseButton::RIGHT
)
255 mbIsLastPointValid
= false;
259 if (e
.Buttons
!= awt::MouseButton::LEFT
)
262 // check, whether up- and down press are on exactly
263 // the same pixel. If that's the case, ignore the
264 // click, and pass on the event to low-prio
265 // handlers. This effectively permits effect
266 // advancements via clicks also when user paint is
268 if( mbIsLastMouseDownPosValid
&&
269 ::basegfx::B2DPoint( e
.X
,
270 e
.Y
) == maLastMouseDownPos
)
272 mbIsLastMouseDownPosValid
= false;
276 // invalidate, next downpress will have to start a new
278 mbIsLastPointValid
= false;
280 // eat mouse click (though we don't process it
281 // _directly_, it enables the drag mode
285 virtual bool handleMouseDragged( const awt::MouseEvent
& e
) override
290 if (e
.Buttons
== awt::MouseButton::RIGHT
)
292 mbIsLastPointValid
= false;
296 if(mbIsEraseModeActivated
)
298 //define the last point as an object
299 //we suppose that there's no way this point could be valid
300 ::basegfx::B2DPolygon aPoly
;
302 maLastPoint
.setX( e
.X
-mnSize
);
303 maLastPoint
.setY( e
.Y
-mnSize
);
305 aPoly
.append( maLastPoint
);
307 maLastPoint
.setX( e
.X
-mnSize
);
308 maLastPoint
.setY( e
.Y
+mnSize
);
310 aPoly
.append( maLastPoint
);
311 maLastPoint
.setX( e
.X
+mnSize
);
312 maLastPoint
.setY( e
.Y
+mnSize
);
314 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
);
324 //now we have defined a Polygon that is closed
326 //The point is to redraw the LastPoint the way it was originally on the bitmap,
328 for (const auto& rxView
: maViews
)
331 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
332 SlideBitmapSharedPtr
pBitmap( mrSlide
.getCurrentSlideBitmap( rxView
) );
333 ::cppcanvas::CanvasSharedPtr
pCanvas( rxView
->getCanvas() );
335 ::basegfx::B2DHomMatrix
aViewTransform( rxView
->getTransformation() );
336 const ::basegfx::B2DPoint
aOutPosPixel( aViewTransform
* ::basegfx::B2DPoint() );
338 // setup a canvas with device coordinate space, the slide
339 // bitmap already has the correct dimension.
340 ::cppcanvas::CanvasSharedPtr
pDevicePixelCanvas( pCanvas
->clone() );
342 pDevicePixelCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
344 // render at given output position
345 pBitmap
->move( aOutPosPixel
);
347 ::basegfx::B2DPolyPolygon
aPolyPoly(aPoly
);
348 aViewTransform
.translate(-aOutPosPixel
.getX(), -aOutPosPixel
.getY());
349 aPolyPoly
.transform(aViewTransform
);
350 // set clip so that we just redraw a part of the canvas
351 pBitmap
->clip(aPolyPoly
);
352 pBitmap
->draw( pDevicePixelCanvas
);
354 mrScreenUpdater
.notifyUpdate(rxView
,true);
360 if( !mbIsLastPointValid
)
362 mbIsLastPointValid
= true;
363 maLastPoint
.setX( e
.X
);
364 maLastPoint
.setY( e
.Y
);
368 ::basegfx::B2DPolygon aPoly
;
369 aPoly
.append( maLastPoint
);
371 maLastPoint
.setX( e
.X
);
372 maLastPoint
.setY( e
.Y
);
374 aPoly
.append( maLastPoint
);
376 // paint to all views
377 for (const auto& rxView
: maViews
)
379 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
380 ::cppcanvas::BaseGfxFactory::createPolyPolygon( rxView
->getCanvas(),
385 pPolyPoly
->setStrokeWidth(mnStrokeWidth
);
386 pPolyPoly
->setRGBALineColor( maStrokeColor
.getIntegerColor() );
388 maPolygons
.push_back(pPolyPoly
);
392 // screen update necessary to show painting
393 mrScreenUpdater
.notifyUpdate();
396 // mouse events captured
400 virtual bool handleMouseMoved( const awt::MouseEvent
& /*e*/ ) override
403 return false; // did not handle the event
407 ScreenUpdater
& mrScreenUpdater
;
408 UnoViewVector maViews
;
409 PolyPolygonVector maPolygons
;
410 RGBColor maStrokeColor
;
411 double mnStrokeWidth
;
412 basegfx::B2DPoint maLastPoint
;
413 basegfx::B2DPoint maLastMouseDownPos
;
414 bool mbIsLastPointValid
;
415 bool mbIsLastMouseDownPosValid
;
416 // added bool for erasing purpose :
417 bool mbIsEraseAllModeActivated
;
418 bool mbIsEraseModeActivated
;
424 UserPaintOverlaySharedPtr
UserPaintOverlay::create( const RGBColor
& rStrokeColor
,
426 const SlideShowContext
& rContext
,
427 PolyPolygonVector
&& rPolygons
,
430 UserPaintOverlaySharedPtr
pRet( new UserPaintOverlay( rStrokeColor
,
433 std::move(rPolygons
),
439 UserPaintOverlay::UserPaintOverlay( const RGBColor
& rStrokeColor
,
441 const SlideShowContext
& rContext
,
442 PolyPolygonVector
&& rPolygons
,
444 mpHandler( std::make_shared
<PaintOverlayHandler
>( rStrokeColor
,
446 rContext
.mrScreenUpdater
,
447 rContext
.mrViewContainer
,
448 //adding a link to Slide
449 dynamic_cast<Slide
&>(rContext
.mrCursorManager
),
450 std::move(rPolygons
), bActive
)),
451 mrMultiplexer( rContext
.mrEventMultiplexer
)
453 mrMultiplexer
.addClickHandler( mpHandler
, 3.0 );
454 mrMultiplexer
.addMouseMoveHandler( mpHandler
, 3.0 );
455 mrMultiplexer
.addViewHandler( mpHandler
);
456 mrMultiplexer
.addUserPaintHandler(mpHandler
);
459 PolyPolygonVector
const & UserPaintOverlay::getPolygons() const
461 return mpHandler
->getPolygons();
464 void UserPaintOverlay::drawPolygons()
466 mpHandler
->drawPolygons();
469 UserPaintOverlay::~UserPaintOverlay()
473 mrMultiplexer
.removeMouseMoveHandler( mpHandler
);
474 mrMultiplexer
.removeClickHandler( mpHandler
);
475 mrMultiplexer
.removeViewHandler( mpHandler
);
476 mpHandler
->dispose();
478 catch (const uno::Exception
&)
480 TOOLS_WARN_EXCEPTION("slideshow", "");
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */