PageRenderTime 72ms CodeModel.GetById 20ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

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