tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / slideshow / source / engine / rehearsetimingsactivity.cxx
blob0d8295716092893fb66a0b7430d7bf78b0e5a41f
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 <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>
28 #include <cppcanvas/vclfactory.hxx>
29 #include <basegfx/range/b2drange.hxx>
30 #include <osl/diagnose.h>
31 #include <comphelper/diagnose_ex.hxx>
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>
38 #include <eventqueue.hxx>
39 #include <screenupdater.hxx>
40 #include <eventmultiplexer.hxx>
41 #include <activitiesqueue.hxx>
42 #include <slideshowcontext.hxx>
43 #include <mouseeventhandler.hxx>
44 #include "rehearsetimingsactivity.hxx"
46 #include <algorithm>
48 using namespace com::sun::star;
49 using namespace com::sun::star::uno;
51 namespace slideshow::internal {
53 class RehearseTimingsActivity::WakeupEvent : public Event
55 public:
56 WakeupEvent( std::shared_ptr< ::canvas::tools::ElapsedTime > const& pTimeBase,
57 ActivitySharedPtr const& rActivity,
58 ActivitiesQueue & rActivityQueue ) :
59 Event(u"WakeupEvent"_ustr),
60 maTimer(pTimeBase),
61 mnNextTime(0.0),
62 mpActivity(rActivity),
63 mrActivityQueue( rActivityQueue )
66 WakeupEvent( const WakeupEvent& ) = delete;
67 WakeupEvent& operator=( const WakeupEvent& ) = delete;
69 virtual void dispose() override {}
70 virtual bool fire() override
72 ActivitySharedPtr pActivity( mpActivity.lock() );
73 if( !pActivity )
74 return false;
76 return mrActivityQueue.addActivity( pActivity );
79 virtual bool isCharged() const override { return true; }
80 virtual double getActivationTime( double nCurrentTime ) const override
82 const double nElapsedTime( maTimer.getElapsedTime() );
84 return ::std::max( nCurrentTime,
85 nCurrentTime - nElapsedTime + mnNextTime );
88 /// Start the internal timer
89 void start() { maTimer.reset(); }
91 /** Set the next timeout this object should generate.
93 @param nextTime
94 Absolute time, measured from the last start() call,
95 when this event should wakeup the Activity again. If
96 your time is relative, simply call start() just before
97 every setNextTimeout() call.
99 void setNextTimeout( double nextTime ) { mnNextTime = nextTime; }
101 private:
102 ::canvas::tools::ElapsedTime maTimer;
103 double mnNextTime;
104 std::weak_ptr<Activity> mpActivity;
105 ActivitiesQueue& mrActivityQueue;
108 class RehearseTimingsActivity::MouseHandler : public MouseEventHandler
110 public:
111 explicit MouseHandler( RehearseTimingsActivity& rta );
113 MouseHandler( const MouseHandler& ) = delete;
114 MouseHandler& operator=( const MouseHandler& ) = delete;
116 void reset();
117 bool hasBeenClicked() const { return mbHasBeenClicked; }
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;
125 private:
126 bool isInArea( css::awt::MouseEvent const & evt ) const;
127 void updatePressedState( const bool pressedState ) const;
129 RehearseTimingsActivity& mrActivity;
130 bool mbHasBeenClicked;
131 bool mbMouseStartedInArea;
134 const sal_Int32 LEFT_BORDER_SPACE = 10;
135 const sal_Int32 LOWER_BORDER_SPACE = 30;
137 RehearseTimingsActivity::RehearseTimingsActivity( const SlideShowContext& rContext ) :
138 mrEventQueue(rContext.mrEventQueue),
139 mrScreenUpdater(rContext.mrScreenUpdater),
140 mrEventMultiplexer(rContext.mrEventMultiplexer),
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)
153 maFont.SetFontHeight( maFont.GetFontHeight() * 2 );
154 maFont.SetAverageFontWidth( maFont.GetAverageFontWidth() * 2 );
155 maFont.SetAlignment( ALIGN_BASELINE );
156 maFont.SetColor( COL_BLACK );
158 // determine sprite size (in pixel):
159 ScopedVclPtrInstance< VirtualDevice > blackHole;
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, u"XX:XX:XX"_ustr );
166 maSpriteSizePixel.setX( rect.getOpenWidth() * 12 / 10 );
167 maSpriteSizePixel.setY( metric.GetLineHeight() * 11 / 10 );
168 mnYOffset = (metric.GetAscent() + (metric.GetLineHeight() / 20));
170 for( const auto& rView : rContext.mrViewContainer )
171 viewAdded( rView );
174 RehearseTimingsActivity::~RehearseTimingsActivity()
178 stop();
180 catch (const uno::Exception&)
182 TOOLS_WARN_EXCEPTION("slideshow", "");
186 std::shared_ptr<RehearseTimingsActivity> RehearseTimingsActivity::create(
187 const SlideShowContext& rContext )
189 std::shared_ptr<RehearseTimingsActivity> pActivity(
190 new RehearseTimingsActivity( rContext ));
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 );
199 rContext.mrEventMultiplexer.addViewHandler( pActivity );
201 return pActivity;
204 void RehearseTimingsActivity::start()
206 maElapsedTime.reset();
207 mbDrawPressed = false;
208 mbActive = true;
210 // paint and show all sprites:
211 paintAllSprites();
212 for_each_sprite( []( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
213 { return pSprite->show(); } );
215 mrActivitiesQueue.addActivity( std::dynamic_pointer_cast<Activity>(shared_from_this()) );
217 mpMouseHandler->reset();
218 mrEventMultiplexer.addClickHandler(
219 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
220 mrEventMultiplexer.addMouseMoveHandler(
221 mpMouseHandler, 42 /* highest prio of all, > 3.0 */ );
224 double RehearseTimingsActivity::stop()
226 mrEventMultiplexer.removeMouseMoveHandler( mpMouseHandler );
227 mrEventMultiplexer.removeClickHandler( mpMouseHandler );
229 mbActive = false; // will be removed from queue
231 for_each_sprite( []( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
232 { return pSprite->hide(); } );
234 return maElapsedTime.getElapsedTime();
237 bool RehearseTimingsActivity::hasBeenClicked() const
239 if (mpMouseHandler)
240 return mpMouseHandler->hasBeenClicked();
241 return false;
244 // Disposable:
245 void RehearseTimingsActivity::dispose()
247 stop();
249 mpWakeUpEvent.reset();
250 mpMouseHandler.reset();
252 ViewsVecT().swap( maViews );
255 // Activity:
256 double RehearseTimingsActivity::calcTimeLag() const
258 return 0.0;
261 bool RehearseTimingsActivity::perform()
263 if( !isActive() )
264 return false;
266 if( !mpWakeUpEvent )
267 return false;
269 mpWakeUpEvent->start();
270 mpWakeUpEvent->setNextTimeout( 0.5 );
271 mrEventQueue.addEvent( mpWakeUpEvent );
273 paintAllSprites();
275 // sprites changed, need screen update
276 mrScreenUpdater.notifyUpdate();
278 return false; // don't reinsert, WakeupEvent will perform
279 // that after the given timeout
282 bool RehearseTimingsActivity::isActive() const
284 return mbActive;
287 void RehearseTimingsActivity::dequeued()
289 // not used here
292 void RehearseTimingsActivity::end()
294 if (isActive())
296 stop();
297 mbActive = false;
301 basegfx::B2DRange RehearseTimingsActivity::calcSpriteRectangle( UnoViewSharedPtr const& rView ) const
303 const Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
304 UNO_QUERY );
305 if( !xBitmap.is() )
306 return basegfx::B2DRange();
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;
317 basegfx::B2DSize spriteSize( maSpriteSizePixel.getX(),
318 maSpriteSizePixel.getY() );
319 spriteSize *= transformation;
320 return basegfx::B2DRange(
321 spritePos.getX(), spritePos.getY(),
322 spritePos.getX() + spriteSize.getWidth(),
323 spritePos.getY() + spriteSize.getHeight() );
326 void RehearseTimingsActivity::viewAdded( const UnoViewSharedPtr& rView )
328 cppcanvas::CustomSpriteSharedPtr sprite(
329 rView->createSprite( basegfx::B2DSize(
330 maSpriteSizePixel.getX()+2,
331 maSpriteSizePixel.getY()+2 ),
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() ) );
341 if( maViews.empty() )
342 maSpriteRectangle = spriteRectangle;
344 maViews.emplace_back( rView, sprite );
346 if (isActive())
347 sprite->show();
350 void RehearseTimingsActivity::viewRemoved( const UnoViewSharedPtr& rView )
352 std::erase_if(
353 maViews,
354 [&rView]
355 ( const ViewsVecT::value_type& cp )
356 { return rView == cp.first; } );
359 void RehearseTimingsActivity::viewChanged( const UnoViewSharedPtr& rView )
361 // find entry corresponding to modified view
362 ViewsVecT::iterator aModifiedEntry(
363 std::find_if(
364 maViews.begin(),
365 maViews.end(),
366 [&rView]
367 ( const ViewsVecT::value_type& cp )
368 { return rView == cp.first; } )
371 OSL_ASSERT( aModifiedEntry != maViews.end() );
372 if( aModifiedEntry == maViews.end() )
373 return;
375 // new sprite pos, transformation might have changed:
376 maSpriteRectangle = calcSpriteRectangle( rView );
378 // reposition sprite:
379 aModifiedEntry->second->move( maSpriteRectangle.getMinimum() );
381 // sprites changed, need screen update
382 mrScreenUpdater.notifyUpdate( rView, false );
385 void RehearseTimingsActivity::viewsChanged()
387 if( maViews.empty() )
388 return;
390 // new sprite pos, transformation might have changed:
391 maSpriteRectangle = calcSpriteRectangle( maViews.front().first );
393 ::basegfx::B2DPoint nMin = maSpriteRectangle.getMinimum();
394 // reposition sprites
395 for_each_sprite( [nMin]( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
396 { return pSprite->move( nMin ); } );
398 // sprites changed, need screen update
399 mrScreenUpdater.notifyUpdate();
402 void RehearseTimingsActivity::paintAllSprites() const
404 for_each_sprite(
405 [this]( const ::cppcanvas::CustomSpriteSharedPtr& pSprite )
406 { return this->paint( pSprite->getContentCanvas() ); } );
409 void RehearseTimingsActivity::paint( cppcanvas::CanvasSharedPtr const & canvas ) const
411 // build timer string:
412 const sal_Int32 nTimeSecs =
413 static_cast<sal_Int32>(maElapsedTime.getElapsedTime());
414 OUStringBuffer buf;
415 sal_Int32 n = nTimeSecs / 3600;
416 if (n < 10)
417 buf.append( '0' );
418 buf.append( OUString::number(n) + ":" );
419 n = ((nTimeSecs % 3600) / 60);
420 if (n < 10)
421 buf.append( '0' );
422 buf.append( OUString::number(n) + ":" );
423 n = (nTimeSecs % 60);
424 if (n < 10)
425 buf.append( '0' );
426 buf.append( n );
427 const OUString time = buf.makeStringAndClear();
429 // create the MetaFile:
430 GDIMetaFile metaFile;
431 ScopedVclPtrInstance< VirtualDevice > blackHole;
432 metaFile.Record( blackHole );
433 metaFile.SetPrefSize( Size( 1, 1 ) );
434 blackHole->EnableOutput(false);
435 blackHole->SetMapMode(MapMode(MapUnit::MapPixel));
436 blackHole->SetFont( maFont );
437 tools::Rectangle rect( 0,0,
438 maSpriteSizePixel.getX(),
439 maSpriteSizePixel.getY());
440 if (mbDrawPressed)
442 blackHole->SetTextColor( COL_BLACK );
443 blackHole->SetFillColor( COL_LIGHTGRAY );
444 blackHole->SetLineColor( COL_GRAY );
446 else
448 blackHole->SetTextColor( COL_BLACK );
449 blackHole->SetFillColor( COL_WHITE );
450 blackHole->SetLineColor( COL_GRAY );
452 blackHole->DrawRect( rect );
453 blackHole->GetTextBoundRect( rect, time );
454 blackHole->DrawText(
455 Point( (maSpriteSizePixel.getX() - rect.getOpenWidth()) / 2,
456 mnYOffset ), time );
458 metaFile.Stop();
459 metaFile.WindStart();
461 cppcanvas::RendererSharedPtr renderer(
462 cppcanvas::VCLFactory::createRenderer(
463 canvas, metaFile, cppcanvas::Renderer::Parameters() ) );
464 const bool succ = renderer->draw();
465 OSL_ASSERT( succ );
469 RehearseTimingsActivity::MouseHandler::MouseHandler( RehearseTimingsActivity& rta ) :
470 mrActivity(rta),
471 mbHasBeenClicked(false),
472 mbMouseStartedInArea(false)
475 void RehearseTimingsActivity::MouseHandler::reset()
477 mbHasBeenClicked = false;
478 mbMouseStartedInArea = false;
481 bool RehearseTimingsActivity::MouseHandler::isInArea(
482 awt::MouseEvent const & evt ) const
484 return mrActivity.maSpriteRectangle.isInside(
485 basegfx::B2DPoint( evt.X, evt.Y ) );
488 void RehearseTimingsActivity::MouseHandler::updatePressedState(
489 const bool pressedState ) const
491 if( pressedState != mrActivity.mbDrawPressed )
493 mrActivity.mbDrawPressed = pressedState;
494 mrActivity.paintAllSprites();
496 mrActivity.mrScreenUpdater.notifyUpdate();
500 // MouseEventHandler
501 bool RehearseTimingsActivity::MouseHandler::handleMousePressed(
502 awt::MouseEvent const & evt )
504 if( evt.Buttons == awt::MouseButton::LEFT && isInArea(evt) )
506 mbMouseStartedInArea = true;
507 updatePressedState(true);
508 return true; // consume event
510 return false;
513 bool RehearseTimingsActivity::MouseHandler::handleMouseReleased(
514 awt::MouseEvent const & evt )
516 if( evt.Buttons == awt::MouseButton::LEFT && mbMouseStartedInArea )
518 mbHasBeenClicked = isInArea(evt); // fini if in
519 mbMouseStartedInArea = false;
520 updatePressedState(false);
521 if( !mbHasBeenClicked )
522 return true; // consume event, else next slide (manual advance)
524 return false;
527 bool RehearseTimingsActivity::MouseHandler::handleMouseDragged(
528 awt::MouseEvent const & evt )
530 if( mbMouseStartedInArea )
531 updatePressedState( isInArea(evt) );
532 return false;
535 bool RehearseTimingsActivity::MouseHandler::handleMouseMoved(
536 awt::MouseEvent const & /*evt*/ )
538 return false;
541 } // namespace presentation
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */