fixed: thumbnail assignment in video library.
[xbmc:xbmc-antiquated.git] / XBMC / guilib / GUIMultiImage.cpp
1 #include "include.h"
2 #include "../xbmc/FileItem.h"
3 #include "GUIMultiImage.h"
4 #include "TextureManager.h"
5 #include "../xbmc/FileSystem/HDDirectory.h"
6 #include "../xbmc/utils/GUIInfoManager.h"
7 #include "../xbmc/util.h"
8
9 using namespace DIRECTORY;
10
11 CGUIMultiImage::CGUIMultiImage(DWORD dwParentID, DWORD dwControlId, float posX, float posY, float width, float height, const CStdString& strTexturePath, DWORD timePerImage, DWORD fadeTime, bool randomized, bool loop)
12     : CGUIControl(dwParentID, dwControlId, posX, posY, width, height)
13 {
14   m_currentPath = m_texturePath = strTexturePath;
15   CUtil::AddSlashAtEnd(m_currentPath);
16   CUtil::AddSlashAtEnd(m_texturePath);
17   m_currentImage = 0;
18   m_timePerImage = timePerImage;
19   m_fadeTime = fadeTime;
20   m_randomized = randomized;
21   m_loop = loop;
22   m_aspectRatio = CGUIImage::ASPECT_RATIO_STRETCH;
23   ControlType = GUICONTROL_MULTI_IMAGE;
24   m_bDynamicResourceAlloc=false;
25   m_Info = 0;
26   m_directoryLoaded = false;
27 }
28
29 CGUIMultiImage::~CGUIMultiImage(void)
30 {
31 }
32
33 void CGUIMultiImage::Render()
34 {
35   // check if we're hidden, and deallocate + return
36   if (!IsVisible() && m_visible != DELAYED)
37   {
38     if (m_bDynamicResourceAlloc && IsAllocated())
39       FreeResources();
40     return;
41   }
42
43   // check for conditional information before we
44   // alloc as this can free our resources
45   if (m_Info)
46   {
47     CStdString texturePath = g_infoManager.GetImage(m_Info, WINDOW_INVALID);
48     if (texturePath != m_currentPath && !texturePath.IsEmpty())
49     {
50       m_currentPath = texturePath;
51       FreeResources();
52       LoadDirectory();
53     }
54     else if (texturePath.IsEmpty() && m_currentPath != m_texturePath)
55     {
56       m_currentPath = m_texturePath;
57       FreeResources();
58       LoadDirectory();
59     }
60   }
61
62   if (!IsAllocated())
63     AllocResources();
64
65   // if we're delayed, we allocate (above) but there's no need to render.
66   if (m_visible == DELAYED)
67     return CGUIControl::Render();
68
69   if (!m_images.empty())
70   {
71     // Set a viewport so that we don't render outside the defined area
72     g_graphicsContext.SetViewPort(m_posX, m_posY, m_width, m_height);
73     m_images[m_currentImage]->Render();
74
75     unsigned int nextImage = m_currentImage + 1;
76     if (nextImage >= m_images.size())
77       nextImage = m_loop ? 0 : m_currentImage;  // stay on the last image if <loop>no</loop>
78
79     if (nextImage != m_currentImage)
80     {
81       // check if we should be loading a new image yet
82       if (m_imageTimer.IsRunning() && m_imageTimer.GetElapsedMilliseconds() > m_timePerImage)
83       {
84         m_imageTimer.Stop();
85         // grab a new image
86         LoadImage(nextImage);
87         // start the fade timer
88         m_fadeTimer.StartZero();
89       }
90
91       // check if we are still fading
92       if (m_fadeTimer.IsRunning())
93       {
94         // check if the fade timer has run out
95         float timeFading = m_fadeTimer.GetElapsedMilliseconds();
96         if (timeFading > m_fadeTime)
97         {
98           m_fadeTimer.Stop();
99           // swap images
100           m_images[m_currentImage]->FreeResources();
101           m_images[nextImage]->SetAlpha(255);
102           m_currentImage = nextImage;
103           // start the load timer
104           m_imageTimer.StartZero();
105         }
106         else
107         { // perform the fade
108           float fadeAmount = timeFading / m_fadeTime;
109           m_images[nextImage]->SetAlpha((unsigned char)(255 * fadeAmount));
110         }
111         m_images[nextImage]->Render();
112       }
113     }
114     g_graphicsContext.RestoreViewPort();
115   }
116   CGUIControl::Render();
117 }
118
119 bool CGUIMultiImage::OnAction(const CAction &action)
120 {
121   return false;
122 }
123
124 bool CGUIMultiImage::OnMessage(CGUIMessage &message)
125 {
126   if (message.GetMessage() == GUI_MSG_REFRESH_THUMBS)
127   {
128     if (m_Info)
129       FreeResources();
130     return true;
131   }
132   return CGUIControl::OnMessage(message);
133 }
134
135 void CGUIMultiImage::PreAllocResources()
136 {
137   FreeResources();
138 }
139
140 void CGUIMultiImage::AllocResources()
141 {
142   FreeResources();
143   CGUIControl::AllocResources();
144
145   if (!m_directoryLoaded)
146     LoadDirectory();
147
148   // Randomize or sort our images if necessary
149   if (m_randomized)
150     random_shuffle(m_files.begin(), m_files.end());
151
152   for (unsigned int i=0; i < m_files.size(); i++)
153   {
154     CGUIImage *pImage = new CGUIImage(GetParentID(), GetID(), m_posX, m_posY, m_width, m_height, m_files[i]);
155     if (pImage)
156       m_images.push_back(pImage);
157   }
158   // Load in the current image, and reset our timer
159   m_imageTimer.StartZero();
160   m_fadeTimer.Stop();
161   m_currentImage = 0;
162   if (m_images.empty())
163     return;
164
165   LoadImage(m_currentImage);
166 }
167
168 void CGUIMultiImage::LoadImage(int image)
169 {
170   if (image < 0 || image >= (int)m_images.size())
171     return;
172
173   m_images[image]->AllocResources();
174   m_images[image]->SetColorDiffuse(m_diffuseColor);
175
176   // Scale image so that it will fill our render area
177   if (m_aspectRatio != CGUIImage::ASPECT_RATIO_STRETCH)
178   {
179     // image is scaled so that the aspect ratio is maintained (taking into account the TV pixel ratio)
180     // and so that it fills the allocated space (so is zoomed then cropped)
181     float sourceAspectRatio = (float)m_images[image]->GetTextureWidth() / m_images[image]->GetTextureHeight();
182     float aspectRatio = sourceAspectRatio / g_graphicsContext.GetPixelRatio(g_graphicsContext.GetVideoResolution());
183
184     float newWidth = m_width;
185     float newHeight = newWidth / aspectRatio;
186     if ((m_aspectRatio == CGUIImage::ASPECT_RATIO_SCALE && newHeight < m_height) ||
187         (m_aspectRatio == CGUIImage::ASPECT_RATIO_KEEP && newHeight > m_height))
188     {
189       newHeight = m_height;
190       newWidth = newHeight * aspectRatio;
191     }
192     m_images[image]->SetPosition(m_posX - (newWidth - m_width)*0.5f, m_posY - (newHeight - m_height)*0.5f);
193     m_images[image]->SetWidth(newWidth);
194     m_images[image]->SetHeight(newHeight);
195   }
196 }
197
198 void CGUIMultiImage::FreeResources()
199 {
200   for (unsigned int i = 0; i < m_images.size(); ++i)
201   {
202     m_images[i]->FreeResources();
203     delete m_images[i];
204   }
205
206   m_images.clear();
207   m_currentImage = 0;
208   CGUIControl::FreeResources();
209 }
210
211 void CGUIMultiImage::DynamicResourceAlloc(bool bOnOff)
212 {
213   CGUIControl::DynamicResourceAlloc(bOnOff);
214   m_bDynamicResourceAlloc=bOnOff;
215 }
216
217 bool CGUIMultiImage::CanFocus() const
218 {
219   return false;
220 }
221
222 void CGUIMultiImage::SetAspectRatio(CGUIImage::GUIIMAGE_ASPECT_RATIO ratio)
223 {
224   if (m_aspectRatio != ratio)
225   {
226     m_aspectRatio = ratio;
227     m_bInvalidated = true;
228   }
229 }
230
231 void CGUIMultiImage::LoadDirectory()
232 {
233   // Load any images from our texture bundle first
234   m_files.clear();
235
236   // don't load any images if our path is empty
237   if (m_currentPath.IsEmpty()) return;
238
239   // check to see if we have a single image or a folder of images
240   CFileItem item(m_currentPath, true);
241   if (item.IsPicture())
242   {
243     m_files.push_back(g_TextureManager.GetTexturePath(m_currentPath));
244   }
245   else
246   { // folder of images
247     g_TextureManager.GetBundledTexturesFromPath(m_currentPath, m_files);
248
249     // Load in our images from the directory specified
250     // m_currentPath is relative (as are all skin paths)
251     CStdString realPath = g_TextureManager.GetTexturePath(m_currentPath);
252     CHDDirectory dir;
253     CFileItemList items;
254     dir.GetDirectory(realPath, items);
255     for (int i=0; i < items.Size(); i++)
256     {
257       CFileItem *pItem = items[i];
258       if (pItem->IsPicture())
259         m_files.push_back(pItem->m_strPath);
260     }
261   }
262
263   // sort our images - they'll be randomized in AllocResources() if necessary
264   sort(m_files.begin(), m_files.end());
265
266   // flag as loaded - no point in constantly reloading them
267   m_directoryLoaded = true;
268 }