Get the style color and number just once
[LibreOffice.git] / slideshow / source / engine / slide / userpaintoverlay.cxx
blob460e5c5de00aa95511a4c558c7ddb7d5c11341eb
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 <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>
37 #include <slide.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
48 public:
49 PaintOverlayHandler( const RGBColor& rStrokeColor,
50 double nStrokeWidth,
51 ScreenUpdater& rScreenUpdater,
52 const UnoViewContainer& rViews,
53 Slide& rSlide,
54 PolyPolygonVector&& rPolygons,
55 bool bActive ) :
56 mrScreenUpdater( rScreenUpdater ),
57 maViews(),
58 maPolygons( std::move(rPolygons) ),
59 maStrokeColor( rStrokeColor ),
60 mnStrokeWidth( nStrokeWidth ),
61 maLastPoint(),
62 maLastMouseDownPos(),
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 ),
69 mrSlide(rSlide),
70 mnSize(100),
71 mbActive( bActive )
73 for( const auto& rView : rViews )
74 viewAdded( rView );
76 drawPolygons();
79 void dispose()
81 maViews.clear();
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 std::erase(maViews, rView);
95 virtual void viewChanged( const UnoViewSharedPtr& /*rView*/ ) override
97 // TODO(F2): for persistent drawings, need to store
98 // polygon and repaint here.
101 virtual void viewsChanged() override
103 // TODO(F2): for persistent drawings, need to store
104 // polygon and repaint here.
107 bool colorChanged( RGBColor const& rUserColor ) override
109 mbIsLastPointValid = false;
110 mbActive = true;
111 maStrokeColor = rUserColor;
112 mbIsEraseModeActivated = false;
113 return true;
116 bool widthChanged( double nUserStrokeWidth ) override
118 mnStrokeWidth = nUserStrokeWidth;
119 mbIsEraseModeActivated = false;
120 return true;
123 void repaintWithoutPolygons()
125 // must get access to the instance to erase all polygon
126 for( const auto& rxView : maViews )
128 // fully clear view content to background color
129 //rxView->getCanvas()->clear();
131 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
132 SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( rxView ) );
133 ::cppcanvas::CanvasSharedPtr pCanvas( rxView->getCanvas() );
135 const ::basegfx::B2DHomMatrix aViewTransform( rxView->getTransformation() );
136 const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
138 // setup a canvas with device coordinate space, the slide
139 // bitmap already has the correct dimension.
140 ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
142 pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
144 // render at given output position
145 pBitmap->move( aOutPosPixel );
147 // clear clip (might have been changed, e.g. from comb
148 // transition)
149 pBitmap->clip( ::basegfx::B2DPolyPolygon() );
150 pBitmap->draw( pDevicePixelCanvas );
152 mrScreenUpdater.notifyUpdate(rxView,true);
156 bool eraseAllInkChanged( bool bEraseAllInk ) override
158 mbIsEraseAllModeActivated = bEraseAllInk;
159 // if the erase all mode is activated it will remove all ink from slide,
160 // therefore destroy all the polygons stored
161 if(mbIsEraseAllModeActivated)
163 // The Erase Mode should be deactivated
164 mbIsEraseModeActivated = false;
165 repaintWithoutPolygons();
166 maPolygons.clear();
168 mbIsEraseAllModeActivated=false;
169 return true;
172 bool eraseInkWidthChanged( sal_Int32 rEraseInkSize ) override
174 // Change the size
175 mnSize=rEraseInkSize;
176 // Changed to mode Erase
177 mbIsEraseModeActivated = true;
178 return true;
181 bool switchPenMode() override
183 mbIsLastPointValid = false;
184 mbActive = true;
185 mbIsEraseModeActivated = false;
186 return true;
189 bool switchEraserMode() override
191 mbIsLastPointValid = false;
192 mbActive = true;
193 mbIsEraseModeActivated = true;
194 return true;
197 bool disable() override
199 mbIsLastPointValid = false;
200 mbIsLastMouseDownPosValid = false;
201 mbActive = false;
202 return true;
205 //Draw all registered polygons.
206 void drawPolygons()
208 for( const auto& rxPolygon : maPolygons )
210 rxPolygon->draw();
212 // screen update necessary to show painting
213 mrScreenUpdater.notifyUpdate();
216 //Retrieve all registered polygons.
217 const PolyPolygonVector& getPolygons() const
219 return maPolygons;
222 // MouseEventHandler methods
223 virtual bool handleMousePressed( const awt::MouseEvent& e ) override
225 if( !mbActive )
226 return false;
228 if (e.Buttons == awt::MouseButton::RIGHT)
230 mbIsLastPointValid = false;
231 return false;
234 if (e.Buttons != awt::MouseButton::LEFT)
235 return false;
237 maLastMouseDownPos.setX( e.X );
238 maLastMouseDownPos.setY( e.Y );
239 mbIsLastMouseDownPosValid = true;
241 // eat mouse click (though we don't process it
242 // _directly_, it enables the drag mode
243 return true;
246 virtual bool handleMouseReleased( const awt::MouseEvent& e ) override
248 if( !mbActive )
249 return false;
251 if (e.Buttons == awt::MouseButton::RIGHT)
253 mbIsLastPointValid = false;
254 return false;
257 if (e.Buttons != awt::MouseButton::LEFT)
258 return false;
260 // check, whether up- and down press are on exactly
261 // the same pixel. If that's the case, ignore the
262 // click, and pass on the event to low-prio
263 // handlers. This effectively permits effect
264 // advancements via clicks also when user paint is
265 // enabled.
266 if( mbIsLastMouseDownPosValid &&
267 ::basegfx::B2DPoint( e.X,
268 e.Y ) == maLastMouseDownPos )
270 mbIsLastMouseDownPosValid = false;
271 return false;
274 // invalidate, next downpress will have to start a new
275 // polygon.
276 mbIsLastPointValid = false;
278 // eat mouse click (though we don't process it
279 // _directly_, it enables the drag mode
280 return true;
283 virtual bool handleMouseDragged( const awt::MouseEvent& e ) override
285 if( !mbActive )
286 return false;
288 if (e.Buttons == awt::MouseButton::RIGHT)
290 mbIsLastPointValid = false;
291 return false;
294 if(mbIsEraseModeActivated)
296 //define the last point as an object
297 //we suppose that there's no way this point could be valid
298 ::basegfx::B2DPolygon aPoly;
300 maLastPoint.setX( e.X-mnSize );
301 maLastPoint.setY( e.Y-mnSize );
303 aPoly.append( maLastPoint );
305 maLastPoint.setX( e.X-mnSize );
306 maLastPoint.setY( e.Y+mnSize );
308 aPoly.append( maLastPoint );
309 maLastPoint.setX( e.X+mnSize );
310 maLastPoint.setY( e.Y+mnSize );
312 aPoly.append( maLastPoint );
313 maLastPoint.setX( e.X+mnSize );
314 maLastPoint.setY( e.Y-mnSize );
316 aPoly.append( maLastPoint );
317 maLastPoint.setX( e.X-mnSize );
318 maLastPoint.setY( e.Y-mnSize );
320 aPoly.append( maLastPoint );
322 //now we have defined a Polygon that is closed
324 //The point is to redraw the LastPoint the way it was originally on the bitmap,
325 //of the slide
326 for (const auto& rxView : maViews)
329 //get via SlideImpl instance the bitmap of the slide unmodified to redraw it
330 SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( rxView ) );
331 ::cppcanvas::CanvasSharedPtr pCanvas( rxView->getCanvas() );
333 ::basegfx::B2DHomMatrix aViewTransform( rxView->getTransformation() );
334 const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
336 // setup a canvas with device coordinate space, the slide
337 // bitmap already has the correct dimension.
338 ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
340 pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
342 // render at given output position
343 pBitmap->move( aOutPosPixel );
345 ::basegfx::B2DPolyPolygon aPolyPoly(aPoly);
346 aViewTransform.translate(-aOutPosPixel.getX(), -aOutPosPixel.getY());
347 aPolyPoly.transform(aViewTransform);
348 // set clip so that we just redraw a part of the canvas
349 pBitmap->clip(aPolyPoly);
350 pBitmap->draw( pDevicePixelCanvas );
352 mrScreenUpdater.notifyUpdate(rxView,true);
356 else
358 if( !mbIsLastPointValid )
360 mbIsLastPointValid = true;
361 maLastPoint.setX( e.X );
362 maLastPoint.setY( e.Y );
364 else
366 ::basegfx::B2DPolygon aPoly;
367 aPoly.append( maLastPoint );
369 maLastPoint.setX( e.X );
370 maLastPoint.setY( e.Y );
372 aPoly.append( maLastPoint );
374 // paint to all views
375 for (const auto& rxView : maViews)
377 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
378 ::cppcanvas::BaseGfxFactory::createPolyPolygon( rxView->getCanvas(),
379 aPoly ) );
381 if( pPolyPoly )
383 pPolyPoly->setStrokeWidth(mnStrokeWidth);
384 pPolyPoly->setRGBALineColor( maStrokeColor.getIntegerColor() );
385 pPolyPoly->draw();
386 maPolygons.push_back(pPolyPoly);
390 // screen update necessary to show painting
391 mrScreenUpdater.notifyUpdate();
394 // mouse events captured
395 return true;
398 virtual bool handleMouseMoved( const awt::MouseEvent& /*e*/ ) override
400 // not used here
401 return false; // did not handle the event
404 private:
405 ScreenUpdater& mrScreenUpdater;
406 UnoViewVector maViews;
407 PolyPolygonVector maPolygons;
408 RGBColor maStrokeColor;
409 double mnStrokeWidth;
410 basegfx::B2DPoint maLastPoint;
411 basegfx::B2DPoint maLastMouseDownPos;
412 bool mbIsLastPointValid;
413 bool mbIsLastMouseDownPosValid;
414 // added bool for erasing purpose :
415 bool mbIsEraseAllModeActivated;
416 bool mbIsEraseModeActivated;
417 Slide& mrSlide;
418 sal_Int32 mnSize;
419 bool mbActive;
422 UserPaintOverlaySharedPtr UserPaintOverlay::create( const RGBColor& rStrokeColor,
423 double nStrokeWidth,
424 const SlideShowContext& rContext,
425 PolyPolygonVector&& rPolygons,
426 bool bActive )
428 UserPaintOverlaySharedPtr pRet( new UserPaintOverlay( rStrokeColor,
429 nStrokeWidth,
430 rContext,
431 std::move(rPolygons),
432 bActive));
434 return pRet;
437 UserPaintOverlay::UserPaintOverlay( const RGBColor& rStrokeColor,
438 double nStrokeWidth,
439 const SlideShowContext& rContext,
440 PolyPolygonVector&& rPolygons,
441 bool bActive ) :
442 mpHandler( std::make_shared<PaintOverlayHandler>( rStrokeColor,
443 nStrokeWidth,
444 rContext.mrScreenUpdater,
445 rContext.mrViewContainer,
446 //adding a link to Slide
447 dynamic_cast<Slide&>(rContext.mrCursorManager),
448 std::move(rPolygons), bActive )),
449 mrMultiplexer( rContext.mrEventMultiplexer )
451 mrMultiplexer.addClickHandler( mpHandler, 3.0 );
452 mrMultiplexer.addMouseMoveHandler( mpHandler, 3.0 );
453 mrMultiplexer.addViewHandler( mpHandler );
454 mrMultiplexer.addUserPaintHandler(mpHandler);
457 PolyPolygonVector const & UserPaintOverlay::getPolygons() const
459 return mpHandler->getPolygons();
462 void UserPaintOverlay::drawPolygons()
464 mpHandler->drawPolygons();
467 UserPaintOverlay::~UserPaintOverlay()
471 mrMultiplexer.removeMouseMoveHandler( mpHandler );
472 mrMultiplexer.removeClickHandler( mpHandler );
473 mrMultiplexer.removeViewHandler( mpHandler );
474 mpHandler->dispose();
476 catch (const uno::Exception&)
478 TOOLS_WARN_EXCEPTION("slideshow", "");
483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */