vdr 2.7.3
themes.c
Go to the documentation of this file.
1/*
2 * themes.c: Color themes used by skins
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: themes.c 2.2 2012/02/17 13:57:32 kls Exp $
8 */
9
10#include "themes.h"
11#include <dirent.h>
12#include <string.h>
13#include "config.h"
14#include "tools.h"
15
16// --- cTheme ----------------------------------------------------------------
17
19{
20 name = strdup("default");
21 memset(colorNames, 0, sizeof(colorNames));
22 memset(colorValues, 0, sizeof(colorValues));
23 descriptions[0] = strdup("Default");
24}
25
27{
28 free(name);
29 for (int i = 0; i < MaxThemeColors; i++)
30 free(colorNames[i]);
31}
32
33bool cTheme::FileNameOk(const char *FileName, bool SetName)
34{
35 const char *error = NULL;
36 if (!isempty(FileName)) {
37 const char *d = strrchr(FileName, '/');
38 if (d)
39 FileName = d + 1;
40 const char *n = strchr(FileName, '-');
41 if (n) {
42 if (n > FileName) {
43 if (!strchr(++n, '-')) {
44 const char *e = strchr(n, '.');
45 if (e && strcmp(e, ".theme") == 0) {
46 if (e - n >= 1) {
47 // FileName is ok
48 if (SetName) {
49 free(name);
50 name = strndup(n, e - n);
51 }
52 }
53 else
54 error = "missing theme name";
55 }
56 else
57 error = "invalid extension";
58 }
59 else
60 error = "too many '-'";
61 }
62 else
63 error = "missing skin name";
64 }
65 else
66 error = "missing '-'";
67 }
68 else
69 error = "empty";
70 if (error)
71 esyslog("ERROR: invalid theme file name (%s): '%s'", error, FileName);
72 return !error;
73}
74
75const char *cTheme::Description(void)
76{
78 if (!s)
79 s = descriptions[0];
80 return s ? s : name;
81}
82
83bool cTheme::Load(const char *FileName, bool OnlyDescriptions)
84{
85 if (!FileNameOk(FileName, true))
86 return false;
87 bool result = false;
88 if (!OnlyDescriptions)
89 isyslog("loading %s", FileName);
90 FILE *f = fopen(FileName, "r");
91 if (f) {
92 int line = 0;
93 result = true;
94 char *s;
95 const char *error = NULL;
96 cReadLine ReadLine;
97 while ((s = ReadLine.Read(f)) != NULL) {
98 line++;
99 char *p = strchr(s, '#');
100 if (p)
101 *p = 0;
102 s = stripspace(skipspace(s));
103 if (!isempty(s)) {
104 char *n = s;
105 char *v = strchr(s, '=');
106 if (v) {
107 *v++ = 0;
108 n = stripspace(skipspace(n));
109 v = stripspace(skipspace(v));
110 if (strstr(n, "Description") == n) {
111 int lang = 0;
112 char *l = strchr(n, '.');
113 if (l)
114 lang = I18nLanguageIndex(++l);
115 if (lang >= 0) {
116 free(descriptions[lang]);
117 descriptions[lang] = strdup(v);
118 }
119 else
120 error = "invalid language code";
121 }
122 else if (!OnlyDescriptions) {
123 for (int i = 0; i < MaxThemeColors; i++) {
124 if (colorNames[i]) {
125 if (strcmp(n, colorNames[i]) == 0) {
126 char *p = NULL;
127 errno = 0;
128 tColor c = strtoul(v, &p, 16);
129 if (!errno && !*p)
130 colorValues[i] = c;
131 else
132 error = "invalid color value";
133 break;
134 }
135 }
136 else {
137 error = "unknown color name";
138 break;
139 }
140 }
141 }
142 }
143 else
144 error = "missing value";
145 }
146 if (error) {
147 result = false;
148 break;
149 }
150 }
151 if (!result)
152 esyslog("ERROR: error in %s, line %d%s%s", FileName, line, error ? ": " : "", error ? error : "");
153 fclose(f);
154 }
155 else
156 LOG_ERROR_STR(FileName);
157 return result;
158}
159
160bool cTheme::Save(const char *FileName)
161{
162 if (!FileNameOk(FileName))
163 return false;
164 bool result = true;
165 cSafeFile f(FileName);
166 if (f.Open()) {
167 for (int i = 0; i < I18nLanguages()->Size(); i++) {
168 if (descriptions[i])
169 fprintf(f, "Description%s%.*s = %s\n", i ? "." : "", 3, i ? I18nLanguageCode(i) : "", descriptions[i]);
170 }
171 for (int i = 0; i < MaxThemeColors; i++) {
172 if (colorNames[i])
173 fprintf(f, "%s = %08X\n", colorNames[i], colorValues[i]);
174 }
175 if (!f.Close())
176 result = false;
177 }
178 else
179 result = false;
180 return result;
181}
182
183int cTheme::AddColor(const char *Name, tColor Color)
184{
185 for (int i = 0; i < MaxThemeColors; i++) {
186 if (colorNames[i]) {
187 if (strcmp(Name, colorNames[i]) == 0) {
188 colorValues[i] = Color;
189 return i;
190 }
191 }
192 else {
193 colorNames[i] = strdup(Name);
194 colorValues[i] = Color;
195 return i;
196 }
197 }
198 return -1;
199}
200
202{
203 return (Subject >= 0 && Subject < MaxThemeColors) ? colorValues[Subject] : 0;
204}
205
206// --- cThemes ---------------------------------------------------------------
207
208char *cThemes::themesDirectory = NULL;
209
211{
212 numThemes = 0;
213 names = 0;
214 fileNames = NULL;
215 descriptions = NULL;
216}
217
219{
220 Clear();
221}
222
224{
225 for (int i = 0; i < numThemes; i++) {
226 free(names[i]);
227 free(fileNames[i]);
228 free(descriptions[i]);
229 }
230 free(names);
231 free(fileNames);
232 free(descriptions);
233 numThemes = 0;
234 names = 0;
235 fileNames = NULL;
236 descriptions = NULL;
237}
238
239bool cThemes::Load(const char *SkinName)
240{
241 Clear();
242 if (themesDirectory) {
244 struct dirent *e;
245 while ((e = d.Next()) != NULL) {
246 if (strstr(e->d_name, SkinName) == e->d_name && e->d_name[strlen(SkinName)] == '-') {
249 if (Theme.Load(*FileName, true)) {
250 if (char **NewBuffer = (char **)realloc(names, (numThemes + 1) * sizeof(char *))) {
251 names = NewBuffer;
252 names[numThemes] = strdup(Theme.Name());
253 }
254 else {
255 esyslog("ERROR: out of memory");
256 break;
257 }
258 if (char **NewBuffer = (char **)realloc(fileNames, (numThemes + 1) * sizeof(char *))) {
259 fileNames = NewBuffer;
260 fileNames[numThemes] = strdup(*FileName);
261 }
262 else {
263 esyslog("ERROR: out of memory");
264 break;
265 }
266 if (char **NewBuffer = (char **)realloc(descriptions, (numThemes + 1) * sizeof(char *))) {
267 descriptions = NewBuffer;
269 }
270 else {
271 esyslog("ERROR: out of memory");
272 break;
273 }
274 numThemes++;
275 }
276 }
277 }
278 return numThemes > 0;
279 }
280 return false;
281}
282
283int cThemes::GetThemeIndex(const char *Description)
284{
285 int index = 0;
286 for (int i = 0; i < numThemes; i++) {
287 if (strcmp(descriptions[i], Description) == 0)
288 return i;
289 if (strcmp(descriptions[i], "Default") == 0)
290 index = i;
291 }
292 return index;
293}
294
295void cThemes::SetThemesDirectory(const char *ThemesDirectory)
296{
297 free(themesDirectory);
298 themesDirectory = strdup(ThemesDirectory);
300}
301
302void cThemes::Load(const char *SkinName, const char *ThemeName, cTheme *Theme)
303{
304 cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, ThemeName);
305 if (access(FileName, F_OK) == 0) // the file exists
307}
308
309void cThemes::Save(const char *SkinName, cTheme *Theme)
310{
311 cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, Theme->Name());
312 if (access(FileName, F_OK) != 0) // the file does not exist
314}
struct dirent * Next(void)
Definition tools.c:1601
char * Read(FILE *f)
Definition tools.c:1520
bool Open(void)
Definition tools.c:1752
bool Close(void)
Definition tools.c:1762
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1188
const char * Description(void)
Returns a user visible, single line description of this theme.
Definition themes.c:75
const char * Name(void)
Definition themes.h:30
@ MaxThemeColors
Definition themes.h:19
bool Save(const char *FileName)
Saves the theme data to the given file.
Definition themes.c:160
cStringList descriptions
Definition themes.h:22
~cTheme()
Definition themes.c:26
bool FileNameOk(const char *FileName, bool SetName=false)
Definition themes.c:33
char * colorNames[MaxThemeColors]
Definition themes.h:23
int AddColor(const char *Name, tColor Color)
Adds a color with the given Name to this theme, initializes it with Color and returns an index into t...
Definition themes.c:183
tColor Color(int Subject)
Returns the color for the given Subject.
Definition themes.c:201
tColor colorValues[MaxThemeColors]
Definition themes.h:24
char * name
Definition themes.h:21
cTheme(void)
Creates a new theme class.
Definition themes.c:18
bool Load(const char *FileName, bool OnlyDescriptions=false)
Loads the theme data from the given file.
Definition themes.c:83
static void SetThemesDirectory(const char *ThemesDirectory)
Definition themes.c:295
static char * themesDirectory
Definition themes.h:67
int numThemes
Definition themes.h:63
char ** fileNames
Definition themes.h:65
int GetThemeIndex(const char *Description)
Definition themes.c:283
~cThemes()
Definition themes.c:218
cThemes(void)
Definition themes.c:210
void Clear(void)
Definition themes.c:223
bool Load(const char *SkinName)
Definition themes.c:239
static void Save(const char *SkinName, cTheme *Theme)
Definition themes.c:309
char ** names
Definition themes.h:64
char ** descriptions
Definition themes.h:66
const char * FileName(int Index)
Definition themes.h:75
int Size(void) const
Definition tools.h:754
uint32_t tColor
Definition font.h:30
const cStringList * I18nLanguages(void)
Returns the list of available languages.
Definition i18n.c:249
int I18nLanguageIndex(const char *Code)
Returns the index of the language with the given three letter language Code.
Definition i18n.c:276
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition i18n.c:231
const char * I18nLanguageCode(int Language)
Returns the three letter language code of the given Language (which is an index as returned by I18nCu...
Definition i18n.c:271
static cTheme Theme
Definition skinclassic.c:21
bool isempty(const char *s)
Definition tools.c:354
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition tools.c:504
char * stripspace(char *s)
Definition tools.c:224
cString AddDirectory(const char *DirName, const char *FileName)
Definition tools.c:407
#define LOG_ERROR_STR(s)
Definition tools.h:40
char * skipspace(const char *s)
Definition tools.h:244
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36