2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "AddonManager.h"
23 #include "filesystem/File.h"
24 #include "filesystem/SpecialProtocol.h"
25 #include "guilib/WindowIDs.h"
26 #include "utils/URIUtils.h"
27 #include "utils/log.h"
28 #include "utils/StringUtils.h"
29 #include "settings/GUISettings.h"
31 // fallback for new skin resolution code
32 #include "filesystem/Directory.h"
35 using namespace XFILE;
37 #define SKIN_MIN_VERSION 2.1f
39 boost::shared_ptr<ADDON::CSkinInfo> g_SkinInfo;
44 CSkinInfo::CSkinInfo(const AddonProps &props, const RESOLUTION_INFO &resolution)
45 : CAddon(props), m_defaultRes(resolution)
49 CSkinInfo::CSkinInfo(const cp_extension_t *ext)
53 if (CAddonMgr::Get().GetExtElements(ext->configuration, "res", elements))
55 for (ELEMENTS::iterator i = elements.begin(); i != elements.end(); ++i)
57 int width = atoi(CAddonMgr::Get().GetExtValue(*i, "@width"));
58 int height = atoi(CAddonMgr::Get().GetExtValue(*i, "@height"));
59 bool defRes = CAddonMgr::Get().GetExtValue(*i, "@default").Equals("true");
60 CStdString folder = CAddonMgr::Get().GetExtValue(*i, "@folder");
62 CStdStringArray fracs;
63 CStdString strAspect = CAddonMgr::Get().GetExtValue(*i, "@aspect");
64 StringUtils::SplitString(strAspect, ":", fracs);
65 if (fracs.size() == 2)
66 aspect = (float)(atof(fracs[0].c_str())/atof(fracs[1].c_str()));
67 if (width > 0 && height > 0)
69 RESOLUTION_INFO res(width, height, aspect, folder);
70 res.strId = strAspect; // for skin usage, store aspect string in strId
73 m_resolutions.push_back(res);
78 { // no resolutions specified -> backward compatibility
79 CStdString defaultWide = CAddonMgr::Get().GetExtValue(ext->configuration, "@defaultwideresolution");
80 if (defaultWide.IsEmpty())
81 defaultWide = CAddonMgr::Get().GetExtValue(ext->configuration, "@defaultresolution");
82 TranslateResolution(defaultWide, m_defaultRes);
85 CStdString str = CAddonMgr::Get().GetExtValue(ext->configuration, "@effectslowdown");
87 m_effectsSlowDown = (float)atof(str.c_str());
89 m_effectsSlowDown = 1.f;
91 str = CAddonMgr::Get().GetExtValue(ext->configuration, "@debugging");
92 m_debugging = !strcmp(str.c_str(), "true");
94 LoadStartupWindows(ext);
98 CSkinInfo::~CSkinInfo()
104 closestRes(const RESOLUTION_INFO &target) : m_target(target) { };
105 bool operator()(const RESOLUTION_INFO &i, const RESOLUTION_INFO &j)
107 float diff = fabs(i.DisplayRatio() - m_target.DisplayRatio()) - fabs(j.DisplayRatio() - m_target.DisplayRatio());
108 if (diff < 0) return true;
109 if (diff > 0) return false;
110 diff = fabs((float)i.iHeight - m_target.iHeight) - fabs((float)j.iHeight - m_target.iHeight);
111 if (diff < 0) return true;
112 if (diff > 0) return false;
113 return fabs((float)i.iWidth - m_target.iWidth) < fabs((float)j.iWidth - m_target.iWidth);
115 RESOLUTION_INFO m_target;
118 void CSkinInfo::Start()
120 if (!m_resolutions.size())
121 { // try falling back to whatever resolutions exist in the directory
123 CDirectory::GetDirectory(Path(), items, "", DIR_FLAG_NO_FILE_DIRS);
124 for (int i = 0; i < items.Size(); i++)
127 if (items[i]->m_bIsFolder && TranslateResolution(items[i]->GetLabel(), res))
128 m_resolutions.push_back(res);
132 if (!m_resolutions.empty())
134 // find the closest resolution
135 const RESOLUTION_INFO &target = g_graphicsContext.GetResInfo();
136 RESOLUTION_INFO& res = *std::min_element(m_resolutions.begin(), m_resolutions.end(), closestRes(target));
137 m_currentAspect = res.strId;
141 CStdString CSkinInfo::GetSkinPath(const CStdString& strFile, RESOLUTION_INFO *res, const CStdString& strBaseDir /* = "" */) const
143 if (m_resolutions.empty())
144 return ""; // invalid skin
146 CStdString strPathToUse = Path();
147 if (!strBaseDir.IsEmpty())
148 strPathToUse = strBaseDir;
150 // if the caller doesn't care about the resolution just use a temporary
151 RESOLUTION_INFO tempRes;
155 // find the closest resolution
156 const RESOLUTION_INFO &target = g_graphicsContext.GetResInfo();
157 *res = *std::min_element(m_resolutions.begin(), m_resolutions.end(), closestRes(target));
159 CStdString strPath = URIUtils::AddFileToFolder(strPathToUse, res->strMode);
160 strPath = URIUtils::AddFileToFolder(strPath, strFile);
161 if (CFile::Exists(strPath))
164 // use the default resolution
167 strPath = URIUtils::AddFileToFolder(strPathToUse, res->strMode);
168 strPath = URIUtils::AddFileToFolder(strPath, strFile);
172 bool CSkinInfo::HasSkinFile(const CStdString &strFile) const
174 return CFile::Exists(GetSkinPath(strFile));
177 double CSkinInfo::GetMinVersion()
179 return SKIN_MIN_VERSION;
182 void CSkinInfo::LoadIncludes()
184 CStdString includesPath = CSpecialProtocol::TranslatePathConvertCase(GetSkinPath("includes.xml"));
185 CLog::Log(LOGINFO, "Loading skin includes from %s", includesPath.c_str());
186 m_includes.ClearIncludes();
187 m_includes.LoadIncludes(includesPath);
190 void CSkinInfo::ResolveIncludes(TiXmlElement *node, std::map<int, bool>* xmlIncludeConditions /* = NULL */)
192 if(xmlIncludeConditions)
193 xmlIncludeConditions->clear();
195 m_includes.ResolveIncludes(node, xmlIncludeConditions);
198 int CSkinInfo::GetStartWindow() const
200 int windowID = g_guiSettings.GetInt("lookandfeel.startupwindow");
201 assert(m_startupWindows.size());
202 for (vector<CStartupWindow>::const_iterator it = m_startupWindows.begin(); it != m_startupWindows.end(); it++)
204 if (windowID == (*it).m_id)
207 // return our first one
208 return m_startupWindows[0].m_id;
211 bool CSkinInfo::LoadStartupWindows(const cp_extension_t *ext)
213 m_startupWindows.clear();
214 m_startupWindows.push_back(CStartupWindow(WINDOW_HOME, "513"));
215 m_startupWindows.push_back(CStartupWindow(WINDOW_PVR, "19180"));
216 m_startupWindows.push_back(CStartupWindow(WINDOW_PROGRAMS, "0"));
217 m_startupWindows.push_back(CStartupWindow(WINDOW_PICTURES, "1"));
218 m_startupWindows.push_back(CStartupWindow(WINDOW_MUSIC, "2"));
219 m_startupWindows.push_back(CStartupWindow(WINDOW_VIDEOS, "3"));
220 m_startupWindows.push_back(CStartupWindow(WINDOW_FILES, "7"));
221 m_startupWindows.push_back(CStartupWindow(WINDOW_SETTINGS_MENU, "5"));
222 m_startupWindows.push_back(CStartupWindow(WINDOW_WEATHER, "8"));
226 void CSkinInfo::GetSkinPaths(std::vector<CStdString> &paths) const
229 GetSkinPath("Home.xml", &res);
230 if (!res.strMode.empty())
231 paths.push_back(URIUtils::AddFileToFolder(Path(), res.strMode));
232 if (res.strMode != m_defaultRes.strMode)
233 paths.push_back(URIUtils::AddFileToFolder(Path(), m_defaultRes.strMode));
236 bool CSkinInfo::TranslateResolution(const CStdString &name, RESOLUTION_INFO &res)
238 if (name.Equals("pal"))
239 res = RESOLUTION_INFO(720, 576, 4.0f/3, "pal");
240 else if (name.Equals("pal16x9"))
241 res = RESOLUTION_INFO(720, 576, 16.0f/9, "pal16x9");
242 else if (name.Equals("ntsc"))
243 res = RESOLUTION_INFO(720, 480, 4.0f/3, "ntsc");
244 else if (name.Equals("ntsc16x9"))
245 res = RESOLUTION_INFO(720, 480, 16.0f/9, "ntsc16x9");
246 else if (name.Equals("720p"))
247 res = RESOLUTION_INFO(1280, 720, 0, "720p");
248 else if (name.Equals("1080i"))
249 res = RESOLUTION_INFO(1920, 1080, 0, "1080i");
255 int CSkinInfo::GetFirstWindow() const
257 int startWindow = GetStartWindow();
258 if (HasSkinFile("Startup.xml"))
259 startWindow = WINDOW_STARTUP_ANIM;
263 bool CSkinInfo::IsInUse() const
265 // Could extend this to prompt for reverting to the standard skin perhaps
266 return g_guiSettings.GetString("lookandfeel.skin") == ID();
269 const INFO::CSkinVariableString* CSkinInfo::CreateSkinVariable(const CStdString& name, int context)
271 return m_includes.CreateSkinVariable(name, context);
274 } /*namespace ADDON*/