fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / slideshow / source / engine / rehearsetimingsactivity.cxx
blob15d6e6e3fcb47eeeb03f80126c51b3b47650da61
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 <boost/current_function.hpp>
22 #include <rtl/ustrbuf.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/metric.hxx>
27 #include <vcl/settings.hxx>
29 #include <cppcanvas/vclfactory.hxx>
30 #include <cppcanvas/basegfxfactory.hxx>
31 #include <basegfx/range/b2drange.hxx>
33 #include <comphelper/anytostring.hxx>
34 #include <cppuhelper/exc_hlp.hxx>
36 #include <com/sun/star/awt/MouseButton.hpp>
37 #include <com/sun/star/awt/MouseEvent.hpp>
38 #include <com/sun/star/rendering/XBitmap.hpp>
40 #include "eventqueue.hxx"
41 #include "screenupdater.hxx"
42 #include "eventmultiplexer.hxx"
43 #include "activitiesqueue.hxx"
44 #include "slideshowcontext.hxx"
45 #include "mouseeventhandler.hxx"
46 #include "rehearsetimingsactivity.hxx"
48 #include <boost/bind.hpp>
49 #include <o3tl/compat_functional.hxx>
50 #include <algorithm>
52 using namespace com::sun::star;
53 using namespace com::sun::star::uno;
55 namespace slideshow {
56 namespace internal {
58 class RehearseTimingsActivity::WakeupEvent : public Event,
59 private ::boost::noncopyable
61 public:
62 WakeupEvent( boost::shared_ptr< ::canvas::tools::ElapsedTime > const& pTimeBase,
63 ActivitySharedPtr const& rActivity,
64 ActivitiesQueue & rActivityQueue ) :
65 Event("WakeupEvent"),
66 maTimer(pTimeBase),
67 mnNextTime(0.0),
68 mpActivity(rActivity),
69 mrActivityQueue( rActivityQueue )
72 virtual void dispose() SAL_OVERRIDE {}
73 virtual bool fire() SAL_OVERRIDE
75 ActivitySharedPtr pActivity( mpActivity.lock() );
76 if( !pActivity )
77 return false;
79 return mrActivityQueue.addActivity( pActivity );
82 virtual bool isCharged() const SAL_OVERRIDE { return true; }
83 virtual double getActivationTime( double nCurrentTime ) const SAL_OVERRIDE
85 const double nElapsedTime( maTimer.getElapsedTime() );
87 return ::std::max( nCurrentTime,
88 nCurrentTime - nElapsedTime + mnNextTime );
91 /// Start the internal timer
92 void start() { maTimer.reset(); }
94 /** Set the next timeout this object should generate.
96 @param nextTime
97 Absolute time, measured from the last start() call,
98 when this event should wakeup the Activity again. If
99 your time is relative, simply call start() just before
100 every setNextTimeout() call.
102 void setNextTimeout( double nextTime ) { mnNextTime = nextTime; }
104 private:
105 ::canvas::tools::ElapsedTime maTimer;
106 double mnNextTime;
107 boost::weak_ptr<Activity> mpActivity;
108 ActivitiesQueue& mrActivityQueue;
111 class RehearseTimingsActivity::MouseHandler : public MouseEventHandler,
112 private boost::noncopyable
114 public:
115 explicit MouseHandler( RehearseTimingsActivity& rta );
117 void reset();
118 bool hasBeenClicked() const { return mbHasBeenClicked; }
120 // MouseEventHandler
121 virtual bool handleMousePressed( awt::MouseEvent const & evt ) SAL_OVERRIDE;
122 virtual bool handleMouseReleased( awt::MouseEvent const & evt ) SAL_OVERRIDE;
123 virtual bool handleMouseEntered( awt::MouseEvent const & evt ) SAL_OVERRIDE;
124 virtual bool handleMouseExited( awt::MouseEvent const & evt ) SAL_OVERRIDE;
125 virtual bool handleMouseDragged( awt::MouseEvent const & evt ) SAL_OVERRIDE;
126 virtual bool handleMouseMoved( awt::MouseEvent const & evt ) SAL_OVERRIDE;
128 private:
129 bool isInArea( com::sun::star::awt::MouseEvent const & evt ) const;
130 void updatePressedState( const bool pressedState ) const;
132 RehearseTimingsActivity& mrActivity;
133 bool mbHasBeenClicked;
134 bool mbMouseStartedInArea;
137 const sal_Int32 LEFT_BORDER_SPACE = 10;
138 const sal_Int32 LOWER_BORDER_SPACE = 30;
140 RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rContext ) :
141 mrEventQueue(rContext.mrEventQueue),
142 mrScreenUpdater(rContext.mrScreenUpdater),
143 mrEventMultiplexer(rContext.mrEventMultiplexer),
144 mrActivitiesQueue(rContext.mrActivitiesQueue),
145 maElapsedTime( rContext.mrEventQueue.getTimer() ),
146 maViews(),
147 maSpriteRectangle(),
148 maFont( Application::GetSettings().GetStyleSettings().GetInfoFont() ),
149 mpWakeUpEvent(),
150 mpMouseHandler(),
151 maSpriteSizePixel(),
152 mnYOffset(0),
153 mbActive(false),
154 mbDrawPressed(false)
156 maFont.SetHeight( maFont.GetHeight() * 2 );
157 maFont.SetWidth( maFont.GetWidth() * 2 );
158 maFont.SetAlign( ALIGN_BASELINE );
159 maFont.SetColor( COL_BLACK );
161 // determine sprite size (in pixel):
162 ScopedVclPtrInstance< VirtualDevice > blackHole;
163 blackHole->EnableOutput(false);
164 blackHole->SetFont( maFont );
165 blackHole->SetMapMode( MAP_PIXEL );
166 Rectangle rect;
167 const FontMetric metric( blackHole->GetFontMetric() );
168 blackHole->GetTextBoundRect( rect, OUString("XX:XX:XX") );
169 maSpriteSizePixel.setX( rect.getWidth() * 12 / 10 );
170 maSpriteSizePixel.setY( metric.GetLineHeight() * 11 / 10 );
171 mnYOffset = (metric.GetAscent() + (metric.GetLineHeight() / 20));
173 std::for_each( rContext.mrViewContainer.begin(),
174 rContext.mrViewContainer.end(),
175 boost::bind( &RehearseTimingsActivity::viewAdded,
176 this,
177 _1 ));
180 RehearseTimingsActivity::~RehearseTimingsActivity()
184 stop();
186 catch (uno::Exception &)
188 OSL_FAIL( OUStringToOString(
189 comphelper::anyToString(
190 cppu::getCaughtException() ),
191 RTL_TEXTENCODING_UTF8 ).getStr() );
195 boost::shared_ptr<RehearseTimingsActivity> RehearseTimingsActivity::create(
196 const SlideShowContext& rContext )
198 boost::shared_ptr<RehearseTimingsActivity> pActivity(
199 new RehearseTimingsActivity( rContext ));
201 pActivity->mpMouseHandler.reset(
202 new MouseHandler(*pActivity.get()) );
203 pActivity->mpWakeUpEvent.reset(
204 new WakeupEvent( rContext.mrEventQueue.getTimer(),
205 pActivity,
206 rContext.mrActivitiesQueue ));
208 rContext.mrEventMultiplexer.addViewHandler( pActivity );
210 return pActivity;
213 void RehearseTimingsActivity::start()
215 maElapsedTime.reset();
216 mbDrawPressed = false;
217 mbActive = true;
219 // paint and show all sprites:
220 paintAllSprites();
221 for_each_sprite( boost::bind( &cppcanvas::Sprite::show, _1 ) );
223 mrActivitiesQueue.addActivity( shared_from_this() );
225 mpMouseHandler->reset();
226 mrEventMultiplexer.addClickHandler(
227 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
228 mrEventMultiplexer.addMouseMoveHandler(
229 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
232 double RehearseTimingsActivity::stop()
234 mrEventMultiplexer.removeMouseMoveHandler( mpMouseHandler );
235 mrEventMultiplexer.removeClickHandler( mpMouseHandler );
237 mbActive = false; // will be removed from queue
239 for_each_sprite( boost::bind( &cppcanvas::Sprite::hide, _1 ) );
241 return maElapsedTime.getElapsedTime();
244 bool RehearseTimingsActivity::hasBeenClicked() const
246 if (mpMouseHandler)
247 return mpMouseHandler->hasBeenClicked();
248 return false;
251 // Disposable:
252 void RehearseTimingsActivity::dispose()
254 stop();
256 mpWakeUpEvent.reset();
257 mpMouseHandler.reset();
259 ViewsVecT().swap( maViews );
262 // Activity:
263 double RehearseTimingsActivity::calcTimeLag() const
265 return 0.0;
268 bool RehearseTimingsActivity::perform()
270 if( !isActive() )
271 return false;
273 if( !mpWakeUpEvent )
274 return false;
276 mpWakeUpEvent->start();
277 mpWakeUpEvent->setNextTimeout( 0.5 );
278 mrEventQueue.addEvent( mpWakeUpEvent );
280 paintAllSprites();
282 // sprites changed, need screen update
283 mrScreenUpdater.notifyUpdate();
285 return false; // don't reinsert, WakeupEvent will perform
286 // that after the given timeout
289 bool RehearseTimingsActivity::isActive() const
291 return mbActive;
294 void RehearseTimingsActivity::dequeued()
296 // not used here
299 void RehearseTimingsActivity::end()
301 if (isActive())
303 stop();
304 mbActive = false;
308 basegfx::B2DRange RehearseTimingsActivity::calcSpriteRectangle( UnoViewSharedPtr const& rView ) const
310 const Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
311 UNO_QUERY );
312 if( !xBitmap.is() )
313 return basegfx::B2DRange();
315 const geometry::IntegerSize2D realSize( xBitmap->getSize() );
316 // pixel:
317 basegfx::B2DPoint spritePos(
318 std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
319 std::max<sal_Int32>( 0, realSize.Height - maSpriteSizePixel.getY()
320 - LOWER_BORDER_SPACE ) );
321 basegfx::B2DHomMatrix transformation( rView->getTransformation() );
322 transformation.invert();
323 spritePos *= transformation;
324 basegfx::B2DSize spriteSize( maSpriteSizePixel.getX(),
325 maSpriteSizePixel.getY() );
326 spriteSize *= transformation;
327 return basegfx::B2DRange(
328 spritePos.getX(), spritePos.getY(),
329 spritePos.getX() + spriteSize.getX(),
330 spritePos.getY() + spriteSize.getY() );
333 void RehearseTimingsActivity::viewAdded( const UnoViewSharedPtr& rView )
335 cppcanvas::CustomSpriteSharedPtr sprite(
336 rView->createSprite( basegfx::B2DSize(
337 maSpriteSizePixel.getX()+2,
338 maSpriteSizePixel.getY()+2 ),
339 1001.0 )); // sprite should be in front of all
340 // other sprites
341 sprite->setAlpha( 0.8 );
342 const basegfx::B2DRange spriteRectangle(
343 calcSpriteRectangle( rView ) );
344 sprite->move( basegfx::B2DPoint(
345 spriteRectangle.getMinX(),
346 spriteRectangle.getMinY() ) );
348 if( maViews.empty() )
349 maSpriteRectangle = spriteRectangle;
351 maViews.push_back( ViewsVecT::value_type( rView, sprite ) );
353 if (isActive())
354 sprite->show();
357 void RehearseTimingsActivity::viewRemoved( const UnoViewSharedPtr& rView )
359 maViews.erase(
360 std::remove_if(
361 maViews.begin(), maViews.end(),
362 boost::bind(
363 std::equal_to<UnoViewSharedPtr>(),
364 rView,
365 // select view:
366 boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ))),
367 maViews.end() );
370 void RehearseTimingsActivity::viewChanged( const UnoViewSharedPtr& rView )
372 // find entry corresponding to modified view
373 ViewsVecT::iterator aModifiedEntry(
374 std::find_if(
375 maViews.begin(),
376 maViews.end(),
377 boost::bind(
378 std::equal_to<UnoViewSharedPtr>(),
379 rView,
380 // select view:
381 boost::bind( o3tl::select1st<ViewsVecT::value_type>(), _1 ))));
383 OSL_ASSERT( aModifiedEntry != maViews.end() );
384 if( aModifiedEntry == maViews.end() )
385 return;
387 // new sprite pos, transformation might have changed:
388 maSpriteRectangle = calcSpriteRectangle( rView );
390 // reposition sprite:
391 aModifiedEntry->second->move( maSpriteRectangle.getMinimum() );
393 // sprites changed, need screen update
394 mrScreenUpdater.notifyUpdate( rView );
397 void RehearseTimingsActivity::viewsChanged()
399 if( !maViews.empty() )
401 // new sprite pos, transformation might have changed:
402 maSpriteRectangle = calcSpriteRectangle( maViews.front().first );
404 // reposition sprites
405 for_each_sprite( boost::bind( &cppcanvas::Sprite::move,
407 maSpriteRectangle.getMinimum()) );
409 // sprites changed, need screen update
410 mrScreenUpdater.notifyUpdate();
414 void RehearseTimingsActivity::paintAllSprites() const
416 for_each_sprite(
417 boost::bind( &RehearseTimingsActivity::paint, this,
418 // call getContentCanvas() on each sprite:
419 boost::bind(
420 &cppcanvas::CustomSprite::getContentCanvas, _1 ) ) );
423 void RehearseTimingsActivity::paint( cppcanvas::CanvasSharedPtr const & canvas ) const
425 // build timer string:
426 const sal_Int32 nTimeSecs =
427 static_cast<sal_Int32>(maElapsedTime.getElapsedTime());
428 OUStringBuffer buf;
429 sal_Int32 n = (nTimeSecs / 3600);
430 if (n < 10)
431 buf.append( '0' );
432 buf.append( n );
433 buf.append( ':' );
434 n = ((nTimeSecs % 3600) / 60);
435 if (n < 10)
436 buf.append( '0' );
437 buf.append( n );
438 buf.append( ':' );
439 n = (nTimeSecs % 60);
440 if (n < 10)
441 buf.append( '0' );
442 buf.append( n );
443 const OUString time = buf.makeStringAndClear();
445 // create the MetaFile:
446 GDIMetaFile metaFile;
447 ScopedVclPtrInstance< VirtualDevice > blackHole;
448 metaFile.Record( blackHole );
449 metaFile.SetPrefSize( Size( 1, 1 ) );
450 blackHole->EnableOutput(false);
451 blackHole->SetMapMode( MAP_PIXEL );
452 blackHole->SetFont( maFont );
453 Rectangle rect = Rectangle( 0,0,
454 maSpriteSizePixel.getX(),
455 maSpriteSizePixel.getY());
456 if (mbDrawPressed)
458 blackHole->SetTextColor( COL_BLACK );
459 blackHole->SetFillColor( COL_LIGHTGRAY );
460 blackHole->SetLineColor( COL_GRAY );
462 else
464 blackHole->SetTextColor( COL_BLACK );
465 blackHole->SetFillColor( COL_WHITE );
466 blackHole->SetLineColor( COL_GRAY );
468 blackHole->DrawRect( rect );
469 blackHole->GetTextBoundRect( rect, time );
470 blackHole->DrawText(
471 Point( (maSpriteSizePixel.getX() - rect.getWidth()) / 2,
472 mnYOffset ), time );
474 metaFile.Stop();
475 metaFile.WindStart();
477 cppcanvas::RendererSharedPtr renderer(
478 cppcanvas::VCLFactory::createRenderer(
479 canvas, metaFile, cppcanvas::Renderer::Parameters() ) );
480 const bool succ = renderer->draw();
481 OSL_ASSERT( succ );
482 (void)succ;
486 RehearseTimingsActivity::MouseHandler::MouseHandler( RehearseTimingsActivity& rta ) :
487 mrActivity(rta),
488 mbHasBeenClicked(false),
489 mbMouseStartedInArea(false)
492 void RehearseTimingsActivity::MouseHandler::reset()
494 mbHasBeenClicked = false;
495 mbMouseStartedInArea = false;
498 bool RehearseTimingsActivity::MouseHandler::isInArea(
499 awt::MouseEvent const & evt ) const
501 return mrActivity.maSpriteRectangle.isInside(
502 basegfx::B2DPoint( evt.X, evt.Y ) );
505 void RehearseTimingsActivity::MouseHandler::updatePressedState(
506 const bool pressedState ) const
508 if( pressedState != mrActivity.mbDrawPressed )
510 mrActivity.mbDrawPressed = pressedState;
511 mrActivity.paintAllSprites();
513 mrActivity.mrScreenUpdater.notifyUpdate();
517 // MouseEventHandler
518 bool RehearseTimingsActivity::MouseHandler::handleMousePressed(
519 awt::MouseEvent const & evt )
521 if( evt.Buttons == awt::MouseButton::LEFT && isInArea(evt) )
523 mbMouseStartedInArea = true;
524 updatePressedState(true);
525 return true; // consume event
527 return false;
530 bool RehearseTimingsActivity::MouseHandler::handleMouseReleased(
531 awt::MouseEvent const & evt )
533 if( evt.Buttons == awt::MouseButton::LEFT && mbMouseStartedInArea )
535 mbHasBeenClicked = isInArea(evt); // fini if in
536 mbMouseStartedInArea = false;
537 updatePressedState(false);
538 if( !mbHasBeenClicked )
539 return true; // consume event, else next slide (manual advance)
541 return false;
544 bool RehearseTimingsActivity::MouseHandler::handleMouseEntered(
545 awt::MouseEvent const & /*evt*/ )
547 return false;
550 bool RehearseTimingsActivity::MouseHandler::handleMouseExited(
551 awt::MouseEvent const & /*evt*/ )
553 return false;
556 bool RehearseTimingsActivity::MouseHandler::handleMouseDragged(
557 awt::MouseEvent const & evt )
559 if( mbMouseStartedInArea )
560 updatePressedState( isInArea(evt) );
561 return false;
564 bool RehearseTimingsActivity::MouseHandler::handleMouseMoved(
565 awt::MouseEvent const & /*evt*/ )
567 return false;
570 } // namespace internal
571 } // namespace presentation
573 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */