LibreOffice Module slideshow (master) 1
rehearsetimingsactivity.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <rtl/ustrbuf.hxx>
22#include <vcl/svapp.hxx>
23#include <vcl/gdimtf.hxx>
24#include <vcl/virdev.hxx>
25#include <vcl/metric.hxx>
26#include <vcl/settings.hxx>
27
30#include <osl/diagnose.h>
32
33#include <com/sun/star/awt/MouseButton.hpp>
34#include <com/sun/star/awt/MouseEvent.hpp>
35#include <com/sun/star/rendering/XBitmap.hpp>
36#include <com/sun/star/rendering/XCanvas.hpp>
37
38#include <eventqueue.hxx>
39#include <screenupdater.hxx>
40#include <eventmultiplexer.hxx>
41#include <activitiesqueue.hxx>
42#include <slideshowcontext.hxx>
43#include <mouseeventhandler.hxx>
45
46#include <algorithm>
47
48using namespace com::sun::star;
49using namespace com::sun::star::uno;
50
51namespace slideshow::internal {
52
54{
55public:
56 WakeupEvent( std::shared_ptr< ::canvas::tools::ElapsedTime > const& pTimeBase,
57 ActivitySharedPtr const& rActivity,
58 ActivitiesQueue & rActivityQueue ) :
59 Event("WakeupEvent"),
60 maTimer(pTimeBase),
61 mnNextTime(0.0),
62 mpActivity(rActivity),
63 mrActivityQueue( rActivityQueue )
64 {}
65
66 WakeupEvent( const WakeupEvent& ) = delete;
67 WakeupEvent& operator=( const WakeupEvent& ) = delete;
68
69 virtual void dispose() override {}
70 virtual bool fire() override
71 {
72 ActivitySharedPtr pActivity( mpActivity.lock() );
73 if( !pActivity )
74 return false;
75
76 return mrActivityQueue.addActivity( pActivity );
77 }
78
79 virtual bool isCharged() const override { return true; }
80 virtual double getActivationTime( double nCurrentTime ) const override
81 {
82 const double nElapsedTime( maTimer.getElapsedTime() );
83
84 return ::std::max( nCurrentTime,
85 nCurrentTime - nElapsedTime + mnNextTime );
86 }
87
89 void start() { maTimer.reset(); }
90
99 void setNextTimeout( double nextTime ) { mnNextTime = nextTime; }
100
101private:
104 std::weak_ptr<Activity> mpActivity;
106};
107
109{
110public:
111 explicit MouseHandler( RehearseTimingsActivity& rta );
112
113 MouseHandler( const MouseHandler& ) = delete;
115
116 void reset();
117 bool hasBeenClicked() const { return mbHasBeenClicked; }
118
119 // MouseEventHandler
120 virtual bool handleMousePressed( awt::MouseEvent const & evt ) override;
121 virtual bool handleMouseReleased( awt::MouseEvent const & evt ) override;
122 virtual bool handleMouseDragged( awt::MouseEvent const & evt ) override;
123 virtual bool handleMouseMoved( awt::MouseEvent const & evt ) override;
124
125private:
126 bool isInArea( css::awt::MouseEvent const & evt ) const;
127 void updatePressedState( const bool pressedState ) const;
128
132};
133
134const sal_Int32 LEFT_BORDER_SPACE = 10;
135const sal_Int32 LOWER_BORDER_SPACE = 30;
136
138 mrEventQueue(rContext.mrEventQueue),
139 mrScreenUpdater(rContext.mrScreenUpdater),
141 mrActivitiesQueue(rContext.mrActivitiesQueue),
142 maElapsedTime( rContext.mrEventQueue.getTimer() ),
143 maViews(),
144 maSpriteRectangle(),
145 maFont( Application::GetSettings().GetStyleSettings().GetLabelFont() ),
146 mpWakeUpEvent(),
147 mpMouseHandler(),
148 maSpriteSizePixel(),
149 mnYOffset(0),
150 mbActive(false),
151 mbDrawPressed(false)
152{
157
158 // determine sprite size (in pixel):
160 blackHole->EnableOutput(false);
161 blackHole->SetFont( maFont );
162 blackHole->SetMapMode(MapMode(MapUnit::MapPixel));
163 tools::Rectangle rect;
164 const FontMetric metric( blackHole->GetFontMetric() );
165 blackHole->GetTextBoundRect( rect, "XX:XX:XX" );
166 maSpriteSizePixel.setX( rect.getOpenWidth() * 12 / 10 );
167 maSpriteSizePixel.setY( metric.GetLineHeight() * 11 / 10 );
168 mnYOffset = (metric.GetAscent() + (metric.GetLineHeight() / 20));
169
170 for( const auto& rView : rContext.mrViewContainer )
171 viewAdded( rView );
172}
173
175{
176 try
177 {
178 stop();
179 }
180 catch (const uno::Exception&)
181 {
182 TOOLS_WARN_EXCEPTION("slideshow", "");
183 }
184}
185
186std::shared_ptr<RehearseTimingsActivity> RehearseTimingsActivity::create(
187 const SlideShowContext& rContext )
188{
189 std::shared_ptr<RehearseTimingsActivity> pActivity(
190 new RehearseTimingsActivity( rContext ));
191
192 pActivity->mpMouseHandler =
193 std::make_shared<MouseHandler>(*pActivity);
194 pActivity->mpWakeUpEvent =
195 std::make_shared<WakeupEvent>( rContext.mrEventQueue.getTimer(),
196 pActivity,
197 rContext.mrActivitiesQueue );
198
199 rContext.mrEventMultiplexer.addViewHandler( pActivity );
200
201 return pActivity;
202}
203
205{
207 mbDrawPressed = false;
208 mbActive = true;
209
210 // paint and show all sprites:
212 for_each_sprite( []( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
213 { return pSprite->show(); } );
214
215 mrActivitiesQueue.addActivity( std::dynamic_pointer_cast<Activity>(shared_from_this()) );
216
217 mpMouseHandler->reset();
219 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
221 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
222}
223
225{
228
229 mbActive = false; // will be removed from queue
230
231 for_each_sprite( []( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
232 { return pSprite->hide(); } );
233
235}
236
238{
239 if (mpMouseHandler)
240 return mpMouseHandler->hasBeenClicked();
241 return false;
242}
243
244// Disposable:
246{
247 stop();
248
249 mpWakeUpEvent.reset();
250 mpMouseHandler.reset();
251
252 ViewsVecT().swap( maViews );
253}
254
255// Activity:
257{
258 return 0.0;
259}
260
262{
263 if( !isActive() )
264 return false;
265
266 if( !mpWakeUpEvent )
267 return false;
268
269 mpWakeUpEvent->start();
270 mpWakeUpEvent->setNextTimeout( 0.5 );
272
274
275 // sprites changed, need screen update
277
278 return false; // don't reinsert, WakeupEvent will perform
279 // that after the given timeout
280}
281
283{
284 return mbActive;
285}
286
288{
289 // not used here
290}
291
293{
294 if (isActive())
295 {
296 stop();
297 mbActive = false;
298 }
299}
300
302{
303 const Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
304 UNO_QUERY );
305 if( !xBitmap.is() )
306 return basegfx::B2DRange();
307
308 const geometry::IntegerSize2D realSize( xBitmap->getSize() );
309 // pixel:
310 basegfx::B2DPoint spritePos(
311 std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
312 std::max<sal_Int32>( 0, realSize.Height - maSpriteSizePixel.getY()
313 - LOWER_BORDER_SPACE ) );
314 basegfx::B2DHomMatrix transformation( rView->getTransformation() );
315 transformation.invert();
316 spritePos *= transformation;
319 spriteSize *= transformation;
320 return basegfx::B2DRange(
321 spritePos.getX(), spritePos.getY(),
322 spritePos.getX() + spriteSize.getWidth(),
323 spritePos.getY() + spriteSize.getHeight() );
324}
325
327{
329 rView->createSprite( basegfx::B2DSize(
332 1001.0 )); // sprite should be in front of all
333 // other sprites
334 sprite->setAlpha( 0.8 );
335 const basegfx::B2DRange spriteRectangle(
336 calcSpriteRectangle( rView ) );
337 sprite->move( basegfx::B2DPoint(
338 spriteRectangle.getMinX(),
339 spriteRectangle.getMinY() ) );
340
341 if( maViews.empty() )
342 maSpriteRectangle = spriteRectangle;
343
344 maViews.emplace_back( rView, sprite );
345
346 if (isActive())
347 sprite->show();
348}
349
351{
352 maViews.erase(
353 std::remove_if( maViews.begin(), maViews.end(),
354 [&rView]
355 ( const ViewsVecT::value_type& cp )
356 { return rView == cp.first; } ),
357 maViews.end() );
358}
359
361{
362 // find entry corresponding to modified view
363 ViewsVecT::iterator aModifiedEntry(
364 std::find_if(
365 maViews.begin(),
366 maViews.end(),
367 [&rView]
368 ( const ViewsVecT::value_type& cp )
369 { return rView == cp.first; } )
370 );
371
372 OSL_ASSERT( aModifiedEntry != maViews.end() );
373 if( aModifiedEntry == maViews.end() )
374 return;
375
376 // new sprite pos, transformation might have changed:
378
379 // reposition sprite:
380 aModifiedEntry->second->move( maSpriteRectangle.getMinimum() );
381
382 // sprites changed, need screen update
383 mrScreenUpdater.notifyUpdate( rView, false );
384}
385
387{
388 if( maViews.empty() )
389 return;
390
391 // new sprite pos, transformation might have changed:
393
395 // reposition sprites
396 for_each_sprite( [nMin]( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
397 { return pSprite->move( nMin ); } );
398
399 // sprites changed, need screen update
401}
402
404{
406 [this]( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
407 { return this->paint( pSprite->getContentCanvas() ); } );
408}
409
411{
412 // build timer string:
413 const sal_Int32 nTimeSecs =
414 static_cast<sal_Int32>(maElapsedTime.getElapsedTime());
415 OUStringBuffer buf;
416 sal_Int32 n = nTimeSecs / 3600;
417 if (n < 10)
418 buf.append( '0' );
419 buf.append( OUString::number(n) + ":" );
420 n = ((nTimeSecs % 3600) / 60);
421 if (n < 10)
422 buf.append( '0' );
423 buf.append( OUString::number(n) + ":" );
424 n = (nTimeSecs % 60);
425 if (n < 10)
426 buf.append( '0' );
427 buf.append( n );
428 const OUString time = buf.makeStringAndClear();
429
430 // create the MetaFile:
431 GDIMetaFile metaFile;
433 metaFile.Record( blackHole );
434 metaFile.SetPrefSize( Size( 1, 1 ) );
435 blackHole->EnableOutput(false);
436 blackHole->SetMapMode(MapMode(MapUnit::MapPixel));
437 blackHole->SetFont( maFont );
438 tools::Rectangle rect( 0,0,
441 if (mbDrawPressed)
442 {
443 blackHole->SetTextColor( COL_BLACK );
444 blackHole->SetFillColor( COL_LIGHTGRAY );
445 blackHole->SetLineColor( COL_GRAY );
446 }
447 else
448 {
449 blackHole->SetTextColor( COL_BLACK );
450 blackHole->SetFillColor( COL_WHITE );
451 blackHole->SetLineColor( COL_GRAY );
452 }
453 blackHole->DrawRect( rect );
454 blackHole->GetTextBoundRect( rect, time );
455 blackHole->DrawText(
456 Point( (maSpriteSizePixel.getX() - rect.getOpenWidth()) / 2,
457 mnYOffset ), time );
458
459 metaFile.Stop();
460 metaFile.WindStart();
461
465 const bool succ = renderer->draw();
466 OSL_ASSERT( succ );
467}
468
469
471 mrActivity(rta),
472 mbHasBeenClicked(false),
473 mbMouseStartedInArea(false)
474{}
475
477{
478 mbHasBeenClicked = false;
479 mbMouseStartedInArea = false;
480}
481
483 awt::MouseEvent const & evt ) const
484{
485 return mrActivity.maSpriteRectangle.isInside(
486 basegfx::B2DPoint( evt.X, evt.Y ) );
487}
488
490 const bool pressedState ) const
491{
492 if( pressedState != mrActivity.mbDrawPressed )
493 {
494 mrActivity.mbDrawPressed = pressedState;
495 mrActivity.paintAllSprites();
496
497 mrActivity.mrScreenUpdater.notifyUpdate();
498 }
499}
500
501// MouseEventHandler
503 awt::MouseEvent const & evt )
504{
505 if( evt.Buttons == awt::MouseButton::LEFT && isInArea(evt) )
506 {
507 mbMouseStartedInArea = true;
508 updatePressedState(true);
509 return true; // consume event
510 }
511 return false;
512}
513
515 awt::MouseEvent const & evt )
516{
517 if( evt.Buttons == awt::MouseButton::LEFT && mbMouseStartedInArea )
518 {
519 mbHasBeenClicked = isInArea(evt); // fini if in
520 mbMouseStartedInArea = false;
521 updatePressedState(false);
522 if( !mbHasBeenClicked )
523 return true; // consume event, else next slide (manual advance)
524 }
525 return false;
526}
527
529 awt::MouseEvent const & evt )
530{
531 if( mbMouseStartedInArea )
532 updatePressedState( isInArea(evt) );
533 return false;
534}
535
537 awt::MouseEvent const & /*evt*/ )
538{
539 return false;
540}
541
542} // namespace presentation
543
544/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Long GetLineHeight() const
tools::Long GetAscent() const
void WindStart()
void Record(OutputDevice *pOutDev)
void SetPrefSize(const Size &rSize)
B2DPoint getMinimum() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getWidth() const
TYPE getHeight() const
TYPE getX() const
void setY(TYPE fY)
TYPE getY() const
void setX(TYPE fX)
double getElapsedTime() const
static RendererSharedPtr createRenderer(const CanvasSharedPtr &rCanvas, const ::GDIMetaFile &rMtf, const Renderer::Parameters &rParms)
This class handles the XSprite updates needed for animations, such as moves, scales etc.
bool addActivity(const ActivitySharedPtr &pActivity)
Add the given activity to the queue.
void removeClickHandler(const MouseEventHandlerSharedPtr &rHandler)
void removeMouseMoveHandler(const MouseEventHandlerSharedPtr &rHandler)
void addClickHandler(const MouseEventHandlerSharedPtr &rHandler, double nPriority)
Register a mouse handler that is called on mouse click.
void addMouseMoveHandler(const MouseEventHandlerSharedPtr &rHandler, double nPriority)
Register a mouse handler that is called for mouse moves.
void addViewHandler(const ViewEventHandlerWeakPtr &rHandler)
Register an event handler that will be called when views are changed.
std::shared_ptr< ::canvas::tools::ElapsedTime > const & getTimer() const
Gets the queue's timer object.
Definition: eventqueue.hxx:116
bool addEvent(const EventSharedPtr &event)
Add the given event to the queue.
Definition: eventqueue.cxx:79
Definition of Event interface.
Definition: event.hxx:33
Interface for handling mouse events.
virtual bool handleMouseMoved(awt::MouseEvent const &evt) override
virtual bool handleMouseReleased(awt::MouseEvent const &evt) override
MouseHandler & operator=(const MouseHandler &)=delete
virtual bool handleMousePressed(awt::MouseEvent const &evt) override
virtual bool handleMouseDragged(awt::MouseEvent const &evt) override
WakeupEvent(std::shared_ptr< ::canvas::tools::ElapsedTime > const &pTimeBase, ActivitySharedPtr const &rActivity, ActivitiesQueue &rActivityQueue)
virtual void dispose() override
Dispose all object references.
void setNextTimeout(double nextTime)
Set the next timeout this object should generate.
virtual double getActivationTime(double nCurrentTime) const override
Query the activation time instant this event shall be fired, if it was inserted at instant nCurrentTi...
WakeupEvent & operator=(const WakeupEvent &)=delete
virtual bool isCharged() const override
Query whether this event is still charged, i.e.
virtual void dispose() override
Dispose all object references.
void start()
Starts and shows the timer; adds to activity queue.
virtual double calcTimeLag() const override
Calculates whether the activity lags time.
virtual void viewRemoved(const UnoViewSharedPtr &rView) override
Notify removed view.
RehearseTimingsActivity(const RehearseTimingsActivity &)=delete
::basegfx::B2DRange calcSpriteRectangle(UnoViewSharedPtr const &rView) const
virtual void end() override
Forces this activity deactivate and get to its end state (if possible), but does not dispose.
void paint(::cppcanvas::CanvasSharedPtr const &canvas) const
bool hasBeenClicked() const
Determines whether the timer button has been clicked.
::basegfx::B2DRange maSpriteRectangle
screen rect of sprite (in view coordinates!)
virtual bool perform() override
Perform the activity associated with this interface's implementation.
virtual void viewAdded(const UnoViewSharedPtr &rView) override
Notify new view.
virtual void dequeued() override
Notifies the Activity that it has now left the ActivitiesQueue.
virtual bool isActive() const override
Query whether this activity is still continuing.
std::vector< std::pair< UnoViewSharedPtr, std::shared_ptr< cppcanvas::CustomSprite > > > ViewsVecT
virtual void viewChanged(const UnoViewSharedPtr &rView) override
Notify changed view.
virtual void viewsChanged() override
Notify that all views changed.
static std::shared_ptr< RehearseTimingsActivity > create(const SlideShowContext &rContext)
Creates the activity.
void notifyUpdate()
Notify screen update.
tools::Long getOpenWidth() const
tools::Long GetFontHeight() const
void SetAverageFontWidth(tools::Long nWidth)
void SetColor(const Color &)
void SetFontHeight(tools::Long nHeight)
void SetAlignment(TextAlign)
tools::Long GetAverageFontWidth() const
constexpr ::Color COL_GRAY(0x80, 0x80, 0x80)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define TOOLS_WARN_EXCEPTION(area, stream)
ALIGN_BASELINE
IntrinsicAnimationActivity & mrActivity
sal_Int64 n
std::shared_ptr< ::cppcanvas::CustomSprite > CustomSpriteSharedPtr
std::shared_ptr< ::cppcanvas::Renderer > RendererSharedPtr
std::shared_ptr< Canvas > CanvasSharedPtr
::std::shared_ptr< Activity > ActivitySharedPtr
Definition: activity.hxx:83
std::shared_ptr< UnoView > UnoViewSharedPtr
bool mbActive
When true, show() was called. Slide hidden otherwise.
Definition: slideimpl.cxx:254
EventMultiplexer & mrEventMultiplexer
Definition: slideview.cxx:728
EventQueue & mrEventQueue
Definition: slideview.cxx:729
Common arguments for slideshow objects.
const UnoViewContainer & mrViewContainer