- 21-06-2006 fixed: <colordiffuse> didn't work for multiimage.
[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   m_images[image]->SetColourDiffuse(GetColourDiffuse());
156
157   // Scale image so that it will fill our render area
158   if (m_aspectRatio != CGUIImage::ASPECT_RATIO_STRETCH)
159   {
160     // image is scaled so that the aspect ratio is maintained (taking into account the TV pixel ratio)
161     // and so that it fills the allocated space (so is zoomed then cropped)
162     float sourceAspectRatio = (float)m_images[image]->GetTextureWidth() / m_images[image]->GetTextureHeight();
163     float aspectRatio = sourceAspectRatio / g_graphicsContext.GetPixelRatio(g_graphicsContext.GetVideoResolution());
164
165     unsigned int newWidth = m_dwWidth;
166     unsigned int newHeight = (unsigned int)((float)newWidth / aspectRatio);
167     if ((m_aspectRatio == CGUIImage::ASPECT_RATIO_SCALE && newHeight < m_dwHeight) ||
168         (m_aspectRatio == CGUIImage::ASPECT_RATIO_KEEP && newHeight > m_dwHeight))
169     {
170       newHeight = m_dwHeight;
171       newWidth = (unsigned int)((float)newHeight * aspectRatio);
172     }
173     m_images[image]->SetPosition(m_iPosX - (int)(newWidth - m_dwWidth)/2, m_iPosY - (int)(newHeight - m_dwHeight)/2);
174     m_images[image]->SetWidth(newWidth);
175     m_images[image]->SetHeight(newHeight);
176   }
177 }
178
179 void CGUIMultiImage::FreeResources()
180 {
181   for (unsigned int i = 0; i < m_images.size(); ++i)
182   {
183     m_images[i]->FreeResources();
184     delete m_images[i];
185   }
186
187   m_images.clear();
188   m_currentImage = 0;
189   CGUIControl::FreeResources();
190 }
191
192 void CGUIMultiImage::DynamicResourceAlloc(bool bOnOff)
193 {
194   CGUIControl::DynamicResourceAlloc(bOnOff);
195   m_bDynamicResourceAlloc=bOnOff;
196 }
197
198 bool CGUIMultiImage::CanFocus() const
199 {
200   return false;
201 }
202
203 void CGUIMultiImage::SetAspectRatio(CGUIImage::GUIIMAGE_ASPECT_RATIO ratio)
204 {
205   if (m_aspectRatio != ratio)
206   {
207     m_aspectRatio = ratio;
208     m_bInvalidated = true;
209   }
210 }
211
212 CGUIImage::GUIIMAGE_ASPECT_RATIO CGUIMultiImage::GetAspectRatio() const
213
214   return m_aspectRatio;
215 }
216
217 void CGUIMultiImage::LoadDirectory()
218 {
219   // Load any images from our texture bundle first
220   m_files.clear();
221
222   // don't load any images if our path is empty
223   if (m_currentPath.IsEmpty()) return;
224
225   // check to see if we have a single image or a folder of images
226   CFileItem item(m_currentPath, true);
227   if (item.IsPicture())
228   {
229     m_files.push_back(g_TextureManager.GetTexturePath(m_currentPath));
230   }
231   else
232   { // folder of images
233     g_TextureManager.GetBundledTexturesFromPath(m_currentPath, m_files);
234
235     // Load in our images from the directory specified
236     // m_currentPath is relative (as are all skin paths)
237     CStdString realPath = g_TextureManager.GetTexturePath(m_currentPath);
238     CHDDirectory dir;
239     CFileItemList items;
240     dir.GetDirectory(realPath, items);
241     for (int i=0; i < items.Size(); i++)
242     {
243       CFileItem *pItem = items[i];
244       if (pItem->IsPicture())
245         m_files.push_back(pItem->m_strPath);
246     }
247   }
248
249   // sort our images - they'll be randomized in AllocResources() if necessary
250   sort(m_files.begin(), m_files.end());
251
252   // flag as loaded - no point in constantly reloading them
253   m_directoryLoaded = true;
254 }