xref: /core/sd/source/ui/slideshow/showwin.cxx (revision d526bd7d)
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 #include <com/sun/star/awt/Key.hpp>
21 
22 #include "showwindow.hxx"
23 #include "slideshowimpl.hxx"
24 
25 #include <unotools/localedatawrapper.hxx>
26 #include <unotools/syslocale.hxx>
27 #include <sfx2/viewfrm.hxx>
28 #include <sfx2/sfxsids.hrc>
29 
30 
31 #include <slideshow.hxx>
32 #include <ViewShell.hxx>
33 #include <sdresid.hxx>
34 #include <helpids.h>
35 #include <strings.hrc>
36 
37 #include <sal/log.hxx>
38 #include <vcl/settings.hxx>
39 #include <vcl/virdev.hxx>
40 
41 using namespace ::com::sun::star;
42 
43 namespace sd {
44 
45 static const sal_uInt64 HIDE_MOUSE_TIMEOUT = 10000;
46 static const sal_uInt64 SHOW_MOUSE_TIMEOUT = 1000;
47 
48 ShowWindow::ShowWindow( const ::rtl::Reference< SlideshowImpl >& xController, vcl::Window* pParent )
49 : ::sd::Window( pParent )
50 , mnPauseTimeout( SLIDE_NO_TIMEOUT )
51 , mnRestartPageIndex( PAGE_NO_END )
52 , meShowWindowMode(SHOWWINDOWMODE_NORMAL)
53 , mbShowNavigatorAfterSpecialMode( false )
54 , mbMouseAutoHide(true)
55 , mbMouseCursorHidden(false)
56 , mnFirstMouseMove(0)
57 , mxController( xController )
58 {
59     SetOutDevViewType( OutDevViewType::SlideShow );
60 
61     // Do never mirror the preview window.  This explicitly includes right
62     // to left writing environments.
63     EnableRTL (false);
64 
65     MapMode aMap(GetMapMode());
66     aMap.SetMapUnit(MapUnit::Map100thMM);
67     SetMapMode(aMap);
68 
69     // set HelpId
70     SetHelpId( HID_SD_WIN_PRESENTATION );
71 
72     maPauseTimer.SetInvokeHandler( LINK( this, ShowWindow, PauseTimeoutHdl ) );
73     maPauseTimer.SetTimeout( 1000 );
74     maMouseTimer.SetInvokeHandler( LINK( this, ShowWindow, MouseTimeoutHdl ) );
75     maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
76 
77     maShowBackground = Wallpaper( COL_BLACK );
78     SetBackground(); // avoids that VCL paints any background!
79     GetParent()->Show();
80     AddEventListener( LINK( this, ShowWindow, EventHdl ) );
81 }
82 
83 ShowWindow::~ShowWindow()
84 {
85     disposeOnce();
86 }
87 
88 void ShowWindow::dispose()
89 {
90     maPauseTimer.Stop();
91     maMouseTimer.Stop();
92     ::sd::Window::dispose();
93 }
94 
95 void ShowWindow::KeyInput(const KeyEvent& rKEvt)
96 {
97     bool bReturn = false;
98 
99     if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
100     {
101         TerminateShow();
102         bReturn = true;
103     }
104     else if( SHOWWINDOWMODE_END == meShowWindowMode )
105     {
106         const int nKeyCode = rKEvt.GetKeyCode().GetCode();
107         switch( nKeyCode )
108         {
109         case KEY_PAGEUP:
110         case KEY_LEFT:
111         case KEY_UP:
112         case KEY_P:
113         case KEY_HOME:
114         case KEY_END:
115         case awt::Key::CONTEXTMENU:
116             // these keys will be handled by the slide show even
117             // while in end mode
118             break;
119         default:
120             TerminateShow();
121             bReturn = true;
122         }
123     }
124     else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
125     {
126         RestartShow();
127         bReturn = true;
128     }
129     else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
130     {
131         const int nKeyCode = rKEvt.GetKeyCode().GetCode();
132         switch( nKeyCode )
133         {
134         case KEY_ESCAPE:
135             TerminateShow();
136             bReturn = true;
137             break;
138         case KEY_PAGEUP:
139         case KEY_RIGHT:
140         case KEY_UP:
141         case KEY_P:
142         case KEY_HOME:
143         case KEY_END:
144         case awt::Key::CONTEXTMENU:
145             // these keys will be handled by the slide show even
146             // while in end mode
147             break;
148         default:
149             RestartShow();
150             bReturn = true;
151             break;
152         }
153     }
154 
155     if( !bReturn )
156     {
157         if( mxController.is() )
158             bReturn = mxController->keyInput(rKEvt);
159 
160         if( !bReturn )
161         {
162             if( mpViewShell )
163             {
164                 mpViewShell->KeyInput(rKEvt,this);
165             }
166             else
167             {
168                 Window::KeyInput(rKEvt);
169             }
170         }
171     }
172 
173     if( mpViewShell )
174         mpViewShell->SetActiveWindow( this );
175 }
176 
177 void ShowWindow::MouseButtonDown(const MouseEvent& /*rMEvt*/)
178 {
179     if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
180     {
181         TerminateShow();
182     }
183     else if( mpViewShell )
184     {
185         mpViewShell->SetActiveWindow( this );
186     }
187 }
188 
189 void ShowWindow::MouseMove(const MouseEvent& /*rMEvt*/)
190 {
191     if( mbMouseAutoHide )
192     {
193         if( mbMouseCursorHidden )
194         {
195             if( mnFirstMouseMove )
196             {
197                 // if this is not the first mouse move while hidden, see if
198                 // enough time has pasted to show mouse pointer again
199                 sal_uInt64 nTime = ::tools::Time::GetSystemTicks();
200                 if( (nTime - mnFirstMouseMove) >= SHOW_MOUSE_TIMEOUT )
201                 {
202                     ShowPointer( true );
203                     mnFirstMouseMove = 0;
204                     mbMouseCursorHidden = false;
205                     maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
206                     maMouseTimer.Start();
207                 }
208             }
209             else
210             {
211                 // if this is the first mouse move, note current
212                 // time and start idle timer to cancel show mouse pointer
213                 // again if not enough mouse movement is measured
214                 mnFirstMouseMove = ::tools::Time::GetSystemTicks();
215                 maMouseTimer.SetTimeout( 2*SHOW_MOUSE_TIMEOUT );
216                 maMouseTimer.Start();
217             }
218         }
219         else
220         {
221             // current mousemove restarts the idle timer to hide the mouse
222             maMouseTimer.Start();
223         }
224     }
225 
226     if( mpViewShell )
227         mpViewShell->SetActiveWindow( this );
228 }
229 
230 void ShowWindow::MouseButtonUp(const MouseEvent& rMEvt)
231 {
232     if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode )
233     {
234         TerminateShow();
235     }
236     else if( (SHOWWINDOWMODE_END == meShowWindowMode) && !rMEvt.IsRight() )
237     {
238         TerminateShow();
239     }
240     else if( (( SHOWWINDOWMODE_BLANK == meShowWindowMode ) || ( SHOWWINDOWMODE_PAUSE == meShowWindowMode ))
241              && !rMEvt.IsRight() )
242     {
243         RestartShow();
244     }
245     else
246     {
247         if( mxController.is() )
248             mxController->mouseButtonUp( rMEvt );
249     }
250 }
251 
252 /**
253  * if FuSlideShow is still available, forward it
254  */
255 void ShowWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect)
256 {
257     if( (meShowWindowMode == SHOWWINDOWMODE_NORMAL) || (meShowWindowMode == SHOWWINDOWMODE_PREVIEW) )
258     {
259         if( mxController.is() )
260         {
261             mxController->paint();
262         }
263         else if(mpViewShell )
264         {
265             mpViewShell->Paint(rRect, this);
266         }
267     }
268     else
269     {
270         DrawWallpaper( rRect, maShowBackground );
271 
272         if( SHOWWINDOWMODE_END == meShowWindowMode )
273         {
274             DrawEndScene();
275         }
276         else if( SHOWWINDOWMODE_PAUSE == meShowWindowMode )
277         {
278             DrawPauseScene( false );
279         }
280         else if( SHOWWINDOWMODE_BLANK == meShowWindowMode )
281         {
282             // just blank through background color => nothing to be done here
283         }
284     }
285 }
286 
287 void ShowWindow::LoseFocus()
288 {
289     Window::LoseFocus();
290 
291     if( SHOWWINDOWMODE_PREVIEW == meShowWindowMode)
292         TerminateShow();
293 }
294 
295 void ShowWindow::SetEndMode()
296 {
297     if( !(( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView()) )
298         return;
299 
300     DeleteWindowFromPaintView();
301     meShowWindowMode = SHOWWINDOWMODE_END;
302     maShowBackground = Wallpaper( COL_BLACK );
303 
304     // hide navigator if it is visible
305     if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
306     {
307         mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
308         mbShowNavigatorAfterSpecialMode = true;
309     }
310 
311     Invalidate();
312 }
313 
314 bool ShowWindow::SetPauseMode( sal_Int32 nTimeout, Graphic const * pLogo )
315 {
316     rtl::Reference< SlideShow > xSlideShow;
317 
318     if( mpViewShell )
319         xSlideShow = SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() );
320 
321     if( xSlideShow.is() && !nTimeout )
322     {
323         xSlideShow->jumpToPageIndex( 0 );
324     }
325     else if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
326     {
327         DeleteWindowFromPaintView();
328         mnPauseTimeout = nTimeout;
329         mnRestartPageIndex = 0;
330         meShowWindowMode = SHOWWINDOWMODE_PAUSE;
331         maShowBackground = Wallpaper( COL_BLACK );
332 
333         // hide navigator if it is visible
334         if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
335         {
336             mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
337             mbShowNavigatorAfterSpecialMode = true;
338         }
339 
340         if( pLogo )
341             maLogo = *pLogo;
342 
343         Invalidate();
344 
345         if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
346             maPauseTimer.Start();
347     }
348 
349     return( SHOWWINDOWMODE_PAUSE == meShowWindowMode );
350 }
351 
352 bool ShowWindow::SetBlankMode( sal_Int32 nPageIndexToRestart, const Color& rBlankColor )
353 {
354     if( ( SHOWWINDOWMODE_NORMAL == meShowWindowMode ) && mpViewShell && mpViewShell->GetView() )
355     {
356         DeleteWindowFromPaintView();
357         mnRestartPageIndex = nPageIndexToRestart;
358         meShowWindowMode = SHOWWINDOWMODE_BLANK;
359         maShowBackground = Wallpaper( rBlankColor );
360 
361         // hide navigator if it is visible
362         if( mpViewShell->GetViewFrame()->GetChildWindow( SID_NAVIGATOR ) )
363         {
364             mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR, false );
365             mbShowNavigatorAfterSpecialMode = true;
366         }
367 
368         Invalidate();
369     }
370 
371     return( SHOWWINDOWMODE_BLANK == meShowWindowMode );
372 }
373 
374 void ShowWindow::SetPreviewMode()
375 {
376     meShowWindowMode = SHOWWINDOWMODE_PREVIEW;
377 }
378 
379 void ShowWindow::TerminateShow()
380 {
381     maLogo.Clear();
382     maPauseTimer.Stop();
383     maMouseTimer.Stop();
384     Erase();
385     maShowBackground = Wallpaper( COL_BLACK );
386     meShowWindowMode = SHOWWINDOWMODE_NORMAL;
387     mnPauseTimeout = SLIDE_NO_TIMEOUT;
388 
389     if( mpViewShell )
390     {
391         // show navigator?
392         if( mbShowNavigatorAfterSpecialMode )
393         {
394             mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
395             mbShowNavigatorAfterSpecialMode = false;
396         }
397     }
398 
399     if( mxController.is() )
400         mxController->endPresentation();
401 
402     mnRestartPageIndex = PAGE_NO_END;
403 }
404 
405 void ShowWindow::RestartShow()
406 {
407     RestartShow( mnRestartPageIndex );
408 }
409 
410 void ShowWindow::RestartShow( sal_Int32 nPageIndexToRestart )
411 
412 {
413     ShowWindowMode eOldShowWindowMode = meShowWindowMode;
414 
415     maLogo.Clear();
416     maPauseTimer.Stop();
417     Erase();
418     maShowBackground = Wallpaper( COL_BLACK );
419     meShowWindowMode = SHOWWINDOWMODE_NORMAL;
420     mnPauseTimeout = SLIDE_NO_TIMEOUT;
421 
422     if( mpViewShell )
423     {
424         rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( mpViewShell->GetViewShellBase() ) );
425 
426         if( xSlideShow.is() )
427         {
428             AddWindowToPaintView();
429 
430             if( SHOWWINDOWMODE_BLANK == eOldShowWindowMode )
431             {
432                 xSlideShow->pause(false);
433                 Invalidate();
434             }
435             else
436             {
437                 xSlideShow->jumpToPageIndex( nPageIndexToRestart );
438             }
439         }
440     }
441 
442     mnRestartPageIndex = PAGE_NO_END;
443 
444     // show navigator?
445     if( mbShowNavigatorAfterSpecialMode )
446     {
447         if (mpViewShell)
448             mpViewShell->GetViewFrame()->ShowChildWindow( SID_NAVIGATOR );
449         mbShowNavigatorAfterSpecialMode = false;
450     }
451 }
452 
453 void ShowWindow::DrawPauseScene( bool bTimeoutOnly )
454 {
455     const MapMode&  rMap = GetMapMode();
456     const Point     aOutOrg( PixelToLogic( Point() ) );
457     const Size      aOutSize( GetOutputSize() );
458     const Size      aTextSize(LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), rMap));
459     const Size      aOffset(LogicToLogic(Size(1000, 1000), MapMode(MapUnit::Map100thMM), rMap));
460     OUString        aText( SdResId( STR_PRES_PAUSE ) );
461     bool            bDrawn = false;
462 
463     vcl::Font       aFont( GetSettings().GetStyleSettings().GetMenuFont() );
464     const vcl::Font aOldFont( GetFont() );
465 
466     aFont.SetFontSize( aTextSize );
467     aFont.SetColor( COL_WHITE );
468     aFont.SetCharSet( aOldFont.GetCharSet() );
469     aFont.SetLanguage( aOldFont.GetLanguage() );
470 
471     if( !bTimeoutOnly && ( maLogo.GetType() != GraphicType::NONE ) )
472     {
473         Size aGrfSize;
474 
475         if (maLogo.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
476             aGrfSize = PixelToLogic( maLogo.GetPrefSize() );
477         else
478             aGrfSize = LogicToLogic( maLogo.GetPrefSize(), maLogo.GetPrefMapMode(), rMap );
479 
480         const Point aGrfPos( std::max( aOutOrg.X() + aOutSize.Width() - aGrfSize.Width() - aOffset.Width(), aOutOrg.X() ),
481                              std::max( aOutOrg.Y() + aOutSize.Height() - aGrfSize.Height() - aOffset.Height(), aOutOrg.Y() ) );
482 
483         if( maLogo.IsAnimated() )
484             maLogo.StartAnimation( this, aGrfPos, aGrfSize, reinterpret_cast<sal_IntPtr>(this) );
485         else
486             maLogo.Draw( this, aGrfPos, aGrfSize );
487     }
488 
489     if( SLIDE_NO_TIMEOUT != mnPauseTimeout )
490     {
491         MapMode         aVMap( rMap );
492         ScopedVclPtrInstance< VirtualDevice > pVDev( *this );
493 
494         aVMap.SetOrigin( Point() );
495         pVDev->SetMapMode( aVMap );
496         pVDev->SetBackground( Wallpaper( COL_BLACK ) );
497 
498         // set font first, to determine real output height
499         pVDev->SetFont( aFont );
500 
501         const Size aVDevSize( aOutSize.Width(), pVDev->GetTextHeight() );
502 
503         if( pVDev->SetOutputSize( aVDevSize ) )
504         {
505             // Note: if performance gets an issue here, we can use NumberFormatter directly
506             SvtSysLocale                aSysLocale;
507             const LocaleDataWrapper&    aLocaleData = aSysLocale.GetLocaleData();
508 
509             aText += " ( " + aLocaleData.getDuration( ::tools::Time( 0, 0, mnPauseTimeout ) ) + " )";
510             pVDev->DrawText( Point( aOffset.Width(), 0 ), aText );
511             DrawOutDev( Point( aOutOrg.X(), aOffset.Height() ), aVDevSize, Point(), aVDevSize, *pVDev );
512             bDrawn = true;
513         }
514     }
515 
516     if( !bDrawn )
517     {
518         SetFont( aFont );
519         DrawText( Point( aOutOrg.X() + aOffset.Width(), aOutOrg.Y() + aOffset.Height() ), aText );
520         SetFont( aOldFont );
521     }
522 }
523 
524 void ShowWindow::DrawEndScene()
525 {
526     const vcl::Font aOldFont( GetFont() );
527     vcl::Font       aFont( GetSettings().GetStyleSettings().GetMenuFont() );
528 
529     const Point     aOutOrg( PixelToLogic( Point() ) );
530     const Size      aTextSize(LogicToLogic(Size(0, 14), MapMode(MapUnit::MapPoint), GetMapMode()));
531     const OUString  aText( SdResId( STR_PRES_SOFTEND ) );
532 
533     aFont.SetFontSize( aTextSize );
534     aFont.SetColor( COL_WHITE );
535     aFont.SetCharSet( aOldFont.GetCharSet() );
536     aFont.SetLanguage( aOldFont.GetLanguage() );
537     SetFont( aFont );
538     DrawText( Point( aOutOrg.X() + aTextSize.Height(), aOutOrg.Y() + aTextSize.Height() ), aText );
539     SetFont( aOldFont );
540 }
541 
542 IMPL_LINK( ShowWindow, PauseTimeoutHdl, Timer*, pTimer, void )
543 {
544     if( !( --mnPauseTimeout ) )
545         RestartShow();
546     else
547     {
548         DrawPauseScene( true );
549         pTimer->Start();
550     }
551 }
552 
553 IMPL_LINK_NOARG(ShowWindow, MouseTimeoutHdl, Timer *, void)
554 {
555     if( mbMouseCursorHidden )
556     {
557         // not enough mouse movements since first recording so
558         // cancel show mouse pointer for now
559         mnFirstMouseMove = 0;
560     }
561     else
562     {
563         // mouse has been idle too long, hide pointer
564         ShowPointer( false );
565         mbMouseCursorHidden = true;
566     }
567 }
568 
569 IMPL_LINK( ShowWindow, EventHdl, VclWindowEvent&, rEvent, void )
570 {
571     if( mbMouseAutoHide )
572     {
573         if (rEvent.GetId() == VclEventId::WindowShow)
574         {
575             maMouseTimer.SetTimeout( HIDE_MOUSE_TIMEOUT );
576             maMouseTimer.Start();
577         }
578     }
579 }
580 
581 void ShowWindow::DeleteWindowFromPaintView()
582 {
583     if( mpViewShell->GetView() )
584         mpViewShell->GetView()->DeleteWindowFromPaintView( this );
585 
586     sal_uInt16 nChild = GetChildCount();
587     while( nChild-- )
588         GetChild( nChild )->Show( false );
589 }
590 
591 void ShowWindow::AddWindowToPaintView()
592 {
593     if( mpViewShell->GetView() )
594         mpViewShell->GetView()->AddWindowToPaintView( this, nullptr );
595 
596     sal_uInt16 nChild = GetChildCount();
597     while( nChild-- )
598         GetChild( nChild )->Show();
599 }
600 
601 // Override the sd::Window's CreateAccessible to create a different accessible object
602 css::uno::Reference<css::accessibility::XAccessible>
603     ShowWindow::CreateAccessible()
604 {
605     css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible(false);
606     if (xAcc.get())
607     {
608         return xAcc;
609     }
610     if (mpViewShell != nullptr)
611     {
612         xAcc = mpViewShell->CreateAccessibleDocumentView (this);
613         SetAccessible(xAcc);
614         return xAcc;
615     }
616     else
617     {
618         SAL_WARN("sd", "::sd::Window::CreateAccessible: no view shell");
619         return vcl::Window::CreateAccessible ();
620     }
621 }
622 } // end of namespace sd
623 
624 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
625