/xbmc/guilib/GUIMultiImage.cpp

http://github.com/xbmc/xbmc · C++ · 319 lines · 250 code · 41 blank · 28 comment · 55 complexity · 9649bf70b7e72bd42fc3c6f03ea4579e MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2018 Team Kodi
  3. * This file is part of Kodi - https://kodi.tv
  4. *
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * See LICENSES/README.md for more information.
  7. */
  8. #include "GUIMultiImage.h"
  9. #include "FileItem.h"
  10. #include "GUIMessage.h"
  11. #include "ServiceBroker.h"
  12. #include "TextureCache.h"
  13. #include "TextureManager.h"
  14. #include "WindowIDs.h"
  15. #include "filesystem/Directory.h"
  16. #include "input/Key.h"
  17. #include "utils/FileExtensionProvider.h"
  18. #include "utils/JobManager.h"
  19. #include "utils/Random.h"
  20. #include "utils/StringUtils.h"
  21. #include "utils/URIUtils.h"
  22. using namespace KODI::GUILIB;
  23. using namespace XFILE;
  24. CGUIMultiImage::CGUIMultiImage(int parentID, int controlID, float posX, float posY, float width, float height, const CTextureInfo& texture, unsigned int timePerImage, unsigned int fadeTime, bool randomized, bool loop, unsigned int timeToPauseAtEnd)
  25. : CGUIControl(parentID, controlID, posX, posY, width, height),
  26. m_image(0, 0, posX, posY, width, height, texture)
  27. {
  28. m_currentImage = 0;
  29. m_timePerImage = timePerImage + fadeTime;
  30. m_timeToPauseAtEnd = timeToPauseAtEnd;
  31. m_image.SetCrossFade(fadeTime);
  32. m_randomized = randomized;
  33. m_loop = loop;
  34. ControlType = GUICONTROL_MULTI_IMAGE;
  35. m_bDynamicResourceAlloc=false;
  36. m_directoryStatus = UNLOADED;
  37. m_jobID = 0;
  38. }
  39. CGUIMultiImage::CGUIMultiImage(const CGUIMultiImage &from)
  40. : CGUIControl(from), m_texturePath(from.m_texturePath), m_imageTimer(), m_files(), m_image(from.m_image)
  41. {
  42. m_timePerImage = from.m_timePerImage;
  43. m_timeToPauseAtEnd = from.m_timeToPauseAtEnd;
  44. m_randomized = from.m_randomized;
  45. m_loop = from.m_loop;
  46. m_bDynamicResourceAlloc=false;
  47. m_directoryStatus = UNLOADED;
  48. if (m_texturePath.IsConstant())
  49. m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
  50. m_currentImage = 0;
  51. ControlType = GUICONTROL_MULTI_IMAGE;
  52. m_jobID = 0;
  53. }
  54. CGUIMultiImage::~CGUIMultiImage(void)
  55. {
  56. CancelLoading();
  57. }
  58. void CGUIMultiImage::UpdateVisibility(const CGUIListItem *item)
  59. {
  60. CGUIControl::UpdateVisibility(item);
  61. // check if we're hidden, and deallocate if so
  62. if (!IsVisible() && m_visible != DELAYED)
  63. {
  64. if (m_bDynamicResourceAlloc && m_bAllocated)
  65. FreeResources();
  66. return;
  67. }
  68. // we are either delayed or visible, so we can allocate our resources
  69. if (m_directoryStatus == UNLOADED)
  70. LoadDirectory();
  71. if (!m_bAllocated)
  72. AllocResources();
  73. if (m_directoryStatus == LOADED)
  74. OnDirectoryLoaded();
  75. }
  76. void CGUIMultiImage::UpdateInfo(const CGUIListItem *item)
  77. {
  78. // check for conditional information before we
  79. // alloc as this can free our resources
  80. if (!m_texturePath.IsConstant())
  81. {
  82. std::string texturePath;
  83. if (item)
  84. texturePath = m_texturePath.GetItemLabel(item, true);
  85. else
  86. texturePath = m_texturePath.GetLabel(m_parentID);
  87. if (texturePath != m_currentPath)
  88. {
  89. // a new path - set our current path and tell ourselves to load our directory
  90. m_currentPath = texturePath;
  91. CancelLoading();
  92. }
  93. }
  94. }
  95. void CGUIMultiImage::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
  96. {
  97. // Set a viewport so that we don't render outside the defined area
  98. if (m_directoryStatus == READY && !m_files.empty())
  99. {
  100. unsigned int nextImage = m_currentImage + 1;
  101. if (nextImage >= m_files.size())
  102. nextImage = m_loop ? 0 : m_currentImage; // stay on the last image if <loop>no</loop>
  103. if (nextImage != m_currentImage)
  104. {
  105. // check if we should be loading a new image yet
  106. unsigned int timeToShow = m_timePerImage;
  107. if (0 == nextImage) // last image should be paused for a bit longer if that's what the skinner wishes.
  108. timeToShow += m_timeToPauseAtEnd;
  109. if (m_imageTimer.IsRunning() && m_imageTimer.GetElapsedMilliseconds() > timeToShow)
  110. {
  111. // grab a new image
  112. m_currentImage = nextImage;
  113. m_image.SetFileName(m_files[m_currentImage]);
  114. MarkDirtyRegion();
  115. m_imageTimer.StartZero();
  116. }
  117. }
  118. }
  119. else if (m_directoryStatus != LOADING)
  120. m_image.SetFileName("");
  121. if (CServiceBroker::GetWinSystem()->GetGfxContext().SetClipRegion(m_posX, m_posY, m_width, m_height))
  122. {
  123. if (m_image.SetColorDiffuse(m_diffuseColor))
  124. MarkDirtyRegion();
  125. m_image.DoProcess(currentTime, dirtyregions);
  126. CServiceBroker::GetWinSystem()->GetGfxContext().RestoreClipRegion();
  127. }
  128. CGUIControl::Process(currentTime, dirtyregions);
  129. }
  130. void CGUIMultiImage::Render()
  131. {
  132. m_image.Render();
  133. CGUIControl::Render();
  134. }
  135. bool CGUIMultiImage::OnAction(const CAction &action)
  136. {
  137. return false;
  138. }
  139. bool CGUIMultiImage::OnMessage(CGUIMessage &message)
  140. {
  141. if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
  142. {
  143. if (!m_texturePath.IsConstant())
  144. FreeResources();
  145. return true;
  146. }
  147. return CGUIControl::OnMessage(message);
  148. }
  149. void CGUIMultiImage::AllocResources()
  150. {
  151. FreeResources();
  152. CGUIControl::AllocResources();
  153. if (m_directoryStatus == UNLOADED)
  154. LoadDirectory();
  155. }
  156. void CGUIMultiImage::FreeResources(bool immediately)
  157. {
  158. m_image.FreeResources(immediately);
  159. m_currentImage = 0;
  160. CancelLoading();
  161. m_files.clear();
  162. CGUIControl::FreeResources(immediately);
  163. }
  164. void CGUIMultiImage::DynamicResourceAlloc(bool bOnOff)
  165. {
  166. CGUIControl::DynamicResourceAlloc(bOnOff);
  167. m_bDynamicResourceAlloc=bOnOff;
  168. }
  169. void CGUIMultiImage::SetInvalid()
  170. {
  171. m_image.SetInvalid();
  172. CGUIControl::SetInvalid();
  173. }
  174. bool CGUIMultiImage::CanFocus() const
  175. {
  176. return false;
  177. }
  178. void CGUIMultiImage::SetAspectRatio(const CAspectRatio &ratio)
  179. {
  180. m_image.SetAspectRatio(ratio);
  181. }
  182. void CGUIMultiImage::LoadDirectory()
  183. {
  184. // clear current stuff out
  185. m_files.clear();
  186. // don't load any images if our path is empty
  187. if (m_currentPath.empty()) return;
  188. /* Check the fast cases:
  189. 1. Picture extension
  190. 2. Cached picture (in case an extension is not present)
  191. 3. Bundled folder
  192. */
  193. CFileItem item(m_currentPath, false);
  194. if (item.IsPicture() || CTextureCache::GetInstance().HasCachedImage(m_currentPath))
  195. m_files.push_back(m_currentPath);
  196. else // bundled folder?
  197. CServiceBroker::GetGUI()->GetTextureManager().GetBundledTexturesFromPath(m_currentPath, m_files);
  198. if (!m_files.empty())
  199. { // found - nothing more to do
  200. OnDirectoryLoaded();
  201. return;
  202. }
  203. // slow(er) checks necessary - do them in the background
  204. CSingleLock lock(m_section);
  205. m_directoryStatus = LOADING;
  206. m_jobID = CJobManager::GetInstance().AddJob(new CMultiImageJob(m_currentPath), this, CJob::PRIORITY_NORMAL);
  207. }
  208. void CGUIMultiImage::OnDirectoryLoaded()
  209. {
  210. // Randomize or sort our images if necessary
  211. if (m_randomized)
  212. KODI::UTILS::RandomShuffle(m_files.begin(), m_files.end());
  213. else
  214. sort(m_files.begin(), m_files.end());
  215. // flag as loaded - no point in constantly reloading them
  216. m_directoryStatus = READY;
  217. m_imageTimer.StartZero();
  218. m_currentImage = 0;
  219. m_image.SetFileName(m_files.empty() ? "" : m_files[0]);
  220. }
  221. void CGUIMultiImage::CancelLoading()
  222. {
  223. CSingleLock lock(m_section);
  224. if (m_directoryStatus == LOADING)
  225. CJobManager::GetInstance().CancelJob(m_jobID);
  226. m_directoryStatus = UNLOADED;
  227. }
  228. void CGUIMultiImage::OnJobComplete(unsigned int jobID, bool success, CJob *job)
  229. {
  230. CSingleLock lock(m_section);
  231. if (m_directoryStatus == LOADING && strncmp(job->GetType(), "multiimage", 10) == 0)
  232. {
  233. m_files = ((CMultiImageJob *)job)->m_files;
  234. m_directoryStatus = LOADED;
  235. }
  236. }
  237. void CGUIMultiImage::SetInfo(const GUIINFO::CGUIInfoLabel &info)
  238. {
  239. m_texturePath = info;
  240. if (m_texturePath.IsConstant())
  241. m_currentPath = m_texturePath.GetLabel(WINDOW_INVALID);
  242. }
  243. std::string CGUIMultiImage::GetDescription() const
  244. {
  245. return m_image.GetDescription();
  246. }
  247. CGUIMultiImage::CMultiImageJob::CMultiImageJob(const std::string &path)
  248. : m_path(path)
  249. {
  250. }
  251. bool CGUIMultiImage::CMultiImageJob::DoWork()
  252. {
  253. // check to see if we have a single image or a folder of images
  254. CFileItem item(m_path, false);
  255. item.FillInMimeType();
  256. if (item.IsPicture() || StringUtils::StartsWithNoCase(item.GetMimeType(), "image/"))
  257. {
  258. m_files.push_back(m_path);
  259. }
  260. else
  261. {
  262. // Load in images from the directory specified
  263. // m_path is relative (as are all skin paths)
  264. std::string realPath = CServiceBroker::GetGUI()->GetTextureManager().GetTexturePath(m_path, true);
  265. if (realPath.empty())
  266. return true;
  267. URIUtils::AddSlashAtEnd(realPath);
  268. CFileItemList items;
  269. CDirectory::GetDirectory(realPath, items, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions()+ "|.tbn|.dds", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO);
  270. for (int i=0; i < items.Size(); i++)
  271. {
  272. CFileItem* pItem = items[i].get();
  273. if (pItem && (pItem->IsPicture() || StringUtils::StartsWithNoCase(pItem->GetMimeType(), "image/")))
  274. m_files.push_back(pItem->GetPath());
  275. }
  276. }
  277. return true;
  278. }