2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIWindowSlideShow.h"
12 #include "FileItemList.h"
13 #include "GUIDialogPictureInfo.h"
14 #include "GUIInfoManager.h"
15 #include "GUIUserMessages.h"
16 #include "ServiceBroker.h"
17 #include "TextureDatabase.h"
19 #include "application/Application.h"
20 #include "application/ApplicationComponents.h"
21 #include "application/ApplicationPlayer.h"
22 #include "application/ApplicationPowerHandling.h"
23 #include "filesystem/Directory.h"
24 #include "guilib/GUIComponent.h"
25 #include "guilib/GUILabelControl.h"
26 #include "guilib/GUIWindowManager.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "guilib/Texture.h"
29 #include "input/actions/Action.h"
30 #include "input/actions/ActionIDs.h"
31 #include "input/mouse/MouseEvent.h"
32 #include "interfaces/AnnouncementManager.h"
33 #include "pictures/GUIViewStatePictures.h"
34 #include "pictures/PictureThumbLoader.h"
35 #include "pictures/SlideShowDelegator.h"
36 #include "playlists/PlayListTypes.h"
37 #include "rendering/RenderSystem.h"
38 #include "settings/DisplaySettings.h"
39 #include "settings/Settings.h"
40 #include "settings/SettingsComponent.h"
41 #include "utils/Random.h"
42 #include "utils/URIUtils.h"
43 #include "utils/Variant.h"
44 #include "utils/XTimeUtils.h"
45 #include "utils/log.h"
46 #include "video/VideoFileItemClassify.h"
52 using namespace KODI::VIDEO
;
53 using namespace MESSAGING
;
54 using namespace XFILE
;
55 using namespace std::chrono_literals
;
57 #define MAX_ZOOM_FACTOR 10
58 #define MAX_PICTURE_SIZE 2048*2048
60 #define IMMEDIATE_TRANSITION_TIME 1
62 #define PICTURE_MOVE_AMOUNT 0.02f
63 #define PICTURE_MOVE_AMOUNT_ANALOG 0.01f
64 #define PICTURE_MOVE_AMOUNT_TOUCH 0.002f
65 #define PICTURE_VIEW_BOX_COLOR 0xffffff00 // YELLOW
66 #define PICTURE_VIEW_BOX_BACKGROUND 0xff000000 // BLACK
68 #define ROTATION_SNAP_RANGE 10.0f
71 #define CONTROL_PAUSE 13
73 static float zoomamount
[10] = { 1.0f
, 1.2f
, 1.5f
, 2.0f
, 2.8f
, 4.0f
, 6.0f
, 9.0f
, 13.5f
, 20.0f
};
75 CBackgroundPicLoader::CBackgroundPicLoader() : CThread("BgPicLoader")
79 CBackgroundPicLoader::~CBackgroundPicLoader()
84 void CBackgroundPicLoader::Create(CGUIWindowSlideShow
*pCallback
)
86 m_pCallback
= pCallback
;
88 CThread::Create(false);
91 void CBackgroundPicLoader::Process()
93 auto totalTime
= std::chrono::milliseconds(0);
94 unsigned int count
= 0;
96 { // loop around forever, waiting for the app to call LoadPic
97 if (AbortableWait(m_loadPic
, 10ms
) == WAIT_SIGNALED
)
101 auto start
= std::chrono::steady_clock::now();
102 std::unique_ptr
<CTexture
> texture
=
103 CTexture::LoadFromFile(m_strFileName
, m_maxWidth
, m_maxHeight
);
105 auto end
= std::chrono::steady_clock::now();
106 auto duration
= std::chrono::duration_cast
<std::chrono::milliseconds
>(end
- start
);
108 totalTime
+= duration
;
111 bool bFullSize
= false;
114 bFullSize
= ((int)texture
->GetWidth() < m_maxWidth
) && ((int)texture
->GetHeight() < m_maxHeight
);
117 int iSize
= texture
->GetWidth() * texture
->GetHeight() - MAX_PICTURE_SIZE
;
118 if ((iSize
+ (int)texture
->GetWidth() > 0) || (iSize
+ (int)texture
->GetHeight() > 0))
120 if (!bFullSize
&& texture
->GetWidth() == CServiceBroker::GetRenderSystem()->GetMaxTextureSize())
122 if (!bFullSize
&& texture
->GetHeight() == CServiceBroker::GetRenderSystem()->GetMaxTextureSize())
126 m_pCallback
->OnLoadPic(m_iPic
, m_iSlideNumber
, m_strFileName
, std::move(texture
),
133 CLog::Log(LOGDEBUG
, "Time for loading {} images: {} ms, average {} ms", count
,
134 totalTime
.count(), totalTime
.count() / count
);
137 void CBackgroundPicLoader::LoadPic(int iPic
, int iSlideNumber
, const std::string
&strFileName
, const int maxWidth
, const int maxHeight
)
140 m_iSlideNumber
= iSlideNumber
;
141 m_strFileName
= strFileName
;
142 m_maxWidth
= maxWidth
;
143 m_maxHeight
= maxHeight
;
148 CGUIWindowSlideShow::CGUIWindowSlideShow(void)
149 : CGUIDialog(WINDOW_SLIDESHOW
, "SlideShow.xml")
151 m_Resolution
= RES_INVALID
;
152 m_loadType
= KEEP_IN_MEMORY
;
153 m_bLoadNextPic
= false;
154 CServiceBroker::GetSlideShowDelegator().SetDelegate(this);
158 CGUIWindowSlideShow::~CGUIWindowSlideShow()
160 CServiceBroker::GetSlideShowDelegator().ResetDelegate();
163 void CGUIWindowSlideShow::AnnouncePlayerPlay(const CFileItemPtr
& item
)
166 param
["player"]["speed"] = m_bSlideShow
&& !m_bPause
? 1 : 0;
167 param
["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
168 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPlay", item
, param
);
171 void CGUIWindowSlideShow::AnnouncePlayerPause(const CFileItemPtr
& item
)
174 param
["player"]["speed"] = 0;
175 param
["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
176 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPause", item
, param
);
179 void CGUIWindowSlideShow::AnnouncePlayerStop(const CFileItemPtr
& item
)
182 param
["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
184 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnStop", item
, param
);
187 void CGUIWindowSlideShow::AnnouncePlaylistClear()
190 data
["playlistid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
191 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Playlist
, "OnClear", data
);
194 void CGUIWindowSlideShow::AnnouncePlaylistAdd(const CFileItemPtr
& item
, int pos
)
197 data
["playlistid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
198 data
["position"] = pos
;
199 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Playlist
, "OnAdd", item
, data
);
202 void CGUIWindowSlideShow::AnnouncePropertyChanged(const std::string
&strProperty
, const CVariant
&value
)
204 if (strProperty
.empty() || value
.isNull())
208 data
["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE
);
209 data
["property"][strProperty
] = value
;
210 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player
, "OnPropertyChanged",
214 bool CGUIWindowSlideShow::IsPlaying() const
216 return m_Image
[m_iCurrentPic
]->IsLoaded();
219 void CGUIWindowSlideShow::Reset()
221 m_bSlideShow
= false;
224 m_bPlayingVideo
= false;
225 m_bErrorMessage
= false;
229 m_Image
[0]->UnLoad();
233 m_Image
[0] = CSlideShowPic::CreateSlideShowPicture();
237 m_Image
[1]->UnLoad();
241 m_Image
[1] = CSlideShowPic::CreateSlideShowPicture();
244 m_fInitialRotate
= 0.0f
;
247 m_fInitialZoom
= 0.0f
;
252 m_iLastFailedNextSlide
= -1;
254 AnnouncePlaylistClear();
255 m_Resolution
= CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution();
258 void CGUIWindowSlideShow::OnDeinitWindow(int nextWindowID
)
260 if (m_Resolution
!= CDisplaySettings::GetInstance().GetCurrentResolution())
262 //FIXME: Use GUI resolution for now
263 //CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(CDisplaySettings::GetInstance().GetCurrentResolution(), true);
266 if (nextWindowID
!= WINDOW_FULLSCREEN_VIDEO
&&
267 nextWindowID
!= WINDOW_FULLSCREEN_GAME
)
269 // wait for any outstanding picture loads
270 if (m_pBackgroundLoader
)
272 // sleep until the loader finishes loading the current pic
273 CLog::Log(LOGDEBUG
,"Waiting for BackgroundLoader thread to close");
274 while (m_pBackgroundLoader
->IsLoading())
275 KODI::TIME::Sleep(10ms
);
277 CLog::Log(LOGDEBUG
,"Stopping BackgroundLoader thread");
278 m_pBackgroundLoader
->StopThread();
279 m_pBackgroundLoader
.reset();
281 // and close the images.
285 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPicturesInfoProvider().SetCurrentSlide(nullptr);
286 m_bSlideShow
= false;
288 CGUIDialog::OnDeinitWindow(nextWindowID
);
291 void CGUIWindowSlideShow::Add(const CFileItem
*picture
)
293 CFileItemPtr
item(new CFileItem(*picture
));
294 if (!item
->HasVideoInfoTag() && !item
->HasPictureInfoTag())
296 // item without tag; get mimetype then we can tell whether it's video item
297 item
->FillInMimeType();
300 // then it is a picture and force tag generation
301 item
->GetPictureInfoTag();
303 AnnouncePlaylistAdd(item
, m_slides
.size());
305 m_slides
.emplace_back(std::move(item
));
308 void CGUIWindowSlideShow::ShowNext()
310 if (m_slides
.size() == 1)
314 m_iNextSlide
= GetNextSlide();
318 m_bLoadNextPic
= true;
321 void CGUIWindowSlideShow::ShowPrevious()
323 if (m_slides
.size() == 1)
327 m_iNextSlide
= GetNextSlide();
331 m_bLoadNextPic
= true;
334 void CGUIWindowSlideShow::Select(const std::string
& strPicture
)
336 for (size_t i
= 0; i
< m_slides
.size(); ++i
)
338 const CFileItemPtr item
= m_slides
.at(i
);
339 if (item
->GetPath() == strPicture
)
342 if (!m_Image
[m_iCurrentPic
]->IsLoaded() &&
343 (!m_pBackgroundLoader
|| !m_pBackgroundLoader
->IsLoading()))
345 // will trigger loading current slide when next Process call.
347 m_iNextSlide
= GetNextSlide();
352 m_bLoadNextPic
= true;
359 void CGUIWindowSlideShow::GetSlideShowContents(CFileItemList
&list
)
361 for (size_t index
= 0; index
< m_slides
.size(); index
++)
362 list
.Add(std::make_shared
<CFileItem
>(*m_slides
.at(index
)));
365 std::shared_ptr
<const CFileItem
> CGUIWindowSlideShow::GetCurrentSlide()
367 if (m_iCurrentSlide
>= 0 && m_iCurrentSlide
< static_cast<int>(m_slides
.size()))
368 return m_slides
.at(m_iCurrentSlide
);
369 return CFileItemPtr();
372 bool CGUIWindowSlideShow::InSlideShow() const
377 void CGUIWindowSlideShow::StartSlideShow()
382 AnnouncePlayerPlay(m_slides
.at(m_iCurrentSlide
));
385 void CGUIWindowSlideShow::SetDirection(int direction
)
387 direction
= direction
>= 0 ? 1 : -1;
388 if (m_iDirection
!= direction
)
390 m_iDirection
= direction
;
391 m_iNextSlide
= GetNextSlide();
395 void CGUIWindowSlideShow::Process(unsigned int currentTime
, CDirtyRegionList
®ions
)
397 const RESOLUTION_INFO res
= CServiceBroker::GetWinSystem()->GetGfxContext().GetResInfo();
399 // reset the screensaver if we're in a slideshow
400 // (unless we are the screensaver!)
401 auto& components
= CServiceBroker::GetAppComponents();
402 const auto appPower
= components
.GetComponent
<CApplicationPowerHandling
>();
403 if (m_bSlideShow
&& !m_bPause
&& !appPower
->IsInScreenSaver())
404 appPower
->ResetScreenSaver();
405 int iSlides
= m_slides
.size();
409 // if we haven't processed yet, we should mark the whole screen
412 regions
.emplace_back(CRect(
413 0.0f
, 0.0f
, static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()),
414 static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight())));
418 if (m_iCurrentSlide
< 0 || m_iCurrentSlide
>= static_cast<int>(m_slides
.size()))
420 if (m_iNextSlide
< 0 || m_iNextSlide
>= static_cast<int>(m_slides
.size()))
421 m_iNextSlide
= GetNextSlide();
423 // Create our background loader if necessary
424 if (!m_pBackgroundLoader
)
426 m_pBackgroundLoader
= std::make_unique
<CBackgroundPicLoader
>();
427 m_pBackgroundLoader
->Create(this);
430 bool bSlideShow
= m_bSlideShow
&& !m_bPause
&& !m_bPlayingVideo
;
431 if (bSlideShow
&& m_slides
.at(m_iCurrentSlide
)->HasProperty("unplayable"))
433 m_iNextSlide
= GetNextSlide();
434 if (m_iCurrentSlide
== m_iNextSlide
)
436 m_iCurrentSlide
= m_iNextSlide
;
437 m_iNextSlide
= GetNextSlide();
441 { // we have an error when loading either the current or next picture
442 // check to see if we have a picture loaded
443 CLog::Log(LOGDEBUG
, "We have an error loading picture {}!", m_pBackgroundLoader
->SlideNumber());
444 if (m_iCurrentSlide
== m_pBackgroundLoader
->SlideNumber())
446 if (m_Image
[m_iCurrentPic
]->IsLoaded())
448 // current image was already loaded, so we can ignore this error.
449 m_bErrorMessage
= false;
453 CLog::Log(LOGERROR
, "Error loading the current image {}: {}", m_iCurrentSlide
,
454 m_slides
.at(m_iCurrentSlide
)->GetPath());
455 if (!IsVideo(*m_slides
.at(m_iCurrentPic
)))
457 // try next if we are in slideshow
458 CLog::Log(LOGINFO
, "set image {} unplayable", m_slides
.at(m_iCurrentSlide
)->GetPath());
459 m_slides
.at(m_iCurrentSlide
)->SetProperty("unplayable", true);
461 if (m_bLoadNextPic
|| (bSlideShow
&& !m_bPause
&& !IsVideo(*m_slides
.at(m_iCurrentPic
))))
463 // change to next item, wait loading.
464 m_iCurrentSlide
= m_iNextSlide
;
465 m_iNextSlide
= GetNextSlide();
466 m_bErrorMessage
= false;
468 // else just drop through - there's nothing we can do (error message will be displayed)
471 else if (m_iNextSlide
== m_pBackgroundLoader
->SlideNumber())
473 CLog::Log(LOGERROR
, "Error loading the next image {}: {}", m_iNextSlide
,
474 m_slides
.at(m_iNextSlide
)->GetPath());
475 // load next image failed, then skip to load next of next if next is not video.
476 if (!IsVideo(*m_slides
.at(m_iNextSlide
)))
478 CLog::Log(LOGINFO
, "set image {} unplayable", m_slides
.at(m_iNextSlide
)->GetPath());
479 m_slides
.at(m_iNextSlide
)->SetProperty("unplayable", true);
480 // change to next item, wait loading.
481 m_iNextSlide
= GetNextSlide();
484 { // prevent reload the next pic and repeat fail.
485 m_iLastFailedNextSlide
= m_iNextSlide
;
487 m_bErrorMessage
= false;
490 { // Non-current and non-next slide, just ignore error.
491 CLog::Log(LOGERROR
, "Error loading the non-current non-next image {}/{}: {}", m_iNextSlide
,
492 m_pBackgroundLoader
->SlideNumber(), m_slides
.at(m_iNextSlide
)->GetPath());
493 m_bErrorMessage
= false;
498 { // hack, just mark it all
499 regions
.emplace_back(CRect(
500 0.0f
, 0.0f
, static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()),
501 static_cast<float>(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight())));
506 if (!m_Image
[m_iCurrentPic
]->IsLoaded() && !m_pBackgroundLoader
->IsLoading())
507 { // load first image
508 CFileItemPtr item
= m_slides
.at(m_iCurrentSlide
);
509 std::string picturePath
= GetPicturePath(item
.get());
510 if (!picturePath
.empty())
513 CLog::Log(LOGDEBUG
, "Loading the thumb {} for current video {}: {}", picturePath
,
514 m_iCurrentSlide
, item
->GetPath());
516 CLog::Log(LOGDEBUG
, "Loading the current image {}: {}", m_iCurrentSlide
, item
->GetPath());
518 // load using the background loader
519 int maxWidth
, maxHeight
;
521 GetCheckedSize((float)res
.iWidth
* m_fZoom
,
522 (float)res
.iHeight
* m_fZoom
,
523 maxWidth
, maxHeight
);
524 m_pBackgroundLoader
->LoadPic(m_iCurrentPic
, m_iCurrentSlide
, picturePath
, maxWidth
, maxHeight
);
525 m_iLastFailedNextSlide
= -1;
526 m_bLoadNextPic
= false;
530 // check if we should discard an already loaded next slide
531 if (m_Image
[1 - m_iCurrentPic
]->IsLoaded() &&
532 m_Image
[1 - m_iCurrentPic
]->SlideNumber() != m_iNextSlide
)
533 m_Image
[1 - m_iCurrentPic
]->Close();
535 if (m_iNextSlide
!= m_iCurrentSlide
&& m_Image
[m_iCurrentPic
]->IsLoaded() &&
536 !m_Image
[1 - m_iCurrentPic
]->IsLoaded() && !m_pBackgroundLoader
->IsLoading() &&
537 m_iLastFailedNextSlide
!= m_iNextSlide
)
538 { // load the next image
539 m_iLastFailedNextSlide
= -1;
540 CFileItemPtr item
= m_slides
.at(m_iNextSlide
);
541 std::string picturePath
= GetPicturePath(item
.get());
542 if (!picturePath
.empty() && (!IsVideo(*item
) || !m_bSlideShow
|| m_bPause
))
545 CLog::Log(LOGDEBUG
, "Loading the thumb {} for next video {}: {}", picturePath
, m_iNextSlide
,
548 CLog::Log(LOGDEBUG
, "Loading the next image {}: {}", m_iNextSlide
, item
->GetPath());
550 int maxWidth
, maxHeight
;
551 GetCheckedSize((float)res
.iWidth
* m_fZoom
,
552 (float)res
.iHeight
* m_fZoom
,
553 maxWidth
, maxHeight
);
554 m_pBackgroundLoader
->LoadPic(1 - m_iCurrentPic
, m_iNextSlide
, picturePath
, maxWidth
, maxHeight
);
558 bool bPlayVideo
= IsVideo(*m_slides
.at(m_iCurrentSlide
)) && m_iVideoSlide
!= m_iCurrentSlide
;
562 // render the current image
563 if (m_Image
[m_iCurrentPic
]->IsLoaded())
565 if (m_Image
[m_iCurrentPic
]->IsAnimating())
568 m_Image
[m_iCurrentPic
]->SetInSlideshow(bSlideShow
);
569 m_Image
[m_iCurrentPic
]->Pause(!bSlideShow
);
570 m_Image
[m_iCurrentPic
]->Process(currentTime
, regions
);
573 // Check if we should be transitioning immediately
574 if (m_bLoadNextPic
&& m_Image
[m_iCurrentPic
]->IsLoaded())
576 CLog::Log(LOGDEBUG
, "Starting immediate transition due to user wanting slide {}",
577 m_slides
.at(m_iNextSlide
)->GetPath());
578 if (m_Image
[m_iCurrentPic
]->StartTransition())
580 m_Image
[m_iCurrentPic
]->SetTransitionTime(1, IMMEDIATE_TRANSITION_TIME
);
581 m_bLoadNextPic
= false;
586 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
588 // render the next image
589 if (m_Image
[m_iCurrentPic
]->DrawNextImage())
591 if (m_bSlideShow
&& !m_bPause
&& IsVideo(*m_slides
.at(m_iNextSlide
)))
593 // do not show thumb of video when playing slideshow
595 else if (m_Image
[1 - m_iCurrentPic
]->IsLoaded())
597 if (appPlayer
->IsPlayingVideo())
598 appPlayer
->ClosePlayer();
599 m_bPlayingVideo
= false;
602 // first time render the next image, make sure using current display effect.
603 if (!m_Image
[1 - m_iCurrentPic
]->IsStarted())
605 CSlideShowPic::DISPLAY_EFFECT effect
= GetDisplayEffect(m_iNextSlide
);
606 if (m_Image
[1 - m_iCurrentPic
]->DisplayEffectNeedChange(effect
))
607 m_Image
[1 - m_iCurrentPic
]->Reset(effect
);
610 if (m_Image
[1 - m_iCurrentPic
]->IsAnimating())
613 // set the appropriate transition time
614 m_Image
[1 - m_iCurrentPic
]->SetTransitionTime(0,
615 m_Image
[m_iCurrentPic
]->GetTransitionTime(1));
616 m_Image
[1 - m_iCurrentPic
]->Pause(!m_bSlideShow
|| m_bPause
||
617 IsVideo(*m_slides
.at(m_iNextSlide
)));
618 m_Image
[1 - m_iCurrentPic
]->Process(currentTime
, regions
);
620 else // next pic isn't loaded. We should hang around if it is in progress
622 if (m_pBackgroundLoader
->IsLoading())
624 // CLog::Log(LOGDEBUG, "Having to hold the current image ({}) while we load {}", m_vecSlides[m_iCurrentSlide], m_vecSlides[m_iNextSlide]);
625 m_Image
[m_iCurrentPic
]->Keep();
630 // check if we should swap images now
631 if (m_Image
[m_iCurrentPic
]->IsFinished() ||
632 (m_bLoadNextPic
&& !m_Image
[m_iCurrentPic
]->IsLoaded()))
634 m_bLoadNextPic
= false;
635 if (m_Image
[m_iCurrentPic
]->IsFinished())
636 CLog::Log(LOGDEBUG
, "Image {} is finished rendering, switching to {}",
637 m_slides
.at(m_iCurrentSlide
)->GetPath(), m_slides
.at(m_iNextSlide
)->GetPath());
639 // what if it's bg loading?
640 CLog::Log(LOGDEBUG
, "Image {} is not loaded, switching to {}",
641 m_slides
.at(m_iCurrentSlide
)->GetPath(), m_slides
.at(m_iNextSlide
)->GetPath());
643 if (m_Image
[m_iCurrentPic
]->IsFinished() && m_iCurrentSlide
== m_iNextSlide
&&
644 m_Image
[m_iCurrentPic
]->SlideNumber() == m_iNextSlide
)
645 m_Image
[m_iCurrentPic
]->Reset(GetDisplayEffect(m_iCurrentSlide
));
648 if (m_Image
[m_iCurrentPic
]->IsLoaded())
649 m_Image
[m_iCurrentPic
]->Reset(GetDisplayEffect(m_iCurrentSlide
));
651 m_Image
[m_iCurrentPic
]->Close();
653 if ((m_Image
[1 - m_iCurrentPic
]->IsLoaded() &&
654 m_Image
[1 - m_iCurrentPic
]->SlideNumber() == m_iNextSlide
) ||
655 (m_pBackgroundLoader
->IsLoading() && m_pBackgroundLoader
->SlideNumber() == m_iNextSlide
&&
656 m_pBackgroundLoader
->Pic() == 1 - m_iCurrentPic
))
658 m_iCurrentPic
= 1 - m_iCurrentPic
;
662 m_Image
[1 - m_iCurrentPic
]->Close();
663 m_iCurrentPic
= 1 - m_iCurrentPic
;
665 m_iCurrentSlide
= m_iNextSlide
;
666 m_iNextSlide
= GetNextSlide();
668 bPlayVideo
= IsVideo(*m_slides
.at(m_iCurrentSlide
)) && m_iVideoSlide
!= m_iCurrentSlide
;
670 AnnouncePlayerPlay(m_slides
.at(m_iCurrentSlide
));
677 if (bPlayVideo
&& !PlayVideo())
680 if (m_Image
[m_iCurrentPic
]->IsLoaded())
681 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPicturesInfoProvider().SetCurrentSlide(m_slides
.at(m_iCurrentSlide
).get());
684 if (IsVideo(*m_slides
.at(m_iCurrentSlide
)) && appPlayer
&& appPlayer
->IsRenderingGuiLayer())
688 CGUIWindow::Process(currentTime
, regions
);
689 m_renderRegion
.SetRect(0, 0, (float)CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth(), (float)CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight());
692 void CGUIWindowSlideShow::Render()
694 if (m_slides
.empty())
697 CGraphicContext
& gfxCtx
= CServiceBroker::GetWinSystem()->GetGfxContext();
698 gfxCtx
.Clear(0xff000000);
700 if (IsVideo(*m_slides
.at(m_iCurrentSlide
)))
702 gfxCtx
.SetViewWindow(0, 0, m_coordsRes
.iWidth
, m_coordsRes
.iHeight
);
703 gfxCtx
.SetRenderingResolution(gfxCtx
.GetVideoResolution(), false);
705 auto& components
= CServiceBroker::GetAppComponents();
706 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
708 if (appPlayer
->IsRenderingVideoLayer())
710 const CRect old
= gfxCtx
.GetScissors();
711 CRect region
= GetRenderRegion();
712 region
.Intersect(old
);
713 gfxCtx
.SetScissors(region
);
715 gfxCtx
.SetScissors(old
);
719 const ::UTILS::COLOR::Color alpha
= gfxCtx
.MergeAlpha(0xff000000) >> 24;
720 appPlayer
->Render(false, alpha
);
723 gfxCtx
.SetRenderingResolution(m_coordsRes
, m_needsScaling
);
727 if (m_Image
[m_iCurrentPic
]->IsLoaded())
728 m_Image
[m_iCurrentPic
]->Render();
730 if (m_Image
[m_iCurrentPic
]->DrawNextImage() && m_Image
[1 - m_iCurrentPic
]->IsLoaded())
731 m_Image
[1 - m_iCurrentPic
]->Render();
734 RenderErrorMessage();
735 CGUIWindow::Render();
738 void CGUIWindowSlideShow::RenderEx()
740 if (IsVideo(*m_slides
.at(m_iCurrentSlide
)))
742 auto& components
= CServiceBroker::GetAppComponents();
743 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
744 appPlayer
->Render(false, 255, false);
747 CGUIWindow::RenderEx();
750 int CGUIWindowSlideShow::GetNextSlide()
752 if (m_slides
.size() <= 1)
753 return m_iCurrentSlide
;
754 int step
= m_iDirection
>= 0 ? 1 : -1;
755 int nextSlide
= (m_iCurrentSlide
+ step
+ m_slides
.size()) % m_slides
.size();
756 while (nextSlide
!= m_iCurrentSlide
)
758 if (!m_slides
.at(nextSlide
)->HasProperty("unplayable"))
760 nextSlide
= (nextSlide
+ step
+ m_slides
.size()) % m_slides
.size();
762 return m_iCurrentSlide
;
765 EVENT_RESULT
CGUIWindowSlideShow::OnMouseEvent(const CPoint
& point
, const MOUSE::CMouseEvent
& event
)
767 if (event
.m_id
== ACTION_GESTURE_NOTIFY
)
769 int result
= EVENT_RESULT_ROTATE
| EVENT_RESULT_ZOOM
;
770 if (m_iZoomFactor
== 1 || !m_Image
[m_iCurrentPic
]->m_bCanMoveHorizontally
)
771 result
|= EVENT_RESULT_SWIPE
;
773 result
|= EVENT_RESULT_PAN_HORIZONTAL
;
775 if (m_Image
[m_iCurrentPic
]->m_bCanMoveVertically
)
776 result
|= EVENT_RESULT_PAN_VERTICAL
;
778 return (EVENT_RESULT
)result
;
780 else if (event
.m_id
== ACTION_GESTURE_BEGIN
)
782 m_firstGesturePoint
= point
;
783 m_fInitialZoom
= m_fZoom
;
784 m_fInitialRotate
= m_fRotate
;
785 return EVENT_RESULT_HANDLED
;
787 else if (event
.m_id
== ACTION_GESTURE_PAN
)
789 // zoomed in - free move mode
790 if (m_iZoomFactor
!= 1 && (m_Image
[m_iCurrentPic
]->m_bCanMoveHorizontally
||
791 m_Image
[m_iCurrentPic
]->m_bCanMoveVertically
))
793 Move(PICTURE_MOVE_AMOUNT_TOUCH
/ m_iZoomFactor
* (m_firstGesturePoint
.x
- point
.x
), PICTURE_MOVE_AMOUNT_TOUCH
/ m_iZoomFactor
* (m_firstGesturePoint
.y
- point
.y
));
794 m_firstGesturePoint
= point
;
796 return EVENT_RESULT_HANDLED
;
798 else if (event
.m_id
== ACTION_GESTURE_SWIPE_LEFT
|| event
.m_id
== ACTION_GESTURE_SWIPE_RIGHT
)
800 if (m_iZoomFactor
== 1 || !m_Image
[m_iCurrentPic
]->m_bCanMoveHorizontally
)
802 // on zoomlevel 1 just detect swipe left and right
803 if (event
.m_id
== ACTION_GESTURE_SWIPE_LEFT
)
804 OnAction(CAction(ACTION_NEXT_PICTURE
));
806 OnAction(CAction(ACTION_PREV_PICTURE
));
809 else if (event
.m_id
== ACTION_GESTURE_END
|| event
.m_id
== ACTION_GESTURE_ABORT
)
811 if (m_fRotate
!= 0.0f
)
813 // "snap" to nearest of 0, 90, 180 and 270 if the
814 // difference in angle is +/-10 degrees
815 float reminder
= fmodf(m_fRotate
, 90.0f
);
816 if (fabs(reminder
) < ROTATION_SNAP_RANGE
)
818 else if (reminder
> 90.0f
- ROTATION_SNAP_RANGE
)
819 Rotate(90.0f
- reminder
);
820 else if (-reminder
> 90.0f
- ROTATION_SNAP_RANGE
)
821 Rotate(-90.0f
- reminder
);
824 m_fInitialZoom
= 0.0f
;
825 m_fInitialRotate
= 0.0f
;
826 return EVENT_RESULT_HANDLED
;
828 else if (event
.m_id
== ACTION_GESTURE_ZOOM
)
830 ZoomRelative(m_fInitialZoom
* event
.m_offsetX
, true);
831 return EVENT_RESULT_HANDLED
;
833 else if (event
.m_id
== ACTION_GESTURE_ROTATE
)
835 Rotate(m_fInitialRotate
+ event
.m_offsetX
- m_fRotate
, true);
836 return EVENT_RESULT_HANDLED
;
838 return EVENT_RESULT_UNHANDLED
;
841 bool CGUIWindowSlideShow::OnAction(const CAction
&action
)
843 switch (action
.GetID())
845 case ACTION_SHOW_INFO
:
847 CGUIDialogPictureInfo
*pictureInfo
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogPictureInfo
>(WINDOW_DIALOG_PICTURE_INFO
);
850 // no need to set the picture here, it's done in Render()
858 AnnouncePlayerStop(m_slides
.at(m_iCurrentSlide
));
859 auto& components
= CServiceBroker::GetAppComponents();
860 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
861 if (appPlayer
->IsPlayingVideo())
862 appPlayer
->ClosePlayer();
867 case ACTION_NEXT_PICTURE
:
871 case ACTION_PREV_PICTURE
:
875 case ACTION_MOVE_RIGHT
:
876 if (m_iZoomFactor
== 1 || !m_Image
[m_iCurrentPic
]->m_bCanMoveHorizontally
)
879 Move(PICTURE_MOVE_AMOUNT
, 0);
882 case ACTION_MOVE_LEFT
:
883 if (m_iZoomFactor
== 1 || !m_Image
[m_iCurrentPic
]->m_bCanMoveHorizontally
)
886 Move( -PICTURE_MOVE_AMOUNT
, 0);
889 case ACTION_MOVE_DOWN
:
890 Move(0, PICTURE_MOVE_AMOUNT
);
894 Move(0, -PICTURE_MOVE_AMOUNT
);
898 case ACTION_PLAYER_PLAY
:
899 if (m_slides
.size() == 0)
901 if (IsVideo(*m_slides
.at(m_iCurrentSlide
)))
903 if (!m_bPlayingVideo
)
913 else if (!m_bSlideShow
|| m_bPause
)
918 if (m_Image
[m_iCurrentPic
]->IsLoaded())
920 CSlideShowPic::DISPLAY_EFFECT effect
= GetDisplayEffect(m_iCurrentSlide
);
921 if (m_Image
[m_iCurrentPic
]->DisplayEffectNeedChange(effect
))
922 m_Image
[m_iCurrentPic
]->Reset(effect
);
924 AnnouncePlayerPlay(m_slides
.at(m_iCurrentSlide
));
926 else if (action
.GetID() == ACTION_PAUSE
)
929 AnnouncePlayerPause(m_slides
.at(m_iCurrentSlide
));
933 case ACTION_ZOOM_OUT
:
934 Zoom(m_iZoomFactor
- 1);
938 Zoom(m_iZoomFactor
+ 1);
941 case ACTION_GESTURE_SWIPE_UP
:
942 case ACTION_GESTURE_SWIPE_DOWN
:
943 if (m_iZoomFactor
== 1 || !m_Image
[m_iCurrentPic
]->m_bCanMoveVertically
)
945 bool swipeOnLeft
= action
.GetAmount() < CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth() / 2.0f
;
946 bool swipeUp
= action
.GetID() == ACTION_GESTURE_SWIPE_UP
;
947 if (swipeUp
== swipeOnLeft
)
954 case ACTION_ROTATE_PICTURE_CW
:
958 case ACTION_ROTATE_PICTURE_CCW
:
962 case ACTION_ZOOM_LEVEL_NORMAL
:
963 case ACTION_ZOOM_LEVEL_1
:
964 case ACTION_ZOOM_LEVEL_2
:
965 case ACTION_ZOOM_LEVEL_3
:
966 case ACTION_ZOOM_LEVEL_4
:
967 case ACTION_ZOOM_LEVEL_5
:
968 case ACTION_ZOOM_LEVEL_6
:
969 case ACTION_ZOOM_LEVEL_7
:
970 case ACTION_ZOOM_LEVEL_8
:
971 case ACTION_ZOOM_LEVEL_9
:
972 Zoom((action
.GetID() - ACTION_ZOOM_LEVEL_NORMAL
) + 1);
975 case ACTION_ANALOG_MOVE
:
976 // this action is used and works, when CAction object provides both x and y coordinates
977 Move(action
.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG
, -action
.GetAmount(1)*PICTURE_MOVE_AMOUNT_ANALOG
);
979 case ACTION_ANALOG_MOVE_X_LEFT
:
980 Move(-action
.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG
, 0.0f
);
982 case ACTION_ANALOG_MOVE_X_RIGHT
:
983 Move(action
.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG
, 0.0f
);
985 case ACTION_ANALOG_MOVE_Y_UP
:
986 Move(0.0f
, -action
.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG
);
988 case ACTION_ANALOG_MOVE_Y_DOWN
:
989 Move(0.0f
, action
.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG
);
993 return CGUIDialog::OnAction(action
);
999 void CGUIWindowSlideShow::RenderErrorMessage()
1001 if (!m_bErrorMessage
)
1004 const CGUIControl
*control
= GetControl(LABEL_ROW1
);
1005 if (NULL
== control
|| control
->GetControlType() != CGUIControl::GUICONTROL_LABEL
)
1010 CGUIFont
*pFont
= static_cast<const CGUILabelControl
*>(control
)->GetLabelInfo().font
;
1011 CGUITextLayout::DrawText(pFont
, 0.5f
*CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth(), 0.5f
*CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight(), 0xffffffff, 0, g_localizeStrings
.Get(747), XBFONT_CENTER_X
| XBFONT_CENTER_Y
);
1014 bool CGUIWindowSlideShow::OnMessage(CGUIMessage
& message
)
1016 switch ( message
.GetMessage() )
1018 case GUI_MSG_WINDOW_INIT
:
1020 m_Resolution
= (RESOLUTION
) CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_PICTURES_DISPLAYRESOLUTION
);
1022 //FIXME: Use GUI resolution for now
1023 if (false /*m_Resolution != CDisplaySettings::GetInstance().GetCurrentResolution() && m_Resolution != INVALID && m_Resolution!=AUTORES*/)
1024 CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(m_Resolution
, false);
1026 m_Resolution
= CServiceBroker::GetWinSystem()->GetGfxContext().GetVideoResolution();
1028 CGUIDialog::OnMessage(message
);
1030 // turn off slideshow if we only have 1 image
1031 if (m_slides
.size() <= 1)
1032 m_bSlideShow
= false;
1038 case GUI_MSG_SHOW_PICTURE
:
1040 const std::string
& strFile
= message
.GetStringParam();
1042 CFileItem
item(strFile
, false);
1044 RunSlideShow("", false, false, true, "", false);
1048 case GUI_MSG_START_SLIDESHOW
:
1050 const std::string
& strFolder
= message
.GetStringParam();
1051 unsigned int iParams
= message
.GetParam1();
1052 const std::string
& beginSlidePath
= message
.GetStringParam(1);
1054 bool bRecursive
= false;
1055 bool bRandom
= false;
1056 bool bNotRandom
= false;
1057 bool bPause
= false;
1060 if ((iParams
& 1) == 1)
1062 if ((iParams
& 2) == 2)
1064 if ((iParams
& 4) == 4)
1066 if ((iParams
& 8) == 8)
1069 RunSlideShow(strFolder
, bRecursive
, bRandom
, bNotRandom
, beginSlidePath
, !bPause
);
1073 case GUI_MSG_PLAYLISTPLAYER_STOPPED
:
1078 case GUI_MSG_PLAYBACK_STOPPED
:
1080 if (m_bPlayingVideo
)
1082 m_bPlayingVideo
= false;
1090 case GUI_MSG_PLAYBACK_ENDED
:
1092 if (m_bPlayingVideo
)
1094 m_bPlayingVideo
= false;
1099 if (m_iCurrentSlide
== m_iNextSlide
)
1101 m_Image
[m_iCurrentPic
]->Close();
1102 m_iCurrentPic
= 1 - m_iCurrentPic
;
1103 m_iCurrentSlide
= m_iNextSlide
;
1104 m_iNextSlide
= GetNextSlide();
1105 AnnouncePlayerPlay(m_slides
.at(m_iCurrentSlide
));
1114 return CGUIDialog::OnMessage(message
);
1117 void CGUIWindowSlideShow::RenderPause()
1118 { // display the pause icon
1121 SET_CONTROL_VISIBLE(CONTROL_PAUSE
);
1125 SET_CONTROL_HIDDEN(CONTROL_PAUSE
);
1129 void CGUIWindowSlideShow::Rotate(float fAngle
, bool immediate
/* = false */)
1131 if (m_Image
[m_iCurrentPic
]->DrawNextImage())
1134 m_fRotate
+= fAngle
;
1136 m_Image
[m_iCurrentPic
]->Rotate(fAngle
, immediate
);
1139 void CGUIWindowSlideShow::Zoom(int iZoom
)
1141 if (iZoom
> MAX_ZOOM_FACTOR
|| iZoom
< 1)
1144 ZoomRelative(zoomamount
[iZoom
- 1]);
1147 void CGUIWindowSlideShow::ZoomRelative(float fZoom
, bool immediate
/* = false */)
1149 if (fZoom
< zoomamount
[0])
1150 fZoom
= zoomamount
[0];
1151 else if (fZoom
> zoomamount
[MAX_ZOOM_FACTOR
- 1])
1152 fZoom
= zoomamount
[MAX_ZOOM_FACTOR
- 1];
1154 if (m_Image
[m_iCurrentPic
]->DrawNextImage())
1159 // find the nearest zoom factor
1160 for (unsigned int i
= 1; i
< MAX_ZOOM_FACTOR
; i
++)
1162 if (m_fZoom
> zoomamount
[i
])
1165 if (fabs(m_fZoom
- zoomamount
[i
- 1]) < fabs(m_fZoom
- zoomamount
[i
]))
1168 m_iZoomFactor
= i
+ 1;
1173 m_Image
[m_iCurrentPic
]->Zoom(m_fZoom
, immediate
);
1176 void CGUIWindowSlideShow::Move(float fX
, float fY
)
1178 if (m_Image
[m_iCurrentPic
]->IsLoaded() && m_Image
[m_iCurrentPic
]->GetZoom() > 1)
1179 { // we move in the opposite direction, due to the fact we are moving
1180 // the viewing window, not the picture.
1181 m_Image
[m_iCurrentPic
]->Move(-fX
, -fY
);
1185 bool CGUIWindowSlideShow::PlayVideo()
1187 CFileItemPtr item
= m_slides
.at(m_iCurrentSlide
);
1188 if (!item
|| !IsVideo(*item
))
1190 CLog::Log(LOGDEBUG
, "Playing current video slide {}", item
->GetPath());
1191 m_bPlayingVideo
= true;
1192 m_iVideoSlide
= m_iCurrentSlide
;
1193 bool ret
= g_application
.PlayFile(*item
, "");
1198 CLog::Log(LOGINFO
, "set video {} unplayable", item
->GetPath());
1199 item
->SetProperty("unplayable", true);
1201 m_bPlayingVideo
= false;
1206 CSlideShowPic::DISPLAY_EFFECT
CGUIWindowSlideShow::GetDisplayEffect(int iSlideNumber
) const
1208 if (m_bSlideShow
&& !m_bPause
&& !IsVideo(*m_slides
.at(iSlideNumber
)))
1209 return CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_DISPLAYEFFECTS
) ? CSlideShowPic::EFFECT_RANDOM
: CSlideShowPic::EFFECT_NONE
;
1211 return CSlideShowPic::EFFECT_NO_TIMEOUT
;
1214 void CGUIWindowSlideShow::OnLoadPic(int iPic
,
1216 const std::string
& strFileName
,
1217 std::unique_ptr
<CTexture
> pTexture
,
1222 // set the pic's texture + size etc.
1223 if (iSlideNumber
>= static_cast<int>(m_slides
.size()) || GetPicturePath(m_slides
.at(iSlideNumber
).get()) != strFileName
)
1224 { // throw this away - we must have cleared the slideshow while we were still loading
1227 CLog::Log(LOGDEBUG
, "Finished background loading slot {}, {}: {}", iPic
, iSlideNumber
,
1228 m_slides
.at(iSlideNumber
)->GetPath());
1229 m_Image
[iPic
]->SetOriginalSize(pTexture
->GetOriginalWidth(), pTexture
->GetOriginalHeight(),
1231 m_Image
[iPic
]->SetTexture(iSlideNumber
, std::move(pTexture
), GetDisplayEffect(iSlideNumber
));
1233 m_Image
[iPic
]->m_bIsComic
= false;
1234 if (URIUtils::IsInRAR(m_slides
.at(m_iCurrentSlide
)->GetPath()) || URIUtils::IsInZIP(m_slides
.at(m_iCurrentSlide
)->GetPath())) // move to top for cbr/cbz
1236 CURL
url(m_slides
.at(m_iCurrentSlide
)->GetPath());
1237 const std::string
& strHostName
= url
.GetHostName();
1238 if (URIUtils::HasExtension(strHostName
, ".cbr|.cbz"))
1240 m_Image
[iPic
]->m_bIsComic
= true;
1241 m_Image
[iPic
]->Move((float)m_Image
[iPic
]->GetOriginalWidth(),
1242 (float)m_Image
[iPic
]->GetOriginalHeight());
1246 else if (iSlideNumber
>= static_cast<int>(m_slides
.size()) || GetPicturePath(m_slides
.at(iSlideNumber
).get()) != strFileName
)
1247 { // Failed to load image. and not match values calling LoadPic, then something is changed, ignore.
1249 "CGUIWindowSlideShow::OnLoadPic({}, {}, {}) on failure not match current state (cur "
1250 "{}, next {}, curpic {}, pic[0, 1].slidenumber={}, {}, {})",
1251 iPic
, iSlideNumber
, strFileName
, m_iCurrentSlide
, m_iNextSlide
, m_iCurrentPic
,
1252 m_Image
[0]->SlideNumber(), m_Image
[1]->SlideNumber(),
1253 iSlideNumber
>= static_cast<int>(m_slides
.size())
1255 : m_slides
.at(iSlideNumber
)->GetPath());
1258 { // Failed to load image. What should be done??
1259 // We should wait for the current pic to finish rendering, then transition it out,
1260 // release the texture, and try and reload this pic from scratch
1261 m_bErrorMessage
= true;
1266 void CGUIWindowSlideShow::Shuffle()
1268 KODI::UTILS::RandomShuffle(m_slides
.begin(), m_slides
.end());
1269 m_iCurrentSlide
= 0;
1270 m_iNextSlide
= GetNextSlide();
1273 AnnouncePropertyChanged("shuffled", true);
1276 int CGUIWindowSlideShow::NumSlides() const
1278 return m_slides
.size();
1281 int CGUIWindowSlideShow::CurrentSlide() const
1283 return m_iCurrentSlide
+ 1;
1286 void CGUIWindowSlideShow::AddFromPath(const std::string
&strPath
,
1288 SortBy method
, SortOrder order
, SortAttribute sortAttributes
,
1289 const std::string
&strExtensions
)
1293 // reset the slideshow
1297 path_set recursivePaths
;
1298 AddItems(strPath
, &recursivePaths
, method
, order
, sortAttributes
);
1301 AddItems(strPath
, NULL
, method
, order
, sortAttributes
);
1305 void CGUIWindowSlideShow::RunSlideShow(const std::string
&strPath
,
1306 bool bRecursive
/* = false */, bool bRandom
/* = false */,
1307 bool bNotRandom
/* = false */, const std::string
&beginSlidePath
/* = "" */,
1308 bool startSlideShow
/* = true */, SortBy method
/* = SortByLabel */,
1309 SortOrder order
/* = SortOrderAscending */, SortAttribute sortAttributes
/* = SortAttributeNone */,
1310 const std::string
&strExtensions
)
1313 const auto& components
= CServiceBroker::GetAppComponents();
1314 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
1315 if (appPlayer
->IsPlayingVideo())
1316 g_application
.StopPlaying();
1318 AddFromPath(strPath
, bRecursive
, method
, order
, sortAttributes
, strExtensions
);
1323 // mutually exclusive options
1324 // if both are set, clear both and use the gui setting
1325 if (bRandom
&& bNotRandom
)
1326 bRandom
= bNotRandom
= false;
1328 // NotRandom overrides the window setting
1329 if ((!bNotRandom
&& CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_SLIDESHOW_SHUFFLE
)) || bRandom
)
1332 if (!beginSlidePath
.empty())
1333 Select(beginSlidePath
);
1342 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW
);
1345 void CGUIWindowSlideShow::PlayPicture()
1347 if (m_iCurrentSlide
>= 0 && m_iCurrentSlide
< static_cast<int>(m_slides
.size()))
1348 AnnouncePlayerPlay(m_slides
.at(m_iCurrentSlide
));
1351 void CGUIWindowSlideShow::AddItems(const std::string
&strPath
, path_set
*recursivePaths
, SortBy method
, SortOrder order
, SortAttribute sortAttributes
)
1353 // check whether we've already added this path
1356 std::string
path(strPath
);
1357 URIUtils::RemoveSlashAtEnd(path
);
1358 if (recursivePaths
->find(path
) != recursivePaths
->end())
1360 recursivePaths
->insert(path
);
1363 CFileItemList items
;
1364 CGUIViewStateWindowPictures
viewState(items
);
1366 // fetch directory and sort accordingly
1367 if (!CDirectory::GetDirectory(strPath
, items
, viewState
.GetExtensions(), DIR_FLAG_NO_FILE_DIRS
))
1370 items
.Sort(method
, order
, sortAttributes
);
1372 // need to go into all subdirs
1373 for (int i
= 0; i
< items
.Size(); i
++)
1375 CFileItemPtr item
= items
[i
];
1376 if (item
->m_bIsFolder
&& recursivePaths
)
1378 AddItems(item
->GetPath(), recursivePaths
);
1380 else if (!item
->m_bIsFolder
&& !URIUtils::IsRAR(item
->GetPath()) && !URIUtils::IsZIP(item
->GetPath()))
1381 { // add to the slideshow
1387 void CGUIWindowSlideShow::GetCheckedSize(float width
, float height
, int &maxWidth
, int &maxHeight
)
1389 maxWidth
= CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
1390 maxHeight
= CServiceBroker::GetRenderSystem()->GetMaxTextureSize();
1393 std::string
CGUIWindowSlideShow::GetPicturePath(CFileItem
*item
)
1395 bool isVideo
= IsVideo(*item
);
1396 std::string picturePath
= item
->GetDynPath();
1399 picturePath
= item
->GetArt("thumb");
1400 if (picturePath
.empty() && !item
->HasProperty("nothumb"))
1402 CPictureThumbLoader thumbLoader
;
1403 thumbLoader
.LoadItem(item
);
1404 picturePath
= item
->GetArt("thumb");
1405 if (picturePath
.empty())
1406 item
->SetProperty("nothumb", true);
1413 void CGUIWindowSlideShow::RunSlideShow(const std::vector
<std::string
>& paths
, int start
/* = 0*/)
1415 auto dialog
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIWindowSlideShow
>(WINDOW_SLIDESHOW
);
1418 std::vector
<CFileItemPtr
> items
;
1419 items
.reserve(paths
.size());
1420 for (const auto& path
: paths
)
1421 items
.push_back(std::make_shared
<CFileItem
>(CTextureUtils::GetWrappedImageURL(path
), false));
1424 dialog
->m_bPause
= true;
1425 dialog
->m_bSlideShow
= false;
1426 dialog
->m_iDirection
= 1;
1427 dialog
->m_iCurrentSlide
= start
;
1428 dialog
->m_iNextSlide
= (start
+ 1) % items
.size();
1429 dialog
->m_slides
= std::move(items
);