[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pictures / GUIWindowSlideShow.cpp
blob495e8c35260f3dd7efa9362a145c15a71c2ae3fb
1 /*
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.
7 */
9 #include "GUIWindowSlideShow.h"
11 #include "FileItem.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"
18 #include "URL.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"
48 #include <memory>
49 #include <random>
51 using namespace KODI;
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
70 #define LABEL_ROW1 10
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()
81 StopThread();
84 void CBackgroundPicLoader::Create(CGUIWindowSlideShow *pCallback)
86 m_pCallback = pCallback;
87 m_isLoading = false;
88 CThread::Create(false);
91 void CBackgroundPicLoader::Process()
93 auto totalTime = std::chrono::milliseconds(0);
94 unsigned int count = 0;
95 while (!m_bStop)
96 { // loop around forever, waiting for the app to call LoadPic
97 if (AbortableWait(m_loadPic, 10ms) == WAIT_SIGNALED)
99 if (m_pCallback)
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;
109 count++;
110 // tell our parent
111 bool bFullSize = false;
112 if (texture)
114 bFullSize = ((int)texture->GetWidth() < m_maxWidth) && ((int)texture->GetHeight() < m_maxHeight);
115 if (!bFullSize)
117 int iSize = texture->GetWidth() * texture->GetHeight() - MAX_PICTURE_SIZE;
118 if ((iSize + (int)texture->GetWidth() > 0) || (iSize + (int)texture->GetHeight() > 0))
119 bFullSize = true;
120 if (!bFullSize && texture->GetWidth() == CServiceBroker::GetRenderSystem()->GetMaxTextureSize())
121 bFullSize = true;
122 if (!bFullSize && texture->GetHeight() == CServiceBroker::GetRenderSystem()->GetMaxTextureSize())
123 bFullSize = true;
126 m_pCallback->OnLoadPic(m_iPic, m_iSlideNumber, m_strFileName, std::move(texture),
127 bFullSize);
128 m_isLoading = false;
132 if (count > 0)
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)
139 m_iPic = iPic;
140 m_iSlideNumber = iSlideNumber;
141 m_strFileName = strFileName;
142 m_maxWidth = maxWidth;
143 m_maxHeight = maxHeight;
144 m_isLoading = true;
145 m_loadPic.Set();
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);
155 Reset();
158 CGUIWindowSlideShow::~CGUIWindowSlideShow()
160 CServiceBroker::GetSlideShowDelegator().ResetDelegate();
163 void CGUIWindowSlideShow::AnnouncePlayerPlay(const CFileItemPtr& item)
165 CVariant param;
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)
173 CVariant param;
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)
181 CVariant param;
182 param["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE);
183 param["end"] = true;
184 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnStop", item, param);
187 void CGUIWindowSlideShow::AnnouncePlaylistClear()
189 CVariant data;
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)
196 CVariant data;
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())
205 return;
207 CVariant data;
208 data["player"]["playerid"] = static_cast<int>(PLAYLIST::Id::TYPE_PICTURE);
209 data["property"][strProperty] = value;
210 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnPropertyChanged",
211 data);
214 bool CGUIWindowSlideShow::IsPlaying() const
216 return m_Image[m_iCurrentPic]->IsLoaded();
219 void CGUIWindowSlideShow::Reset()
221 m_bSlideShow = false;
222 m_bShuffled = false;
223 m_bPause = false;
224 m_bPlayingVideo = false;
225 m_bErrorMessage = false;
227 if (m_Image[0])
229 m_Image[0]->UnLoad();
230 m_Image[0]->Close();
233 m_Image[0] = CSlideShowPic::CreateSlideShowPicture();
235 if (m_Image[1])
237 m_Image[1]->UnLoad();
238 m_Image[1]->Close();
241 m_Image[1] = CSlideShowPic::CreateSlideShowPicture();
243 m_fRotate = 0.0f;
244 m_fInitialRotate = 0.0f;
245 m_iZoomFactor = 1;
246 m_fZoom = 1.0f;
247 m_fInitialZoom = 0.0f;
248 m_iCurrentSlide = 0;
249 m_iNextSlide = 1;
250 m_iCurrentPic = 0;
251 m_iDirection = 1;
252 m_iLastFailedNextSlide = -1;
253 m_slides.clear();
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);
276 // stop the thread
277 CLog::Log(LOGDEBUG,"Stopping BackgroundLoader thread");
278 m_pBackgroundLoader->StopThread();
279 m_pBackgroundLoader.reset();
281 // and close the images.
282 m_Image[0]->Close();
283 m_Image[1]->Close();
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();
299 if (!IsVideo(*item))
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)
311 return;
313 m_iDirection = 1;
314 m_iNextSlide = GetNextSlide();
315 m_iZoomFactor = 1;
316 m_fZoom = 1.0f;
317 m_fRotate = 0.0f;
318 m_bLoadNextPic = true;
321 void CGUIWindowSlideShow::ShowPrevious()
323 if (m_slides.size() == 1)
324 return;
326 m_iDirection = -1;
327 m_iNextSlide = GetNextSlide();
328 m_iZoomFactor = 1;
329 m_fZoom = 1.0f;
330 m_fRotate = 0.0f;
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)
341 m_iDirection = 1;
342 if (!m_Image[m_iCurrentPic]->IsLoaded() &&
343 (!m_pBackgroundLoader || !m_pBackgroundLoader->IsLoading()))
345 // will trigger loading current slide when next Process call.
346 m_iCurrentSlide = i;
347 m_iNextSlide = GetNextSlide();
349 else
351 m_iNextSlide = i;
352 m_bLoadNextPic = true;
354 return ;
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
374 return m_bSlideShow;
377 void CGUIWindowSlideShow::StartSlideShow()
379 m_bSlideShow = true;
380 m_iDirection = 1;
381 if (m_slides.size())
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 &regions)
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();
406 if (!iSlides)
407 return;
409 // if we haven't processed yet, we should mark the whole screen
410 if (!HasProcessed())
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())));
415 MarkDirtyRegion();
418 if (m_iCurrentSlide < 0 || m_iCurrentSlide >= static_cast<int>(m_slides.size()))
419 m_iCurrentSlide = 0;
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)
435 return;
436 m_iCurrentSlide = m_iNextSlide;
437 m_iNextSlide = GetNextSlide();
440 if (m_bErrorMessage)
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;
451 else
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();
483 else
484 { // prevent reload the next pic and repeat fail.
485 m_iLastFailedNextSlide = m_iNextSlide;
487 m_bErrorMessage = false;
489 else
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;
497 if (m_bErrorMessage)
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())));
502 MarkDirtyRegion();
503 return;
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())
512 if (IsVideo(*item))
513 CLog::Log(LOGDEBUG, "Loading the thumb {} for current video {}: {}", picturePath,
514 m_iCurrentSlide, item->GetPath());
515 else
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))
544 if (IsVideo(*item))
545 CLog::Log(LOGDEBUG, "Loading the thumb {} for next video {}: {}", picturePath, m_iNextSlide,
546 item->GetPath());
547 else
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;
559 if (bPlayVideo)
560 bSlideShow = false;
562 // render the current image
563 if (m_Image[m_iCurrentPic]->IsLoaded())
565 if (m_Image[m_iCurrentPic]->IsAnimating())
566 MarkDirtyRegion();
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;
582 MarkDirtyRegion();
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;
600 m_iVideoSlide = -1;
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())
611 MarkDirtyRegion();
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());
638 else
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));
646 else
648 if (m_Image[m_iCurrentPic]->IsLoaded())
649 m_Image[m_iCurrentPic]->Reset(GetDisplayEffect(m_iCurrentSlide));
650 else
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;
660 else
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));
672 m_iZoomFactor = 1;
673 m_fZoom = 1.0f;
674 m_fRotate = 0.0f;
677 if (bPlayVideo && !PlayVideo())
678 return;
680 if (m_Image[m_iCurrentPic]->IsLoaded())
681 CServiceBroker::GetGUI()->GetInfoManager().GetInfoProviders().GetPicturesInfoProvider().SetCurrentSlide(m_slides.at(m_iCurrentSlide).get());
683 RenderPause();
684 if (IsVideo(*m_slides.at(m_iCurrentSlide)) && appPlayer && appPlayer->IsRenderingGuiLayer())
686 MarkDirtyRegion();
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())
695 return;
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);
714 gfxCtx.Clear(0);
715 gfxCtx.SetScissors(old);
717 else if (appPlayer)
719 const ::UTILS::COLOR::Color alpha = gfxCtx.MergeAlpha(0xff000000) >> 24;
720 appPlayer->Render(false, alpha);
723 gfxCtx.SetRenderingResolution(m_coordsRes, m_needsScaling);
725 else
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"))
759 return nextSlide;
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;
772 else
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));
805 else
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)
817 Rotate(-reminder);
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);
848 if (pictureInfo)
850 // no need to set the picture here, it's done in Render()
851 pictureInfo->Open();
854 break;
855 case ACTION_STOP:
857 if (m_slides.size())
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();
863 Close();
864 break;
867 case ACTION_NEXT_PICTURE:
868 ShowNext();
869 break;
871 case ACTION_PREV_PICTURE:
872 ShowPrevious();
873 break;
875 case ACTION_MOVE_RIGHT:
876 if (m_iZoomFactor == 1 || !m_Image[m_iCurrentPic]->m_bCanMoveHorizontally)
877 ShowNext();
878 else
879 Move(PICTURE_MOVE_AMOUNT, 0);
880 break;
882 case ACTION_MOVE_LEFT:
883 if (m_iZoomFactor == 1 || !m_Image[m_iCurrentPic]->m_bCanMoveHorizontally)
884 ShowPrevious();
885 else
886 Move( -PICTURE_MOVE_AMOUNT, 0);
887 break;
889 case ACTION_MOVE_DOWN:
890 Move(0, PICTURE_MOVE_AMOUNT);
891 break;
893 case ACTION_MOVE_UP:
894 Move(0, -PICTURE_MOVE_AMOUNT);
895 break;
897 case ACTION_PAUSE:
898 case ACTION_PLAYER_PLAY:
899 if (m_slides.size() == 0)
900 break;
901 if (IsVideo(*m_slides.at(m_iCurrentSlide)))
903 if (!m_bPlayingVideo)
905 if (m_bSlideShow)
907 SetDirection(1);
908 m_bPause = false;
910 PlayVideo();
913 else if (!m_bSlideShow || m_bPause)
915 m_bSlideShow = true;
916 m_bPause = false;
917 SetDirection(1);
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)
928 m_bPause = true;
929 AnnouncePlayerPause(m_slides.at(m_iCurrentSlide));
931 break;
933 case ACTION_ZOOM_OUT:
934 Zoom(m_iZoomFactor - 1);
935 break;
937 case ACTION_ZOOM_IN:
938 Zoom(m_iZoomFactor + 1);
939 break;
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)
948 Rotate(90.0f);
949 else
950 Rotate(-90.0f);
952 break;
954 case ACTION_ROTATE_PICTURE_CW:
955 Rotate(90.0f);
956 break;
958 case ACTION_ROTATE_PICTURE_CCW:
959 Rotate(-90.0f);
960 break;
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);
973 break;
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);
978 break;
979 case ACTION_ANALOG_MOVE_X_LEFT:
980 Move(-action.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG, 0.0f);
981 break;
982 case ACTION_ANALOG_MOVE_X_RIGHT:
983 Move(action.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG, 0.0f);
984 break;
985 case ACTION_ANALOG_MOVE_Y_UP:
986 Move(0.0f, -action.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG);
987 break;
988 case ACTION_ANALOG_MOVE_Y_DOWN:
989 Move(0.0f, action.GetAmount()*PICTURE_MOVE_AMOUNT_ANALOG);
990 break;
992 default:
993 return CGUIDialog::OnAction(action);
995 MarkDirtyRegion();
996 return true;
999 void CGUIWindowSlideShow::RenderErrorMessage()
1001 if (!m_bErrorMessage)
1002 return ;
1004 const CGUIControl *control = GetControl(LABEL_ROW1);
1005 if (NULL == control || control->GetControlType() != CGUIControl::GUICONTROL_LABEL)
1007 return;
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);
1025 else
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;
1034 return true;
1036 break;
1038 case GUI_MSG_SHOW_PICTURE:
1040 const std::string& strFile = message.GetStringParam();
1041 Reset();
1042 CFileItem item(strFile, false);
1043 Add(&item);
1044 RunSlideShow("", false, false, true, "", false);
1046 break;
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);
1053 //decode params
1054 bool bRecursive = false;
1055 bool bRandom = false;
1056 bool bNotRandom = false;
1057 bool bPause = false;
1058 if (iParams > 0)
1060 if ((iParams & 1) == 1)
1061 bRecursive = true;
1062 if ((iParams & 2) == 2)
1063 bRandom = true;
1064 if ((iParams & 4) == 4)
1065 bNotRandom = true;
1066 if ((iParams & 8) == 8)
1067 bPause = true;
1069 RunSlideShow(strFolder, bRecursive, bRandom, bNotRandom, beginSlidePath, !bPause);
1071 break;
1073 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
1076 break;
1078 case GUI_MSG_PLAYBACK_STOPPED:
1080 if (m_bPlayingVideo)
1082 m_bPlayingVideo = false;
1083 m_iVideoSlide = -1;
1084 if (m_bSlideShow)
1085 m_bPause = true;
1088 break;
1090 case GUI_MSG_PLAYBACK_ENDED:
1092 if (m_bPlayingVideo)
1094 m_bPlayingVideo = false;
1095 m_iVideoSlide = -1;
1096 if (m_bSlideShow)
1098 m_bPause = false;
1099 if (m_iCurrentSlide == m_iNextSlide)
1100 break;
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));
1106 m_iZoomFactor = 1;
1107 m_fZoom = 1.0f;
1108 m_fRotate = 0.0f;
1112 break;
1114 return CGUIDialog::OnMessage(message);
1117 void CGUIWindowSlideShow::RenderPause()
1118 { // display the pause icon
1119 if (m_bPause)
1121 SET_CONTROL_VISIBLE(CONTROL_PAUSE);
1123 else
1125 SET_CONTROL_HIDDEN(CONTROL_PAUSE);
1129 void CGUIWindowSlideShow::Rotate(float fAngle, bool immediate /* = false */)
1131 if (m_Image[m_iCurrentPic]->DrawNextImage())
1132 return;
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)
1142 return;
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())
1155 return;
1157 m_fZoom = fZoom;
1159 // find the nearest zoom factor
1160 for (unsigned int i = 1; i < MAX_ZOOM_FACTOR; i++)
1162 if (m_fZoom > zoomamount[i])
1163 continue;
1165 if (fabs(m_fZoom - zoomamount[i - 1]) < fabs(m_fZoom - zoomamount[i]))
1166 m_iZoomFactor = i;
1167 else
1168 m_iZoomFactor = i + 1;
1170 break;
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))
1189 return false;
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, "");
1194 if (ret == true)
1195 return true;
1196 else
1198 CLog::Log(LOGINFO, "set video {} unplayable", item->GetPath());
1199 item->SetProperty("unplayable", true);
1201 m_bPlayingVideo = false;
1202 m_iVideoSlide = -1;
1203 return 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;
1210 else
1211 return CSlideShowPic::EFFECT_NO_TIMEOUT;
1214 void CGUIWindowSlideShow::OnLoadPic(int iPic,
1215 int iSlideNumber,
1216 const std::string& strFileName,
1217 std::unique_ptr<CTexture> pTexture,
1218 bool bFullSize)
1220 if (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
1225 return;
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(),
1230 bFullSize);
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.
1248 CLog::Log(LOGDEBUG,
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())
1254 ? ""
1255 : m_slides.at(iSlideNumber)->GetPath());
1257 else
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;
1263 MarkDirtyRegion();
1266 void CGUIWindowSlideShow::Shuffle()
1268 KODI::UTILS::RandomShuffle(m_slides.begin(), m_slides.end());
1269 m_iCurrentSlide = 0;
1270 m_iNextSlide = GetNextSlide();
1271 m_bShuffled = true;
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,
1287 bool bRecursive,
1288 SortBy method, SortOrder order, SortAttribute sortAttributes,
1289 const std::string &strExtensions)
1291 if (strPath!="")
1293 // reset the slideshow
1294 Reset();
1295 if (bRecursive)
1297 path_set recursivePaths;
1298 AddItems(strPath, &recursivePaths, method, order, sortAttributes);
1300 else
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)
1312 // stop any video
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);
1320 if (!NumSlides())
1321 return;
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)
1330 Shuffle();
1332 if (!beginSlidePath.empty())
1333 Select(beginSlidePath);
1335 if (startSlideShow)
1336 StartSlideShow();
1337 else
1339 PlayPicture();
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
1354 if (recursivePaths)
1356 std::string path(strPath);
1357 URIUtils::RemoveSlashAtEnd(path);
1358 if (recursivePaths->find(path) != recursivePaths->end())
1359 return;
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))
1368 return;
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
1382 Add(item.get());
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();
1397 if (isVideo)
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);
1409 return picturePath;
1413 void CGUIWindowSlideShow::RunSlideShow(const std::vector<std::string>& paths, int start /* = 0*/)
1415 auto dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIWindowSlideShow>(WINDOW_SLIDESHOW);
1416 if (dialog)
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));
1423 dialog->Reset();
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);
1430 dialog->Open();