1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rehearsetimingsactivity.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 #include <boost/current_function.hpp>
35 #include <rtl/ustrbuf.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/metric.hxx>
40 #include <cppcanvas/vclfactory.hxx>
41 #include <cppcanvas/basegfxfactory.hxx>
42 #include <basegfx/range/b2drange.hxx>
44 #include <comphelper/anytostring.hxx>
45 #include <cppuhelper/exc_hlp.hxx>
47 #include <com/sun/star/awt/MouseButton.hpp>
48 #include <com/sun/star/awt/MouseEvent.hpp>
49 #include <com/sun/star/rendering/XBitmap.hpp>
51 #include "eventqueue.hxx"
52 #include "screenupdater.hxx"
53 #include "eventmultiplexer.hxx"
54 #include "activitiesqueue.hxx"
55 #include "slideshowcontext.hxx"
56 #include "mouseeventhandler.hxx"
57 #include "rehearsetimingsactivity.hxx"
59 #include <boost/bind.hpp>
62 using namespace com::sun::star
;
63 using namespace com::sun::star::uno
;
68 class RehearseTimingsActivity::WakeupEvent
: public Event
,
69 private ::boost::noncopyable
72 WakeupEvent( boost::shared_ptr
< ::canvas::tools::ElapsedTime
> const& pTimeBase
,
73 ActivitySharedPtr
const& rActivity
,
74 ActivitiesQueue
& rActivityQueue
) :
77 mpActivity(rActivity
),
78 mrActivityQueue( rActivityQueue
)
81 virtual void dispose() {}
84 ActivitySharedPtr
pActivity( mpActivity
.lock() );
88 return mrActivityQueue
.addActivity( pActivity
);
91 virtual bool isCharged() const { return true; }
92 virtual double getActivationTime( double nCurrentTime
) const
94 const double nElapsedTime( maTimer
.getElapsedTime() );
96 return ::std::max( nCurrentTime
,
97 nCurrentTime
- nElapsedTime
+ mnNextTime
);
100 /// Start the internal timer
101 void start() { maTimer
.reset(); }
103 /** Set the next timeout this object should generate.
106 Absolute time, measured from the last start() call,
107 when this event should wakeup the Activity again. If
108 your time is relative, simply call start() just before
109 every setNextTimeout() call.
111 void setNextTimeout( double nextTime
) { mnNextTime
= nextTime
; }
114 ::canvas::tools::ElapsedTime maTimer
;
116 boost::weak_ptr
<Activity
> mpActivity
;
117 ActivitiesQueue
& mrActivityQueue
;
120 class RehearseTimingsActivity::MouseHandler
: public MouseEventHandler
,
121 private boost::noncopyable
124 explicit MouseHandler( RehearseTimingsActivity
& rta
);
127 bool hasBeenClicked() const { return mbHasBeenClicked
; }
130 virtual bool handleMousePressed( awt::MouseEvent
const & evt
);
131 virtual bool handleMouseReleased( awt::MouseEvent
const & evt
);
132 virtual bool handleMouseEntered( awt::MouseEvent
const & evt
);
133 virtual bool handleMouseExited( awt::MouseEvent
const & evt
);
134 virtual bool handleMouseDragged( awt::MouseEvent
const & evt
);
135 virtual bool handleMouseMoved( awt::MouseEvent
const & evt
);
138 bool isInArea( com::sun::star::awt::MouseEvent
const & evt
) const;
139 void updatePressedState( const bool pressedState
) const;
141 RehearseTimingsActivity
& mrActivity
;
142 bool mbHasBeenClicked
;
143 bool mbMouseStartedInArea
;
146 const sal_Int32 LEFT_BORDER_SPACE
= 10;
147 const sal_Int32 LOWER_BORDER_SPACE
= 30;
149 RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext
& rContext
) :
150 mrEventQueue(rContext
.mrEventQueue
),
151 mrScreenUpdater(rContext
.mrScreenUpdater
),
152 mrEventMultiplexer(rContext
.mrEventMultiplexer
),
153 mrActivitiesQueue(rContext
.mrActivitiesQueue
),
154 maElapsedTime( rContext
.mrEventQueue
.getTimer() ),
157 maFont( Application::GetSettings().GetStyleSettings().GetInfoFont() ),
165 maFont
.SetHeight( maFont
.GetHeight() * 2 );
166 maFont
.SetWidth( maFont
.GetWidth() * 2 );
167 maFont
.SetAlign( ALIGN_BASELINE
);
168 maFont
.SetColor( COL_BLACK
);
170 // determine sprite size (in pixel):
171 VirtualDevice blackHole
;
172 blackHole
.EnableOutput(false);
173 blackHole
.SetFont( maFont
);
174 blackHole
.SetMapMode( MAP_PIXEL
);
176 const FontMetric
metric( blackHole
.GetFontMetric() );
177 blackHole
.GetTextBoundRect(
178 rect
, String(RTL_CONSTASCII_USTRINGPARAM("XX:XX:XX")) );
179 maSpriteSizePixel
.setX( rect
.getWidth() * 12 / 10 );
180 maSpriteSizePixel
.setY( metric
.GetLineHeight() * 11 / 10 );
181 mnYOffset
= (metric
.GetAscent() + (metric
.GetLineHeight() / 20));
183 std::for_each( rContext
.mrViewContainer
.begin(),
184 rContext
.mrViewContainer
.end(),
185 boost::bind( &RehearseTimingsActivity::viewAdded
,
190 RehearseTimingsActivity::~RehearseTimingsActivity()
196 catch (uno::Exception
&)
198 OSL_ENSURE( false, rtl::OUStringToOString(
199 comphelper::anyToString(
200 cppu::getCaughtException() ),
201 RTL_TEXTENCODING_UTF8
).getStr() );
205 boost::shared_ptr
<RehearseTimingsActivity
> RehearseTimingsActivity::create(
206 const SlideShowContext
& rContext
)
208 boost::shared_ptr
<RehearseTimingsActivity
> pActivity(
209 new RehearseTimingsActivity( rContext
));
211 pActivity
->mpMouseHandler
.reset(
212 new MouseHandler(*pActivity
.get()) );
213 pActivity
->mpWakeUpEvent
.reset(
214 new WakeupEvent( rContext
.mrEventQueue
.getTimer(),
216 rContext
.mrActivitiesQueue
));
218 rContext
.mrEventMultiplexer
.addViewHandler( pActivity
);
223 void RehearseTimingsActivity::start()
225 maElapsedTime
.reset();
226 mbDrawPressed
= false;
229 // paint and show all sprites:
231 for_each_sprite( boost::bind( &cppcanvas::Sprite::show
, _1
) );
233 mrActivitiesQueue
.addActivity( shared_from_this() );
235 mpMouseHandler
->reset();
236 mrEventMultiplexer
.addClickHandler(
237 mpMouseHandler
, 42 /* highest prio of all, > 3.0 */ );
238 mrEventMultiplexer
.addMouseMoveHandler(
239 mpMouseHandler
, 42 /* highest prio of all, > 3.0 */ );
242 double RehearseTimingsActivity::stop()
244 mrEventMultiplexer
.removeMouseMoveHandler( mpMouseHandler
);
245 mrEventMultiplexer
.removeClickHandler( mpMouseHandler
);
247 mbActive
= false; // will be removed from queue
249 for_each_sprite( boost::bind( &cppcanvas::Sprite::hide
, _1
) );
251 return maElapsedTime
.getElapsedTime();
254 bool RehearseTimingsActivity::hasBeenClicked() const
257 return mpMouseHandler
->hasBeenClicked();
262 void RehearseTimingsActivity::dispose()
266 mpWakeUpEvent
.reset();
267 mpMouseHandler
.reset();
269 ViewsVecT().swap( maViews
);
273 double RehearseTimingsActivity::calcTimeLag() const
278 bool RehearseTimingsActivity::perform()
286 mpWakeUpEvent
->start();
287 mpWakeUpEvent
->setNextTimeout( 0.5 );
288 mrEventQueue
.addEvent( mpWakeUpEvent
);
292 // sprites changed, need screen update
293 mrScreenUpdater
.notifyUpdate();
295 return false; // don't reinsert, WakeupEvent will perform
296 // that after the given timeout
299 bool RehearseTimingsActivity::isActive() const
304 void RehearseTimingsActivity::dequeued()
309 void RehearseTimingsActivity::end()
318 basegfx::B2DRange
RehearseTimingsActivity::calcSpriteRectangle( UnoViewSharedPtr
const& rView
) const
320 const Reference
<rendering::XBitmap
> xBitmap( rView
->getCanvas()->getUNOCanvas(),
323 return basegfx::B2DRange();
325 const geometry::IntegerSize2D
realSize( xBitmap
->getSize() );
327 basegfx::B2DPoint
spritePos(
328 std::min
<sal_Int32
>( realSize
.Width
, LEFT_BORDER_SPACE
),
329 std::max
<sal_Int32
>( 0, realSize
.Height
- maSpriteSizePixel
.getY()
330 - LOWER_BORDER_SPACE
) );
331 basegfx::B2DHomMatrix
transformation( rView
->getTransformation() );
332 transformation
.invert();
333 spritePos
*= transformation
;
334 basegfx::B2DSize
spriteSize( maSpriteSizePixel
.getX(),
335 maSpriteSizePixel
.getY() );
336 spriteSize
*= transformation
;
337 return basegfx::B2DRange(
338 spritePos
.getX(), spritePos
.getY(),
339 spritePos
.getX() + spriteSize
.getX(),
340 spritePos
.getY() + spriteSize
.getY() );
343 void RehearseTimingsActivity::viewAdded( const UnoViewSharedPtr
& rView
)
345 cppcanvas::CustomSpriteSharedPtr
sprite(
346 rView
->createSprite( basegfx::B2DSize(
347 maSpriteSizePixel
.getX()+2,
348 maSpriteSizePixel
.getY()+2 ),
349 1001.0 )); // sprite should be in front of all
351 sprite
->setAlpha( 0.8 );
352 const basegfx::B2DRange
spriteRectangle(
353 calcSpriteRectangle( rView
) );
354 sprite
->move( basegfx::B2DPoint(
355 spriteRectangle
.getMinX(),
356 spriteRectangle
.getMinY() ) );
358 if( maViews
.empty() )
359 maSpriteRectangle
= spriteRectangle
;
361 maViews
.push_back( ViewsVecT::value_type( rView
, sprite
) );
367 void RehearseTimingsActivity::viewRemoved( const UnoViewSharedPtr
& rView
)
371 maViews
.begin(), maViews
.end(),
373 std::equal_to
<UnoViewSharedPtr
>(),
376 boost::bind( std::select1st
<ViewsVecT::value_type
>(), _1
))),
380 void RehearseTimingsActivity::viewChanged( const UnoViewSharedPtr
& rView
)
382 // find entry corresponding to modified view
383 ViewsVecT::iterator
aModifiedEntry(
388 std::equal_to
<UnoViewSharedPtr
>(),
391 boost::bind( std::select1st
<ViewsVecT::value_type
>(), _1
))));
393 OSL_ASSERT( aModifiedEntry
!= maViews
.end() );
394 if( aModifiedEntry
== maViews
.end() )
397 // new sprite pos, transformation might have changed:
398 maSpriteRectangle
= calcSpriteRectangle( rView
);
400 // reposition sprite:
401 aModifiedEntry
->second
->move( maSpriteRectangle
.getMinimum() );
403 // sprites changed, need screen update
404 mrScreenUpdater
.notifyUpdate( rView
);
407 void RehearseTimingsActivity::viewsChanged()
409 if( !maViews
.empty() )
411 // new sprite pos, transformation might have changed:
412 maSpriteRectangle
= calcSpriteRectangle( maViews
.front().first
);
414 // reposition sprites
415 for_each_sprite( boost::bind( &cppcanvas::Sprite::move
,
417 boost::cref(maSpriteRectangle
.getMinimum())) );
419 // sprites changed, need screen update
420 mrScreenUpdater
.notifyUpdate();
424 void RehearseTimingsActivity::paintAllSprites() const
427 boost::bind( &RehearseTimingsActivity::paint
, this,
428 // call getContentCanvas() on each sprite:
430 &cppcanvas::CustomSprite::getContentCanvas
, _1
) ) );
433 void RehearseTimingsActivity::paint( cppcanvas::CanvasSharedPtr
const & canvas
) const
435 // build timer string:
436 const sal_Int32 nTimeSecs
=
437 static_cast<sal_Int32
>(maElapsedTime
.getElapsedTime());
438 rtl::OUStringBuffer buf
;
439 sal_Int32 n
= (nTimeSecs
/ 3600);
441 buf
.append( static_cast<sal_Unicode
>('0') );
443 buf
.append( static_cast<sal_Unicode
>(':') );
444 n
= ((nTimeSecs
% 3600) / 60);
446 buf
.append( static_cast<sal_Unicode
>('0') );
448 buf
.append( static_cast<sal_Unicode
>(':') );
449 n
= (nTimeSecs
% 60);
451 buf
.append( static_cast<sal_Unicode
>('0') );
453 const rtl::OUString time
= buf
.makeStringAndClear();
455 // create the MetaFile:
456 GDIMetaFile metaFile
;
457 VirtualDevice blackHole
;
458 metaFile
.Record( &blackHole
);
459 metaFile
.SetPrefSize( Size( 1, 1 ) );
460 blackHole
.EnableOutput(false);
461 blackHole
.SetMapMode( MAP_PIXEL
);
462 blackHole
.SetFont( maFont
);
463 Rectangle rect
= Rectangle( 0,0,
464 maSpriteSizePixel
.getX(),
465 maSpriteSizePixel
.getY());
468 blackHole
.SetTextColor( COL_BLACK
);
469 blackHole
.SetFillColor( COL_LIGHTGRAY
);
470 blackHole
.SetLineColor( COL_GRAY
);
474 blackHole
.SetTextColor( COL_BLACK
);
475 blackHole
.SetFillColor( COL_WHITE
);
476 blackHole
.SetLineColor( COL_GRAY
);
478 blackHole
.DrawRect( rect
);
479 blackHole
.GetTextBoundRect( rect
, time
);
481 Point( (maSpriteSizePixel
.getX() - rect
.getWidth()) / 2,
485 metaFile
.WindStart();
487 cppcanvas::RendererSharedPtr
renderer(
488 cppcanvas::VCLFactory::getInstance().createRenderer(
489 canvas
, metaFile
, cppcanvas::Renderer::Parameters() ) );
490 const bool succ
= renderer
->draw();
496 RehearseTimingsActivity::MouseHandler::MouseHandler( RehearseTimingsActivity
& rta
) :
498 mbHasBeenClicked(false),
499 mbMouseStartedInArea(false)
502 void RehearseTimingsActivity::MouseHandler::reset()
504 mbHasBeenClicked
= false;
505 mbMouseStartedInArea
= false;
508 bool RehearseTimingsActivity::MouseHandler::isInArea(
509 awt::MouseEvent
const & evt
) const
511 return mrActivity
.maSpriteRectangle
.isInside(
512 basegfx::B2DPoint( evt
.X
, evt
.Y
) );
515 void RehearseTimingsActivity::MouseHandler::updatePressedState(
516 const bool pressedState
) const
518 if( pressedState
!= mrActivity
.mbDrawPressed
)
520 mrActivity
.mbDrawPressed
= pressedState
;
521 mrActivity
.paintAllSprites();
523 mrActivity
.mrScreenUpdater
.notifyUpdate();
528 bool RehearseTimingsActivity::MouseHandler::handleMousePressed(
529 awt::MouseEvent
const & evt
)
531 if( evt
.Buttons
== awt::MouseButton::LEFT
&& isInArea(evt
) )
533 mbMouseStartedInArea
= true;
534 updatePressedState(true);
535 return true; // consume event
540 bool RehearseTimingsActivity::MouseHandler::handleMouseReleased(
541 awt::MouseEvent
const & evt
)
543 if( evt
.Buttons
== awt::MouseButton::LEFT
&& mbMouseStartedInArea
)
545 mbHasBeenClicked
= isInArea(evt
); // fini if in
546 mbMouseStartedInArea
= false;
547 updatePressedState(false);
548 if( !mbHasBeenClicked
)
549 return true; // consume event, else next slide (manual advance)
554 bool RehearseTimingsActivity::MouseHandler::handleMouseEntered(
555 awt::MouseEvent
const & /*evt*/ )
560 bool RehearseTimingsActivity::MouseHandler::handleMouseExited(
561 awt::MouseEvent
const & /*evt*/ )
566 bool RehearseTimingsActivity::MouseHandler::handleMouseDragged(
567 awt::MouseEvent
const & evt
)
569 if( mbMouseStartedInArea
)
570 updatePressedState( isInArea(evt
) );
574 bool RehearseTimingsActivity::MouseHandler::handleMouseMoved(
575 awt::MouseEvent
const & /*evt*/ )
580 } // namespace internal
581 } // namespace presentation