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